FreeBASIC Manual
------------------------------------------------------------

This document last compiled : 2026/05/14 16:04:19
from https://www.freebasic.net/wiki/


-------------------------------------------------------------- PrintToc ----
Table of Contents

   Welcome to FreeBASIC
   Getting Help with FreeBASIC

Language Documentation

   .
      ...

   _
      __DATE__
      __DATE_ISO__
      __FB_64BIT__
      __FB_ANDROID__
      __FB_ARG_COUNT__
      __FB_ARG_EXTRACT__
      __FB_ARG_LEFTOF__
      __Fb_Arg_Listexpand__
      __FB_ARG_RIGHTOF__
      __FB_ARGC__
      __FB_ARGV__
      __FB_ARM__
      __FB_ASM__
      __FB_BACKEND__
      __FB_BIGENDIAN__
      __FB_BUILD_DATE__
      __FB_BUILD_DATE_ISO__
      __FB_BUILD_FORK_ID__
      __FB_BUILD_SHA1__
      __FB_CYGWIN__
      __FB_DARWIN__
      __FB_DEBUG__
      __FB_DOS__
      __FB_ERR__
      __FB_EVAL__
      __FB_FPMODE__
      __FB_FPU__
      __FB_FREEBSD__
      __FB_GCC__
      __FB_GUI__
      __FB_IIF__
      __FB_JOIN__
      __FB_JS__
      __FB_LANG__
      __FB_LINUX__
      __Fb_Loongarch64__
      __FB_MAIN__
      __FB_MIN_VERSION__
      __FB_MT__
      __FB_NETBSD__
      __FB_OPENBSD__
      __FB_OPTIMIZE__
      __FB_OPTION_BYVAL__
      __FB_OPTION_DYNAMIC__
      __FB_OPTION_ESCAPE__
      __FB_OPTION_EXPLICIT__
      __FB_OPTION_GOSUB__
      __FB_OPTION_PRIVATE__
      __FB_OPTION_PROFILE__
      __FB_OUT_DLL__
      __FB_OUT_EXE__
      __FB_OUT_LIB__
      __FB_OUT_OBJ__
      __FB_PCOS__
      __FB_PPC__
      __FB_PROFILE__
      __Fb_Query_Symbol__
      __FB_QUOTE__
      __Fb_Riscv64__
      __Fb_S390X__
      __FB_SIGNATURE__
      __FB_SSE__
      __FB_UNIQUEID__
      __FB_UNIQUEID_POP__
      __FB_UNIQUEID_PUSH__
      __FB_UNIX__
      __FB_UNQUOTE__
      __FB_VECTORIZE__
      __FB_VER_MAJOR__
      __FB_VER_MINOR__
      __FB_VER_PATCH__
      __FB_VERSION__
      __FB_WIN32__
      __FB_X86__
      __FB_XBOX__
      __FILE__
      __FILE_NQ__
      __FUNCTION__
      __FUNCTION_NQ__
      __LINE__
      __PATH__
      __TIME__

   #
      #assert
      #Cmdline
      #define
      #else
      #elseif
      #elseifdef
      #elseifndef
      #endif
      #endmacro
      #error
      #if
      #ifdef
      #ifndef
      #inclib
      #include
      #lang
      #libpath
      #line
      #macro
      #pragma
      #Pragma Reserve
      #print
      #undef

   $
      $Dynamic
      $Include
      $Lang
      $Static

   ?
      ? (Shortcut For 'Print')
      ? # (Shortcut For 'Print #')
      ? Using (Shortcut For 'Print Using')

   A
      Abs
      Abstract (Member)
      Access
      Acos
      Add (Graphics Put)
      Alias (Name)
      Alias (Modifier)
      Allocate
      Alpha (Graphics Put)
      And
      AndAlso
      And (Graphics Put)
      Any
      Append
      Arraylen
      Arraysize
      As
      Asc
      Asin
      Asm
      Assert
      AssertWarn
      Atan2
      Atn
      Audio

   B
      Balance
      Base (Initialization)
      Base (Member Access)
      Beep
      Bin
      Binary
      Bit
      BitReset
      BitSet
      BLoad
      Boolean
      BSave
      Byref (Parameters)
      Byref (Function Results)
      Byref (Variables)
      Byte
      ByVal

   C
      Call
      CAllocate
      Case
      Cast
      Capture
      CBool
      CByte
      CDbl
      cdecl
      Chain
      Channel
      ChDir
      Chr
      CInt
      Circle
      Class
      Clear
      CLng
      CLngInt
      Close
      Cls
      Color
      Command
      Common
      CondBroadcast
      CondCreate
      CondDestroy
      CondSignal
      CondWait
      Const
      Const (Member)
      Const (Qualifier)
      Constructor
      Constructor (Module)
      Continue
      Cos
      CPtr
      CShort
      CSign
      CSng
      CsrLin
      CUByte
      CUInt
      CULng
      CULngInt
      CUnsg
      CurDir
      CUShort
      Custom (Graphics Put)
      Cva_Arg
      Cva_Copy
      Cva_End
      Cva_List
      Cva_Start
      CVD
      CVI
      CVL
      CVLongInt
      CVS
      CVShort

   D
      Data
      Date
      DateAdd
      DateDiff
      DatePart
      DateSerial
      DateValue
      Day
      Deallocate
      Declare
      DefByte
      DefDbl
      defined
      DefInt
      DefLng
      DefLongInt
      DefShort
      DefSng
      DefStr
      DefUByte
      DefUInt
      Defulongint
      DefUShort
      Delete (Statement)
      Destructor
      Destructor (Module)
      Device
      Dim
      Dir
      Do
      Do...Loop
      Double
      Draw
      Draw String
      DyLibFree
      DyLibLoad
      DyLibSymbol

   E
      Else
      ElseIf
      Encoding
      End (Block)
      End (Statement)
      End If
      Enum
      Environ Statement
      Environ
      Envelope
      Eoc
      EOF
      Eqv
      Erase
      Erfn
      Erl
      Ermn
      Err
      Error
      Event (Message Data From Screenevent)
      Exec
      ExePath
      Exit
      Exp
      Export
      Extends
      Extends Wstring
      Extends Zstring
      Extern
      Extern...End Extern

   F
      False
      Fastcall
      Fb_Memcopy
      fb_MemCopyClear
      Fb_Memmove
      Fbarray (Array Descriptor Structure And Access)
      Fb_No_Gfxlib
      Fb_No_Sfxlib
      Field
      FileAttr
      FileCopy
      FileDateTime
      FileExists
      FileFlush
      FileLen
      FileSetEof
      Fix
      Flip
      For
      For...Next
      Format
      Frac
      Fre
      FreeFile
      Function
      Function (Member)
      Function (Pointer)

   G
      Get (Graphics)
      Get # (File I/O)
      GetJoystick
      GetKey
      GetMouse
      Getxpad
      Generated Sound Commands
      GoSub
      Goto

   H
      Hex
      HiByte
      HiWord
      Hour

   I
      If...Then
      IIf
      ImageConvertRow
      ImageCreate
      ImageDestroy
      ImageInfo
      Imp
      Implements
      Import
      Inkey
      Inp
      Input (Statement)
      Input (File I/O)
      Input #
      Input()
      Instrument
      InStr
      InStrRev
      Int
      Integer
      Is (Select Case)
      Is (Run-Time Type Information Operator)
      IsDate
      IsRedirected

   K
      Kill

   L
      LBound
      LCase
      Left
      Len
      Let
      Lib
      Line
      Line Input
      Line Input #
      LoByte
      LOC
      Local
      Locate
      Lock
      LOF
      Log
      Long
      LongInt
      Loop
      LoWord
      LPos
      LPrint
      LSet
      LTrim

   M
      Midi
      Mid (Statement)
      Mid (Function)
      Minute
      MKD
      MkDir
      MKI
      MKL
      MKLongInt
      MKS
      MKShort
      Mod
      Month
      MonthName
      Music
      MultiKey
      MutexCreate
      MutexDestroy
      MutexLock
      MutexUnlock

   N
      Naked
      Name
      Namespace
      New (Expression)
      New (Placement)
      Next
      Next (Resume)
      Noise
      Note
      Not
      Now

   O
      Object
      Oct
      Octave
      OffsetOf
      On Error
      On...Gosub
      On...Goto
      Once
      Open
      Open Com
      Open Cons
      Open Err
      Open Lpt
      Open Pipe
      Open Scrn
      Open Tcp
      Open Tcp Server
      Operator
      Option()
      Option Base
      Option ByVal
      Option Dynamic
      Option Escape
      Option Explicit
      Option Gosub
      Option Nogosub
      Option NoKeyword
      Option Private
      Option Static
      Or
      Or (Graphics Put)
      OrElse
      Out
      Output
      Overload
      Override

   P
      Paint
      Palette
      Pan
      pascal
      PCopy
      Peek
      Play
      PMap
      Point
      PointCoord
      Pointer
      Poke
      Pos
      Preserve
      PReset
      Print
      Print #
      Print Using
      Private
      Private: (Access Control)
      ProcPtr
      Property
      Protected: (Access Control)
      Pset (Statement)
      Pset (Graphics Put)
      Ptr (Shortcut For 'Pointer')
      Public
      Public: (Access Control)
      Put (Graphics)
      Put # (File I/O)

   R
      Random
      Randomize
      Read
      Read (File Access)
      Read Write (File Access)
      Reallocate
      ReDim
      Rem
      Reset
      Rest
      Restore
      Resume
      Resume Next
      Return (From Procedure)
      Return (From Gosub)
      RGB
      RGBA
      Right
      RmDir
      Rnd
      RSet
      RTrim
      Run

   S
      SAdd
      Scope
      Screen (Graphics)
      Screen (Console)
      ScreenCopy
      ScreenControl
      ScreenEvent
      ScreenGLProc
      ScreenInfo
      ScreenList
      ScreenLock
      ScreenPtr
      ScreenRes
      ScreenSet
      ScreenSync
      ScreenUnlock
      Second
      Seek (Statement)
      Seek (Function)
      Select Case
      SetDate
      SetEnviron
      SetMouse
      SetTime
      Sgn
      Sfx
      Shared
      Shell
      Shl
      Short
      Shr
      Sin
      Single
      SizeOf
      Sleep
      Sound
      Space
      Spc
      Sqr
      Static
      Static (Member)
      stdcall
      Step
      Stick
      Stop
      Str
      Strig
      Stream
      String (Function)
      String
      StrPtr
      Sub
      Sub (Member)
      Sub (Pointer)
      Swap
      System

   T
      Tab
      Tan
      Tcp Accept
      Tempo
      Then
      This
      Thiscall
      ThreadCall
      ThreadCreate
      ThreadDetach
      ThreadSelf
      ThreadWait
      Time
      Timer
      TimeSerial
      TimeValue
      To
      Tone
      Trans (Graphics Put)
      Trim
      True
      Type (Alias)
      Type (Temporary)
      Type (Udt)
      TypeOf

   U
      UBound
      UByte
      UCase
      UInteger
      ULong
      ULongInt
      Union
      Unlock
      Unsigned
      Until
      UShort
      Using (Print)
      Using (Namespaces)

   V
      va_arg
      va_first
      va_next
      Val
      ValLng
      ValInt
      ValUInt
      ValULng
      Var
      VarPtr
      View Print
      View (Graphics)
      Virtual (Member)
      Voice
      Vol
      Volume

   W
      Wait
      Wave
      WBin
      WChr
      Weekday
      WeekdayName
      Wend
      While
      While...Wend
      WHex
      Width
      Window
      WindowTitle
      WInput
      With
      WOct
      Write
      Write #
      Write (File Access)
      WSpace
      WStr
      Wstring (Data Type)
      Wstring (Function)

   X
      Xor
      Xor (Graphics Put)

   Y
      Year

   Z
      ZString
   Operator List

   Variables and Data Types
      Variable Declarations
      User Defined Types
      Standard Data Types
      Standard Data Type Limits
      Converting Between Data Types

   Assignment operators
      Operator =[>] (Assignment)
      Operator &= (Concatenate And Assign)
      Operator += (Add And Assign)
      Operator -= (Subtract And Assign)
      Operator *= (Multiply And Assign)
      Operator /= (Divide And Assign)
      Operator \= (Integer Divide And Assign)
      Operator ^= (Exponentiate And Assign)
      Operator Let (Assignment)
      Operator Let() (Assignment)
      Operator Mod= (Modulus And Assign)
      Operator And= (Conjunction And Assign)
      Operator Eqv= (Equivalence And Assign)
      Operator Imp= (Implication And Assign)
      Operator Or= (Inclusive Disjunction And Assign)
      Operator Xor= (Exclusive Disjunction And Assign)
      Operator Shl= (Shift Left And Assign)
      Operator Shr= (Shift Right And Assign)

   Arithmetic operators
      Operator + (Add)
      Operator - (Subtract)
      Operator * (Multiply)
      Operator / (Divide)
      Operator \ (Integer Divide)
      Operator ^ (Exponentiate)
      Operator Mod (Modulus)
      Operator - (Negate)
      Operator Shl (Shift Left)
      Operator Shr (Shift Right)

   Conditional operators
      Operator = (Equal)
      Operator <> (Not Equal)
      Operator < (Less Than)
      Operator <= (Less Than Or Equal)
      Operator >= (Greater Than Or Equal)
      Operator > (Greater Than)
      Operator Is (Run-Time Type Information)

   Logical operators
      Operator And (Conjunction)
      Operator Eqv (Equivalence)
      Operator Imp (Implication)
      Operator Not (Complement)
      Operator Or (Inclusive Disjunction)
      Operator Xor (Exclusive Disjunction)

   Short circuit operators
      Operator Andalso (Short Circuit Conjunction)
      Operator Orelse (Short Circuit Inclusive Disjunction)

   Indexing operators
      Operator () (Array Index)
      Operator [] (String Index)
      Operator [] (Pointer Index)

   String operators
      Operator + (String Concatenation)
      Operator & (String Concatenation With Conversion)
      Operator Strptr (String Pointer)

   Preprocessor operators
      Operator # (Stringize)
      Operator ## (Concatenation)
      Operator ! (Escaped String Literal)
      Operator $ (Non-Escaped String Literal)

   Pointer operators
      Operator Varptr (Variable Pointer)
      Operator Strptr (String Pointer)
      Operator Procptr (Procedure Pointer And Vtable Index)
      Operator @ (Address Of)
      Operator * (Value Of)

   Type or Class operators
      Operator . (Member Access)
      Operator -> (Pointer To Member Access)
      Operator Is (Run-Time Type Information)

   Memory operators
      Operator New Expression
      Operator New Overload
      Operator Placement New
      Operator Delete Statement
      Operator Delete Overload

   Iterating operators
      Operator For
      Operator Step
      Operator Next
      Operator Precedence
      Bitwise Operators & Truth Tables

   Statements
      Control Flow
      Procedures
      Modularizing

   Other
      Preprocessor
      Escape Sequences In String Literals
      Meta-statements
      Intrinsic Defines
      Error Handling
      Inline Asm

Runtime Library Reference
   Array Functions
   Bit Manipulation
   Console Functions
   Date and Time Functions
   Error Handling Functions
   File IO Functions
   Mathematical Functions
   Memory Functions
   Operating System Functions
   String Functions
   Threading Support Functions
   User Input Functions

Graphics Library Reference
   2D Drawing Functions
   User Input Functions
   Screen Functions
   Supported graphics drivers (backends)
   Keyboard Scan Codes
   Default Palettes

Tutorials

   Getting Started
      Hello World
      FreeBASIC Primer #1

   Source Files
      Source Files (.bas)
      Header Files (.bi)
      Using Prebuilt Libraries
      Manage Reusable Procedures by Including Source vs Compiled Modules

   Lexical Conventions
      Comments
      Identifier Rules
      Literals
      Labels
      Line Continuation
      Line Separator

   Variables and Datatypes
      Constants and Enumerations
      Numeric Types
      Strings (string, zstring, and wstring)
      Coercion and Conversion
      Constants
      Variables

      Arrays
         Overview
         Fixed-length Arrays
         Variable-length Arrays
         Array Indexing
         Passing Arrays to Procedures

      Pointers
         Overview
         Pointer Arithmetic

      References
         From Pointers to References
         Using References

   Declarations
      Implicit Declarations
      Initialization
      Storage Classes
      Variable Scope
      Simple Variable Lifetime vs Scope
      Dynamic Object and Data Lifetime
      Namespaces
      Variable and Procedure Linkage

   User Defined Types
      Overview
      Type Aliases
      Temporary Types
      Type (UDT/Alias/Temporary) and Union
      Constructors and Destructors (basics)
      Member Procedures
      Properties
      Variable-length member data
      Member Access Rights and Encapsulation
      Operator Overloading
      Iterators
      New and Delete
      Types as Objects
      Composition, Aggregation, Inheritance
      Inheritance Polymorphism
      Constructors, '=' Assignment-Operators, and Destructors (advanced, part #1)
      Constructors, '=' Assignment-Operators, and Destructors (advanced, part #2)

   Statements and Expressions
      Differences between Expressions and Statements
      Constant Expressions
      Assignments
      Operator Precedence
      Control Flow Statements

   Procedures
      Procedures Overview
      Passing Arguments to Procedures
      Returning a Value
      Procedure Scopes
      Calling Conventions
      Recursion
      Callback
      Constructors and Destructors
      Pointers to Procedures
      Variadic Arguments

   Graphics
      FreeBASIC GfxLib overview
      Graphics Mode Refresh and Anti-Flickering
      Internal Graphics Formats
      External Graphics File Formats
      Lite regulation function to be integrated into user loop for FPS control
      Fine-grain procedure for waiting and in-loop procedure for fine-regulating FPS

   Multi-Threading
      Overview
      Threads
      Mutual Exclusion
      Conditional Variables
      Critical Sections
      Critical Sections FAQ

   Making Binaries
      Executables
      Static Libraries
      Shared Libraries (DLLs)
      Profiling with fb's profiler
      Profiling for gmon/gprof

   Preprocessor
      Overview
      Conditional Compilation
      Macros

   Other Topics
      ASCII
      Date Serials
      Radians
      Error Handling
      Event Handling
      Intrinsic Defines
      Identifier Look-ups in namespaces and types

   Technical Articles
      Inline Asm
      C Standard Library Functions
      File I/O with FreeBASIC
      Dynamic memory management with FreeBASIC
      Replace Recursion with Iteration
      OBJECT built-in and RTTI info
      Embed and Access binary Data in Executable
      Use Implicit / Overload New([]) and Delete([]) Operators with Inheritance Polymorphism
      Emulate a TLS (Thread Local Storage) and a TP (Thread Pooling) feature

   Community Tutorials

   Community Code Library

External Libraries Index

   Graphical/test-based user interfaces
      CGUI
      Curses
      GTK+
      IUP
      wxC
      Windows API
      X11

   Graphics
      Allegro
      DUGL
      caca
      Cairo
      DISLIN
      freeglut
      FreeImage
      Freetype2
      GD
      GIFLIB
      GLUT
      GLFW
      GRX
      IL (DevIL)
      japi
      jpeglib
      JPGalleg
      libpng
      OpenGL
      PDFlib
      SDL
      TinyPTC

   Music/Sound, Audio/Video
      BASS
      BASSMOD
      Flite
      FMOD
      MediaInfo
      mpg123
      Ogg
      OpenAL
      PortAudio
      sfx
      sndfile
      VLC
      Vorbis

   Database
      GDBM
      MySQL
      PostgreSQL
      SQLite

   Development Helpers
      CUnit
      GDSL
      gettext (includes libintl)
      GNU ASpell
      libbfd

   Embeddable Languages
      JNI
      json-c
      libffi
      libjit
      Lua
      SpiderMonkey

   Cryptography
      cryptlib
      UUID

   Mathematics
      big_int
      Chipmunk
      GMP
      GSL
      Newton
      ODE

   Networking
      cgi-util
      curl
      FastCGI
      ZeroMQ

   eXtensible Markup Language (XML)
      Expat
      libxml
      libxslt
      Mini-XML

   Regular Expressions
      PCRE
      TRE

   Compression
      bzip2
      libzip
      liblzma
      LZO
      QuickLZ
      zlib

   System APIs
      C Runtime Library
      DOS API
      disphelper
      GLib
      Windows API
      X11

Using the FreeBASIC compiler
   Installing FreeBASIC
   Requirements
   Running FreeBASIC
   Using the Command Line

   Command Line Options
      @< file >
      -a < name >
      -arch < type >
      -asm < format >
      -b < name >
      -buildprefix
      -c
      -C
      -d < name=val >
      -dll
      -dylib
      -e
      -earray
      -earraydims
      -eassert
      -edebug
      -edebuginfo
      -elocation
      -entry < name >
      -enullptr
      -eunwind
      -ex
      -exx
      -export
      -forcelang <name>
      -fpmode < type >
      -fpu < type >
      -g
      -gen < backend >
      -i < name >
      -include < name >
      -l < name >
      -lang < name >
      -lib
      -m < name >
      -map < name >
      -maxerr < val >
      -mt
      -nodeflibs
      -nolib < name(s) >
      -noerrline
      -noobjinfo
      -nostrip
      -o < name >
      -O < level >
      -p < name >
      -pic
      -pp
      -prefix < path >
      -print < option >
      -profgen
      -profile
      -r
      -R
      -rr
      -RR
      -s < name >
      -showincludes
      -static
      -strip
      -sysroot < path >
      -t < value >
      -target < platform >
      -v
      -vec < level >
      -version
      -w < value >
      -Wa < opt >
      -Wc < opt >
      -Wl < opt >
      -x < name >
      -z < value >
   Debugging with FreeBASIC
   Compiler Error Messages
   Tools used by fbc
   Installing gcc for -gen gcc

FreeBASIC dialects and QBASIC
   FreeBASIC and Qbasic
   Differences from QB
   FreeBASIC Dialects

FAQs
   Compiler FAQ
   Graphics Library FAQ
   Runtime Library FAQ
   Xbox port FAQ
   DOS related FAQ
   Windows related FAQ
   Linux related FAQ

Miscellaneous
   Obsolete Keywords
   Glossary
   Miscellaneous Keywords
   C Standard Library Functions
   ASCII Character Codes
   Runtime Error Codes
   C/C++ vs. FreeBASIC syntax comparison
   C/C++ vs. FreeBASIC integer data type comparison

Hacking on FreeBASIC
   Developer's Table of Contents

------------------------------------------------------- CompilerWelcome ----
Welcome to FreeBASIC

Welcome to our world!  This page is an overview of our online warehouse of 
knowledge.  Enjoy your surfing and we hope this will be the first of many 
visits.

Introduction
   FreeBASIC is a free, BASIC compiler for Windows (32-bit and 64-bit), 32 
   bit protected-mode DOS (COFF executables, like DJGPP), and Linux (x86, 
   x86_64, and ARM).  It is open source and licensed under the GPL. It is 
   designed to be syntax compatible with QuickBASIC, while expanding on the 
   language and capabilities. It can create programs for MS-Windows, DOS 
   and Linux, and is being ported to other platforms. See About FreeBASIC 
   and Main Features.

Latest Version
   FreeBASIC is a beta release compiler and development is ongoing.  With 
   each full update, many features are added, and bugs from previous 
   releases are fixed.  To see the latest version available, visit 
   the News section on the forum.

Requirements and Installation
   Minimum hardware is listed on the Requirements page.  Visit our 
   Installation page for setting up FreeBASIC on your computer.

Running
   FreeBASIC is a compiler and as such is not packaged with an IDE 
   (Integrated Development Editor), although there are a few IDE's 
   available. For information on using FreeBASIC without an IDE, see Running
   .

Compatibility with QuickBASIC
   FreeBASIC is designed to be syntax compatible with QuickBASIC.  For best 
   code-compatibility with QuickBASIC, the QB dialect can be used when 
   compiling source code. See FreeBASIC Dialects and Differences from QB.

Documentation
   All official documentation can be found online in the wiki at 
   https://www.freebasic.net/wiki.  The online documentation is the most 
   up-to-date resource available.  In all cases it can be regarded as the 
   correct version.  The downloadable versions of the manual are snapshots 
   of the documentation available at a particular time and should be mostly 
   correct for a specific released version of the compiler.  However, we do 
   not maintain multiple versions of the documentation so there may be some 
   discrepancies.

Starting points in the Manual
   * Table of Contents
   * Getting Help with FreeBASIC
   * Programmer's Guide

Starting points on the Web
   * Official Website at https://www.freebasic.net
   * Official Forums at https://www.freebasic.net/forum

Thank you for using FreeBASIC.  Happy coding!



---------------------------------------------------------- CompilerHelp ----
Getting help with FreeBASIC

There are several options available for getting help with FreeBASIC.

The Manual
   This huge user's manual is full of information that can help you learn 
   to write programs using FreeBASIC.  

   The manual is available online at https://www.freebasic.net/wiki.  There 
   is a search box at the top of every page to help you find what you're 
   looking for.

   If you are unfamiliar with FreeBASIC or the documentation, you may find 
   these pages a good place to start:
      * Table of Contents
      * Programmer's Guide
      * Library Headers Index
      * Glossary
      * Compiler FAQ
      * Graphics Library FAQ
      * Runtime Library FAQ

   A downloadable manual (in CHM format) is available from the sourceforge 
   project page at https://sourceforge.net/projects/fbc which features a 
   full table of contents, searching capabilities, an index, plus all the 
   same content as the online version.

   Searching the manual on or offline is an excellent place to start 
   finding help about how to write and use FreeBASIC programs.

Examples and Source Code
   In the ./examples directory located where FreeBASIC was installed on 
   your system are hundreds of examples to be compiled and run.  Most of 
   the external library examples will need additional libraries to be 
   downloaded to allow them to work.  See Library Headers Index for a full 
   list.

Tutorials
   Community created tutorials about FreeBASIC can be found at 
   CommunityTutorials.  Some selected tutorials are included in this 
   manual.

FreeBASIC Forum
   An active community forum can be found at https://www.freebasic.net/forum
   with several sub-forums.  The forum has a search feature that can help 
   you find answers to questions or problems that may have already been 
   asked and solved.  First do a search for your problem, if you can't find 
   the answer then post a message in one of the sub-forums.

Chat
   IRC or Internet Relay Chat is a great way to chat with the developers 
   and other users, some of whom are very knowledgeable.  There are several 
   ways to connect to IRC, if you know what you're doing simply join 
   #freebasic on FreeNode.

   If you haven't the foggiest what IRC is and you have Java installed, you 
   can simply go here.

   If you're trying to get help, the most important thing is to be patient. 
   Sometimes you won't get a reply right away. Stick around or check back 
   and the Community will try and assist you.





============================================================================
  LANGUAGE DOCUMENTATION
  ----------------------



============================================================================
    .

------------------------------------------------------------- KeyPgDots ----
... (Ellipsis)

Used in place of procedure parameter to pass a variable number of 
arguments, or as the upper bound in an array declaration to denote that the 
number of elements will be determined by the initializer.

Syntax
   Declare { Sub | Function } proc_name cdecl ( param_list, ... )  { | [ 
   ByRef ] As return_type }

   #define identifier( [ parameters, ] variadic_parameter... ) body

   Dim array_symbol ([lbound To] ...) [As datatype] => { expression_list }

Description
   Variadic Procedures
      The ellipsis (three dots, ...) is used in procedure declarations and 
      definitions to indicate a variable argument list.

      A first argument (at least) must always be specified and the 
      procedure must be called with the C calling convention cdecl.

      In the procedure body, Cva_List data type, and Cva_Arg macro can be 
      used to expand the ellipsis parameter (...) to obtain the values of 
      the arguments passed to the variadic procedure.  The argument list, 
      once initialized with Cva_Start or copied with Cva_Copy, can be 
      passed to another procedure taking a Cva_List parameter.

      On some targets, for backwards compatibility, va_first, va_arg and 
      va_next can still be used to handle the variable arguments.

      Only numeric types and pointers are supported as variable arguments 
      (all bytes and shorts passed on variable arguments are implicitly 
      converted to integers, all singles passed on variable arguments are 
      implicitly converted to doubles).  Strings can be passed, in which 
      case a ZString Ptr to the string data is taken.

      A variadic procedure name can never be overloaded.

   Variadic Macros
      Using an ellipsis behind the last parameter in a #define or #macro 
      declaration allows creation of a variadic macro. This means it is 
      possible to pass any number of arguments to the variadic_parameter, 
      which can be used in the body as if it was a normal macro parameter. 
      The variadic_parameter will expand to the full list of arguments 
      passed to it, including commas, and can also be completely empty.

      Note: To distinguish between the different arguments passed by 
      variadic_parameter, you can first convert variadic_parameter to a 
      string using the Operator # (Preprocessor Stringize), then 
      differentiate in this string (#variadic_parameter) each passed 
      argument by locating the separators (usually a comma).

   Array Upper Bound
      Using an ellipsis in place of the upper bound in an array declaration 
      causes the upper bound to be set according to the data that appears 
      in the expression_list.  When the ellipsis is used in this manner, an 
      initializer must appear, and cannot be Any.

Example
   Declare Function foo cdecl (x As Integer, ...) As Integer

   Dim As Integer myarray(0 To ...) = {0, 1, 2, 3}
   Print LBound(myarray), UBound(myarray)   '' 0, 3

   '' Using a variadic macro to wrap a variadic function
   #include "crt.bi"
   #define eprintf(Format, args...) fprintf(stderr, Format, args)
   eprintf(!"Hello from printf: %i %s %i\n", 5, "test", 123)

   '' LISP-like accessors allowing to modify comma-separated lists
   #define car(a, b...) a
   #define cdr(a, b...) b

Differences from QB
   * New to FreeBASIC

See also
   * cdecl
   * Cva_List
   * Cva_Arg
   * va_arg
   * va_first
   * va_next
   * Dim
   * Static
   * #define




============================================================================
    _

----------------------------------------------------------- KeyPgDddate ----
__DATE__

Intrinsic define (macro value) set by the compiler

Syntax
   __DATE__

Description
   Substitutes the compiler date in a literal string ("mm-dd-yyyy" format) 
   where used.

Example
   Print "Compile Date: " & __DATE__


   Compile Date: 09-29-2011

Differences from QB
   * New to FreeBASIC

See also
   * __DATE_ISO__
   * __TIME__
   * Date



-------------------------------------------------------- KeyPgDddateiso ----
__DATE_ISO__

Intrinsic define (macro value) set by the compiler

Syntax
   __DATE_ISO__

Description
   Substitutes the compiler date in a literal string ("yyyy-mm-dd" format) 
   where used.  This format is in line with ISO 8601 and can be used for 
   lexicographical date comparisons.

Example
   Print "Compile Date: " & __DATE_ISO__

   If __DATE_ISO__ < "2011-12-25" Then
      Print "Compiled before Christmas day 2011"
   Else
      Print "Compiled after Christmas day 2011"
   End If


   Compile Date: 2011-09-29
   Compiled before Christmas Day 2011

Differences from QB
   * New to FreeBASIC

See also
   * __DATE__
   * __TIME__
   * Date



-------------------------------------------------------- KeyPgDdfb64bit ----
__FB_64BIT__

Intrinsic define set by the compiler

Syntax
   __FB_64BIT__

Description
   Define created at compile time if the the compilation target is 64bit, 
   otherwise undefined.

Example
   #ifdef __FB_64BIT__
     '...instructions for 64bit OSes...
   #else
     '...instructions for other OSes
   #endif 

Differences from QB
   * New to FreeBASIC

See also
   * __FB_LINUX__
   * __FB_FREEBSD__
   * __FB_OPENBSD__
   * __FB_NETBSD__
   * __FB_CYGWIN__
   * __FB_DARWIN__
   * __FB_PCOS__
   * Compiler Option: -target



------------------------------------------------------ KeyPgDdfbandroid ----
__FB_ANDROID__

Intrinsic define set by the compiler

Syntax
   __FB_ANDROID__

Description
   Define without a value created at compile time when targeting android 
   platforms, when the -target android command line option is used. It can 
   be used to compile parts of the program only for a such target.

Example
   #ifdef __FB_ANDROID__
     '...instructions only for android target...
   #else
     '...instructions not for android target...
   #endif 

Version
   * Since fbc 1.20.0

Differences from QB
   * New to FreeBASIC

See also
   * Compiling FB for Android



----------------------------------------------------- KeyPgDdfbargcount ----
__FB_ARG_COUNT__

Intrinsic define (macro) performed by the compiler.

Syntax
   __FB_ARG_COUNT__( args... )

Parameters
   args...
      argument list

Description
   Counts the number of arguments in the argument list (args...) and 
   returns the corresponding value.
   A value is always returned, with 0 corresponding to an empty argument 
   list.

   Because the argument separator is the comma (,), the returned value for 
   a non-empty argument list is the number of main commas (non-nested) plus 
   1.

Example
   #macro m( args... )
      Print __FB_ARG_COUNT__( args )
   #endmacro

   m()
   m(a)
   m(b,c)
   m(,d)
   m(,e,)
   m(,,,)

   Sleep

   /' Output:
    0
    1
    2
    2
    3
    4
   '/
      

   ' macro with a variadic parameter which can contain several sub-parameters:
   '   To distinguish between the different arguments passed by a variadic_parameter,
   '   you can first convert the variadic_parameter to a string using the Operator # (Preprocessor Stringize),
   '   then differentiate in this string (#variadic_parameter) each passed argument by locating the separators (usually a comma)
   '   in a [For...Next] loop based on the number of arguments (__FB_ARG_COUNT__) passed to the macro.

   #macro average(result, arg...)
      Scope
         Dim As String s = #arg
         If s <> "" Then
            result = 0
            For I As Integer = 1 To __FB_ARG_COUNT__( arg ) - 1
               Dim As Integer k = InStr(1, s, ",")
               result += Val(Left(s, k - 1))
               s = Mid(s, k + 1)
            Next I
            result += Val(s)
            result /= __FB_ARG_COUNT__( arg )
         End If
      End Scope
   #endmacro

   Dim As Double result
   average(result, 1, 2, 3, 4, 5, 6)
   Print result

   Sleep

   /' Output :
    3.5
   '/
      

Version
   * Since fbc 1.08.0

Differences from QB
   * New to FreeBASIC

See also
   * __FB_ARG_LEFTOF__
   * __FB_ARG_RIGHTOF__
   * __FB_ARG_EXTRACT__
   * __Fb_Arg_Listexpand__



--------------------------------------------------- KeyPgDdfbargextract ----
__FB_ARG_EXTRACT__

Intrinsic define (macro) performed by the compiler.

Syntax
   __FB_ARG_EXTRACT__( index, args... )

Parameters
   index
      zero-based offset from the first argument (zero or positive integer 
      value)
   args...
      argument list

Description
   Returns the argument from the argument list (args...) corresponding to 
   the index value (index).

   If the requested index value refers to an argument that does not exist 
   in the supplied argument list (index value too large), nothing is 
   returned.

Example
   #print __FB_ARG_EXTRACT__( 1, 7, 89.78, "Postman" )

   /' Compiler output:
   89.78
   '/
      

   '   In this example, the '__FB_EVAL__' is absolutely mandatory in this 'print_last' macro,
   '   because the numeric expression '__FB_ARG_COUNT__( args ) - 1' must be fully evaluated
   '   before being used as the index argument of '__FB_ARG_EXTRACT__'

   #macro print_last( args... )
      #define last_arg_num __FB_EVAL__( __FB_ARG_COUNT__( args ) - 1 )
      #print __FB_ARG_EXTRACT__( last_arg_num, args )
   #endmacro

   print_last( 7, 89.78, "Postman" )

   /' Compiler output:
   Postman
   '/
      

Version
   * Since fbc 1.08.0

Differences from QB
   * New to FreeBASIC

See also
   * __FB_ARG_LEFTOF__
   * __FB_ARG_RIGHTOF__
   * __FB_ARG_COUNT__
   * __Fb_Arg_Listexpand__



---------------------------------------------------- KeyPgDdfbargleftof ----
__FB_ARG_LEFTOF__

Intrinsic define (macro) performed by the compiler.

Syntax
   __FB_ARG_LEFTOF__( arg, sep [, ret] )

Parameters
   arg
      argument
   sep
      separator, obviously different from the comma (,)
   ret
      default return if separator not found

Description
   Returns the left token of the argument (arg), based on the separator (
   sep).
   (in the expression of the argument, the tokens and the separator must be 
   spaced)

   By default, if the default return (ret) is not given, the macro returns 
   nothing (empty token) if the separator (sep) is not found.
   Otherwise, if the default return (ret) is given, the macro returns the 
   default return (ret) if the separator (sep) is not found.

Example
   #macro m( arg )
      Scope
         Var v = __FB_ARG_LEFTOF__( arg, versus, "Not found 'versus'" )
         Print v
      End Scope
   #endmacro

   m(1 versus 2)
   m("left-side" versus "right-side")
   m(3.14 verso pi)

   Sleep

   /' Output:
    1
   left-side
   Not found 'versus'
   '/

   See also __FB_ARG_RIGHTOF__ example.

Version
   * Since fbc 1.08.0

Differences from QB
   * New to FreeBASIC

See also
   * __FB_ARG_RIGHTOF__
   * __FB_ARG_COUNT__
   * __FB_ARG_EXTRACT__
   * __Fb_Arg_Listexpand__



------------------------------------------------ KeyPgDdfbarglistexpand ----
__Fb_Arg_Listexpand__

Intrinsic define (macro) performed by the compiler.

Syntax
   __FB_ARG_LISTEXPAND__( macroname, macroargcount, args... )

Parameters
   macroname
      name of the macro used for extension calls
   macroargcount
      number of parameters for the 'macroname' macro
      expand the parameter list 'args...' according to the 'macroargcount' 
      value:
         - 'macroargcount > 0' : pass 'macroargcount' parameters each time
         - 'macroargcount = 0' : pass all parameters
         - 'macroargcount < 0' : for each parameter passed, the previous 
         'macroargcount' parameters are automatically removed on the next 
         pass
   args...
      argument list

Description
   Expands to one or more 'macroname( .... )' depending on the value of 
   macroargcount and number of arguments in the args... list.

   Returns empty string on invalid index, rather than compile error.

Example
   #macro m( arg... )
      #print "   "##arg
   #endmacro

   #print "macroargcount>0 (=1):"
   __FB_ARG_LISTEXPAND__( m, 1, Hello1, Hello2, Hello3, Hello4)
   #print " "
   #print "macroargcount=0 (=0):"
   __FB_ARG_LISTEXPAND__( m, 0, Hello1, Hello2, Hello3, Hello4)
   #print " "
   #print "macroargcount<0 (=-1):"
   __FB_ARG_LISTEXPAND__( m, -1, Hello1, Hello2, Hello3, Hello4)

   /' Compiler output:
   macroargcount>0 (=1):
      Hello1
      Hello2
      Hello3
      Hello4
    
   macroargcount=0 (=0):
      Hello1, Hello2, Hello3, Hello4
    
   macroargcount<0 (=-1):
      Hello1, Hello2, Hello3, Hello4
      Hello2, Hello3, Hello4
      Hello3, Hello4
      Hello4
   '/

Version
   * Since fbc 1.20.0

Differences from QB
   * New to FreeBASIC

See also
   * __FB_ARG_RIGHTOF__
   * __FB_ARG_LEFTOF__
   * __FB_ARG_COUNT__
   * __FB_ARG_EXTRACT__



--------------------------------------------------- KeyPgDdfbargrightof ----
__FB_ARG_RIGHTOF__

Intrinsic define (macro) performed by the compiler.

Syntax
   __FB_ARG_RIGHTOF__( arg, sep [, ret] )

Parameters
   arg
      argument
   sep
      separator, obviously different from the comma (,)
   ret
      default return if separator not found

Description
   Returns the right token of the argument (arg), based on the separator (
   sep).
   (in the expression of the argument, the tokens and the separator must be 
   spaced)

   By default, if the default return (ret) is not given, the macro returns 
   nothing (empty token) if the separator (sep) is not found.
   Otherwise, if the default return (ret) is given, the macro returns the 
   default return (ret) if the separator (sep) is not found.

Example
   #macro m( arg )
      Scope
         Var v = __FB_ARG_RIGHTOF__( arg, versus, "Not found 'versus'" )
         Print v
      End Scope
   #endmacro

   m(1 versus 2)
   m("left-side" versus "right-side")
   m(pi verso 3.14)

   Sleep

   /' Output:
    2
   right-side
   Not found 'versus'
   '/

   #macro count( range )
      Scope
         Dim x As Integer = __FB_ARG_LEFTOF__( range, To )
         Dim y As Integer = __FB_ARG_RIGHTOF__( range, To )
         Dim s As Integer = Sgn(y - x)
         Print "Counting " & #range
         For i As Integer = x To y Step s
            Print i
         Next i
      End Scope

   #endmacro

   count( 4 To 10 )
   count( 7 To 2 )

   Sleep

   /' Output:
   Counting 4 to 10
    4
    5
    6
    7
    8
    9
    10
   Counting 7 to 2
    7
    6
    5
    4
    3
    2
   '/

Version
   * Since fbc 1.08.0

Differences from QB
   * New to FreeBASIC

See also
   * __FB_ARG_LEFTOF__
   * __FB_ARG_COUNT__
   * __FB_ARG_EXTRACT__
   * __Fb_Arg_Listexpand__



--------------------------------------------------------- KeyPgDdfbargc ----
__FB_ARGC__

Intrinsic define (macro value) set by the compiler

Syntax
   __FB_ARGC__

Description
   Substituted with the number of arguments passed in on the command line 
   including the name of the executable.
   (for example : myprogram parm1, parm2, param3  --> __FB_ARGC__ = 4)

   __FB_ARGC__ is the name of a parameter passed to the program's implicit 
   main function, and therefore is only defined in the module level code of 
   the main module for an application.

Example
   Dim i As Integer
   For i = 0 To __FB_ARGC__ - 1
         Print "arg "; i; " = '"; Command(i); "'"
   Next i

Differences from QB
   * New to FreeBASIC

See also
   * __FB_ARGV__
   * Command



--------------------------------------------------------- KeyPgDdfbargv ----
__FB_ARGV__

Intrinsic define (macro value) set by the compiler

Syntax
   __FB_ARGV__

Description
   Substituted with a pointer to a list of pointers to the zero terminated 
   command line arguments passed in on the command line including the name 
   of the executable.

   __FB_ARGV__ is the name of a parameter passed to the program's implicit 
   main function, and therefore is only defined in the module level code of 
   the main module for an application.

Example
   Sub displayCommandLineArguments( ByVal argc As Integer, ByVal argv As ZString Ptr Ptr )
      Dim i As Integer
      For i = 0 To argc - 1
         Print "arg "; i; " = '"; *argv[i]; "'"
      Next i
   End Sub

   displayCommandLineArguments( __FB_ARGC__, __FB_ARGV__ )

   Sleep

Differences from QB
   * New to FreeBASIC

See also
   * __FB_ARGC__
   * Command



---------------------------------------------------------- KeyPgDdfbarm ----
__FB_ARM__

Intrinsic define set by the compiler

Syntax
   __FB_ARM__

Description
   Define created at compile time if the compilation target uses the ARM 
   CPU architecture, otherwise undefined.

Example
   #ifdef __FB_ARM__
     '...instructions for ARM OSes...
   #else
     '...instructions for other OSes
   #endif 

Differences from QB
   * New to FreeBASIC

See also
   * __FB_X86__
   * __FB_LINUX__
   * __FB_FREEBSD__
   * __FB_OPENBSD__
   * __FB_NETBSD__
   * __FB_CYGWIN__
   * __FB_DARWIN__
   * __FB_PCOS__
   * Compiler Option: -target



---------------------------------------------------------- KeyPgDdfbasm ----
__FB_ASM__

Intrinsic define set by the compiler

Syntax
   __FB_ASM__

Description
   __FB_ASM__ returns a string equal to "intel" or "att" depending on 
   whether inline assembly blocks should use the Intel format or the 
   GCC/AT&T format.

Example
   Dim a As Long
   #if __FB_ASM__ = "intel"
      Asm
          inc dword Ptr [a]
      End Asm
   #else
      Asm
         "incl %0\n" : "+m" (a) : :
      End Asm
   #endif

Version
   * Since fbc 1.02.0

Differences from QB
   * New to FreeBASIC

See also
   * Compiler Option: -asm



------------------------------------------------------ KeyPgDdFBBackend ----
__FB_BACKEND__

Intrinsic define set by the compiler

Syntax
   __FB_BACKEND__

Description
   Defined to either "gas" or "gcc", depending on which backend was 
   specified via -gen.

Example
   Print "Back end is: " & __FB_BACKEND__
      

Differences from QB
   * Did not exist in QB



---------------------------------------------------- KeyPgDdFBBigEndian ----
__FB_BIGENDIAN__

Intrinsic define set by the compiler

Syntax
   __FB_BIGENDIAN__

Description
   Define without a value created at compile time if compiling for a big 
   endian target.

   It can be used to compile parts of the program only if the target is big 
   endian.

Example
   #ifdef __FB_BIGENDIAN__
      '...instructions only for big endian machines
   #else
     '...instructions only for little endian machines
   #endif 

Differences from QB
   * Did not exist in QB



---------------------------------------------------- KeyPgDdFBBuildDate ----
__FB_BUILD_DATE__

Intrinsic define (macro string) set by the compiler

Syntax
   __FB_BUILD_DATE__

Description
   Substituted with the quoted string containing the date (MM-DD-YYYY) the 
   compiler was built on.

Example
      Print "This program compiled with a compiler built on this date:" & __FB_BUILD_DATE__

Differences from QB
   * New to FreeBASIC

See also
   * __FB_BUILD_DATE_ISO__
   * __DATE__
   * __DATE_ISO__



------------------------------------------------- KeyPgDdfbbuilddateiso ----
__FB_BUILD_DATE_ISO__

Intrinsic define (macro string) set by the compiler

Syntax
   __FB_BUILD_DATE_ISO__

Description
   Substituted with the quoted string containing the date (YYYY-MM-DD) the 
   compiler was built on in ISO date format.

Example
      Print "This program compiled with a compiler built on this date:" & __FB_BUILD_DATE_ISO__

Version
   * Since fbc 1.07.1

Differences from QB
   * New to FreeBASIC

See also
   * __FB_BUILD_DATE__
   * __DATE__
   * __DATE_ISO__



-------------------------------------------------- KeyPgDdfbbuildforkid ----
__FB_BUILD_FORK_ID__

Intrinsic define (macro string) set by the compiler

Syntax
   __FB_BUILD_FORK_ID__

Description
   Substituted by a string of the compiler's custom defined project fork 
   identifier name if defined at fbc build time, or an empty string if it 
   was not defined.

   This value is an empty string for releases made by the FreeBASIC 
   Development Team.  Community developers and experimenters may define 
   this value when building their own fbc packages using the makefile to 
   help users identify that fbc may be a special build and may have 
   specific features not in the main release packages.

Example
   Print "fbc fork id: "; __FB_BUILD_FORK_ID__

Version
   * Since fbc 1.20.0

Differences from QB
   * New to FreeBASIC



---------------------------------------------------- KeyPgDdfbbuildsha1 ----
__FB_BUILD_SHA1__

Intrinsic define (macro string) set by the compiler

Syntax
   __FB_BUILD_SHA1__

Description
   Substituted by a string of the compiler's source SHA-1 revision.  The 
   value is set using the SHA-1 commit id of the source code revision used 
   to build the compiler binary, if available.  If the SHA-1 was not 
   available at the time of building the compiler, the value will be an 
   empty string.

Example
   Print __FB_BUILD_SHA1__

Version
   * Since fbc 1.07.1

Differences from QB
   * New to FreeBASIC



------------------------------------------------------- KeyPgDdfbcygwin ----
__FB_CYGWIN__

Intrinsic define set by the compiler

Syntax
   __FB_CYGWIN__

Description
   Define without a value created at compile time in the Cygwin version of 
   the compiler, or when the -target cygwin command line option is used. It 
   can be used to compile parts of the program only if the target is 
   Cygwin.

Example
   #ifdef __FB_CYGWIN__
     '...instructions only for Cygwin...
   #else
     '...instructions not for Cygwin...
   #endif 

Differences from QB
   * New to FreeBASIC

See also
   * __FB_LINUX__
   * __Fb_Win32_
   * __FB_UNIX__
   * Compiler Option: -target



------------------------------------------------------- KeyPgDdfbdarwin ----
__FB_DARWIN__

Intrinsic define set by the compiler

Syntax
   __FB_DARWIN__

Description
   Define without a value created at compile time in the Darwin version of 
   the compiler, or when the -target darwin command line option is used. It 
   can be used to compile parts of the program only if the target is 
   Darwin.

Example
   #ifdef __FB_DARWIN__
     '...instructions only for Darwin...
   #else
     '...instructions not for Darwin...
   #endif 

Differences from QB
   * New to FreeBASIC

See also
   * __FB_LINUX__
   * __FB_WIN32__
   * __FB_UNIX__
   * Compiler Option: -target



-------------------------------------------------------- KeyPgDdfbdebug ----
__FB_DEBUG__

Intrinsic define (macro value) set by the compiler

Syntax
   __FB_DEBUG__

Description
   __FB_DEBUG__ indicates if the the generate debug information option -g 
   or the enable intrinsic define __FB_DEBUG__ option 
   Compiler Option: -edebug was specified on the command line at the time 
   of compilation.

   Returns non-zero (-1) if either option was specified.  Returns zero (0) 
   otherwise.

   __FB_ERR__ can be used to determine in user source code if the -g or 
   -edebug option was specified or implied on the command line.

Example
   #if __FB_DEBUG__ <> 0
         #print Debug mode 
   #else 
         #print Release mode 
   #endif

Differences from QB
   * New to FreeBASIC

See also
   * __FB_ERR__
   * __FB_MT__
   * Compiler Option: -edebug
   * Compiler Option: -g



---------------------------------------------------------- KeyPgDdfbdos ----
__FB_DOS__

Intrinsic define set by the compiler

Syntax
   __FB_DOS__

Description
   Define without a value created at compile time if compiling for the DOS 
   target. Default in the DOS hosted version, or active when the -target dos
   command line option is used. It can be used to compile parts of the 
   program only if the target is DOS. Note: the DOS hosted version cannot 
   compile to other targets than DOS by now.

Example
   #ifdef __FB_DOS__
     ' ... instructions only for DOS ...
     ' ... INT 0x31
   #else
     ' ... instructions not for DOS ...
   #endif 

Differences from QB
   * New to FreeBASIC

See also
   * __FB_LINUX__
   * __FB_WIN32__
   * __FB_PCOS__
   * DOS related FAQ
   * Compiler Option: -target



---------------------------------------------------------- KeyPgDdfberr ----
__FB_ERR__

Intrinsic define (macro value) set by the compiler

Syntax
   __FB_ERR__

Description
   __FB_ERR__ indicates if -e, -ex, or -exx was specified on the compiler 
   command line at the time of compilation of a module.

   __FB_ERR__ indicates if -earray, -enullptr, or -elocation was specified 
   on the compiler command line, or implied by use of -exx, at the time of 
   compilation of a module.

   __FB_ERR__ indicates if -edebug, -edebuginfo, or -eassert was specified 
   on the compiler command line, or implied by use of -g, at the time of 
   compilation of a module.

   __FB_ERR__ indicates if -eunwind was specified on the compiler command 
   line, or implied by use of -e, -ex, or -exx, at the time of compilation 
   of a module.

   __FB_ERR__ indicates if -earraydims was specified on the compiler 
   command line, or implied by use of -exx, at the time of compilation of a 
   module.

   Returns bit-wise OR of the following values:
         +-----+--------------+------------------------------------------+
         |value|flag          |description                               |
         |0    |no flag       |                                          |
         |1    |errorcheck    |implied by '-e', '-ex', '-exx'            |
         |2    |resumeerr     |implied by '-ex', '-exx'                  |
         |4    |extraerrchk   |implied by '-exx'                         |
         |8    |arrayboundchk |implied by '-earray', '-exx'              |
         |16   |nullptrchk    |implied by '-enullptr', '-exx'            |
         |32   |assertions    |implied by '-eassert', '-g'               |
         |64   |debuginfo     |implied by '-edebuginfo', '-g'            |
         |128  |debug         |implied by '-edebug', '-g'                |
         |256  |errlocation   |implied by '-elocation', '-exx'           |
         |512  |unwindinfo    |implied by '-eunwind', '-e', '-ex', '-exx'|
         |1024 |arraydimscheck|implied by '-earraydims', '-exx'          |
         +-----+--------------+------------------------------------------+

   __FB_ERR__ is always defined.

Example
   'Example code to demonstrate a use of __FB_ERR__

   Dim fb_err_value As Integer
   fb_err_value = __FB_ERR__
   If fb_err_value = 0 Then
      Print "no flag enabled"
   Else
      If fb_err_value And 1 Then
         Print "'errorcheck' flag enabled"
      End If
      If fb_err_value And 2 Then
         Print "'resumeerr' flag enabled"
      End If
      If fb_err_value And 4 Then
         Print "'extraerrchk' flag enabled"
      End If
      If fb_err_value And 8 Then
         Print "'arrayboundchk' flag enabled"
      End If
      If fb_err_value And 16 Then
         Print "'nullptrchk' flag enabled"
      End If
      If fb_err_value And 32 Then
         Print "'assertions' flag enabled"
      End If
      If fb_err_value And 64 Then
         Print "'debuginfo' flag enabled"
      End If
      If fb_err_value And 128 Then
         Print "'debug' flag enabled"
      End If
      If fb_err_value And 256 Then
         Print "'errlocation' flag enabled"
      End If
      If fb_err_value And 512 Then
         Print "'unwindinfo' flag enabled"
      End If
      If fb_err_value And 1024 Then
         Print "'arraydimscheck' flag enabled"
      End If
   End If

Version
   * Since fbc 1.20.0: -earraydims indication.
   * Since fbc 1.10.0: -eunwind indication.
   * Since fbc 1.07.0: -earray, -enullptr, -elocation, -edebug, -edebuginfo
     , and -eassert indications.

Differences from QB
   * New to FreeBASIC

See also 
   * __FB_MT__
   * __FB_DEBUG__
   * Compiler Option: -e
   * Compiler Option: -ex
   * Compiler Option: -exx
   * Compiler Option: -eunwind
   * Error Handling



--------------------------------------------------------- KeyPgDdfbeval ----
__FB_EVAL__

Intrinsic define (macro) performed by the compiler.

Syntax
   __FB_EVAL__( arg )

Parameters
   arg
      argument

Description
   Evaluates the argument (constant-expression) at compile time.

   When the argument evaluation produces a string, __FB_EVAL__ returns a 
   string formatted with a preprocessor operator:
      - a Non-Escaped String Literal (of form: $"text"),
      - or an Escaped String Literal (of form: !"text") if needed.
   For other datatypes produced, simple Literals (of Integers, Floating 
   Points, Booleans) without prefix/suffix are returned.

   __FB_EVAL__ macro is useful where there is any of the following:
      - non functional expression (i.e. side-effects),
      - needs to be evaluated (i.e. simplified, respecting the operator 
      precedence) before passing it on,
      - used in a place where fbc would not allow an expression.

Example
   #print 1 + 2
   #print __FB_EVAL__( 1 + 2 )
   #print 4 * Atn(1)
   #print __FB_EVAL__( 4 * Atn(1) )

   /' Compiler output:
   1 + 2
   3
   4 * Atn(1)
   3.141592653589793
   '/
      

   '   In this example, the three '__FB_EVAL__' are absolutely mandatory in this 'assign()' macro.
   '   Even for '__FB_QUOTE__( __FB_EVAL__( expr ) )', because for the case of expr = cos(1/x),
   '   'cos(1/x)' must be properly evaluated before be quoted (after the previous 'assign("x", x+1)'),
   '   otherwise in that case 'cos(1/x+1)' is taken into account (giving 'cos(2)') instead of 'cos(1/(x+1))' (giving 'cos (1/2)')
   '   because the operator precedence is not applied by '__FB_QUOTE__'.

   #macro assign( sym, expr )
      __FB_UNQUOTE__( __FB_EVAL__( "#undef " + sym ) )
      __FB_UNQUOTE__( __FB_EVAL__( "#define " + sym + " " + __FB_QUOTE__( __FB_EVAL__( expr ) ) ) )
   #endmacro

   #define x

   assign( "x", 1 )
   Print x

   assign( "x", x+1 )
   Print x

   assign( "x", Cos(1/x) )
   Print x

   assign( "x", "hello" )
   Print x

   assign( "x", x+x )
   Print x

   /' Output:
    1
    2
    0.877582...
   hello
   hellohello
   '/
      

   See also __FB_ARG_EXTRACT__ example.

Version
   * Since fbc 1.08.0

Differences from QB
   * New to FreeBASIC

See also
   * __FB_QUOTE__
   * __FB_UNQUOTE__



------------------------------------------------------- KeyPgDdfbfpmode ----
__FB_FPMODE__

Intrinsic define set by the compiler

Syntax
   __FB_FPMODE__

Description
   Defined as "fast" if SSE fast arithmetics is enabled, or "precise" 
   otherwise.

Example
   #if __FB_FPMODE__ = "fast"
     ' ... instructions for using fast-mode math ...
   #else
     ' ... instructions for using normal math ...
   #endif

Differences from QB
   * New to FreeBASIC

See also
   * Compiler Option: -fpmode



---------------------------------------------------------- KeyPgDdfbfpu ----
__FB_FPU__

Intrinsic define set by the compiler

Syntax
   __FB_FPU__

Description
   For x86 and x86_64 targets:
      * Defined as "sse" if SSE floating point arithmetics is enabled, and
      * defined as "x87" otherwise

   For arm and aarch64 targets:
      * Defined as "neon" if Advanced SIMD (Neon) extension is enabled, 
        and
      * defined as "x87" otherwise

Example
   #if __FB_FPU__ = "sse"
     ' ... instructions only for SSE ...
   #else
     ' ... instructions not for SSE ...
   #endif

Version
   * __FB_FPU__ = neon added in fbc 1.20.0

Differences from QB
   * New to FreeBASIC

See also
   * __FB_SSE__
   * Compiler Option: -fpu



------------------------------------------------------ KeyPgDdfbfreebsd ----
__FB_FREEBSD__

Intrinsic define set by the compiler

Syntax
   __FB_FREEBSD__

Description
   Define without a value created at compile time in the FreeBSD version of 
   the compiler, or when the -target freebsd command line option is used. 
   It can be used to compile parts of the program only if the target is 
   FreeBSD.

Example
   #ifdef __FB_FREEBSD__
     '...instructions only for FreeBSD...
   #else
     '...instructions not for FreeBSD...
   #endif 

Differences from QB
   * New to FreeBASIC

See also
   * __FB_LINUX__
   * __FB_WIN32__
   * __FB_UNIX__
   * Compiler Option: -target



---------------------------------------------------------- KeyPgDdfbgcc ----
__FB_GCC__

Intrinsic define set by the compiler

Syntax
   __FB_GCC__

Description
   Defined to true (-1) if -gen gcc is used, or false (0) otherwise.

Example
   #if __FB_GCC__ <> 0
         #print Backend Code Emitter And Assembler: gcc
   #else 
         #print Backend Code Emitter And Assembler: Not gcc
   #endif
      

Differences from QB
   * Did not exist in QB



---------------------------------------------------------- KeyPgDdfbgui ----
__FB_GUI__

Intrinsic define (macro value) set by the compiler

Syntax
   __FB_GUI__

Description
   __FB_GUI__ indicates whether GUI subsystem mode is active at the current 
   point in compilation.

   Returns non-zero (-1) if the executable subsystem option -s gui was 
   specified, or if #Pragma Gui is active. Returns zero (0) otherwise.

Example
   #if __FB_GUI__ <> 0
         #print Executable subsystem: gui
   #else 
         #print Executable subsystem: console
   #endif

Version
   * Since fbc 1.06.0

Platform Differences
   * On Windows and Cygwin, this controls the linker subsystem.
   * Other targets may use the same mode value for target-specific startup 
     or runtime behavior.

Differences from QB
   * New to FreeBASIC

See also
   * Compiler Option: -s
   * #pragma



---------------------------------------------------------- KeyPgDdfbiif ----
__FB_IIF__

Intrinsic define (macro) performed by the compiler.

Syntax
   __FB_IIF__( compare-expr, true-expr, false-expr )

Parameters
   compare-expr
      The comparison expression to test.
      A non-zero value evaluates as true, while a value of zero evaluates 
      as false.
   true-expr
      Source code to return if compare-expr is true.
   false-expr
      Source code to return if compare-expr is false.

Description
   __FB_IIF__ returns source code text depending on the result of a 
   comparison expression evaluated at preprocessing-time.
   Its typical use is in the middle of an expression; it avoids splitting 
   it to put a conditional in the middle.

   This intrinsic define (macro) differs from the IIf conditional statement 
   in that __FB_IIF__ is evaluated at compile-time only and returns source 
   code text.  IIf is evaluated at compile-time only if the compare-expr is 
   a constant.  Otherwise IIf expressions are evaluated at run-time.

Example
   ' From the example of the '#ELSE' documentation page:
      '#DEFINE MODULE_VERSION 1
      'Dim a As String
      '#IF (MODULE_VERSION > 0)
      '    a = "Release"
      '#ELSE
      '    a = "Beta"
      '#ENDIF
      'Print "Program is "; a

   ' Simpler code using '__FB_IIF__':
      #define MODULE_VERSION 1
      Dim a As String
      a = __FB_IIF__( MODULE_VERSION > 0, "Release", "Beta" )
      Print "Program is "; a

Version
   * Since fbc 1.10.0

Differences from QB
   * New to FreeBASIC

See also
   * #if
   * #else
   * #endif



--------------------------------------------------------- KeyPgDdfbjoin ----
__FB_JOIN__

Intrinsic define (macro) performed by the compiler.

Syntax
   __FB_JOIN__( arg1, arg2 )

Parameters
   arg1, arg2
      left (1) and right (2) arguments to join

Description
   Joins two token arguments together as one, similar to token pasting 
   operator (##) but more powerfull (will resolve arguments before 
   joining).

Example
   #macro m ( arg1, arg2 )
      #print arg1##arg2
      #print __FB_JOIN__( arg1, arg2 )
   #endmacro

   m(Free, BASIC)

   /' Compiler output:
   FreeBASIC
   FreeBASIC
   '/
      

   #define PREFIX p
   #define SUFFIX _T

   '' this won't work - arguments not expanded
   #define   makename1( x )  PREFIX##x##SUFFIX

   '' this will work - can do this in older versions of fbc too
   #define join( a, b ) a##b
   #define makename2( x ) join( PREFIX, join( x, SUFFIX ) )

   '' built in __FB_JOIN__() -- works pretty much like join() above
   #define   makename3( x )  __FB_JOIN__( PREFIX, __FB_JOIN__( x, SUFFIX ) )

   #macro dump( arg )
      #print #arg
   #endmacro

   dump( makename1(text) )
   dump( makename2(text) )
   dump( makename3(text) )

   /' Compiler output:
   PREFIXtextSUFFIX
   ptext_T
   ptext_T
   '/
      

Version
   * Since fbc 1.08.0

Differences from QB
   * New to FreeBASIC

See also
   * Operator ## (Preprocessor Concatenate)



----------------------------------------------------------- KeyPgDdfbjs ----
__FB_JS__

Intrinsic define set by the compiler

Syntax
   __FB_JS__

Description
   Define without a value created at compile time in the emscripten version 
   of the compiler, when the -target js-asmjs command line option is used. 
   It can be used to compile parts of the program only for a such target.

Example
   #ifdef __FB_JS__
     '...instructions only for emscripten target...
   #else
     '...instructions not for emscripten target...
   #endif 

Differences from QB
   * New to FreeBASIC

See also
   * Compiling FB with Emscripten



--------------------------------------------------------- KeyPgDdfblang ----
__FB_LANG__

Intrinsic define (macro value) set by the compiler

Syntax
   __FB_LANG__

Description
   __FB_LANG__ indicates which language compatibility option was set at the 
   time of compilation of a module.  By default __FB_LANG__ will be set to 
   "fb".  The language compatibility option can be changed using one (or 
   more) of the following methods:
      * -lang command line option
      * -forcelang command line option
      * #lang directive
      * $Lang metacommand

   Returns a lower case string with one of the following values:
         +--------------+----------------------------------------------------------------------------+
         |value         |description                                                                 |
         |''fb''        |FreeBASIC compatibility (default)                                           |
         |''qb''        |QBASIC compatibility                                                        |
         |''fblite''    |FreeBASIC language compatibility, with a more QBASIC-compatible coding style|
         |''deprecated''|FBC version 0.16 compatibility                                              |
         +--------------+----------------------------------------------------------------------------+

   __FB_LANG__ is always defined.

Example
   '' Set option explicit always on

   #ifdef __FB_LANG__
     #if __FB_LANG__ <> "fb"
      Option Explicit
     #endif
   #else
     '' Older version - before lang fb
     Option Explicit
   #endif

Differences from QB
   * New to FreeBASIC

See also 
   * __FB_VERSION__
   * #lang
   * Compiler Option: -lang
   * Compiler Option: -forcelang
   * Compiler Dialects



-------------------------------------------------------- KeyPgDdfblinux ----
__FB_LINUX__

Intrinsic define set by the compiler

Syntax
   __FB_LINUX__

Description
   Define without a value created at compile time when compiling to the 
   Linux target. Default in the Linux hosted version of the compiler, or 
   active when the -target linux command line option is used. It can be 
   used to compile parts of the program only if the target is Linux.

Example
   #ifdef __FB_LINUX__
     ' ... instructions only for Linux ...
     ' ... #libpath "/usr/X11/lib" 
   #else
     ' ... instructions not for Linux ...
   #endif 

Differences from QB
   * New to FreeBASIC

See also
   * __FB_DOS__
   * __FB_WIN32__
   * __FB_UNIX__
   * Compiler Option: -target



-------------------------------------------------- KeyPgDdfbloongarch64 ----
__Fb_Loongarch64__

Intrinsic define set by the compiler

Syntax
   __FB_LOONGARCH64__

Description
   Define created at compile time if the compilation target uses the 64-bit 
   LoongArch CPU architecture, otherwise undefined.

Example
   #ifdef __FB_LOONGARCH64__
     '...instructions for 64-bit LoongArch targets...
   #else
     '...instructions for other targets...
   #endif

Version
   * Since fbc 1.20.1

Differences from QB
   * New to FreeBASIC

See also
   * __FB_64BIT__
   * __FB_LINUX__
   * Compiler Option: -target



--------------------------------------------------------- KeyPgDdFBMain ----
__FB_MAIN__

Intrinsic define set by the compiler

Syntax
   __FB_MAIN__

Description
   __FB_MAIN__ is defined in the main module and not defined in other 
   modules.

   The main module is determined by the compiler as either the first source 
   file listed on the command line or explicitly named using the -m option 
   on the command line.

Example
   #ifdef __FB_MAIN__
     #print Compiling the main module
   #else
     #print Compiling an additional module
   #endif

Differences from QB
   * New to FreeBASIC

See also
   * Compiler Option: -m
   * #ifdef
   * #ifndef



--------------------------------------------------- KeyPgDdFBMinVersion ----
__FB_MIN_VERSION__

Macro function to test minimum compiler version

Syntax
   #define __FB_MIN_VERSION__( major, minor, patch) _
      ((__FB_VER_MAJOR__ > major) or _
      ((__FB_VER_MAJOR__ = major) and ((__FB_VER_MINOR__ > minor) or _
      (__FB_VER_MINOR__ = minor and __FB_VER_PATCH__ >= patch_level))))

Usage
   __FB_MIN_VERSION__( major, minor, patch)

Parameters
   major
      minimum major version to test
   minor
      minimum minor version to test
   patch
      minimum patch version to test

Return Value
   Returns zero (0) if the compiler version is less than the specified 
   version, or non-zero (-1) if the compiler version is greater than or 
   equal to specified version

Description
   __FB_MIN_VERSION__ tests for a minimum version of the compiler.

Example
   #if Not __FB_MIN_VERSION__(0, 18, 2)
       #error fbc must be at least version 0.18.2 To compile This module
   #endif

Differences from QB
   * New to FreeBASIC

See also
   * #if



----------------------------------------------------------- KeyPgDdfbmt ----
__FB_MT__

Intrinsic define (macro value) set by the compiler

Syntax
   __FB_MT__

Description
   __FB_MT__ indicates if the the multithreaded option -mt was specified on 
   the command line at the time of compilation, or whether one of the 
   Threadtcreate or ThreadCall keywords is used more above in the source 
   code.

   Returns non-zero (-1) if the option was specified.  Returns zero (0) 
   otherwise.

Example
   #if __FB_MT__ 
         #print Using multi-threaded library
   #else
         #print Using Single-threaded library
   #endif

Differences from QB
   * New to FreeBASIC

See also 
   * __FB_DEBUG__
   * Compiler Option: -mt



------------------------------------------------------- KeyPgDdfbnetbsd ----
__FB_NETBSD__

Intrinsic define set by the compiler

Syntax
   __FB_NETBSD__

Description
   Define without a value created at compile time in the NetBSD version of 
   the compiler, or when the -target netbsd command line option is used. It 
   can be used to compile parts of the program only if the target is NetBSD
   .

Example
   #ifdef __FB_NETBSD__
     '...instructions only for NetBSD...
   #else
     '...instructions not for NetBSD...
   #endif 

Differences from QB
   * New to FreeBASIC

See also
   * __FB_LINUX__
   * __FB_WIN32__
   * __FB_UNIX__
   * Compiler Option: -target



------------------------------------------------------ KeyPgDdfbopenbsd ----
__FB_OPENBSD__

Intrinsic define set by the compiler

Syntax
   __FB_OPENBSD__

Description
   Define without a value created at compile time in the OpenBSD version of 
   the compiler, or when the -target openbsd command line option is used. 
   It can be used to compile parts of the program only if the target is 
   OpenBSD.

Example
   #ifdef __FB_OPENBSD__
     '...instructions only for OpenBSD...
   #else
     '...instructions not for OpenBSD...
   #endif 

Differences from QB
   * New to FreeBASIC

See also
   * __FB_LINUX__
   * __FB_WIN32__
   * __FB_UNIX__
   * Compiler Option: -target



----------------------------------------------------- KeyPgDdfboptimize ----
__FB_OPTIMIZE__

Intrinsic define set by the compiler

Syntax
   __FB_OPTIMIZE__

Description
   Always defined and will have a value from 0 to 3 (0 by default) to 
   indicate the optimization level passed to the backend compiler via -O.

Example
   Print "Optimization level is: " & __FB_OPTIMIZE__
      

Version
   * Since fbc 1.09.0

Differences from QB
   * Did not exist in QB

See also
   * Compiler Option: -O



-------------------------------------------------- KeyPgDdfboptionbyval ----
__FB_OPTION_BYVAL__

Intrinsic define (macro value) set by the compiler

Syntax
   __FB_OPTION_BYVAL__

Description
   Indicates if parameters to a Function or Sub are passed by reference as 
   with ByRef, or by value as with ByVal by default when the by value / by 
   reference specifier is not explicitly stated.

   __FB_OPTION_BYVAL__ is set to non-zero (-1) if by default parameters are 
   passed value, and zero (0) if by default parameters are passed by 
   reference.

   The default for passing parameters by reference or by value is 
   determined by the -lang command line option used during compilation or 
   usage of Option ByVal in the source file.

Example
   #if( __FB_OPTION_BYVAL__ <> 0 )
     #error Option ByVal must Not be used With This source
   #endif

Differences from QB
   * New to FreeBASIC

See also 
   * ByVal
   * ByRef
   * Option ByVal



------------------------------------------------ KeyPgDdfboptiondynamic ----
__FB_OPTION_DYNAMIC__

Intrinsic define (macro value) set by the compiler

Syntax
   __FB_OPTION_DYNAMIC__

Description
   __FB_OPTION_DYNAMIC__ is defined as true (negative one (-1)) if a recent 
   Option Dynamic statement or '$Dynamic meta-command was issued. 
   Otherwise, it is defined as zero (0).

Example
   #if __FB_OPTION_DYNAMIC__ <> 0
   #error This module must Not use Option Dynamic
   #endif

Differences from QB
   * New to FreeBASIC

See also 
   * Option Dynamic
   * Option Static



------------------------------------------------- KeyPgDdfboptionescape ----
__FB_OPTION_ESCAPE__

Intrinsic define (macro value) set by the compiler

Syntax
   __FB_OPTION_ESCAPE__

Description
   Indicates if by default, string literals are processed for escape 
   characters when not explicitly prefixed with the $ Operator for 
   non-escaped strings, or the ! Operator for escaped strings.

   The default method for processing string literals is set by usage of the 
   -lang command line option during compilation or usage of Option Escape 
   in the source file.

   __FB_OPTION_ESCAPE__ returns zero (0) if the option has not been set.  
   Returns non-zero (-1) if the option has been set.

Example
   #if( __FB_OPTION_ESCAPE__ <> 0 )
     #error Option Escape must Not be used With This include file
   #endif

Differences from QB
   * New to FreeBASIC

See also 
   * Option Escape



----------------------------------------------- KeyPgDdfboptionexplicit ----
__FB_OPTION_EXPLICIT__

Intrinsic define (macro value) set by the compiler

Syntax
   __FB_OPTION_EXPLICIT__

Description
   __FB_OPTION_EXPLICIT__ indicates if Option Explicit has been used 
   previously in the source.  

   Returns zero (0) if the option has not been set.  Returns non-zero (-1) 
   if the option has been set.

Example
   #if( __FB_OPTION_EXPLICIT__ = 0 )
     #error Option Explicit must used With This module
   #endif

Differences from QB
   * New to FreeBASIC

See also 
   * Dim
   * Option Explicit



-------------------------------------------------- KeyPgDdfboptiongosub ----
__FB_OPTION_GOSUB__

Intrinsic define (macro value) set by the compiler

Syntax
   __FB_OPTION_GOSUB__

Description
   Indicates how GoSub and Return will be handled at compile time. If the 
   option is set (-1) then GoSub is allowed and Return is recognized as 
   return-from-gosub only.  If the option is not set (0) then GoSub is not 
   allowed and Return is recognized as return-from-procedure only.

   This macro value can be changed at compile time.  Option Gosub will set 
   the option (enable gosub support) and Option Nogosub will clear the 
   option (disable gosub support).

   __FB_OPTION_GOSUB__ returns zero (0) if the option has not been set.  
   Returns non-zero (-1) if the option has been set.

Example
   #if( __FB_OPTION_GOSUB__ <> 0 )
      '' turn off gosub support
      Option nogosub
   #endif

Dialect Differences
   * Defaults to -1 in the -lang qb dialect and 0 in all other dialects.

Differences from QB
   * New to FreeBASIC

See also 
   * Option Gosub
   * Option Nogosub



------------------------------------------------ KeyPgDdfboptionprivate ----
__FB_OPTION_PRIVATE__

Intrinsic define (macro value) set by the compiler

Syntax
   __FB_OPTION_PRIVATE__

Description
   Indicates if by default Function's and Sub's have module scope or global 
   scope when not explicitly specified with Private or Public.

   The default scope specifier for functions and subs is set by usage of 
   the -lang command line option during compilation or usage of 
   Option Private in the source file.

   Default scope of procedures can be changed during compilation with 
   #Pragma Private.

   __FB_OPTION_PRIVATE__ returns zero (0) if the option has not been set.  
   Returns non-zero (-1) if the option has been set.

Example
   #if( __FB_OPTION_PRIVATE__ <> 0 )
     #error Option Private must Not be used With This module
   #endif

Differences from QB
   * New to FreeBASIC

See also 
   * Option Private
   * Private
   * Public



------------------------------------------------ KeyPgDdfboptionprofile ----
__FB_OPTION_PROFILE__

Intrinsic define set by the compiler

Syntax
   __FB_OPTION_PROFILE__

Description
   Intrinsic define set to an integer to indicate that the profiling code 
   is generated:
      __FB_OPTION_PROFILE__ is set to non-zero when profiling code is 
      generated
      __FB_OPTION_PROFILE__ is set to zero when profiling code is not 
      generated

   #Pragma Profile allows to control the generation of profiling code.
   This allows optionally including or excluding sections of source code to 
   be profiled:
      when #pragma profile = true, then profiling code is generated
      when #pragma profile = false, then profiling code is not generated

Example
   #cmdline "-profgen fb"
   ' profiling code generated
   Print __FB_OPTION_PROFILE__

   #pragma profile = False
   ' profiling code not generated
   Print __FB_OPTION_PROFILE__

   #pragma profile = True
   ' profiling code generated
   Print __FB_OPTION_PROFILE__

Version
   * Since fbc 1.20.0

Differences from QB
   * New to FreeBASIC

See also
   * Compiler Option: -profgen
   * Profiling for gmon/gprof
   * Profiling with fb's profiler
   * #pragma



------------------------------------------------------- KeyPgDdfboutdll ----
__FB_OUT_DLL__

Intrinsic define (macro value) set by the compiler

Syntax
   __FB_OUT_DLL__

Description
   __FB_OUT_DLL__ indicates that the specified output file type on the 
   compiler command line at the time of compilation is a shared library.

   Returns non-zero (-1) if the output is a shared library.  Returns zero 
   (0) otherwise.

   Only one of __FB_OUT_DLL__, __FB_OUT_EXE__, __FB_OUT_LIB__, or 
   __FB_OUT_OBJ__ will evaluate to non-zero (-1).  All others will evaluate 
   to zero (0).

Example
   #if __FB_OUT_DLL__ 
         '... specific instructions when making a shared library (DLL)
   #else
         '... specific instructions when not making a shared library (DLL)
   #endif   

Differences from QB
   * New to FreeBASIC

See also 
   * __FB_OUT_EXE__
   * __FB_OUT_LIB__
   * __FB_OUT_OBJ__
   * Compiler Option: -dll



------------------------------------------------------- KeyPgDdfboutexe ----
__FB_OUT_EXE__

Intrinsic define (macro value) set by the compiler

Syntax
   __FB_OUT_EXE__

Description
   __FB_OUT_EXE__ indicates that the specified output file type on the 
   compiler command line at the time of compilation is an executable.

   Returns non-zero (-1) if the output is an executable.  Returns zero (0) 
   otherwise.

   Only one of __FB_OUT_DLL__, __FB_OUT_EXE__, __FB_OUT_LIB__, or 
   __FB_OUT_OBJ__ will evaluate to non-zero (-1).  All others will evaluate 
   to zero (0).

Example
   #if __FB_OUT_EXE__ 
         '... specific instructions when making an executable
   #else
         '... specific instructions when not making an executable
   #endif

Differences from QB
   * New to FreeBASIC

See also 
   * __FB_OUT_DLL__
   * __FB_OUT_LIB__
   * __FB_OUT_OBJ__



------------------------------------------------------- KeyPgDdfboutlib ----
__FB_OUT_LIB__

Intrinsic define (macro value) set by the compiler

Syntax
   __FB_OUT_LIB__

Description
   __FB_OUT_LIB__ indicates that the specified output file type on the 
   compiler command line at the time of compilation is a static library.

   Returns non-zero (-1) if the output is a static library.  Returns zero 
   (0) otherwise.

   Only one of __FB_OUT_DLL__, __FB_OUT_EXE__, __FB_OUT_LIB__, or 
   __FB_OUT_OBJ__ will evaluate to non-zero (-1).  All others will evaluate 
   to zero (0).

Example
   #if __FB_OUT_LIB__ 
         '... specific instructions when making a static library
   #else
         '... specific instructions when not making a static library
   #endif

Differences from QB
   * New to FreeBASIC

See also 
   * __FB_OUT_EXE__
   * __FB_OUT_DLL__
   * __FB_OUT_OBJ__
   * Compiler Option: -lib



------------------------------------------------------- KeyPgDdfboutobj ----
__FB_OUT_OBJ__

Intrinsic define (macro value) set by the compiler

Syntax
   __FB_OUT_OBJ__

Description
   __FB_OUT_OBJ__ indicates that the specified output file type on the 
   compiler command line at the time of compilation is an object module.

   Returns non-zero (-1) if the output is an object module.  Returns zero 
   (0) otherwise.

   Only one of __FB_OUT_DLL__, __FB_OUT_EXE__, __FB_OUT_LIB__, or 
   __FB_OUT_OBJ__, will evaluate to non-zero (-1).  All others will 
   evaluate to zero (0).

Example
   #if __FB_OUT_OBJ__ 
         '... specific instructions when compiling to an object file only
   #else
         '... specific instructions when not compiling to an object file only
   #endif

Differences from QB
   * New to FreeBASIC

See also 
   * __FB_OUT_EXE__
   * __FB_OUT_DLL__
   * __FB_OUT_LIB__



--------------------------------------------------------- KeyPgDdfbpcos ----
__FB_PCOS__

Intrinsic define set by the compiler

Syntax
   __FB_PCOS__

Description
   Define created at compile time if the OS has filesystem behavior styled 
   like common PC OSes, e.g. DOS, Windows, OS/2, Symbian OS, possibly 
   others. Drive letters, backslashes, that stuff, otherwise undefined.

Example
   #ifdef __FB_PCOS__
     '...instructions for PC-ish OSes...
   #else
     '...instructions for other OSes
   #endif 

Differences from QB
   * New to FreeBASIC

See also
   * __FB_WIN32__
   * __FB_DOS__
   * __FB_XBOX__
   * __FB_UNIX__
   * Compiler Option: -target



---------------------------------------------------------- KeyPgDdfbppc ----
__FB_PPC__

Intrinsic define set by the compiler

Syntax
   __FB_PPC__

Description
   Define created at compile time if the compilation target uses the 
   PowerPC CPU architecture, otherwise undefined.

Example
   #ifdef __FB_PPC__
     '...instructions for PowerPC OSes...
   #else
     '...instructions for other OSes
   #endif 

Version
   * Since fbc 1.09.0

Differences from QB
   * New to FreeBASIC

See also
   * Compiler Option: -target



------------------------------------------------------ KeyPgDdfbprofile ----
__FB_PROFILE__

Intrinsic define set by the compiler

Syntax
   __FB_PROFILE__

Description
   Intrinsic define set to an integer to indicate the profiling method.
   The different value are defined in the ./inc/fbc-int/profile.bi include 
   file (inside Namespace: FB and Enum: PROFGEN_ID):
      * PROFGEN_ID_NONE: profiling is not enabled
      * PROFGEN_ID_GMON: code is being generated for gmon/gprof
      * PROFGEN_ID_CALLS: code is being generated for fb's function call 
        profiler
      * PROFGEN_ID_CYCLES: code is being generated for fb's cycle count 
        call profiler

Example
   #cmdline "-profgen fb"
   #include Once "fbc-int/profile.bi"
   Using FBC

   Print "__FB_PROFILE__ = ";

   Select Case __FB_PROFILE__
   Case PROFGEN_ID_NONE
      Print "PROFGEN_ID_NONE"
   Case PROFGEN_ID_GMON
      Print "PROFGEN_ID_GMON"
   Case PROFGEN_ID_CALLS
      Print "PROFGEN_ID_CALLS"
   Case PROFGEN_ID_CYCLES
      Print "PROFGEN_ID_CYCLES"
   End Select

Version
   * Since fbc 1.20.0

Differences from QB
   * New to FreeBASIC

See also
   * Compiler Option: -profgen
   * Profiling for gmon/gprof
   * Profiling with fb's profiler



-------------------------------------------------- KeyPgDdfbquerysymbol ----
__Fb_Query_Symbol__

Intrinsic define (macro) performed by the compiler, and its associated 
sub-macros.

Syntax
   __FB_QUERY_SYMBOL__( what, sym )

Usage
   The ./inc/fbc-int/symbol.bi header exposes internals of the fbc compiler 
   through the built-in macro __FB_QUERY_SYMBOL__.

   In addition, many convenient sub-macros with 'is' as name prefix (also 
   defined in the file ./inc/fbc-int/symbol.bi) help the user to indirectly 
   call the generic built-in macro __FB_QUERY_SYMBOL__:

      #include once "fbc-int/symbol.bi"
      using FBC

      ' then:
         Dim b As Boolean
         ...
         b = isXXXXX( sym )

Parameters
   sym
      symbol name to query
   b
      boolean to store the return value from the macro
   XXXXX
      body of the sub-macro name standing the kind of query

Description
   __FB_QUERY_SYMBOL__ is a generic built-in macro for querying fbc symbol 
   internals.

   In the file ./inc/fbc-int/symbol.bi, many convenient and specialized 
   sub-macros with 'is' as name prefix ('isXXXXX') are also defined (where 
   'XXXXX' stands for the kind of query).
   They help the user to indirectly call the generic built-in macro 
   __FB_QUERY_SYMBOL__ without knowing the encoding of its first parameter 
   and its return value, but passing the only sym parameter to those 
   sub-macros which only return -1 (for True) or 0 (for False).

   For three of the query types, convenient and specialized sub-macros are 
   available:
      - 'class of symbols' (like variable, constant, procedure, namespace, 
      ...),
      - 'class of data' (like integer, float, string, UDT, ...),
      - 'type of data' (like boolean, byte, ubyte, short, ...).
   in order to test whether a symbol matches an element of the considered 
   family.

Example
   Using convenient sub-macros from the ./inc/fbc-int/symbol.bi file 
   (indirectly calling __FB_QUERY_SYMBOL__)
   #include Once "fbc-int/symbol.bi"
   Using FBC

   Type T
      i As Integer
   End Type
   Dim x As T

   Print isUDT( T )       '' returns -1 (true)
   Print isVariable( T )  '' returns 0 (false)
   Print isUDT( x )       '' returns 0 (false)
   Print isVariable( x )  '' returns -1 (true)

   Sleep

   Using directly __FB_QUERY_SYMBOL__ and some declarations from the 
   ./inc/fbc-int/symbol.bi file to output the data class of a symbol:
   #include Once "fbc-int/symbol.bi"
   Using FBC

   Function dataclassToStr( ByVal classid As fbc.FB_DATACLASS ) As String
      Static As ZString Ptr classnames _
         ( FB_DATACLASS.FB_DATACLASS_INTEGER To FB_DATACLASS.FB_DATACLASS_UDT ) _
         = { @"integer", @"float", @"string", @"udt" }
         
      Select Case classid
      Case LBound(classnames) To UBound(classnames)
         Return *classnames(classid)
      Case Else
         Return "*invalid*"
      End Select
   End Function

   #macro show_dataclass( sym )
      Scope
         Var classid = __FB_QUERY_SYMBOL__( FB_QUERY_SYMBOL.dataclass, sym )
         Print Left( "   [" & classid & "] " & dataclassToStr(classid) + Space(16), 16 ) & ": ";
         Print #sym  
      End Scope
   #endmacro

   Dim As Byte b
   Dim As Double d
   Dim As String s

   Type T
      Dim As Long l
   End Type
   Dim As T t1

   Print "EXAMPLES OF '__FB_QUERY_SYMBOL__( FB_QUERY_SYMBOL.dataclass, sym )':"

   show_dataclass( b )
   show_dataclass( d )
   show_dataclass( s )
   show_dataclass( T )
   show_dataclass( T.l )
   show_dataclass( t1 )
   show_dataclass( t1.l )

   Sleep

   Using directly __FB_QUERY_SYMBOL__ and some declarations from the 
   ./inc/fbc-int/symbol.bi file to output the typename as text, the 
   typename as text with special characters replaced with '_', and the 
   decorated (mangled) type name (WIP), of a symbol:
   #include Once "fbc-int/symbol.bi"
   Using FBC

   Namespace NS
      Type T
         Dim As Const String Const Ptr Ptr pps
      End Type
   End Namespace

   #print TypeOf(NS.T.pps)

   Print "type name    : " & __FB_QUOTE__( __FB_QUERY_SYMBOL__( FB_QUERY_SYMBOL.typename, NS.T.pps ) )
   Print "type name id : " & __FB_QUOTE__( __FB_QUERY_SYMBOL__( FB_QUERY_SYMBOL.typenameid, NS.T.pps ) )
   Print "mangled type : " & __FB_QUOTE__( __FB_QUERY_SYMBOL__( FB_QUERY_SYMBOL.mangletype, NS.T.pps ) )

   Sleep

Version
   * Since fbc 1.20.0 : __FB_QUERY_SYMBOL__ extended to return mangled 
     names
   * Since fbc 1.10.0

Differences from QB
   * New to FreeBASIC



-------------------------------------------------------- KeyPgDdfbquote ----
__FB_QUOTE__

Intrinsic define (macro) performed by the compiler.

Syntax
   __FB_QUOTE__( arg )

Parameters
   arg
      argument

Description
   Converts the argument to a string, similar to stringize operator (#) but 
   can be used anywhere (will expand the argument before conversion).
   More precisely, __FB_QUOTE__ returns an over-quoted text (prefixed with 
   the Operator $ (Non-Escaped String Literal)) compared to the one passed 
   through the argument (the argument may already be a string, and so the 
   return will be an over-quoted string in this case).

Example
   #macro m( arg )
      Scope
         Dim s1 As String = #arg
         Print s1
         Dim s2 As String = __FB_QUOTE__( arg )
         Print s2
      End Scope
   #endmacro

   m(Hello)
   Print
   m("Hello")

   Sleep

   /' Output:
   Hello
   Hello

   "Hello"
   "Hello"
   '/
      

   #macro m( arg1, arg2 )
      Scope
         'Dim s0 As String = #arg1##arg2  ' does not work because arg1##arg2 is not developped before applying #
         Dim s1 As String = #arg1###arg2  ' workaround because #arg => $"arg" and not only "arg"
                                  '    (otherwise the result would be "arg1""arg2" => "arg1"arg2")
         Print s1
         Dim s2 As String = __FB_QUOTE__( arg1##arg2 )
         Print s2
      End Scope
   #endmacro

   m(Free, BASIC)

   Sleep

   /' Output:
   FreeBASIC
   FreeBASIC
   '/
      

   See also __FB_UNQUOTE__ example.

Version
   * Since fbc 1.08.0

Differences from QB
   * New to FreeBASIC

See also
   * __FB_UNQUOTE__
   * __FB_EVAL__



------------------------------------------------------ KeyPgDdfbriscv64 ----
__Fb_Riscv64__

Intrinsic define set by the compiler

Syntax
   __FB_RISCV64__

Description
   Define created at compile time if the compilation target uses the 64-bit 
   RISC-V CPU architecture, otherwise undefined.

Example
   #ifdef __FB_RISCV64__
     '...instructions for 64-bit RISC-V targets...
   #else
     '...instructions for other targets...
   #endif

Version
   * Since fbc 1.20.1

Differences from QB
   * New to FreeBASIC

See also
   * __FB_64BIT__
   * __FB_LINUX__
   * Compiler Option: -target



-------------------------------------------------------- KeyPgDdfbs390x ----
__Fb_S390X__

Intrinsic define set by the compiler

Syntax
   __FB_S390X__

Description
   Define created at compile time if the compilation target uses the s390x 
   CPU architecture, otherwise undefined.

Example
   #ifdef __FB_S390X__
     '...instructions for s390x targets...
   #else
     '...instructions for other targets...
   #endif

Version
   * Since fbc 1.20.1

Differences from QB
   * New to FreeBASIC

See also
   * __FB_BIGENDIAN__
   * __FB_64BIT__
   * __FB_LINUX__
   * Compiler Option: -target



---------------------------------------------------- KeyPgDdfbsignature ----
__FB_SIGNATURE__

Intrinsic define (macro string) set by the compiler

Syntax
   __FB_SIGNATURE__

Description
   Substituted by a signature of the compiler where used.

Example
   Print __FB_SIGNATURE__


   FreeBASIC 0.21.1

Differences from QB
   * New to FreeBASIC

See also
   * __FB_VERSION__
   * __FB_WIN32__
   * __FB_LINUX__
   * __FB_DOS__



---------------------------------------------------------- KeyPgDdfbsse ----
__FB_SSE__

Intrinsic define set by the compiler

Syntax
   __FB_SSE__

Description
   Define without a value created at compile time if SSE floating point 
   arithmetics is enabled.

Example
   #ifdef __FB_SSE__
     ' ... instructions only for SSE ...
   #else
     ' ... instructions not for SSE ...
   #endif

Differences from QB
   * New to FreeBASIC

See also
   * __FB_FPU__
   * Compiler Option: -fpu



----------------------------------------------------- KeyPgDdfbuniqueid ----
__FB_UNIQUEID__

Intrinsic define (macro) performed by the compiler.

Syntax
   __FB_UNIQUEID__( stack-id )

Parameters
   stack-id
      the name of the stack to access

Description
   Gets the identifier at the top of stack identified by stack-id (the size 
   of the stack is not modified).
   (__FB_UNIQUEID_PUSH__ allows to push a new unique identifier on to the 
   stack, and __FB_UNIQUEID_POP__ allows to pop an identifier off of the 
   stack)

   Note:
      - The 'stack-id' name itself is a separate namespace from all other 
      symbols.
      - The stack can only contain 'unique identifiers'.
      - 'unique identifier' is a name of an fb symbol that is unique to the 
      module, so does not conflict or shadow other symbol names ('unique 
      identifier' will have the form 'LT_xxxx' as a name so it might not be 
      completely unique).
      - fb uses the form 'LT_xxxx' internally for labels, symbols, temp 
      variables, etc (so should avoid naming fbc symbols of this form for 
      any fbc program since version 0.0).

   __FB_UNIQUEID__ simply expands to unquoted text. So the name, for 
   example 'Lt_0004', can be used wherever an fb symbol is required (a 
   variable, procedure name, type name, etc.).
   __FB_UNIQUEID__ returns an unquoted empty string when the stack is empty 
   or has never been filled.

Example
   __FB_UNIQUEID_PUSH__( stk )
   #print __FB_UNIQUEID__( stk )

      __FB_UNIQUEID_PUSH__( stk )
      #print __FB_UNIQUEID__( stk )

         __FB_UNIQUEID_PUSH__( stk )
         #print __FB_UNIQUEID__( stk )
         __FB_UNIQUEID_POP__( stk )

      #print __FB_UNIQUEID__( stk )
      __FB_UNIQUEID_POP__( stk )

   #print __FB_UNIQUEID__( stk )
   __FB_UNIQUEID_POP__( stk )

   /' Compiler output example:
   Lt_0006
   Lt_0007
   Lt_0008
   Lt_0007
   Lt_0006
   '/
      

   See also __FB_UNIQUEID_PUSH__ and __FB_UNIQUEID_POP__ examples.

Version
   * Since fbc 1.08.0

Differences from QB
   * New to FreeBASIC

See also
   * __FB_UNIQUEID_PUSH__
   * __FB_UNIQUEID_POP__



-------------------------------------------------- KeyPgDdfbuniqueidpop ----
__FB_UNIQUEID_POP__

Intrinsic define (macro) performed by the compiler.

Syntax
   __FB_UNIQUEID_POP__( stack-id )

Parameters
   stack-id
      the name of the stack to pop

Description
   Pops an identifier off of stack identified by stack-id (the size of the 
   stack is decreased by 1).
   (__FB_UNIQUEID__ allows to get the identifier at the top of the stack, 
   and __FB_UNIQUEID_PUSH__ allows to push a new unique identifier on to 
   the stack)

   Note:
      - The "stack-id" name itself is a separate namespace from all other 
      symbols.
      - The stack can only contain "unique identifiers".
      - "unique identifier" is a name of an fb symbol that is unique to the 
      module, so does not conflict or shadow other symbol names ("unique 
      identifier" will have the form "LT_xxxx" as a name so it might not be 
      completely unique).
      - fb uses the form "LT_xxxx" internally for labels, symbols, temp 
      variables, etc (so should avoid naming fbc symbols of this form for 
      any fbc program since version 0.0).

   When such a stack is no longer in use, it is recommended that it be 
   empty (at the end there must have been applied as many 
   __FB_UNIQUEID_POP__ as __FB_UNIQUEID_PUSH__ for this stack).
   At any time of its use, the number of __FB_UNIQUEID_POP__ applied from 
   the beginning must always be less than or equal to the number of 
   __FB_UNIQUEID_PUSH__ applied.

Example
   See also __FB_UNIQUEID__ example.

   #macro repeat ? ( count )  '' with user named variable
      Scope
         Dim __counter__ As UInteger = count
         While( __counter__)
   #endmacro

   #macro end_repeat  '' with user named variable
            __counter__ -= 1
         Wend
      End Scope   
   #endmacro

   Print "With user named variable:"
   repeat 3
      Print "   outer"
      repeat 2
         Print "   --- inner"
      end_repeat
   end_repeat
   Print

   #undef repeat
   #undef end_repeat

   #macro repeat ? ( count )  '' with "unique identifier" variable
      __FB_UNIQUEID_PUSH__( ctx )
      Dim __FB_UNIQUEID__( ctx ) As UInteger = count
      While( __FB_UNIQUEID__( ctx ) )
   #endmacro

   #macro end_repeat  '' with "unique identifier" variable
         __FB_UNIQUEID__( ctx ) -= 1
      Wend
      __FB_UNIQUEID_POP__( ctx )
   #endmacro

   Print "With ""unique identifier"" variable:"
   repeat 3
      Print "   outer"
      repeat 2
         Print "   --- inner"
      end_repeat
   end_repeat

   Sleep

   /' Output:
   With user named variable:
      outer
      --- inner
      --- inner
      outer
      --- inner
      --- inner
      outer
      --- inner
      --- inner

   With "unique identifier" variable:
      outer
      --- inner
      --- inner
      outer
      --- inner
      --- inner
      outer
      --- inner
      --- inner
   '/
      
The first part of code works, because the '__counter__' variable is defined 
in a [Scope...End Scope] block and therefore allows nesting.
   The second part of code works (without [Scope...End Scope] block) 
   because of using a "unique identifier" (provided by the compiler).

   See also __FB_UNIQUEID_PUSH__ example.

Version
   * Since fbc 1.08.0

Differences from QB
   * New to FreeBASIC

See also
   * __FB_UNIQUEID_PUSH__
   * __FB_UNIQUEID__



------------------------------------------------- KeyPgDdfbuniqueidpush ----
__FB_UNIQUEID_PUSH__

Intrinsic define (macro) performed by the compiler.

Syntax
   __FB_UNIQUEID_PUSH__( stack-id )

Parameters
   stack-id
      the name of the stack to push

Description
   Pushes a new unique identifier on to a stack identified by stack-id (the 
   size of the stack is increased by 1).
   (__FB_UNIQUEID__ allows to get the identifier at the top of the stack, 
   and __FB_UNIQUEID_POP__ allows to pop an identifier off of the stack)

   Note:
      - The "stack-id" name itself is a separate namespace from all other 
      symbols.
      - The stack can only contain "unique identifiers".
      - "unique identifier" is a name of an fb symbol that is unique to the 
      module, so does not conflict or shadow other symbol names ("unique 
      identifier" will have the form "LT_xxxx" as a name so it might not be 
      completely unique).
      - fb uses the form "LT_xxxx" internally for labels, symbols, temp 
      variables, etc (so should avoid naming fbc symbols of this form for 
      any fbc program since version 0.0).

   When such a stack is no longer in use, it is recommended that it be 
   empty (at the end there must have been applied as many 
   __FB_UNIQUEID_POP__ as __FB_UNIQUEID_PUSH__ for this stack).
   At any time of its use, the number of __FB_UNIQUEID_POP__ applied from 
   the beginning must always be less than or equal to the number of 
   __FB_UNIQUEID_PUSH__ applied.

Example
   See also __FB_UNIQUEID__ example.

   ' As the "unique identifiers" (used as jump labels) are successively pushed on to a stack,
   ' the jump-code bodies must be defined in the reversed order than the jump calls.

   #macro go
      __FB_UNIQUEID_PUSH__( stk )
      Goto __FB_UNIQUEID__( stk )
      End If
   #endmacro

   #macro end_go
      __FB_UNIQUEID__( stk ):
      __FB_UNIQUEID_POP__( stk )
   #endmacro
      
   Dim As Integer N

   Do
      Input "Enter a value between 1 and 4 (0 or empty input for exit) ? ", N
      
      If N = 0 Then go
      If N = 1 Then go
      If N = 2 Then go
      If N = 3 Then go
      If N = 4 Then go
      Continue Do
      
      end_go
         Print "You entered 4" : Continue Do
      end_go
         Print "You entered 3" : Continue Do
      end_go
         Print "You entered 2" : Continue Do
      end_go
         Print "You entered 1" : Continue Do
      end_go
         Print "End"           : Exit Do
   Loop

   Sleep
      

   See also __FB_UNIQUEID_POP__ example.

Version
   * Since fbc 1.08.0

Differences from QB
   * New to FreeBASIC

See also
   * __FB_UNIQUEID_POP__
   * __FB_UNIQUEID__



--------------------------------------------------------- KeyPgDdfbunix ----
__FB_UNIX__

Intrinsic define set by the compiler

Syntax
   __FB_UNIX__

Description
   Define created at compile time if the OS is reasonably enough like UNIX 
   that you can call it UNIX, otherwise undefined.

Example
   #ifdef __FB_UNIX__
     '...instructions for UNIX-family OSes...
   #else
     '...instructions for other OSes
   #endif 

Differences from QB
   * New to FreeBASIC

See also
   * __FB_LINUX__
   * __FB_FREEBSD__
   * __FB_OPENBSD__
   * __FB_NETBSD__
   * __FB_CYGWIN__
   * __FB_DARWIN__
   * __FB_PCOS__
   * Compiler Option: -target



------------------------------------------------------ KeyPgDdfbunquote ----
__FB_UNQUOTE__

Intrinsic define (macro) performed by the compiler.

Syntax
   __FB_UNQUOTE__( arg )

Parameters
   arg
      argument

Description
   Takes a literal string and converts it back to tokens.
   More precisely, __FB_UNQUOTE__ returns a sub-quoted text compared to the 
   one passed through the argument (the argument may already be an 
   over-quoted string, and so the return will be a simple string in this 
   case).

Example
   #macro m( arg )
      Scope
         Var v1 = arg
         #print TypeOf(v1)
         Print v1
         Var v2 = __FB_UNQUOTE__( arg )
         #print TypeOf(v2)
         Print v2
      End Scope
   #endmacro

   m("""Hello""")
   m("1")

   Sleep

   /' Compiler output:
   STRING
   STRING
   STRING
   INTEGER
   '/

   /' Output:
   "Hello"
   Hello
   1
    1
   '/
      

   #define X __FB_QUOTE__( Print "hello" )
   #macro Y( arg )
     __FB_UNQUOTE__( arg )
   #endmacro

   Print X
   Y( X )

   /' Output:
   print "hello"
   hello
   '/
      

Version
   * Since fbc 1.08.0

Differences from QB
   * New to FreeBASIC

See also
   * __FB_QUOTE__
   * __FB_EVAL__



---------------------------------------------------- KeyPgDdfbvectorize ----
__FB_VECTORIZE__

Intrinsic define set by the compiler

Syntax
   __FB_VECTORIZE__

Description
   Defined as the vectorisation level number set by the -vec command-line 
   option.

Example
   #if __FB_VECTORIZE__ = 2
     ' ... instructions only for vectorization level 2...
   #else
     ' ...
   #endif

Differences from QB
   * New to FreeBASIC

See also
   * Compiler Option: -vec



----------------------------------------------------- KeyPgDdFBVerMajor ----
__FB_VER_MAJOR__

Intrinsic define (macro value) set by the compiler

Syntax
   __FB_VER_MAJOR__

Description
   __FB_VER_MAJOR__ will return the major version of FreeBASIC currently 
   being used.  For example, the major version is 0 for FreeBASIC 0.90, and 
   will remain 0 until FreeBASIC version 1.0 is released.

Example
   Dim fbMajorVersion As Integer
   Dim fbMinorVersion As Integer
   Dim fbPatchVersion As Integer

   fbMajorVersion = __FB_VER_MAJOR__
   fbMinorVersion = __FB_VER_MINOR__
   fbPatchVersion = __FB_VER_PATCH__

   Print "Welcome to FreeBASIC " & fbMajorVersion & "." & fbMinorVersion & "." & fbPatchVersion

Differences from QB
   * New to FreeBASIC

See also
   * __FB_VER_MINOR__
   * __FB_VER_PATCH__



----------------------------------------------------- KeyPgDdFBVerMinor ----
__FB_VER_MINOR__

Intrinsic define (macro value) set by the compiler

Syntax
   __FB_VER_MINOR__

Description
   __FB_VER_MINOR__ will return the minor version of FreeBASIC currently 
   being used. For FreeBASIC version 0.90.1, for example, the minor version 
   number is 90.

Example
   Dim fbMajorVersion As Integer
   Dim fbMinorVersion As Integer
   Dim fbPatchVersion As Integer

   fbMajorVersion = __FB_VER_MAJOR__
   fbMinorVersion = __FB_VER_MINOR__
   fbPatchVersion = __FB_VER_PATCH__

   Print "Welcome to FreeBASIC " & fbMajorVersion & "." & fbMinorVersion & "." & fbPatchVersion

Differences from QB
   * New to FreeBASIC

See also 
   * __FB_VER_MAJOR__
   * __FB_VER_PATCH__



----------------------------------------------------- KeyPgDdFBVerPatch ----
__FB_VER_PATCH__

Intrinsic define (macro value) set by the compiler

Syntax
   __FB_VER_PATCH__

Description
   __FB_VER_PATCH__ will return the patch/subversion/revision number the 
   version of FreeBASIC currently being used. For FreeBASIC 0.18, for 
   example, there were subversions 1, 2, 3, 4, 5 and 6, resulting in 
   versions 0.18.1 through 0.18.6.

Example
   Dim fbMajorVersion As Integer
   Dim fbMinorVersion As Integer
   Dim fbPatchVersion As Integer

   fbMajorVersion = __FB_VER_MAJOR__
   fbMinorVersion = __FB_VER_MINOR__
   fbPatchVersion = __FB_VER_PATCH__

   Print "Welcome to FreeBASIC " & fbMajorVersion & "." & fbMinorVersion & ", revision " & fbPatchVersion

Differences from QB
   * New to FreeBASIC

See also 
   * __FB_VER_MAJOR__
   * __FB_VER_MINOR__



------------------------------------------------------ KeyPgDdfbversion ----
__FB_VERSION__

Intrinsic define (macro string) set by the compiler

Syntax
    __FB_VERSION__

Description
    Substituted by the version number of the compiler where used.

Example
   #if __FB_VERSION__ < "0.18" 
   #error  Please compile With FB version 0.18 Or above 
   #endif

   This will stop the compilation if the compiler version is below 0.18

Differences from QB
   * Did not exist in QB

See also
   * __FB_SIGNATURE__
   * __FB_WIN32__
   * __FB_LINUX__
   * __FB_DOS__



-------------------------------------------------------- KeyPgDdfbwin32 ----
__FB_WIN32__

Intrinsic define set by the compiler

Syntax
   __FB_WIN32__

Description
   Define without a value created at compile time if compiling to the Win 
   (32-bit or 64-bit) target. Default in Win hosted version, or active if 
   the -target win32 or -target win64 command line option is used. It can 
   be used to compile parts of the program only if the target is Win.

Example
   #ifdef __FB_WIN32__
     ' ... instructions only for Win ...
     ' ... GetProcAddress ...
   #else
     ' ... instructions not for Win ...
   #endif 

Differences from QB
   * New to FreeBASIC

See also
   * __FB_DOS__
   * __FB_LINUX__
   * __FB_PCOS__
   * Compiler Option: -target



---------------------------------------------------------- KeyPgDdfbx86 ----
__FB_X86__

Intrinsic define set by the compiler

Syntax
   __FB_X86__

Description
   Define created at compile time if the compilation target uses the X86 or 
   X86_64 CPU architecture, otherwise undefined.

Example
   #ifdef __FB_X86__
     '...instructions for X86 OSes...
   #else
     '...instructions for other OSes
   #endif 

Version
   * Since fbc 1.08.0

Differences from QB
   * New to FreeBASIC

See also
   * __FB_ARM__
   * Compiler Option: -target



--------------------------------------------------------- KeyPgDdfbxbox ----
__FB_XBOX__

Intrinsic define set by the compiler

Syntax
   __FB_XBOX__

Description
   Define without a value created at compile time when the -target xbox 
   command line option is used. It can be used to compile parts of the 
   program only if the target is Xbox.

Example
   #ifdef __FB_XBOX__
     '...instructions only for Xbox...
   #else
     '...instructions not for Xbox...
   #endif 

Differences from QB
   * New to FreeBASIC

See also
   * __FB_LINUX__
   * __FB_WIN32__
   * Compiler Option: -target



----------------------------------------------------------- KeyPgDdfile ----
__FILE__

Intrinsic define (macro string) set by the compiler

Syntax
   __FILE__

Description
   Substituted with the quoted source file name where used.

   An example of normal use is to report wrong values in debugging.

Example
   Dim a As Integer
   If a<0 Then
      Print "Error: a = " & a & " in " & __FILE__ & " (" & __FUNCTION__ & ") line " & __LINE__
   End If


   Error: a = -32767 in test.bas (MAIN) Line 47

Differences from QB
   * Did not exist in QB

See also
   * __FILE_NQ__
   * __FUNCTION__
   * __LINE__



--------------------------------------------------------- KeyPgDdfilenq ----
__FILE_NQ__

Intrinsic define (macro string) set by the compiler

Syntax
   __FILE_NQ__

Description
   Substituted with the non-quoted source file name where used.

Example
   #print __FILE_NQ__

Differences from QB
   * New to FreeBASIC

See also
   * __FILE__
   * __FUNCTION_NQ__
   * __LINE__



------------------------------------------------------- KeyPgDdfunction ----
__FUNCTION__

Intrinsic define (macro string) set by the compiler

Syntax
   __FUNCTION__

Description
   Substituted with the quoted name of the current function block where 
   used.

   Its normal use is to report wrong values in debugging.

   If __FUNCTION__ is used at the module level, the function name given 
   will be "__FB_MAINPROC__" for the main module, or "__FB_MODLEVELPROC__" 
   for a different module.

Example
   Dim a As Integer

   '...

   If a < 0 Then '' this shouldn't happen
      Print "Error: a = " & a & " in " & __FILE__ & " (" & __FUNCTION__ & ") line " & __LINE__
   End If


   Error: a = -32767 in test.bas (__FB_MAINPROC__) Line 47

Differences from QB
   * Did not exist in QB

See also
   * __FILE__
   * __FUNCTION_NQ__
   * __LINE__



----------------------------------------------------- KeyPgDdfunctionnq ----
__FUNCTION_NQ__

Intrinsic define (macro string) set by the compiler

Syntax
   __FUNCTION_NQ__

Description
   Substituted with the non-quoted name of the current function block where 
   used.

   If __FUNCTION_NQ__ is used at the module level, the function name given 
   will be __FB_MAINPROC__ for the main module, or __FB_MODLEVELPROC__ for 
   a different module.  This is not the actual function name though, so 
   it's not as useful there.

Example
   Sub MySub
     Print "Address of " + __FUNCTION__ + " is ";
     Print Hex( @__FUNCTION_NQ__ )
   End Sub

   MySub


   Address of MYSUB Is 4012D0

Differences from QB
   * Did not exist in QB

See also
   * __FILE_NQ__
   * __FUNCTION__
   * __LINE__



----------------------------------------------------------- KeyPgDdline ----
__LINE__

Intrinsic define (macro value) set by the compiler

Syntax
   __LINE__

Description
   Substituted with the current line number of the source file where used.

   Its normal use is to report wrong values in debugging.

Example
   Dim a As Integer

   If a < 0 Then 
      Print "Error: a = " & a & " in " & __FILE__ & " (" & __FUNCTION__ & ") line " & __LINE__
   End If


   Error: a = -32767 in test.bas (MAIN) Line 47

Differences from QB
   * Did not exist in QB

See also
   * __FILE__
   * __FUNCTION__



----------------------------------------------------------- KeyPgDdpath ----
__PATH__

Intrinsic define (macro string) set by the compiler

Syntax
   __PATH__

Description
   Set to the quoted absolute path of the source file at the time of 
   compilation.

Example
   ' Tell the compiler to seach the source file's
   ' directory for libraries

   #libpath __PATH__

Differences from QB
   * New to FreeBASIC

See also
   * __FILE__



----------------------------------------------------------- KeyPgDdtime ----
__TIME__

Intrinsic define (macro value) set by the compiler

Syntax
   __TIME__

Description
   Substitutes the compiler time in a literal string (24 clock, "hh:mm:ss" 
   format) where used.

Example
   Print "Compile Time: " & __TIME__


   Compile Time: 13:42:57

Differences from QB
   * New to FreeBASIC

See also
   * __DATE__
   * __DATE_ISO__
   * Time




============================================================================
    #

--------------------------------------------------------- KeyPgPpassert ----
#assert

Preprocessor conditional directive

Syntax
   #assert  condition

Parameters
   condition
      A conditional expression that is assumed to be true

Description
   Asserts the truth of a conditional expression at compile time.  If 
   condition is false, compilation will stop with an error.

   This statement differs from the Assert macro in that #assert is 
   evaluated at compile-time and Assert is evaluated at run-time.

Example
   Const MIN = 5, MAX = 10
   #assert MAX > MIN '' cause a compile-time error if MAX <= MIN

Differences from QB
   * New to FreeBASIC

See also
   * Assert
   * #if
   * #error



-------------------------------------------------------- KeyPgPpcmdline ----
#Cmdline

Preprocessor directive

Syntax
   #cmdline "args..."

Parameters
   args...
      argument list (separated by spaces) of valid Compiler Options except 
      -print and also generic option -help.

Description
   #cmdline is a pre-processor directive that allows specifying 
   compiler options from inside the first specified fb source file.  The 
   first source file is the first specified '.bas' file given on the shell 
   or IDE command line invoking the fbc compiler.  #cmdline directives 
   specified in the first source file affect all source files subsequently 
   compiled.  #cmdline directives inside source files other than the first 
   source file are ignored.

   #cmdline is only allowed at module scope and can be conditionally 
   processed with #if pre-processor statements.  #cmdline statements must 
   appear before any declarative or executable statements.  Any #cmdline 
   statements after the first declarative or executable statement are 
   ignored.

   #cmdline directives are processed on the first pass of the the first 
   '.bas' source file when they appear in the source file.  If an invalid 
   command line option is given in the #cmdline statment, compilation 
   immediately aborts. #cmdline directives are ignored on the second pass 
   of the source file even if a conditional #if would add something 
   different on the second pass.

   At first fbc initializes as usual and begins parsing the fb source code 
   using the options given from the shell or IDE's fbc ... command line.  
   As #cmdline directives are processed, they are merged into the current 
   compiler configuration.  Depending on the command line options 
   encountered, fbc can continue parsing, restart the parser, or restart 
   fbc (for example: no restart after #cmdline "-mt", restart the parser 
   after #cmdline "-gen gcc", restart the build after #cmdline "-target 
   win64").

   fbc has no clever way to detect when all the #cmdline directives in 
   source have been processed, so there are 2 pseudo command line options 
   to instruct fbc what to next if it is necessary:
      #cmdline "-end"
         option to restart parser or build if needed.
      #cmdline "-restart"
         option to always restart build.
   If neither #cmdline "-end" nor #cmdline "-restart" were encountered, fbc 
   continues processing to the end of the first source file and restarts 
   only if necessary. 

   Adding -z nocmdline in the shell/IDE command line option ignores 
   #cmdline directives completely in source and allows user to override all 
   source directives using the shell/IDE fbc compiler command line only.

   Adding -w all on the shell/IDE command line option allows to get 
   warnings about ignored #cmdline directives.

Example
   Add a simple option in source to set the optimization level for GCC:
   #cmdline "-O 2"

   Print __FB_OPTIMIZE__  '' just to check the optimization level

   Sleep
         

   When #cmdline is not processed (no 'invalid command-line option' error 
   message is reported):
   (fbc parser is active when checking for #cmdline, so it's expected that 
   it follows sames rules as any other source code)
   '' not processed in single line comments
   '#cmdline "asdf"

   '' not processed in multi line comments
   /'
   #cmdline "-asdf"
   '/

   '' not processed in strings
   Print "#cmdline ""-asdf"""

   '' not processed if skipping over a conditional
   #if 0
      #cmdline "-asdf"
   #endif

   '' not processed when defining macros (as long as the macro is not called)
   #macro DOARGS
      #cmdline "-asdf"
   #endmacro

   Sleep
         

   Set options in source based on real fbc ... compiler command line option 
   given:
   (full error checking is activated depending if debug option '-g' was 
   given on the fbc ... compiler command line)
   '' '-g' command line option given on the real ##//fbc ...//## compiler command line?

   #if __FB_DEBUG__
      #cmdline "-exx -w pedantic -w constness"
   #endif
         

   Define a global symbol for all modules, starting with two modules: 
   main.bas and tools.bas, and compile both with the single '$ fbc 
   main.bas' compiler command line:
   (this is different than #include tools.bas in main.bas because the two 
   modules are compiled separately then linked)
   '' main.bas
   ''
   '' compile with:
   ''   $ fbc main.bas
   ''
   '' and will be same as if we did:
   ''   $ fbc main.bas tools.bas -d DoTrickyStuff

   '' add the tools module
   #cmdline "-b tools.bas"  '' or: #cmdline "tools.bas"

   '' gobal #define for all modules
   #cmdline "-d DoTrickyStuff"

   Declare Function IsTrickyTools() As Boolean

   #ifdef DoTrickyStuff
   Print "DoTrickyStuff is defined in the main.bas module"
   #endif

   If IsTrickyTools() Then
   Print "DoTrickyStuff is defined in the tools.bas module"
   End If

   Sleep
         

   '' tools.bas
   ''

   Function IsTrickyTools() As Boolean
      #ifdef DoTrickyStuff
      Return True
      #else
        Return False
      #endif
   End Function
         

Version
   * Since fbc 1.09.0

Differences from QB
   * New to FreeBASIC

See also
   * fbc command-line
   * Compiler Options
   * Intrinsic Defines



--------------------------------------------------------- KeyPgPpdefine ----
#define

Preprocessor directive to define a macro

Syntax
   #define identifier body
   #define identifier( [ parameters ] ) body
   #define identifier( [ parameters, ] Variadic_Parameter... ) body

Description
   #define allows to declare text-based preprocessor macros. Once the 
   compiler has seen a #define, it will start replacing further occurrences 
   of identifier with body. body may be empty. The expansion is done 
   recursively, until there is nothing more to expand and the compiler can 
   continue analyzing the resulting code. #undef can be used to make the 
   compiler forget about a #define.

   Parameters turn a define into a function-like macro, allowing text 
   arguments to be passed to the macro. Any occurrences of the parameter 
   names in the body will be replaced by the given argument text during 
   expansion.
   If a literal is passed to a macro, the name of the corresponding 
   parameter in the macro body can not be used as a local variable as in a 
   procedure body. To emulate the same functioning as for a procedure, the 
   user must then explicitly declare a local variable (with another name) 
   in the body of the macro and initialize it with the passed parameter 
   name (replaced at preprocessing by the literal passed).

   The # Stringize operator can be used on macro parameters to turn them 
   into string literals, and the ## Concatenate operator can be used to 
   merge tokens together.

   Note: In the function-like #define declaration, the identifier should be 
   followed by the opening parentheses (() immediately without any 
   white-space in between, otherwise the compiler will treat it as part of 
   the body.

   Defines are scoped; they are only visible in the scope they were defined 
   in. If defined at module level, the define is visible throughout the 
   module. If the identifier is defined inside a compound statement having 
   scope (Sub, For..Next, While..Wend, Do..Loop, Scope..End Scope, etc), 
   the identifier define is only visible within that scope. Namespaces on 
   the other hand do not have any effect on the visibility of a define.

   Identifiers can be checked for with #ifdef and others, which can be used 
   to hide parts of code from the compiler (conditional compiling).

   Some user-defined symbols are recognized by the compiler itself.  For 
   example, Fb_No_Gfxlib and Fb_No_Sfxlib change how selected library 
   command words are parsed.

   The result of macro expansion can be checked by using the -pp compiler 
   option.

   #defines are often used to declare constants. The Const statement is a 
   type-safe alternative.

   WARNING: When the define body contains an expression with one operator 
   at least, it may be mandatory to have to surround some terms 
   (parameters, whole body) by parentheses in order to not undergo an 
   unwanted precedence change of operators (if passing as argument an 
   expression with also operators, or if using the define in a main 
   expression with also operators).

Example
   '' Definition and check
   #define DEBUGGING
   #ifdef DEBUGGING
     ' ... statements
   #endif

   '' Simple definition/text replacement
   #define False 0
   #define True (Not False)

   '' Function-like definition
   #define MyRGB(R,G,B) (((R)Shl 16)  Or ((G)Shl 8) Or (B)) 
   Print Hex( MyRGB(&hff, &h00, &hff) )

   '' Line continuation and statements in a definition
   #define printval(bar) _
      Print #bar; " ="; bar

   '' #defines are visible only in the scope where they are defined
   Scope
      #define LOCALDEF 1
   End Scope

   #ifndef LOCALDEF
   #   Print LOCALDEF Is Not defined
   #endif

   '' namespaces have no effect on the visibility of a define
   Namespace foo
   #   define NSDEF
   End Namespace

   #ifdef NSDEF
   #   Print NSDEF Is defined
   #endif

Differences from QB
   * New to FreeBASIC

See also
   * #macro
   * # Preprocessor Stringize
   * ## Preprocessor Concatenate
   * #ifdef
   * #undef
   * Const
   * ...
   * Fb_No_Gfxlib
   * Fb_No_Sfxlib



----------------------------------------------------------- KeyPgPpelse ----
#else

Preprocessor conditional directive

Syntax
   #if (expression)
      ' Conditionally included statements if expression is True
   #else
      ' Conditionally included statements if expression is False 
   #endif

Description
   #else can be added to an #if, #ifdef, or #ifndef block to provide an 
   alternate result to the conditional expression.

Example
   #define MODULE_VERSION 1
   Dim a As String
   #if (MODULE_VERSION > 0)
     a = "Release"
   #else
     a = "Beta"
   #endif
   Print "Program is "; a

Differences from QB
   * New to FreeBASIC

See also
   * #define
   * #macro
   * #if
   * #elseif 
   * #elseifdef 
   * #elseifndef 
   * #endif 
   * #ifdef
   * #ifndef
   * #undef
   * defined



--------------------------------------------------------- KeyPgPpelseif ----
#elseif

Preprocessor conditional directive

Syntax
   #if (expression1)
      ' Conditionally included statements if expression1 is True
   #elseif (expression2)
      ' Conditionally included statements if expression2 is True
   #else
      ' Conditionally included statements if both
      ' expression1 and expression2 are False
   #endif

Description
   #elseif can be added to an #if block to provide an additional 
   conditions.

Example
   #define WORDSIZE 16
   #if (WORDSIZE = 16)
     ' Do some some 16 bit stuff
   #elseif (WORDSIZE = 32)
     ' Do some some 32 bit stuff
   #else
     #error WORDSIZE must be set To 16 Or 32
   #endif

Differences from QB
   * New to Freebasic

See also
   * #define
   * #macro
   * #if
   * #else 
   * #elseifdef 
   * #elseifndef 
   * #endif 
   * #ifdef
   * #ifndef
   * #undef
   * defined



------------------------------------------------------ KeyPgPpelseifdef ----
#elseifdef

Preprocessor conditional directive

Syntax
   #ifdef A
      ' Conditionally included statements if A is defined
   #elseifdef B
      ' Conditionally included statements if A is not defined and B is 
      defined
   #else
      ' Conditionally included statements if both A and B are not defined
   #endif

Description
   #elseifdef can be added to an #if block to provide an additional 
   condition.

   #elseifdef symbol is equivalent to #elseif defined (symbol)

Example
   #define B

   #ifdef A
      Print "A is defined"
   #elseifdef B
      Print "A is not defined and B is defined"
   #else
      Print "both A and B are not defined"
   #endif

Version
   * Since fbc 1.20.0

Differences from QB
   * New to Freebasic

See also
   * #define
   * #macro
   * #if
   * #else 
   * #elseif 
   * #elseifndef 
   * #endif 
   * #ifdef
   * #ifndef
   * #undef
   * defined



----------------------------------------------------- KeyPgPpelseifndef ----
#elseifndef

Preprocessor conditional directive

Syntax
   #ifdef A
      ' Conditionally included statements if A is defined
   #elseifndef B
      ' Conditionally included statements if both A and B are not defined
   #else
      ' Conditionally included statements if A is not defined and B is 
      defined
   #endif

Description
   #elseifndef can be added to an #if block to provide an additional 
   condition.

   #elseifndef symbol is equivalent to #elseif Not defined(symbol)

Example
   #ifdef A
      Print "A is defined"
   #elseifndef B
      Print "both A and B are not defined"
   #else
      Print "A is not defined and B is defined"
   #endif

Version
   * Since fbc 1.20.0

Differences from QB
   * New to Freebasic

See also
   * #define
   * #macro
   * #if
   * #else 
   * #elseif 
   * #elseifdef 
   * #endif 
   * #ifdef
   * #ifndef
   * #undef
   * defined



---------------------------------------------------------- KeyPgPpendif ----
#endif

Preprocessor conditional directive

Syntax
   #endif

Description
   Ends a group of conditional directives

   See #if, #ifdef, or #ifndef for examples of usage.

Example
   #define DEBUG_LEVEL 1
   #if (DEBUG_LEVEL = 1)
     'Conditional statements
   #endif

Differences from QB
   * New to FreeBASIC

See also
   * #define
   * #macro
   * #if
   * #else 
   * #elseif 
   * #elseifdef 
   * #elseifndef 
   * #ifdef
   * #ifndef
   * #undef
   * defined



---------------------------------------------------------- KeyPgPpmacro ----
#Macro...#Endmacro

Preprocessor directive to define a multiline macro

Syntax
   #macro identifier [?] ( [ parameters ] )
      body
   #endmacro

   #macro identifier [?] ( [ parameters, ] Variadic_Parameter... )
      body
   #endmacro

Description
   #macro is the multi-line version of #define.

   If using the optional question mark (?) after the identifier in the 
   definition syntax, macros with parameters can be invoked without using 
   parentheses around the arguments.
   Note: Beware of the possibility of triggering so a conflict with 
   expressions containing the name of the macro as one of their terms.

   Note: Unlike the function-like #define declaration, spaces can be put 
   between the macro name and the opening parenthesis for any declaration 
   syntax of macro.

   WARNING: In the macro body, it may be mandatory to have to surround by 
   parentheses any used parameter if it is inside an expression with one 
   operator at least, in order to not undergo an unwanted precedence change 
   of operators (if passing as argument an expression with also operators).

Example
   ' macro as an expression value

   #macro Print1( a, b )
      a + b
   #endmacro

   Print Print1( "Hello ", "World!" )

   /' Output :
   Hello World!
   '/
      

   ' macro as multiple statements

   #macro Print2( a, b )
      Print a;
      Print " ";
      Print b;
      Print "!"
   #endmacro

   Print2( "Hello", "World" )

   /' Output :
   Hello World!
   '/
      

   ' macro with a variadic parameter

   #macro test1( arg1, arg2... )
      Print arg1
      #if #arg2 = ""
         Print "2nd argument not passed"
      #else
         Print arg2
      #endif
   #endmacro

   test1( "1", "2" )
   Print "-----------------------"
   test1( "3" )
   Print "-----------------------"
   test1( 5, 6 )
   Print "-----------------------"
   test1( 7 )

   /' Output :
   1
   2
   -----------------------
   3
   2nd argument not passed
   -----------------------
    5
    6
   -----------------------
    7
   2nd argument not passed
   '/
      

   ' macro with a variadic parameter which can contain several sub-parameters:
   '   To distinguish between the different arguments passed by variadic_parameter,
   '   you can first convert variadic_parameter to a string using the Operator # (Preprocessor Stringize),
   '   then differentiate in this string (#variadic_parameter) each passed argument by locating the separators (usually a comma).

   #macro test2( arg1, arg2... )
      Print "'" & Trim(#arg1) & "'"
      Scope
         Dim As String s = Trim(#arg2)
         If s <> "" Then
            Do
               Dim As Integer k = InStr(1, s, ",")
               If k = 0 Then
                  Print "'" & s & "'"
                  Exit Do
               End If
               Print "'" & Left(s, k - 1) & "'"
               s = Trim(Mid(s, k+1))
            Loop
         End If
      End Scope
   #endmacro

   test2( 5 )
   Print "----"
   test2( 5,6, 7, , 9, 10, ,,13, 14 )

   /' Output :
   '5'
   ----
   '5'
   '6'
   '7'
   ''
   '9'
   '10'
   ''
   ''
   '13'
   '14'
   '/
      

Version
   * Before fbc 1.08.0, the optional question mark (?) was not available.

Differences from QB
   * New to FreeBASIC

See also
   * #define
   * #ifdef
   * #undef



---------------------------------------------------------- KeyPgPperror ----
#error

Preprocessor diagnostic directive

Syntax
   #error error_text

Parameters
   error_text
      The display message

Description
   #error interrupts compiling to display error_text when compiler finds 
   it, and then parsing continues. 

   This keyword must be surrounded by an #if <condition> ...#endif, so the 
   compiler can reach #error only if <condition> is met.

   In any case, the final status will be "Failed to compile".

Example
   #define c 1

   #if c = 1
     #error Bad value of c 
   #endif

Differences from QB
   * New to FreeBASIC

See also
   * #if
   * #print
   * #assert



------------------------------------------------------------- KeyPgPpif ----
#if

Preprocessor conditional directive

Syntax
   #if (expression)
      ' Conditionally included statements
   #endif

Description
   Conditionally includes statements at compile time.

   Statements contained within the #if / #endif block are included if 
   expression evaluates to True (non-zero) and excluded (ignored) if 
   expression evaluates to False (0).

   This conditional directive differs from the If conditional statement in 
   that #if is evaluated at compile-time and If is evaluated at run-time.

Example
   #define DEBUG_LEVEL 1
   #if (DEBUG_LEVEL >= 2)
     ' This line is not compiled since the expression is False
     Print "Starting application"
   #endif

Differences from QB
   * New to FreeBASIC

See also
   * #define
   * #macro
   * #else 
   * #elseif 
   * #elseifdef 
   * #elseifndef 
   * #endif 
   * #ifdef
   * #ifndef
   * #undef
   * defined
   * #assert 



---------------------------------------------------------- KeyPgPpifdef ----
#ifdef

Preprocessor conditional directive

Syntax
   #ifdef symbol
      ' Conditionally included statements
   #endif

Description
   Conditionally includes statements at compile time.

   Statements within the #ifdef...#endif block are included if symbol is 
   defined and excluded (ignored) if symbol is not defined.

   #ifdef symbol is equivalent to #if defined (symbol)

Example
   #define _DEBUG
   #ifdef _DEBUG
      ' Special statements for debugging
   #endif

Differences from QB
   * New to Freebasic

See also
   * #define
   * #macro
   * #if
   * #else 
   * #elseif 
   * #elseifdef 
   * #elseifndef 
   * #endif 
   * #ifndef
   * #undef
   * defined



--------------------------------------------------------- KeyPgPpifndef ----
#ifndef

Preprocessor conditional directive

Syntax
   #ifndef symbol
      ' Conditionally included statements
   #endif

Description
   Conditionally includes statements at compile time.

   Statements within the #ifndef...#endif block are included if symbol is 
   not defined and excluded (ignored) if symbol is defined.

   #ifndef symbol is equivalent to #if Not defined(symbol)

Example
   #ifndef __MYFILE_BI__
   #define __MYFILE_BI__
      ' Declarations 
   #endif

Differences from QB
   * New to FreeBASIC

See also
   * #define
   * #macro
   * #if
   * #else 
   * #elseif 
   * #elseifdef 
   * #elseifndef 
   * #endif 
   * #ifdef
   * #undef
   * defined



----------------------------------------------------------- KeyPgInclib ----
#inclib

Preprocessor directive

Syntax
   #inclib "libname"

Description
   Includes a library in the linking process as if the user specified 
   -l libname on the command line.

Example
   '' incomplete code snippet

   '' this will include libmystuff.a in the link process
   #inclib "mystuff" 

Differences from QB
   * New to FreeBASIC

See also
   * #include
   * Compiler Option: -l
   * Compiler Option: -p
   * Static Libraries
   * Shared Libraries



---------------------------------------------------------- KeyPgInclude ----
#include

Preprocessor statement to include contents of another source file

Syntax
   #include [once] "file"

Description
   #include inserts source code from another file at the point where the 
   #include directive appears.  This has the effect of compiling the source 
   code from the include file as though it were part of the source file 
   that includes it.  Once the compiler has reached the end of the include 
   file, the original source file continues to be compiled.

   This is useful to remove code from a file and separate it into more 
   files. It is useful to have a single file with declarations in a program 
   formed by several modules. You may include files within an include file, 
   although avoid including the original file into itself, this will not 
   produce valid results. Typically, include files will have an extension 
   of .bi and are mainly used for declaring subs/functions/variables of a 
   library, but any valid source code may be present in an include file.

   The Once specifier tells the compiler to include the file only once even 
   if it is included several times by the source code.

   $Include is an alternative form of include, existing only for 
   compatibility with QuickBASIC. It is recommended to use #include 
   instead.

   The compiler will automatically convert path separator characters ( '/' 
   and '\' ) as needed to properly load the file.  The filename name may be 
   an absolute or relative path.  

   For relative paths, or where no path is given at all, the include file 
   is search for in the following order:
   * Relative from the directory of the source file
   * Relative from the current working directory
   * Relative from addition directories specified with the -i command line 
     option
   * The include folder of the FreeBASIC installation (FreeBASIC\inc, 
     where FreeBASIC is the folder where the fbc executable is located)

Example
   ' header.bi file
   Type FooType
      Bar As Byte
      Barbeque As Byte 
   End Type

   ' main.bas file
   #include "header.bi"

   Dim Foo As FooType

   Foo.Bar = 1
   Foo.Barbeque = 2

Differences from QB
   * New to FreeBASIC

See also
   * #define
   * #inclib
   * Compiler Option: -i
   * Compiler Option: -include



----------------------------------------------------------- KeyPgPplang ----
#lang

Preprocessor statement to set the compiler dialect.

Syntax
   #lang "lang"

Parameters
   "lang"
      The dialect to set, enclosed in double quotes, and must be one of 
      "fb", "fblite", "qb", or "deprecated".

Description
   If the -forcelang option was not given on the command line, #lang can be 
   used to set the dialect for the source module in which it appears.  At 
   most two passes will be made on the source module.  On the first pass, 
   if the specified dialect is anything other than the default dialect 
   (chosen with -lang, or "fb" by default), the compiler will reset the 
   parser for another pass and restart compilation at the beginning of the 
   source module.  If this directive is encountered again on the second 
   pass, and the specified dialect does not match the new current dialect, 
   a warning is issued and compilation continues.  If any errors were 
   encountered on the first pass, the compiler will not attempt a second 
   pass."

   #lang may not be used in any compound statement, scope, or subroutine.  
   However, it may be nested in module level preprocessor statements or 
   used in an include file.

   There is currently no restriction on where this directive may be placed 
   in a source module.  In future this may change, therefore best practice 
   would be to use this directive before the first declaration, definition, 
   or executable statement in the source.

   This directive overrides the -lang option if it was given on the command 
   line.  However, if the -forcelang option was given on the command line, 
   this directive will have no effect.  A warning is issued, the directive 
   is ignored, and compilation will continue.  This allows the user to 
   explicitly override #lang directives.

Example
   #lang "fblite"

Differences from QB
   * New to FreeBASIC

See also
   * $Lang
   * __FB_LANG__
   * Compiler Option: -lang
   * Compiler Option: -forcelang
   * FreeBASIC Dialects
   * #Cmdline



-------------------------------------------------------- KeyPgPplibpath ----
#libpath

Preprocessor statement to add a search path for libraries

Syntax
   #libpath "path"

Description
   Adds a library search path to the linker's list of search paths as if it 
   had been specified on the command line with the '-p' option.

   Paths are relative to the working directory where fbc was invoked and 
   not relative to the directory of the source file.

   No error is generated if the path does not exist and compilation and 
   linking will continue.

Example
   ' search the lib directory for external libraries
   #libpath "lib"

Differences from QB
   * New to FreeBASIC

See also
   * #inclib
   * #include
   * Compiler Option: -p
   * #Cmdline
   * Static Libraries
   * Shared Libraries



----------------------------------------------------------- KeyPgPpline ----
#line

Preprocessor directive to set the current line number and file name

Syntax
   #line number [ "name" ]

Parameters
   number 
      new line number
   "name"
      new file name (optional)

Description
   Informs the compiler of a change in line number and file name and 
   updates the __FILE__ and __LINE__ macro values accordingly.

   Both compile time messages and run-time messages are affected by this 
   directive.

   This directive allows other programs to generate source code for the 
   FreeBASIC compiler and have it return warning and/or error messages that 
   refer to the original source used by the other program.

Example
   #line 155 "outside.src"

   Error 1000

   '' Output is:
   '' Aborting due to runtime error 1000 at line 157 of outside.src()

Differences from QB
   * New to FreeBASIC

See also
   * __FILE__
   * __LINE__



---------------------------------------------------------- KeyPgPpmacro ----
#Macro...#Endmacro

Preprocessor directive to define a multiline macro

Syntax
   #macro identifier [?] ( [ parameters ] )
      body
   #endmacro

   #macro identifier [?] ( [ parameters, ] Variadic_Parameter... )
      body
   #endmacro

Description
   #macro is the multi-line version of #define.

   If using the optional question mark (?) after the identifier in the 
   definition syntax, macros with parameters can be invoked without using 
   parentheses around the arguments.
   Note: Beware of the possibility of triggering so a conflict with 
   expressions containing the name of the macro as one of their terms.

   Note: Unlike the function-like #define declaration, spaces can be put 
   between the macro name and the opening parenthesis for any declaration 
   syntax of macro.

   WARNING: In the macro body, it may be mandatory to have to surround by 
   parentheses any used parameter if it is inside an expression with one 
   operator at least, in order to not undergo an unwanted precedence change 
   of operators (if passing as argument an expression with also operators).

Example
   ' macro as an expression value

   #macro Print1( a, b )
      a + b
   #endmacro

   Print Print1( "Hello ", "World!" )

   /' Output :
   Hello World!
   '/
      

   ' macro as multiple statements

   #macro Print2( a, b )
      Print a;
      Print " ";
      Print b;
      Print "!"
   #endmacro

   Print2( "Hello", "World" )

   /' Output :
   Hello World!
   '/
      

   ' macro with a variadic parameter

   #macro test1( arg1, arg2... )
      Print arg1
      #if #arg2 = ""
         Print "2nd argument not passed"
      #else
         Print arg2
      #endif
   #endmacro

   test1( "1", "2" )
   Print "-----------------------"
   test1( "3" )
   Print "-----------------------"
   test1( 5, 6 )
   Print "-----------------------"
   test1( 7 )

   /' Output :
   1
   2
   -----------------------
   3
   2nd argument not passed
   -----------------------
    5
    6
   -----------------------
    7
   2nd argument not passed
   '/
      

   ' macro with a variadic parameter which can contain several sub-parameters:
   '   To distinguish between the different arguments passed by variadic_parameter,
   '   you can first convert variadic_parameter to a string using the Operator # (Preprocessor Stringize),
   '   then differentiate in this string (#variadic_parameter) each passed argument by locating the separators (usually a comma).

   #macro test2( arg1, arg2... )
      Print "'" & Trim(#arg1) & "'"
      Scope
         Dim As String s = Trim(#arg2)
         If s <> "" Then
            Do
               Dim As Integer k = InStr(1, s, ",")
               If k = 0 Then
                  Print "'" & s & "'"
                  Exit Do
               End If
               Print "'" & Left(s, k - 1) & "'"
               s = Trim(Mid(s, k+1))
            Loop
         End If
      End Scope
   #endmacro

   test2( 5 )
   Print "----"
   test2( 5,6, 7, , 9, 10, ,,13, 14 )

   /' Output :
   '5'
   ----
   '5'
   '6'
   '7'
   ''
   '9'
   '10'
   ''
   ''
   '13'
   '14'
   '/
      

Version
   * Before fbc 1.08.0, the optional question mark (?) was not available.

Differences from QB
   * New to FreeBASIC

See also
   * #define
   * #ifdef
   * #undef



--------------------------------------------------------- KeyPgPpPragma ----
#pragma

Preprocessor directive

Syntax
   #pragma option [ = value ]
   Or
   #pragma push ( option [, value ] )
   Or
   #pragma pop ( option )

Parameters
   Possible values for option and related values:

      +------------+------+--------------------------------------------------------------------------------------------------------------------+
      |Option      | Value| Description                                                                                                        |
      | msbitfields| false| Use bitfields compatible with gcc (default)                                                                        |
      | msbitfields| true | Use bitfields compatible with those used in Microsoft C compilers                                                  |
      | once       | N/A  | cause the source file in which the pragma appears to behave as though it was included with #include once ...       |
      | constness  | false| disable 'CONST qualifier discarded' warning in current source                                                      |
      | constness  | true | enable 'CONST qualifier discarded' warning in current source                                                       |
      | lookup108  | false| use normal symbol lookups for unqualified symbol names                                                             |
      | lookup108  | true | use fbc-1.08.x or earlier symbol lookups for unqualified symbol names                                              |
      | gui        | false| compile in console subsystem mode                                                                                  |
      | gui        | true | compile in GUI subsystem mode                                                                                      |
      | private    | false| allow procedures in sources to be compiled as separate modules with public linkage                                 |
      | private    | true | allow procedures in sources to be compiled as privately included with minimal overhead for changing desired linkage|
      | profile    | false| profiling code is not generated                                                                                    |
      | profile    | true | profiling code is generated                                                                                        |
      +------------+------+--------------------------------------------------------------------------------------------------------------------+

   If value is not given, the compiler assumes True (-1).  A zero (0) value 
   may be used in place of False.  A non-zero (for example, -1) value may 
   be used in place of True.

Description
   Allows the setting of compiler options inside the source code.

   Push saves the current value of the option onto a stack, then assigns 
   the new value (or True) to it. Pop restores the option to its previous 
   value, and removes it from the stack. This mechanism allows options to 
   be changed for a certain part of source code, regardless of the setting 
   used by the context, which is especially useful inside #include header 
   files.

   gui sets the same GUI/console subsystem mode represented by the -s 
   compiler option and __FB_GUI__.  This pragma must be used at module 
   level.

   constness pragma is added for testing fbc compiler.  It will be removed 
   in future at should not be relied upon.

Example
   '' MSVC-compatible bitfields: save the current setting and then enable them
   #pragma push(msbitfields)

   '' do something that requires MS-compatible bitfields here

   '' restore original setting
   #pragma pop(msbitfields)

Version
   * #pragma gui added in version 1.20.1
   * #pragma private and #pragma profile added in version 1.20.0
   * #pragma lookup108 added in version 1.09.0, and to be removed in next 
     minor release

Differences from QB
   * New to FreeBASIC

See also
   * #Pragma Reserve
   * __FB_GUI__
   * Compiler Option: -s
   * #include
   * #Cmdline
   * Preprocessor Overview



-------------------------------------------------- KeyPgPpPragmaReserve ----
#Pragma Reserve

Preprocessor directive

Syntax
      #pragma reserve symbol
   or
      #pragma reserve (extern) symbol
   or
      #pragma reserve (asm) symbol
   or
      #pragma reserve (asm, extern) symbol) or #pragma reserve (extern, 
      asm) symbol)

Parameters
   symbol
      symbol name to reserve.

Description
   #pragma reserved statements are preprocessor directives that allow user 
   to reserve symbol names by accessing to the internal symbol tables of 
   the fbc compiler:
      - #pragma reserve symbol
            statement will reserve a symbol name in the current scope / 
            namespace and generate an error if the symbol is redefined or 
            used in an expression.
      - #pragma reserve (extern) symbol
            statement will reserve a global symbol name and generate a 
            warning if the reserved symbol is used for a module level 
            procedure or shared variable in the global namespace.
      - #pragma reserve (asm) symbol
            statement will reserve an ASM symbol name in all ASM statements 
            and blocks.
      - #pragma reserve (asm, extern) symbol) or #pragma reserve (extern, 
      asm) symbol)
            Do both  previous statements: this combined statement will 
            reserve a global ASM symbol name and generate a warning if the 
            reserved symbol is used for a module level procedure or shared 
            variable in the global namespace.

   The primary objective with the two first syntaxes is to create a 
   mechanism to help deal with some symbols causing compile errors or 
   run-time crashes.
   Some symbol names in fbc compiler are emitted as-is to the backend 
   compilers (gcc, as, etc) where the symbol name is a reserved keyword by 
   the backend compiler.
   There are typically two outcomes:
      - compilation error in the backend,
      - bad code generation in the backend (successful compile and 
      unexpected run time crashes).
   Using #pragma reserve symbol statement allows the fbc compiler to output 
   an error message dedicated to the illegal use of this symbol name in the 
   current scope / namespace.
   Using #pragma reserve (extern)  symbol statement allows the fbc compiler 
   to output a warning message dedicated to the illegal use of this symbol 
   name for a module level procedure or shared variable in the global 
   namespace.

   A closely related secondary objective with the third and forth syntax is 
   ASM words used in ASM blocks and statements.
   This allows to add new ASM instruction name in the fbc ASM keywords list 
   (so not yet implicitly reserved by fbc).
   Therefore, using #pragma reserve (asm) symbol or #pragma reserve (asm, 
   extern) symbol or any #pragma reserve (extern, asm) symbol statement 
   allows the fbc compiler to always emit an undecorated ASM instruction 
   symbol name to the backend compiler.

   Note: #pragma reserve (extern) and #pragma reserve (asm) (and any 
   combined syntax) throw an error if used in any scope block or procedure.

Example
   Example (for the mechanism only) to prohibit/warn the definition/use of 
   a symbol name:
   #pragma reserve myName1
   #pragma reserve myName2
   #pragma reserve myName3
   #pragma reserve myName4
   #pragma reserve myName5
   #pragma reserve (Extern) myName11
   #pragma reserve (Extern) myName12
   #pragma reserve (Extern) myName13
   #pragma reserve (Extern) myName14
   #pragma reserve (Extern) myName15

   Dim As Integer myName1             '' error: Duplicated definition, myName1 in 'Dim As Integer myName1 ...
   Print myName1                      '' error: Illegal use of reserved symbol, found 'myName1' in 'Print myName1 ...

   Scope
      Dim As Integer myName2         '' OK
      Print myName2                  '' OK
   End Scope

   Dim As Integer myName11            '' OK
   Print myName11                     '' OK
   Dim Shared As Integer myName12     '' warning: Use of reserved global or backend symbol, myName12
   Print myName12                     '' OK

   Namespace N
      Dim As Integer myName3         '' OK
      Dim As Integer myName13        '' OK
      Sub myName4()                  '' OK
      End Sub
      Sub myName14()                 '' OK
      End Sub
   End Namespace
   Print N.myName3                    '' OK
   Print N.myName13                   '' OK
   N.myName4()                        '' OK
   N.myName14()                       '' OK

   Sub myName5()                      '' error: Duplicated definition, before ''' in 'Sub myName4() ...
   End Sub
   myName5()                          '' error: Illegal use of reserved symbol, found 'myName4' in 'myName4() ...

   Sub myName15()                     '' warning: Use of reserved global or backend symbol, myName14
   End Sub
   myName15()                         '' OK

   Suppose that 'xyz' is a new ASM instruction not yet entered in the fbc 
   ASM keywords list (so not yet implicitly reserved by fbc), and this 
   'xyz' symbol is also used to define a global variable name:
      - thus fbc emits to the backend compiler a decorated 'xyz' symbol (
      XYZ$) in the inserted ASM block:
   '' for x86_64

   #cmdline "-gen gas64 -r"

   Dim Shared xyz As Integer

   Sub proc Naked()
      Asm
         xyz
         ret
      End Asm
   End Sub

   /'
   OUTPUT in the .asm file:

      .intel_syntax noprefix
      .section .text
      .text
      .globl PROC
   PROC:
      .L_0004:
      XYZ$
      ret
      .L_0005:
      ret
   .....

   '/

      - after reserving the 'xyz' ASM symbol, fbc now emits to the backend 
      compiler an undecorated 'xyz' symbol (xyz) in the inserted ASM block:
   '' for x86_64

   #cmdline "-gen gas64 -r"
   #pragma reserve(Asm) xyz

   Dim Shared xyz As Integer

   Sub proc Naked()
      Asm
         xyz
         ret
      End Asm
   End Sub

   /'
   OUTPUT in the .asm file:

      .intel_syntax noprefix
      .section .text
      .text
      .globl PROC
   PROC:
      .L_0004:
      xyz
      ret
      .L_0005:
      ret
   .....

   '/

Version
   * Since fbc 1.09.0

Differences from QB
   * New to FreeBASIC

See also
   * #pragma
   * Preprocessor Overview



---------------------------------------------------------- KeyPgPpprint ----
#print

Preprocessor diagnostic directive

Syntax
   #print text

Description
   Causes compiler to output text to screen during compilation.

Example
   #print Now compiling module foo

Differences from QB
   * New to FreeBASIC

See also
   * #error



---------------------------------------------------------- KeyPgPpundef ----
#undef

Preprocessor directive to undefine a macro

Syntax
   #undef symbol

Description
   Undefines a symbol previously defined with #define.

   Can be used to ensure that a macro or symbol has a limited lifespan and 
   does not conflict with a similar macro definition that may be defined 
   later in the source code.

   (Note: #undef should not be used to undefine variable or function names 
   used in the current function scope.  The names are needed internally by 
   the compiler and removing them can cause strange and unexpected 
   results.)

Example
   #define ADD2(a_, b_)  ((a_) + (b_))
   Print ADD2(1, 2)
   ' Macro no longer needed so get rid of it ...
   #undef ADD2

Differences from QB
   * New to Freebasic

See also
   * #define
   * #macro
   * #if
   * #else 
   * #elseif 
   * #elseifdef 
   * #elseifndef 
   * #endif 
   * #ifdef
   * #ifndef
   * defined




============================================================================
    $

------------------------------------------------------ KeyPgMetaDynamic ----
$Dynamic

Metacommand to change the way arrays are allocated

Syntax
   '$Dynamic
      or
   Rem $Dynamic

Description
   '$Dynamic is a metacommand that specifies that any following array 
   declarations are variable-length, whether they are declared with 
   constant subscript ranges or not. This remains in effect for the rest of 
   the module in which '$Dynamic is used, and can be overridden with 
   '$Static.  It is equivalent to the Option Dynamic statement.

Example
   ' compile with -lang fblite or qb

   #lang "fblite"

   '$DYNAMIC
   Dim a(100)
   '......
   ReDim a(200)

Dialect Differences
   * Only available in the -lang fblite and -lang qb dialects.

Differences from QB
   * When used inside comments it must be the first token

See also
   * $Static
   * Dim
   * ReDim
   * Erase
   * Option Dynamic



------------------------------------------------------ KeyPgMetaInclude ----
$Include

Metacommand statement to include contents of another source file

Syntax
   '$Include [once]: 'file'
      or
   Rem $Include [once]: 'file'

Description
   $Include inserts source code from another file at the point where the 
   $Include metacommand appears.  This has the effect of compiling the 
   source code from the include file as though it were part of the source 
   file that includes it.  Once the compiler has reached the end of the 
   include file, the original source file continues to be compiled.

   The Once specifier tells the compiler to include the file only once even 
   if it is included several times by the source code.

   '$Include: exists for compatibility with QuickBASIC. It is recommended 
   to use #include instead.

Example
   ' header.bi file
   Type FooType
      Bar As Byte
      Barbeque As Byte 
   End Type
   Dim Foo As FooType

   '' compile with -lang fblite or qb

   #lang "fblite"

   '' main.bas file

   '$INCLUDE: "header.bi"

   Foo.Bar = 1
   Foo.Barbeque = 2

Dialect Differences
   * Only available in the -lang fblite and -lang qb dialects.

Differences from QB
   * None

See also
   * #include



--------------------------------------------------------- KeyPgMetaLang ----
$Lang

Metacommand statement to set the compiler dialect.

Syntax
   '$lang: "lang"
      or
   Rem $lang: "lang"

Parameters
   "lang"
      The dialect to set, enclosed in double quotes, and must be one of 
      "fb", "fblite", "qb", or "deprecated".

Description
   If the -forcelang option was not given on the command line, $Lang can be 
   used to set the dialect for the source module in which it appears.  At 
   most two passes will be made on the source module.  On the first pass, 
   if the specified dialect is anything other than the default dialect 
   (chosen with -lang, or "fb" by default), the compiler will reset the 
   parser for another pass and restart compilation at the beginning of the 
   source module.  If this metacommand is encountered again on the second 
   pass, and the specified dialect does not match the new current dialect, 
   a warning is issued and compilation continues.  If any errors were 
   encountered on the first pass, the compiler will not attempt a second 
   pass.

   $Lang  may not be used in any compound statement, scope, or subroutine.  
   However, it may be nested in module level preprocessor statements or 
   used in an include file.

   There is currently no restriction on where this directive may be placed 
   in a source module.  In future this may change, therefore best practice 
   would be to use this directive before the first declaration, definition, 
   or executable statement in the source.

   This directive overrides the -lang option if it was given on the command 
   line.  However, if the -forcelang option was given on the command line, 
   this directive will have no effect.  A warning is issued, the directive 
   is ignored, and compilation will continue.  This allows the user to 
   explicitly override $Lang metacommands.

   This metacommand was introduced in FreeBASIC version 0.20.0.  Older 
   versions of FB, and QuickBASIC, will treat it as a comment and silently 
   ignore it.

Example
   '$lang: "qb"

Differences from QB
   * New to FreeBASIC
   * QB handles '$lang: as a normal comment

See also
   * #lang
   * __FB_LANG__
   * Compiler Option: -lang
   * Compiler Option: -forcelang
   * FreeBASIC Dialects



------------------------------------------------------- KeyPgMetaStatic ----
$Static

Metacommand to change the way arrays are allocated

Syntax
   '$Static
      or
   Rem $Static

Description
   '$Static is a metacommand that overrides the behavior of $Dynamic, that 
   is, arrays declared with constant subscript ranges are fixed-length. 
   This remains in effect for the rest of the module in which '$Static is 
   used, and can be overridden with $Dynamic.  It is equivalent to the 
   Option Static statement.

Example
   ' compile with -lang fblite or qb

   #lang "fblite"

   '$dynamic
   Dim a(100)   '<<this array will be variable-length
   '$static
   Dim b(100)   '<<this array will be fixed-length

Dialect Differences
   * Only available in the -lang fblite and -lang qb dialects.

Differences from QB
   * When used inside comments it must be the first token

See also
   * $Dynamic
   * Dim
   * Erase
   * ReDim
   * Option Dynamic
   * Option Static




============================================================================
    ?

------------------------------------------------------------ KeyPgPrint ----
(Print | ?)

Writes text to the screen

Syntax
   (Print | ?) [ expressionlist ] [ , | ; ]

Parameters
   expressionlist
      list of items to print

Description
   Print outputs a list of values to the screen. Numeric values are 
   converted to their string representation, with left padding for the 
   sign. Objects of user-defined types must overload Operator Cast () As 
   String.

   Consecutive values in the expression list are separated either by a 
   comma (,) or semicolon (;). A comma indicates printing should take place 
   at the next 14 column boundary, while a semicolon indicates values are 
   printed with no space between them.  This has a similar effect to 
   concatenating expressions using + or &.

   Print also supports the special expressions, Spc() and Tab().  These can 
   be used to space out expressions, or to align the printing to a specific 
   column.

   A new-line character is printed after the values in the expression list 
   unless the expression list is followed by a comma or semicolon.  A Print 
   without any expressions or separators following it will just print a 
   new-line.

   NOTE: Print resets the Err value after each expression is printed.

   NOTE: In graphics mode, Draw String provides a flexible alternative to 
   Print: it prints a string to the screen with pixel positioning, 
   transparent background, and can use a user-supplied font.

Example
   '' print "Hello World!", and a new-line
   Print "Hello World!"

   '' print several strings on one line, then print a new-line
   Print "Hello";
   Print "World"; "!";
   Print

   '' column separator
   Print "Hello!", "World!"

   '' printing variables/expressions
   Dim As Double pi = Atn(1) * 4
   Dim As String s = "FreeBASIC"

   Print "3 * 4 ="; 3 * 4

   Print "Pi is approximately"; pi
   Print s; " is great!"

Dialect Differences
   * In the -lang qb dialect, an extra space is printed after any integer 
     number.

Differences from QB
   * None, when using QBASIC's variable types in -lang qb, except that no 
     extra space is displayed after any floating-point number.
   * Unsigned numbers are printed without a space before them.
   * QB did not support casting for UDTs, so didn't allow them to be Print
     ed.

See also
   * Spc
   * Tab
   * Print #
   * ? #
   * Print Using
   * ? Using
   * Write
   * Draw String
   * Input



---------------------------------------------------------- KeyPgPrintPp ----
(Print | ?) #

Writes a list of values to a file or device

Syntax
   (Print | ?) # filenum, [ expressionlist ] [ , | ; ]

Parameters
   filenum
      The file number of a file or device opened for Output or Append.
   expressionlist
      List of values to write.

Description
   Print # outputs a list of values to a text file or device. Numeric 
   values are converted to their string representation, with left padding 
   for the sign. Objects of user-defined types must overload Operator Cast 
   () As String.

   Consecutive values in the expression list are separated either by a 
   comma (,) or semicolon (;). A comma indicates printing should take place 
   at the next 14 column boundary, while a semicolon indicates values are 
   printed with no space between them.

   A new-line character is printed after the values in the expression list 
   unless the expression list is followed by a comma or semicolon.

   Note that the comma (,) immediately following the file number is still 
   necessary, even the expression list is empty.  In this case a new-line 
   is printed, just as with a normal expression list that doesn't have a 
   comma or semicolon at the end.

   Note:
      - Using Print # is naturally dedicated to Output/Append Access file 
      mode.
      - It is also allowed in Binary/Random Access file mode, but this was 
      never well tested and results may vary.

Example
   Open "bleh.dat"  For Output As #1
      
      Print #1, "abc def"
      Print #1, 1234, 5678.901, "xyz zzz"
      
      Close #1

Dialect Differences
   * In the -lang qb dialect, an extra space is printed after numbers.

Differences from QB
   * None, when using QBASIC's variable types in -lang qb.
   * Unsigned numbers are printed without a space before them.
   * QB did not support casting for UDTs, so didn't allow them to be Print
     ed.

See also
   * Print Using
   * ? Using
   * Print
   * ?
   * Write #
   * Open



------------------------------------------------------- KeyPgPrintusing ----
(Print | ?) Using

Outputs formatted text to the screen or output device.

Syntax
   (Print | ?) [# filenum ,] [ printexpressionlist {,|;} ] Using 
   formatstring ; [ expressionlist [ ; ] ]

Parameters
   filenum
      The file number of a file or device opened for Output or Append.  
      (Alternatively LPrint may be used where appropriate, instead of 
      Print #)
   printexpressionlist
      Optional preceding list of items to print, separated by commas (,) or 
      semi-colons (;) (see Print for more details).
   formatstring
      Format string to use.
   expressionlist
      List of items to format, separated by semi-colons (;).

Description
   Print to screen various expressions using a format determined by the 
   formatstring parameter. Internally, Print Using uses a buffer size of 
   2048 bytes: while it is highly unlikely that this buffer would be 
   filled, it should be noted that output would be truncated should this 
   limit be reached.

   If no expression list is given, the format string will be printed up to 
   the first special marker.  Note that the semi-colon after formatstring 
   is still necessary, even if no expression list is given.

   The format string dictates how the expressions are to be formatted when 
   output to the screen, indicated by the use of special marker characters. 
   There are markers for formatting both string and numeric output:

   String formatting

         +------+------------------------------------------------------------------------------------------------------------------------------------+
         |Marker|Formatting                                                                                                                          |
         |!     |prints the first character of a string                                                                                              |
         |\   \ |prints two or more characters of a string - as many as are occupied by the backslashes ('\') and any enclosed space characters (' ')|
         |&     |prints the entire string                                                                                                            |
         +------+------------------------------------------------------------------------------------------------------------------------------------+

   If an exact amount of characters is specified (with "!" or "\ \"), the 
   string will be truncated or padded with spaces on the right as needed to 
   output that many characters.

   Numeric formatting

         +------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
         |Marker|Formatting                                                                                                                                                            |
         |#     |placeholder for either an integer digit, or a decimal digit if a decimal point precedes it                                                                            |
         |,     |placed after integer digit indicates groups of 3 digits should be separated by commas in fixed-point notation                                                         |
         |.     |placed near # indicates place for the decimal point                                                                                                                   |
         |^^^   |uses exponential notation (E+/-#) when placed after the digit characters                                                                                              |
         |^^^^  |uses exponential notation (E+/-##) when placed after the digit characters                                                                                             |
         |^^^^^ |uses exponential notation (E+/-###) when placed after the digit characters                                                                                            |
         |+     |placed before/after the format string, controls whether the sign of a number is prepended/appended, and causes an explicit '+' sign to be printed for positive numbers|
         |-     |placed after the format string, causes the sign of the number to be appended rather than prepended, appending a space/negative sign for positive/negative numbers     |
         |$$    |placed at the start of integer digits, causes a dollar sign to be prepended to the number (after the sign if one is prepended)                                        |
         |**    |placed at the start of integer digits, causes any padding on the left to be changed from spaces to asterisks                                                          |
         |**$   |placed at the start of integer digits, pads on the left with asterisks, and prepends a dollar sign after the asterisks                                                |
         |&     |prints a number intelligently, using the exact number of digits required (new to version 0.21.0b)                                                                     |
         +------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------+

   All of the special marker characters can be escaped by preceding them 
   with the underscore character "_", allowing them to be printed directly. 
   For example, "_!" is printed as "!", and "__" is printed as "_".

   If a numerical value cannot fit in the number of digits indicated by the 
   format string, the formatting is adapted to fit the number, possibly 
   switching to scientific notation, and the number is printed preceded by 
   the percent "%" character. E.g., the number 1234 with a formatstring of 
   "##.##" would be printed as "%1234.00".

   All other characters within the format string are printed as they 
   appear.

   A new-line character is printed after the values in the expression list 
   unless the expression list is followed by a semicolon (;).

Example

   Print Using "The value is #.## seconds"; 1.019
   Print Using "The ASCII code for the pound sign (_#) is ###"; Asc("#")
   Print Using "The last day in the year is & \ \"; 31; "December"
   Print
   For exponent As Integer = 1 To 5
      Print Using "10 ^ # = ######"; exponent; 10 ^ exponent
   Next exponent

   will produce the output:

   The value Is 1.02 seconds
   The ASCII code For the pound sign (#) Is  35
   The last Day in the Year Is 31 Dec

   10 ^ 1 =     10
   10 ^ 2 =    100
   10 ^ 3 =   1000
   10 ^ 4 =  10000
   10 ^ 5 = 100000

Differences from QB
   * QB didn't allow "&" to be used for printing numbers.

See also
   * Print
   * ?
   * Print #
   * ? #
   * Format
   * Using
   * Palette Using

			


============================================================================
    A

-------------------------------------------------------------- KeyPgAbs ----
Abs

Calculates the absolute value of a number

Syntax
   Declare Function Abs ( ByVal number As Integer ) As Integer
   Declare Function Abs ( ByVal number As UInteger ) As UInteger
   Declare Function Abs ( ByVal number As Double ) As Double

Usage
   result = Abs( number )

Parameters
   number
      Value to find the absolute value of.

Return Value
   The absolute value of number.

Description
   The absolute value of a number is its positive magnitude.  If a number 
   is negative, its value will be negated and the positive result returned. 
   For example, Abs(-1) and Abs(1) both return 1. The required number 
   argument can be any valid numeric expression.
   Unsigned numbers will be treated as if they were signed, i.e. if the 
   highest bit is set the number will be treated as negative, and its value 
   negated.
   The value returned will be greater than or equal to 0, with the 
   exception of signed integers containing the lowest possible negative 
   value that can be stored in its type, in which case negating it will 
   overflow the result.

   The Abs unary Operator can be overloaded with user defined types.

Example
   Dim n As Integer

   Print Abs( -1 )
   Print Abs( -3.1415 )
   Print Abs( 42 )
   Print Abs( n )

   n = -69

   Print Abs( n )

Output:

   1
   3.1415
   42
   0
   69

Dialect Differences
   * In the -lang qb dialect, this operator cannot be overloaded.

Differences from QB
   * None

See also
   * Sgn
   * Operator



--------------------------------------------------------- KeyPgAbstract ----
Abstract

Declare abstract methods

Syntax
   Type typename Extends base_typename
      Declare Abstract Sub|Function|Property|Operator ...
   End Type

Description
   Abstract is a special form of Virtual. The difference is that abstract 
   methods do not have a body, but just the declaration. Essentially this 
   allows the declaration of an interface which can be implemented by 
   various derived types.

   In order to call an abstract method, it must have been overridden and 
   implemented by a derived data type, or else the program will abort.
   As a result, only types that implement all the abstract methods are 
   allowed to create objects. For the same reason, a constructor should not 
   call an unimplemented method.

   Constructors cannot be abstract, since they cannot be virtual. In 
   addition, abstract Destructors are not supported either, because a 
   destructor body (no matter whether implicit or explicit) is needed in 
   order to call base and field destructors.

   Abstracts are called "pure virtual" in C++ (unlike FreeBASIC, C++ allows 
   pure virtuals to have a body, but accessible only statically).

   Note: In a multi-level inheritance, a same named method (same identifier 
   and signature) can be declared Abstract, Virtual or normal (without 
   specifier) at each inheritance hierarchy level. When there is mixing of 
   specifiers, the usual order is abstract -> virtual -> normal, from top 
   to bottom of the inheritance hierarchy.
   The access control (Public/Protected/Private) of an overriding method is 
   not taken into account by the internal polymorphism process, but only 
   for the initial call at compile-time.
   A derived static method cannot override a base virtual/abstract method, 
   but can shadow any base method (including virtual/abstract).

Example
   Type Hello Extends Object
      Declare Abstract Sub hi( )
   End Type

   Type HelloEnglish Extends Hello
      Declare Sub hi( )
   End Type

   Type HelloFrench Extends Hello
      Declare Sub hi( )
   End Type

   Type HelloGerman Extends Hello
      Declare Sub hi( )
   End Type

   Sub HelloEnglish.hi( )
      Print "hello!"
   End Sub

   Sub HelloFrench.hi( )
      Print "Salut!"
   End Sub

   Sub HelloGerman.hi( )
      Print "Hallo!"
   End Sub

      Randomize( Timer( ) )

      Dim As Hello Ptr h

      For i As Integer = 0 To 9
         Select Case( Int( Rnd( ) * 3 ) + 1 )
         Case 1
            h = New HelloFrench
         Case 2
            h = New HelloGerman
         Case Else
            h = New HelloEnglish
         End Select

         h->hi( )
         Delete h
      Next

Dialect Differences
   * Only available in the -lang fb dialect.

Differences from QB
   * New to FreeBASIC

See also
   * Virtual
   * Type
   * Extends
   * Extends Zstring
   * Extends Wstring
   * Object
   * Override



----------------------------------------------------------- KeyPgAccess ----
Access

Clause of the Open statement to specify requested privileges

Syntax
   Open filename for Binary Access {Read | Write | Read Write} as [#]
   filenum

Usage
   open filename for binary Access Read as #filenum
   open filename for binary Access Write as #filenum
   open filename for binary Access Read Write as #filenum

Parameters
   Read
      Open the file with only read privileges.
   Write
      Open the file with only write privileges.
   Read Write
      Open the file with read and write privileges.

Description
   Access is used with the Open statement to request read, write, or read 
   and write privileges.  If the Access clause is not specified, Read Write 
   is assumed.

Example

This example shows how to open the file "data.raw" with Read and then 
"data.out" with Write access, in Binary mode, in an open file number 
returned by FreeFile.
   Dim As Long o

     '' get an open file number.
     o = FreeFile
     
     '' open file for read-only access.    
     Open "data.raw" For Binary Access Read As #o
      
      '' make a buffer in memory thats the entire size of the file
      Dim As UByte file_char( LOF( o ) - 1 )

        '' get the file into the buffer.      
        Get #o, , file_char()
      
     Close
     
     '' get another open file number.
     o = FreeFile
     
     '' open file for write-only access.    
     Open "data.out" For Binary Access Write As #o

      '' put the buffer into the new file.      
      Put #o, , file_char()
      
     Close

     Print "Copied file ""data.raw"" to file ""data.out"""

     Sleep

Differences from QB
   * None known.

See also
   * Open
   * Read
   * Write



------------------------------------------------------------- KeyPgAcos ----
Acos

Finds the arccosine of an angle

Syntax
   Declare Function Acos ( ByVal number As Double ) As Double

Usage
   result = Acos( number )

Parameters
   number
      A cosine value in the range [-1..1].

Return Value
   The arccosine of number, in radians, in the range [0..Pi].

Description
   Acos returns the arccosine of the argument number as a Double within the 
   range of 0 to Pi.  The arccosine is the inverse of the Cos function. The 
   returned angle is measured in radians (not degrees).

   Acos can be overloaded as operator to accept user-defined types.

Example
   Dim h As Double
   Dim a As Double
   Input "Please enter the length of the hypotenuse of a triangle: ", h
   Input "Please enter the length of the adjacent side of the triangle: ", a
   Print ""
   Print "The angle between the sides is"; Acos ( a / h )
   Sleep

The output would look like:

   Please enter the length of the hypotenuse of a triangle: 5
   Please enter the length of the adjacent side of the triangle: 4

   The angle between the sides Is 0.6435011087932843

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Acos.

Differences from QB
   * New to FreeBASIC

See also
   * Cos
   * A Brief Introduction To Trigonometry



----------------------------------------------------------- KeyPgAddGfx ----
Add

Parameter to the Put graphics statement which selects addition as the 
blitting method

Syntax
   Put [ target, ] [ STEP ] ( x,y ), source [ ,( x1,y1 )-( x2,y2 ) ], Add[ 
   ,multiplier ]

Parameters
   Add
      Required.
   multiplier
      Optional value between 0 and 255.  The source pixels are 
      premultiplied by (multiplier / 256) before being added.  If omitted, 
      this value defaults to 255.

Description
   Add selects addition as the method for blitting an image buffer.  For 
   each source and target pixel, the values of each respective component 
   are added together to produce the result.
   The addition is saturated - i.e. if the sum of the two values is 256 or 
   more, then it will be cropped down to 255.

   This method will work in all color modes.  Mask colors (color 0 for 
   indexed images, magenta (RGB(255, 0, 255)) for full color images) will 
   be skipped, though full color values of 0 (RGBA(0, 0, 0, 0)) will have 
   also have no effect.

Example
   ''open a graphics window
   ScreenRes 320, 200, 16

   ''create a sprite containing a circle
   Const As Integer r = 32
   Dim c As Any Ptr = ImageCreate(r * 2 + 1, r * 2 + 1, 0)
   Circle c, (r, r), r, RGB(255, 255, 192), , , 1, f

   ''put the sprite at three different multipier
   ''levels, overlapping each other in the middle
   Put (146 - r, 108 - r), c, Add,  64
   Put (174 - r, 108 - r), c, Add, 128
   Put (160 - r,  84 - r), c, Add, 192

   ''free the memory used by the sprite
   ImageDestroy c

   ''pause the program before closing
   Sleep

Differences from QB
   * New to FreeBASIC

See also
   *Trans
   *Alpha
   *Custom
   * Put (Graphics)



------------------------------------------------------------ KeyPgAlias ----
Alias (Name)

Clause of the Sub and Function statements that provides an alternate 
internal name.

Syntax
   [Declare] { Sub | Function } usablename Alias "alternatename" (...)

Usage
   declare sub usablename Alias "alternatename" ( ... )
      or
   declare function usablename Alias "alternatename" ( ... )
      or
   sub usablename Alias "alternatename" ( ... )
      ...
   end sub
      or
   function usablename Alias "alternatename" ( ... )
      ...
   end function
      or
   type typename Alias "alternatename" ( ... )
      ...
   end type

Description
   Alias gives an alternate name to a procedure.  This alternate name 
   cannot be used within the program to call the procedure, but it is 
   visible (if the function is not private) to the linker when linking with 
   code written in other languages.

   Alias is commonly used for procedures in libraries written in other 
   languages when such procedure names are valid in the other language but 
   invalid in BASIC.  When using Alias with Declare, only the alternate 
   name is used by the linker.

   Differently from normal procedure names, Alias does not change the case 
   of the alternate name, so it is useful when external code requires an 
   exported function with a particular name or with a particular case.

   Alias can be used to specify an alternate name for Type definitions.

   Alias can be used as a modifier that specifies an alternate name 
   mangling for procedure parameters.  See Alias (Modifier)

Example

If there is a sub (without parameter) called xClearScreen in an external 
library and you want to reference it with the name ClearVideoScreen, here 
is sample code to do so:
   Declare Sub ClearVideoScreen Alias "xClearScreen" ()

If there is a function (with parameters and return value) called 
MyFunctioninLib in an external library and you want to reference it with 
the name myfunction, here is sample code to do so:
   Declare Function myfunction Alias "MyFunctioninLib" (ByVal As Long, ByVal As Long, ByVal As ZString Ptr) As Integer

A procedure meant to be used by external C code, exported as MyExportedProc
:
   Function MultiplyByFive cdecl Alias "MyExportedProc" (ByVal Parameter As Integer) As Integer Export
     Return Parameter * 5
   End Function

Differences from QB
   * In QB, Alias only worked with Declare.

See also
   * Declare
   * Export
   * Type (Alias)
   * Alias (Modifier)



---------------------------------------------------- KeyPgAliasModifier ----
Alias (Modifier)

Modifies the data type name mangling (decoration) of a public symbol

Syntax
   ... As [ Const ] datatype alias "modifier" [ Const [ Ptr ... ] ]

Usage
   Dim variable As datatype alias "modifier"
   Type name As datatype alias "modifier"
   Declare Sub name ( param As datatype alias "modifier", ... )
   Declare Function name ( param As datatype alias "modifier", ... ) As 
   datatype alias "modifier"

Parameters
   datatype
      Standard data type or user defined data type to modify
   modifier
      One of the supported modifiers as described in Description section 
      following

Description
   Alias "modifier", when specified following a data type, gives an 
   alternate meaning to the data type, which may be needed for linking with 
   languages other than FreeBASIC.

   Public symbol names are mangled (decorated) to encode information about 
   the data type that is used for the symbol.  When linking with the c 
   language, the special meaning of the alias modifier is meaningless, 
   since the extra information is not encoded in to the public name.  When 
   linking with the c++ language, typically more information is encoded in 
   to the public symbol, and the alias modifier may be required.  The 
   public name is written to the compiled object file, and used by the 
   linker to match symbol names from one object module to another.

   The same rules for mapping data types is used regardless of which 
   backend (gas or gcc) code emitter is used,  And the intent is that FB's 
   compiled code can link consistently with it's own object modules and 
   object modules (or libraries) compiled from other languages.

   Supported Modifiers
      Byte alias "char"
      UByte alias "char"
         Used to map FB's 8-bit byte types to c/c++'s 8-bit char type.

      Long alias "long"
      ULong alias "long"
         On Win 64-bit targets, used to map FB's 32-bit Long and ULong 
         types to c/c++'s 32-bit long [int] type, instead of the 32-bit int 
         type.

      Any alias "char" Ptr
         Maps any ptr to c/c++'s char *.  In c/c++, char, signed char, and 
         unsigned char, are three distinct types.
         * Byte Ptr maps to signed char *
         * UByte Ptr maps to unsigned char *
         * On some platforms the variable argument list va_list type is a 
           typed as a char *, but FB does not have an equivalent type, 
           therefore Any Ptr is used instead.  Linking with names encoded 
           with this type will fail since, normally, FB encodes void * data 
           type instead of char *.
         * alias "char" keeps the any ptr behaviour in FB but then encodes 
           the public name as char * for linking.

      any alias "__builtin_va_list" ptr
         Maps the data type to gcc's __builtin_va_list type
         * expected that gcc's built-in type is a pointer type
         * used on dos, win32, win64, linux-x86, targets
         * see Cvalist for default usage in the cva_list data type

      alias "__builtin_va_list"
         Maps the data type to gcc's __builtin_va_list type
         * expected that gcc's built-in type is a struct type
         * used on aarch64 target
         * see Cvalist for default usage in the cva_list data type

      alias "__builtin_va_list[]"
         Maps the data type to gcc's __builtin_va_list type
         * expected that gcc's built-in type is a struct array type
         * used on linux-x86_64 target
         * see Cvalist for default usage in the cva_list data type

   Data Type Mapping Details

   On all targets, FB to c/c++:
   Several of FB's data types are consistently mapped across all targets:
      * 8-bit Byte maps to signed char
      * 8-bit UByte maps to unsigned char
      * 16-bit Short maps to [signed] short [int]
      * 16-bit UShort maps to unsigned short [int]
      * 32-bit Long maps to int
      * 32-bit ULong maps to unsigned int
      * 64-bit LongInt maps to long long [int]
      * 64-bit ULongInt maps to unsigned long long [int]

   On Dos/Win/Linux 32-bit targets, FB to c/c++:
   Integer on 32-bit targets is 32-bits wide
      * 32-bit Integer maps to long [int]
      * 32-bit UInteger maps to unsigned long [int]

   On Linux 64-bit targets, FB to c/c++:
   Integer on 64-bit targets is 64-bits wide
      * 64-bit Integer maps to long [int]
      * 64-bit UInteger maps to unsigned long [int]

   On Win 64-bit targets, FB to c/c++:
   Integer on 64-bit targets is 64-bits wide.  However, on Win target, 
   c/c++'s long int type is 32-bit, not 64-bit, and we can't use the long 
   long int mangling because it's already used by FB's LongInt type.  
   Reusing the same mangling (decoration) for two different data types 
   would cause function overloading to fail or have duplicate definitions.  
   To preserve FB's behaviour that Integer on 64-bit targets is always 
   64-bits, we mangle (decorate) the symbol with a custom datatype and keep 
   the size at 64-bit.
      * 64-bit Integer maps to custom INTEGER
      * 64-bit UInteger maps to custom UINTEGER
      To create a data type in FB that will map to c/c++'s long [int] 
      32-bit on win, we must use alias modifier.
      * 32-bit Long alias "long"  maps to long [int]
      * 32-bit ULong alias "long"  maps to unsigned long [int]

      For example extern c++ : declare sub proc( byval as long alias "long" 
      ) : end extern.  This allows FreeBASIC to call external c++ 
      procedures (on win-64) requiring a 32-bit long int type.  Usage of 
      Alias in this way affects win-64 targets only, and is ignored on all 
      other targets.

Example
   See example at Alias (Name).

Version
   * Before fbc 1.10.0, the [u]byte alias "char" modifier was not 
     supported.
   * Since fbc 1.06.0

Differences from QB
   * In QB, Alias only worked with Declare.

See also
   * Alias (Name)
   * Declare
   * Export
   * Type (Alias)



--------------------------------------------------------- KeyPgAllocate ----
Allocate

Allocates a block of memory from the free store

Syntax
   Declare Function Allocate cdecl ( ByVal count As UInteger ) As Any Ptr

Usage
   result = Allocate( count )

Parameters
   count
      The size, in bytes, of the block of memory to allocate.

Return Value
   If successful, the address of the start of the allocated memory is 
   returned. Otherwise, if the requested block size could not be allocated, 
   or if count < 0, then the null pointer (0) is returned.

Description
   Allocates, or reserves, count number of bytes from the free store 
   (heap). The newly allocated memory is not initialized.

   As the initial value of newly allocated memory is unspecified, Allocate 
   must not be directly used with String or Udt containing string, because 
   the string descriptor being not cleared (containing random data), that 
   may induce corrupted string or more (trying to write to a random place 
   in memory or trying to deallocate a random pointer).  It is mandatory in 
   that case (with string or UDT containing string) to use CAllocate 
   (clearing memory), or New Expression (calling constructor) in case of 
   UDT, or at worst after Allocate to explicitly clear the descriptor 
   (setting to 0) before the first string use.
   For allocating memory for a ZString or a WString, see the corresponding 
   page.

   The pointer that is returned is an Any Ptr and points to the start of 
   the allocated memory. This pointer is guaranteed to be unique, even if 
   count is zero.

   Allocated memory must be deallocated, or returned back to the free 
   store, with Deallocate when no longer needed. 

Example
   '' This program uses the ALLOCATE(...) function to create a buffer of 15 integers that is
   '' then filled with the first 15 numbers of the Fibonacci Sequence, then output to the
   '' screen. Note the call to DEALLOCATE(...) at the end of the program.

      Const integerCount As Integer = 15

      '' Try allocating memory for a number of integers.
      ''
      Dim buffer As Integer Ptr
      buffer = Allocate(integerCount * SizeOf(Integer))

      If (0 = buffer) Then
         Print "Error: unable to allocate memory, quitting."
         End -1
      End If

      '' Prime and fill the memory with the fibonacci sequence.
      ''
      buffer[0] = 0
      buffer[1] = 1
      For i As Integer = 2 To integerCount - 1
         buffer[i] = buffer[i - 1] + buffer[i - 2]
      Next

      '' Display the sequence.
      ''
      For i As Integer = 0 To integerCount - 1
         Print buffer[i] ;
      Next

      Deallocate(buffer)
      End 0

      Output is:
    0 1 1 2 3 5 8 13 21 34 55 89 144 233 377

   It is important to free allocated memory if it's not going to be used 
   anymore. Unused memory that isn't freed is simply wasting memory, and if 
   the address of that memory is somehow overwritten or forgotten, that 
   memory can never be freed. This condition is known as a memory leak, and 
   should be avoided at all costs. Note that leaked memory is always 
   completely freed when the application terminates, either by an 
   "ordinary" exit or crash, so the leak "persists" only as long as the 
   application runs, nevertheless it's a good habit to free any allocated 
   memory inside your application. The following example demonstrates a 
   function with a memory leak, where the address of allocated memory is 
   lost and isn't and can't be freed anymore. If such a function is called 
   frequently, the total amount of memory wasted can add up quickly.

   '' Bad example of Allocate usage, causing memory leaks

   Sub BadAllocateExample()

      Dim p As Byte Ptr

      p = Allocate(420)   '' assign pointer to new memory

      p = Allocate(420)   '' reassign same pointer to different memory,
                     '' old address is lost and that memory is leaked

      Deallocate(p)

   End Sub

      '' Main
      BadAllocateExample() '' Creates a memory leak 
      Print "Memory leak!"
      BadAllocateExample() '' ... and another
      Print "Memory leak!"
      End

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Allocate 

Differences from QB
   * New to FreeBASIC

See also
   * CAllocate
   * Reallocate
   * Deallocate



--------------------------------------------------------- KeyPgAlphaGfx ----
Alpha

Parameter to the Put graphics statement which selects alpha blending as the 
method

Syntax
   Put [ target, ] [ STEP ] ( x,y ), source [ ,( x1,y1 )-( x2,y2 ) ], Alpha
   Put [ target, ] [ STEP ] ( x,y ), source [ ,( x1,y1 )-( x2,y2 ) ], Alpha
   , alphaval

Parameters
   Alpha
      Required.
   alphaval
      Optional alpha parameter in the range [0..255].  Overrides alpha 
      values in individual pixels.

Description
   Alpha selects alpha blending as the method for Putting an image.  If the 
   alphaval parameter is specified, it overrides the alpha value of each 
   pixel, and the mask color (magenta) will be treated as transparent.  
   This works in 15, 16, 24, or 32-bit color depths.

   If alphaval is not specified, Alpha will only work in 32-bit color 
   depth, and Put will use the alpha value embedded within each pixel.  
   Pixels using the mask color will be treated as normal, and drawn with 
   their given alpha value.

   Alpha also has another mode which allows an 8-bit image to be Put on top 
   of a 32-bit image.  In this case, it will replace the alpha channel of 
   the 32-bit image with the contents of the 8-bit image.

      Alpha values range between 0 and 255.  An alpha value of 0 will not 
      draw the image at all.  All other alpha values are incremented by 1 
      to get a range between 2 and 256, and the result is then divided by 
      256 to get a value between 1/128 and 1, which is used to calculate 
      the exact value of each pixel from the source and destination pixels. 
      Thus, 255 is practically equivalent to drawing using Put with Trans 
      blitting mode, 0 is equivalent to doing nothing at all, and all the 
      other alpha values blend is expected.

Example
   This example compares the two different Alpha modes, including how they 
   react to the mask color
   '' Set up a 32-bit screen
   ScreenRes 320, 200, 32

   '' Draw checkered background
   For y As Integer = 0 To 199
      For x As Integer = 0 To 319
         PSet (x, y), IIf((x Shr 2 Xor y Shr 2) And 1, RGB(160, 160, 160), RGB(128, 128, 128))
      Next x
   Next y

   '' Make image sprite for Putting
   Dim img As Any Ptr = ImageCreate(32, 32, RGBA(0, 0, 0, 0))
   For y As Single = -15.5 To 15.5
      For x As Single = -15.5 To 15.5
         Dim As Integer r, g, b, a
         If y <= 0 Then
            If x <= 0 Then
               r = 255: g = 0: b = 0   '' red
            Else
               r = 0: g = 0: b = 255   '' blue
            End If
         Else
            If x <= 0 Then
               r = 0: g = 255: b = 0   '' green
            Else
               r = 255: g = 0: b = 255 '' magenta (transparent mask color)
            End If
         End If
         a = 255 - (x ^ 2 + y ^ 2)
         If a < 0 Then a = 0': r = 255: g = 0: b = 255
         PSet img, (15.5 + x, 15.5 - y), RGBA(r, g, b, a)
      Next x
   Next y

   '' Put with single Alpha value, Trans for comparison
   Draw String (32, 10), "Single alpha"
   Put (80 - 16,  50 - 16), img, Alpha, 64
   Put (80 - 16, 100 - 16), img, Alpha, 192
   Put (80 - 16, 150 - 16), img, Trans

   '' Put with full Alpha channel
   Draw String (200, 10), "Full alpha"
   Put (240 - 16, 100 - 16), img, Alpha

   '' Free the image memory
   ImageDestroy img

   '' Wait for a keypress
   Sleep

   This example shows the special method for setting a 32-bit alpha channel 
   using an 8-bit image
   Dim As Any Ptr img8, img32
   Dim As Integer x, y, i

   '' Set up an 8-bit graphics screen
   ScreenRes 320, 200, 8
   For i = 0 To 255
      Palette i,  i, i, i
   Next i
   Color 255, 0

   '' Create an 8-bit image
   img8 = ImageCreate(64, 64, 0,  8)
   For y = 0 To 63
      For x = 0 To 63
         Dim As Single x2 = x - 31.5, y2 = y - 31.5
         Dim As Single t = Sqr(x2 ^ 2 + y2 ^ 2) / 5
         PSet img8, (x, y), Sin(t) ^ 2 * 255
      Next x
   Next y

   Draw String (16, 4), "8-bit Alpha sprite"
   Put (16, 16), img8
   Sleep

   '' Set up a 32-bit graphics screen
   ScreenRes 320, 200, 32
   For y = 0 To 199
      For x = 0 To 319
         PSet (x, y), IIf(x - y And 3, RGB(160, 160, 160), RGB(128, 128, 128))
      Next x
   Next y

   '' Create a 32-bit, fully opaque sprite
   img32 = ImageCreate(64, 64, 0, 32)
   For y = 0 To 63
      For x = 0 To 63
         PSet img32, (x, y), RGB(x * 4, y * 4, 128)
      Next x
   Next y

   Draw String (16, 4), "Original Alpha channel"
   Put (16, 16), img32, Alpha

   '' Put a new alpha channel using the 8-bit image
   Put img32, (0, 0), img8, Alpha

   Draw String (16, 104), "New Alpha channel"
   Put (16, 116), img32, Alpha

   ''Free the memory for the two images
   ImageDestroy img8
   ImageDestroy img32

   Sleep

Differences from QB
   * New to FreeBASIC

See also
   * Put (Graphics)
   * Trans
   * Custom



------------------------------------------------------------ KeyPgOpAnd ----
Operator And (Conjunction)

Returns the bitwise-and (conjunction) of two numeric values

Syntax
   Declare Operator And ( ByRef lhs As T1, ByRef rhs As T2 ) As Ret

Usage
   result = lhs And rhs

Parameters
   lhs
      The left-hand side expression.
   T1
      Any numeric or boolean type.
   rhs
      The right-hand side expression.
   T2
      Any numeric or boolean type.
   Ret
      A numeric or boolean type (varies with T1 and T2).

Return Value
   Returns the bitwise-and (conjunction) of the two operands.

Description
   This operator returns the bitwise-and of its operands, a logical 
   operation that results in a value with bits set depending on the bits of 
   the operands (for conversion of a boolean to an integer, false or true 
   boolean value becomes 0 or -1 integer value).

   The truth table below demonstrates all combinations of a boolean-and 
   operation:

      +-------+-------+------+
      |Lhs Bit|Rhs Bit|Result|
      |0      |0      |0     |
      |1      |0      |0     |
      |0      |1      |0     |
      |1      |1      |1     |
      +-------+-------+------+

   No short-circuiting is performed - both expressions are always 
   evaluated.

   The return type depends on the types of values passed. Byte, UByte and 
   floating-point type values are first converted to Integer. If the left 
   and right-hand side types differ only in signedness, then the return 
   type is the same as the left-hand side type (T1), otherwise, the larger 
   of the two types is returned. Only if the left and right-hand side types 
   are both Boolean, the return type is also Boolean.

   This operator can be overloaded for user-defined types.

Example
   ' Using the AND operator on two numeric values
   Dim As UByte numeric_value1, numeric_value2
   numeric_value1 = 15 '00001111
   numeric_value2 = 30 '00011110

   'Result =  14  =     00001110
   Print numeric_value1 And numeric_value2
   Sleep

   ' Using the AND operator on two conditional expressions
   Dim As UByte numeric_value1, numeric_value2
   numeric_value1 = 15
   numeric_value2 = 25

   If numeric_value1 > 10 And numeric_value1 < 20 Then Print "Numeric_Value1 is between 10 and 20"
   If numeric_value2 > 10 And numeric_value2 < 20 Then Print "Numeric_Value2 is between 10 and 20"
   Sleep

   ' This will output "Numeric_Value1 is between 10 and 20" because
   ' both conditions of the IF statement is true
   ' It will not output the result of the second IF statement because the first
   ' condition is true and the second is false.

Dialect Differences
   * In the -lang qb dialect, this operator cannot be overloaded.

Differences from QB
   * None

See also
   * AndAlso
   * Operator Truth Tables



-------------------------------------------------------- KeyPgOpAndAlso ----
Operator Andalso (Short Circuit Conjunction)

Returns the short circuit-and (conjunction) of two numeric values

Syntax
   Declare Operator AndAlso ( ByRef lhs As T1, ByRef rhs As T2 ) As Ret

Usage
   result = lhs AndAlso rhs

Parameters
   lhs
      The left-hand side expression.
   T1
      Any numeric or boolean type.
   rhs
      The right-hand side expression.
   T2
      Any numeric or boolean type.
   Ret
      A numeric or boolean type (varies with T1 and T2).

Return Value
   Returns the short circuit-and (conjunction) of the two operands.

Description
   This operator evaluates the left hand side expression.  If the result is 
   zero, then zero is immediately returned.  If the result is nonzero then 
   the right hand side is evaluated, and the logical result from that is 
   returned.
   (for conversion of a boolean to an integer, false or true boolean value 
   becomes 0 or -1 integer value) 

   The truth table below demonstrates all combinations of a short 
   circuit-and operation, the '-' denotes that the operand is not 
   evaluated.

      +---------+---------------+------+
      |Lhs Value|Rhs Value      |Result|
      |0        |(not evaluated)|0     |
      |nonzero  |0              |0     |
      |nonzero  |nonzero        |-1    |
      +---------+---------------+------+

   AndAlso equivalent to:
   Iif( Lhs <> 0, Rhs <> 0, 0 )

   Short-circuiting is performed - only expressions needed to calculate the 
   result are evaluated.  The left hand side lhs is evaluated first, and 
   only if it evaluates to non-zero (true) is the right hand side rhs also 
   evaluated.  If the left hand side evaluation lhs returns zero (false), 
   it is known that at that point that the overall condition is false, so 
   the right hand side rhs is not evaluated (skipped).

   The return type is almost always an Integer, of the value 0 or -1, 
   denoting false and true respectively. Except if the left and right-hand 
   side types are both Boolean, then the return type is also Boolean.

   This operator cannot be overloaded for user-defined types.

Example
   '' Using the ANDALSO operator to guard against array access
   '' when the index is out of range

   Dim As Integer isprime(1 To 10) = { _
      _ ' 1  2  3  4  5  6  7  8  9  10    (2, 3, 5 and 7 are the only prime numbers)
         0, 1, 1, 0, 1, 0, 1, 0, 0, 0 _
      }

   Dim As Integer n
   Input "Enter a number between 1 and 10: ", n

   '' isprime() array will only be accessed if n is in range
   If (n >= 1 And n <= 10) AndAlso isprime(n) Then
      Print "n is prime"
   Else
      Print "n is not prime, or out of range"
   End If
   Sleep

Differences from QB
   * This operator was not available in QB.

See also
   * OrElse
   * And
   * Operator Truth Tables



----------------------------------------------------------- KeyPgAndGfx ----
And (Graphics Put)

Parameter to the Put graphics statement which uses a bit-wise And as the 
blitting method

Syntax
   Put [ target, ] [ STEP ] ( x,y ), source [ ,( x1,y1 )-( x2,y2 ) ], And

Parameters
   And
      Required.

Description
   The And method combines each source pixel with the corresponding 
   destination pixel, using the bit-wise And function.  The result of this 
   is output as the destination pixel.
   This method works in all graphics modes.  There is no mask color, 
   although color values with all bits set (255 for 8-bit palette modes, or 
   RGBA(255, 255, 255, 255) in full-color modes) will have no effect, 
   because of the behavior of And.

   In full-color modes, each component (red, green, blue and alpha) is kept 
   in a discrete set of bits, so the operation can be made to only affect 
   some of the channels, by making sure the all the values of the other 
   channels are set to 255.

Example
   ''open a graphics window
   ScreenRes 320, 200, 16
   Line (0, 0)-(319, 199), RGB(255, 255, 255), bf

   ''create 3 sprites containing cyan, magenta and yellow circles
   Const As Integer r = 32
   Dim As Any Ptr cc, cm, cy
   cc = ImageCreate(r * 2 + 1, r * 2 + 1, RGBA(255, 255, 255, 255))
   cm = ImageCreate(r * 2 + 1, r * 2 + 1, RGBA(255, 255, 255, 255))
   cy = ImageCreate(r * 2 + 1, r * 2 + 1, RGBA(255, 255, 255, 255))
   Circle cc, (r, r), r, RGB(0, 255, 255), , , 1, f
   Circle cm, (r, r), r, RGB(255, 0, 255), , , 1, f
   Circle cy, (r, r), r, RGB(255, 255, 0), , , 1, f

   ''put the three sprites, overlapping each other in the middle
   Put (146 - r, 108 - r), cc, And
   Put (174 - r, 108 - r), cm, And
   Put (160 - r,  84 - r), cy, And

   ''free the memory used by the sprites
   ImageDestroy cc
   ImageDestroy cm
   ImageDestroy cy

   ''pause the program before closing
   Sleep

Differences from QB
   * None

See also
   * And
   * Put (Graphics)



-------------------------------------------------------------- KeyPgAny ----
Any

The Any keyword is used as a placeholder for a type or value in various 
ways.

Syntax
   Dim identifier As Any Pointer|Ptr
or
   Declare Sub|Function identifier ( ByRef identifier As Any [ , ... ] )
or
   Dim identifier(Any [, Any...]) As DataType
or
   [ Declare ] { Sub | Function } proc_name ( param(Any [, Any...]) As 
   DataType  )
or
   Dim identifier As DataType = Any
or
   New DataType ( Any )
or
   New(Address) DataType [count] { Any }
or
   InStr|InStrRev ( identifier, Any substring )
or
   ProcPtr ( identifier, [Virtual] Any )

Description
   * Pointers (1st syntax):
      A special pointer type called the Any Ptr (or "Any Pointer") allows 
      pointing to any variable type.  If you cast it to a DataType Ptr, it 
      can be indexed or dereferenced to access the memory as an instance of 
      DataType. Pointer arithmetic is allowed on an Any Ptr, and treats it 
      like a Byte Ptr: The pointer is changed by increments of 1.

      A pure Any Ptr has no type checking by the compiler.  It can be 
      implicitly converted to and from other pointer types through 
      assignment or parameter passing.

      Any on its own is not a valid data type for a variable. Also, it is 
      illegal to dereference an Any Ptr (although an Any Ptr Ptr may be 
      dereferenced to produce a Any Ptr).

      This should not be confused with Variant, a Visual Basic data type 
      which can contain any type of variable. FreeBASIC does not provide 
      native support for a Variant type.

   * Byref parameters (2nd syntax):
      Any can be used in procedure prototypes (in a Declare statement) with 
      ByRef parameters to disable the compiler checking for the correct 
      type of the variable passed (this includes the array parameters 
      because always implicitly passed by reference).
      Obviously, this does not work with overload procedures, and therefore 
      neither with UDT member procedures.
      This use of Any exists for compatibility with QB, but can be 
      superseded by procedure overloading.

   * Array dimensions (3rd/4th syntax):
      In array declarations, Any can be specified in place of the array 
      bounds in order to create a dynamic array with a certain amount of 
      dimensions that is determined based on the number of Anys specified 
      (use the syntax with Any is mandatory when declaring a dynamic array 
      member inside a Type).

      In parameter declarations, Any can be also specified instead of empty 
      parenthesis in order to fix the amount of dimensions.

   * Initialization (5th/6th/7th syntax):
      Any can be used as a fake initializer to disable the default 
      initialization of variables to 0, leaving the variable uninitialized. 
      This may save time in critical sections of a program. It is the 
      program's responsibility to fill the variables with meaningful data 
      before reading it.

      For a UDT, the member data fields are also not initialized, and the 
      default constructors, if they exist, are not called.

      Comparison to C/C++: This matches the behavior of a variable 
      declaration without initialization value in C/C++.

      Any is not allowed when the DataType is a var-len String, because 
      there is no string character data, and not initializing the 
      descriptor would be an aberration.

      For a var-len array, Any is used only once at the declaration level, 
      not at each resize level with ReDim (Erase does not reset this 
      initialization state).

      Similar to Any initializers for variables, Any can also be used with 
      the New Expression or Placement New operators in order to leave the 
      newly created object uninitialized (only allowed with data types that 
      do not have a constructor, also excluding the var-len string type).

   * Instr/InstrRev (8th syntax):
      Any can be used with InStr or InStrRev as a qualifier for the 
      substring parameter, to indicate that any individual character in it 
      may be matched.

   * Procptr (9th syntax):
      Any, ie any procedure signature, does not induce any particular 
      selection (compared to its non-use), but just allows for writing 
      ProcPtr always with 2 arguments.

Example
   Declare Sub echo(ByVal x As Any Ptr) '' echo will accept any pointer type

   Dim As Integer a(0 To 9) = Any '' this variable is not initialized
   Dim As Double  d(0 To 4)

   Dim p As Any Ptr

   Dim pa As Integer Ptr = @a(0)
   Print "Not initialized ";
   echo pa       '' pass to echo a pointer to integer

   Dim pd As Double Ptr = @d(0)
   Print "Initialized ";
   echo pd       '' pass to echo a pointer to double

   p = pa     '' assign to p a pointer to integer
   p = pd     '' assign to p a pointer to double      

   Sleep

   Sub echo (ByVal x As Any Ptr)
      Dim As Integer i
      For i = 0 To 39
         'echo interprets the data in the pointer as bytes
         Print Cast(UByte Ptr, x)[i] & " ";
      Next
      Print
   End Sub

   'Example of ANY disabling the variable type checking
   Declare Sub echo (ByRef a As Any) '' ANY disables the checking for the type of data passed to the function

   Dim x As Single
   x = -15
   echo x                  '' Passing a single to a function that expects an integer. The compiler does not complain!!             
   Sleep

   Sub echo (ByRef a As Integer)
     Print Hex(a)         
   End Sub

   Dim a(Any) As Integer ' 1-dimensional dynamic array
   Dim b(Any, Any) As Integer ' 2-dimensional dynamic array
   Dim c(Any, Any, Any) As Integer ' 3-dimensional dynamic array
   ' etc.

   ' Further Redims or array accesses must have a matching amount of dimensions
   ReDim a(0 To 1)
   ReDim b(1 To 10, 2 To 5)
   ReDim c(0 To 9, 0 To 5, 0 To 1)

Dialect Differences
   * Not available in the -lang qb dialect.

Differences from QB
   * Pointers and initializers are new to FreeBASIC.

See also
   * Dim
   * Declare



----------------------------------------------------------- KeyPgAppend ----
Append

Specifies text file to be opened for append mode

Syntax
   Open filename for Append [Encoding encoding_type] [Lock lock_type] as 
   [#]filenum 

Parameters
   filename
      file name to open for append
   encoding_type
      indicates encoding type for the file
   lock_type
      locking to be used while the file is open
   filenum
      unused file number to associate with the open file

Description
   A file mode used with Open to open a text file for writing.

   This mode is used to add text to an existing file  with Print #, or 
   comma separated values with Write#.

   Text files can't be simultaneously read and written in FreeBASIC, so if 
   both functions are required on the same file, it must be opened twice.

   filename must be a string expression resulting in a legal file name in 
   the target OS, without wildcards. The file will be sought for in the 
   present directory, unless the filename contains a path . If the file 
   does not exist, it is created. The pointer is set after the last 
   character of the file.

   Encoding_type indicates the Unicode Encoding of the file, so characters 
   are correctly read. If omitted, "ascii" encoding is defaulted. Only 
   little endian character encodings are supported at the moment. 
      *"utf8"
      *"utf16"
      *"utf32"
      *"ascii" (the default)

   Lock_type indicates the way the file is locked  for other processes, it 
   is one of:
      * Read - the file can be opened simultaneously by other processes, 
        but not for reading
      * Write - the file can be opened simultaneously by other processes, 
        but not for writing
      * Read Write - the file cannot be opened simultaneously by other 
        processes (the default)

   filenum Is a valid FreeBASIC file number (in the range 1..255) not being 
   used for any other file presently open. The file number identifies the 
   file for the rest of file operations. A free file number can be found 
   using the FreeFile function.

Example
   Dim i As Integer
   For i = 1 To 10
      Open "test.txt" For Append As #1
      Print #1, "extending test.txt"
      Close #1
   Next

Differences from QB
   * None

See also
   * Input (File Mode)
   * Open
   * Output
   * Print #
   * ? #
   * Write #



--------------------------------------------------------- KeyPgArrayLen ----
Arraylen

Provides the length of an array given its array-name.

Syntax
   Declare Function ArrayLen ( arrayname() As Const Any ) As UInteger

Usage
   #include once "fbc-int/array.bi"
   using FB
   ...
   result = ArrayLen(arrayname())

Parameters
   arrayname
      The name of the array for which the length is returned.

Description
   Returns the total number of elements of the array specified by 
   arrayname() (taking into account all dimensions of array).

Example
   #include Once "fbc-int/array.bi"
   Using FB

   Dim As LongInt array(4, 5)
   Dim As UInteger array_length

   array_length = ArrayLen(array())
   Print array_length                '' 30

Version
   * Since fbc 1.09.0. 

Differences from QB
   * New to FreeBASIC.

See also
   * Arraysize
   * Fbarray (Array Descriptor Structure And Access)



-------------------------------------------------------- KeyPgArraySize ----
Arraysize

Provides the size of an array given its array-name.

Syntax
   Declare Function ArraySize ( arrayname() As Const Any ) As UInteger

Usage
   #include once "fbc-int/array.bi"
   using FB
   ...
   result = ArraySize(arrayname())

Parameters
   arrayname
      The name of the array for which the size is returned.

Description
   Returns the total size (in bytes) of the array specified by arrayname() 
   (size of array element multiplied by total number of array elements).

Example
   #include Once "fbc-int/array.bi"
   Using FB

   Dim As LongInt array(4, 5)
   Dim As UInteger array_size

   array_size = ArraySize(array())
   Print array_size                 '' 240

Version
   * Since fbc 1.09.0. 

Differences from QB
   * New to FreeBASIC.

See also
   * Arraylen
   * Fbarray (Array Descriptor Structure And Access)



--------------------------------------------------------------- KeyPgAs ----
As

Part of a declaration which specifies a data type, or part of the Open 
statement which specifies a file handle.

Syntax
   symbolname As datatype

   Open ... As #filenumber
   Type ... As datatype

Description
   As is used to declare the type of variables, fields or arguments and is 
   also used in the Open statement to determine the file handle. As is also 
   used with the Type (Alias) syntax, similar to C's typedef statement.

Example
   '' don't try to compile this code, the examples are unrelated
   Declare Sub mySub (X As Integer, Y As Single, Z As String)
   ' ...

   Dim X As Integer
   ' ...

   Type myType
     X As Integer
     Y As Single
     Z As String
   End Type
   ' ...

   Type TheNewType As myType
   ' ...

   Open "test" For Input As #1
   ' ...

Differences from QB
   * The Type (Alias) syntax was not supported in QB.

See also
   * Declare
   * Dim
   * Type
   * Open



-------------------------------------------------------------- KeyPgAsc ----
Asc

Returns the corresponding ASCII or Unicode integer representation of a 
character.

Syntax
   Declare Function Asc ( ByRef str As Const String, ByVal position As 
   Integer = 1 ) As ULong
   Declare Function Asc ( ByVal str As Const ZString Ptr, ByVal position As 
   Integer = 1 ) As ULong
   Declare Function Asc ( ByVal str As Const WString Ptr, ByVal position As 
   Integer = 1 ) As ULong

Usage
   result = Asc( str [, position ] )

Parameters
   str
      The source string.
   position
      The position in the string of a character.

Return Value
   The raw character value stored at position in str.
   If both str and position can be evaluated at compile time (like Asc("a") 
   or Asc(chr(97)) or Asc("abc", 2) ...), the value is returned in a 
   UInteger result, otherwise in a ULong result.

Description
   If str is a String or a ZString, the UByte value at that position is 
   returned. This will be a 7-bit ASCII code, or even a 8-bit character 
   value from some code-page, depending on the string data stored in str.

   If str is a WString, the UShort (Windows) or ULong (Linux) value at that 
   position is returned. This will be a 16bit value on Windows (WStrings 
   use UTF16 there), or a 32bit value on Linux (WStrings use UTF32 there).

   The function returns zero (0) if the string is a zero length string, 
   position is less than one (1), or position is greater than the number of 
   characters in str.

   Chr performs the opposite function for ASCII strings, while WChr is the 
   opposite for Unicode strings, returning a string containing the 
   character represented by the code passed as an argument.

Example
   Print "the ascii code of 'a' is:"; Asc("a")
   Print "the ascii code of 'b' is:"; Asc("abc", 2)

      will produce the output:
   the ascii code of 'a' is: 97
   the ascii code of 'b' is: 98

   Unicode example (Note to documentation editors: don't put inside 
   %%(qbasic) markers or the Russian text will disappear!)
dim a as wstring * 12
   a = "&#1055;&#1088;&#1080;&#1074;&#1077;&#1090;, &#1084;&#1080;&#1088;"
   print "the Unicode of the second char of " & a & " is: " & asc(a, 2)
will produce the output:
the Unicode of the second char of 
&#1055;&#1088;&#1080;&#1074;&#1077;&#1090;, &#1084;&#1080;&#1088; is: 1088

Platform Differences
   * DOS does not support the wide-character string version of Asc.

Differences from QB
   * The optional position argument is new to FreeBASIC.
   * QB does not support the wide-character string version of Asc

See also
   * ASCII Character Codes
   * Chr
   * Str
   * Val



------------------------------------------------------------- KeyPgAsin ----
Asin

Finds the arcsine of a number

Syntax
   Declare Function Asin ( ByVal number As Double ) As Double

Usage
   result = Asin( number )

Parameters
   number
      Sine value in the range [-1..1].

Return Value
   The arcsine of number, in radians, in the range [-Pi/2..Pi/2].

Description
   Asin returns the arcsine of the argument number as a Double within the 
   range of -Pi/2 to Pi/2.  The arcsine is the inverse of the Sin function. 
   The returned angle is measured in radians (not degrees).

   Asin can be overloaded as operator to accept user-defined types.

Example
   Dim h As Double
   Dim o As Double
   Input "Please enter the length of the hypotenuse of a triangle: ", h
   Input "Please enter the length of the opposite side of the triangle: ", o
   Print ""
   Print "The angle between the sides is"; Asin ( o / h )
   Sleep

The output would look like:

   Please enter the length of the hypotenuse of a triangle: 5
   Please enter the length of the opposite side of the triangle: 3
   The angle between the sides Is 0.6435011087932844

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Asin.

Differences from QB
   * New to FreeBASIC

See also
   * Sin
   * A Brief Introduction To Trigonometry



-------------------------------------------------------------- KeyPgAsm ----
Asm

Code block that allows the use of architecture-specific instructions.

Syntax
   Asm
      architecture-dependent instructions
   End Asm

      Or

   Asm architecture-dependent instructions

Description
   The Asm block is used to insert specific machine-code instructions in a 
   program in order to perform operations that cannot be carried out using 
   the features of the language or to hand-optimize performance-sensitive 
   sections of code.

   The current FreeBASIC compiler currently only produces code for Intel 
   80x86-based machines; however, in the future, the compiler might be 
   ported to a platform which does not support the same instruction set.  
   Therefore, Asm blocks should only be used when necessary, and a 
   FreeBASIC-only alternative should be provided if possible.

   The return value of a function may be set by using the Function keyword 
   within brackets as shown in the example below.

   Asm block comments have the same syntax as usual FreeBASIC Comments  - 
   use FreeBASIC-like " ' " comments, not " ; " as usual in assembly code. 

   x86 Specific:

      Syntax
         The syntax of the inline assembler is a simplified form of Intel 
         syntax.  Intel syntax is used by the majority of x86 assemblers, 
         such as MASM, TASM, NASM, YASM and FASM. In general, the 
         destination of an instruction is placed first, followed by the 
         source. Variables and functions defined by a program may be 
         referenced in an Asm block.  The assembler used by FreeBASIC is 
         GAS, using the .intel_syntax noprefix directive, and Asm blocks 
         are passed through unmodified, except for the substitution of 
         local variable names for stack frame references, and commenting 
         removal.

         Instruction syntax is mostly the same as FASM uses, one important 
         difference is that GAS requires size settings to be followed by 
         the word "ptr".

   ' Assuming "n" is a FB global or local ULONG variable
   mov  eax, [n]        ' OK: size is apparent from eax
   inc  [n]             ' Not OK: size is not given
   inc  dword [n]       ' Not OK: size given, but still not accepted by GAS
   inc  dword Ptr [n]   ' OK: "ptr" is needed by GAS here

      Register Preservation
         When an Asm block is opened, the registers ebx, esi, and edi are 
         pushed to the stack, when the block is closed, these registers are 
         popped back from the stack.  This is because these registers are 
         required to be preserved by most or all OS's using the x86 CPU.  
         You can therefore use these registers without explicitly 
         preserving them yourself. You should not change esp and ebp, since 
         they are usually used to address local variables. 
         Note: Inside a Naked procedure, there is no such register 
         preservation.

      Register Names
         The names of the registers for the x86 architecture are written as 
         follows in an Asm block:
         * 4-byte integer registers: eax, ebx, ecx, edx, ebp, esp, edi, 
           esi
         * 2-byte integer registers: ax, bx, cx, dx, bp, sp, di, si (low 
           words of 4-byte e- registers)
         * 1-byte integer registers: al, ah, bl, bh, cl, ch, dl, dh (low 
           and high bytes of 2-byte -x registers)
         * Floating-point registers: st(0), st(1), st(2), st(3), st(4), 
           st(5), st(6), st(7)
         * MMX registers (aliased onto floating-point registers): mm0, mm1
           , mm2, mm3, mm4, mm5, mm6, mm7
         * SSE registers: xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7

      Instruction Set
         See these external references:
         * Original Intel 80386 manual from 1986
         * Latest Intel Pentium 4 manuals
         * NASM x86 Instruction Reference (Please note that NASM is not 
           the assembler used by FreeBASIC, but this page provides a good 
           overview of x86 instructions)

      Unsafe instructions
         Note that the FreeBASIC compiler produces 32-bit protected-mode 
         code for the x86 which usually runs in an unprivileged user level; 
         therefore, privileged and sensitive instructions will assemble 
         fine, but possibly won't work correctly or cause a runtime 
         "General Protection Fault", "Illegal instruction", or SIGILL 
         error. The following are the privileged and sensitive instructions 
         as of the Intel Pentium 4 and Xeon:
         * cli *1
         * clts
         * hlt
         * in *1
         * ins *1
         * int *1               
         * into *1               
         * invd
         * invlpg
         * lgdt
         * lidt
         * lldt
         * lmsw
         * ltr
         * mov to/from CRn, DRn, TRn
         * out *1
         * outs *1
         * rdmsr
         * rdpmc *2
         * rdtsc *2
         * sti *1
         * str
         * wbinvd
         * wrmsr
         * all SSE2 and higher instructions *2

          *1: sensitive to IOPL, fine in DOS 
          *2: sensitive to permission bits in CR4, see below

   The privileged instructions will work "correctly" in DOS when running on 
   a Ring 0 DPMI kernel, like the (non-default) Ring 0 version of CWSDPMI, 
   WDOSX or D3X, nevertheless most of them are not really useful and 
   dangerous when executed from DPMI code. RDTSC (Read Time Stamp Counter) 
   has been shown to be allowed by most, or all OS'es.

   However the usefulness of RDTSC has been diminished with the advent of 
   multi-core and hibernating CPUs. SSE2 and higher instructions are 
   disabled "by default" after CPU initialization, Windows and Linux 
   usually do enable them, in DOS it is business of the DPMI host: HDPMI32 
   will enable them, CWSDPMI won't. The INT instruction is usable in the 
   DOS version/target only, note that it works slightly differently from 
   real mode DOS, see also FaqDOS.

   The segment registers (cs, ds, es, fs, gs) should not be changed from an 
   Asm block, except in certain cases with the DOS port (note that they do 
   NOT work the same way as in real-mode DOS, see also FaqDOS). The 
   operating system or DPMI host is responsible for memory management; the 
   meaning of segments (selectors) in protected mode is very different from 
   real-mode memory addressing.

   Note that those "unsafe" instructions are not guaranteed to raise a 
   "visible" crash even when ran with insufficient privilege - the OS or 
   DPMI host can decide to "emulate" them, either functionally (reading 
   from some CRx works under HDPMI32), or "dummy" (nothing happens, 
   instruction will pass silently, like a NOP).

Example
   '' This is an example for the x86 architecture.
   Function AddFive(ByVal num As Long) As Long
      Asm
         mov eax, [num]
         Add eax, 5
         mov [Function], eax
      End Asm
   End Function

   Dim i As Long = 4

   Print "4 + 5 ="; AddFive(i)

   4 + 5 = 9

   FreeBASIC's Assembler is AS / GAS, the assembler of GCC, so an external 
   program. Some quirks apply:
      * The error lines  returned by FBC for Asm blocks are not related 
        the FB source file. As FBC simply displays the errors returned by 
        AS , the lines are related to the assembly file. To make FreeBASIC 
        preserve them, the compiler must be invoked with the -R option 
        ("don't delete ASM files").
      * The label names are case sensitive inside Asm blocks.

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Asm.

Differences from QB
   * New to FreeBASIC

See also
   * Function
   * Naked



----------------------------------------------------------- KeyPgAssert ----
Assert

Debugging macro that halts program execution if an expression is evaluated 
to 0 (false).

Syntax
   #define Assert(expression) If (expression) = 0 Then : fb_Assert( __FILE__
   , __LINE__, __FUNCTION__, #expression ) : End If

Usage
   Assert( expression )

Parameters
   expression
      Any valid conditional/numeric expression.  If expression evaluates to 
      0 (i.e. "false"), execution is halted.

Description
   The Assert macro is intended for use in debugging and works only if the 
   -g or -eassert option is specified on the fbc command line. In this case 
   it prints an error message and stops the program execution if expression 
   evaluates to 0.

   Its normal use is to check the correct value of the variables or 
   expressions during debugging.

   If -g and -eassert are not passed to fbc, the macro does not generate 
   any code, and has no effect.

   Note: If an Assert fails while the program is in a graphics 
   Screen (Graphics), the error message will not be visible as it will be 
   printed to the graphics screen, which will be closed immediately after.

Example
   Sub foo
    Dim a As Integer
    a=0
    Assert(a=1)
   End Sub

   foo 

   '' If -g or -eassert is used, this code stops with: test.bas(3): assertion failed at FOO: a=1 

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __ASSERT.

Differences from QB
   * New to FreeBASIC

See also
   * #assert
   * AssertWarn
   * Compiler Option: -eassert
   * Compiler Option: -g



------------------------------------------------------- KeyPgAssertwarn ----
AssertWarn

Debugging macro that prints a warning if an expression evaluates to 0.

Syntax
   #define AssertWarn(expression) If (expression) = 0 Then : fb_AssertWarn( 
   __FILE__, __LINE__, __FUNCTION__, #expression ) : End If

Usage
   AssertWarn( expression )

Parameters
   expression
      Any valid expression.  If expression evaluates to 0, a warning 
      message is printed to stderr (console).

Description
   The AssertWarn macro is intended for use in debugging and works only if 
   the -g option is selected in the FBC command line. In this case it 
   prints a warning message if expression evaluates to 0. It doesn't stop 
   the program execution like Assert does.

   Its normal use is to check the correct value of the variables during 
   debugging.

   If -g is not passed to fbc, the macro does not generate any code.

Example
   Sub foo
     Dim a As Integer
     a=0
     AssertWarn(a=1)
   End Sub

   foo 

   '' If -g is used this code prints: test.bas(3): assertion failed at FOO: a=1 

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __ASSERTWARN.

Differences from QB
   * New to FreeBASIC

See also
   * Assert



------------------------------------------------------------ KeyPgAtan2 ----
Atan2

Returns the arctangent of a ratio

Syntax
   Declare Function ATan2 ( ByVal y As Double, ByVal x As Double ) As Double

Usage
   result = ATan2( y, x )

Parameters
   y
      Vertical component of the ratio.
   x
      Horizontal component of the ratio.

Return Value
   The angle whose tangent is y/x, in radians, in the range [-Pi..Pi].

Description
   ATan2 returns the arctangent of the ratio y/x as a Double within the 
   range of -Pi to Pi.  The arctangent is the inverse of the Tan function. 
   The returned angle is measured in radians (not degrees).

   ATan2 cannot be overloaded as operator to accept user-defined types.

Example
   Print Atan2 ( 4, 5 )     'this is the same as PRINT ATN ( 4 / 5 )

The output would be:

   0.6747409422235527

Differences from QB
   * New to FreeBASIC

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Atan2.

See also
   * Tan
   * Atn
   * A Brief Introduction To Trigonometry



-------------------------------------------------------------- KeyPgAtn ----
Atn

Returns the arctangent of a number

Syntax
   Declare Function Atn ( ByVal number As Double ) As Double

Usage
   result = Atn( number )

Parameters
   number
      A number.

Return Value
   The angle, in radians, whose tangent is number, in the range 
   [-Pi/2..Pi/2].

Description
   Atn returns the arctangent of the argument number as a Double within the 
   range of -Pi/2 to Pi/2.  The arctangent is the inverse of the Tan 
   function. The returned angle is measured in radians (not degrees).

   Atn can be overloaded as operator to accept user-defined types.

Example
   Print "Pi ="; Atn ( 1.0 ) * 4
   Print Atn ( 4 / 5 )

The output would be:

   Pi = 3.141592653589793
   0.6747409422235527

Differences from QB
   * None

See also
   * Tan
   * Atan2
   * A Brief Introduction To Trigonometry



============================================================================
    B

----------------------------------------------------- KeyPgSfxGenerated ----
Generated Sound Commands

Commands for generated sound, PLAY strings, and sfxlib mix settings.

Syntax
   Beep [ duration, pitch ]
   Sound frequency, duration
   Sound channel, frequency, duration, volume
   Tone channel, frequency, duration
   Noise channel, duration, volume
   Noise channel, frequency, duration, volume
   Note name, octave, duration
   Note channel, name, octave, duration
   Play music
   Play channel, music
   Play music1, music2
   Play music1, music2, music3
   Tempo bpm
   bpm = Tempo()
   Channel channel
   channel = Channel()
   Octave octave
   octave = Octave()
   Voice instrument
   instrument = Voice()
   Vol level
   Volume level
   level = Volume()
   Volume channel, level
   level = Volume( channel )
   Balance position
   position = Balance()
   Pan channel, position
   position = Pan( channel )
   Wave id, waveform
   Envelope id, attack, decay, sustain, release
   Instrument id, wave_id, envelope_id
   Instrument channel, instrument_id

Description
   These commands synthesize sound directly through sfxlib.  Sound, Tone, 
   Noise, Note, and Play create voices.  Tempo, Channel, Octave, and Voice 
   set defaults used by PLAY-string and generated-sound commands.  Volume, 
   Vol, Balance, and Pan control mix levels and stereo placement.

   Sound accepts the high-impact classic form Sound frequency, duration and
   the explicit channel form Sound channel, frequency, duration, volume.
   When both arguments are integers, duration is interpreted as the PC BASIC
   timer-tick value.

   Wave defines a waveform id.  The currently supported waveform values 
   are:
      * 0 sine
      * 1 square
      * 2 triangle
      * 3 saw
      * 4 noise

   Envelope defines an ADSR envelope using seconds for attack, decay, and 
   release, and a 0.0 to 1.0 sustain level.  Instrument can define an 
   instrument from a waveform and envelope, or assign an instrument to a 
   channel.

   The channel-oriented commands use sfxlib's channel table.  Channels are 
   zero-based.

Example
   See examples/sfxlib/basics-01-generated-sound.bas, 
   examples/sfxlib/basics-02-play-strings.bas, 
   examples/sfxlib/basics-03-channels-mix.bas, 
   examples/sfxlib/basics-04-instruments.bas, and 
   examples/sfxlib/showcase.bas.

Platform Differences
   * On headless or diagnostic runs, SFXLIB_DRIVER=null can be set before 
     program startup to use the null output driver.

Differences from QB
   * New to FreeBASIC.

See also
   * Beep
   * Music
   * Sfx
   * Sound Library Reference



--------------------------------------------------------- KeyPgBaseInit ----
Base (Initializer)

Specifies an initializer for the base UDT in derived Udt constructors

Syntax
   Base ( constructor-parameters... )
or:
   Base ( UDT-initializers... )

Description
   The Base initializer can be used at the top of constructors of derived 
   UDTs. It allows to specify an explicit constructor call or UDT 
   initializers to be used to initialize the base object. It will replace 
   the implicit default initialization, and must appear above any other 
   statements in the constructor it is used in.

   Note: Unlike "Base( )", a "Base (Member Access).Constructor( )" 
   statement does not replace the implicit default initialization done by 
   the constructor of a derived UDT, and can usually not be used legally, 
   because it would result in two constructor calls for the base object 
   (for an inheritance structure extending the built-in Object type, this 
   second base constructor call may also corrupt the vtable pointer to 
   point to the base-type vtable instead of to the type vtable).

Example
   Type SimpleParent
      As Integer a, b, c
   End Type

   Type Child Extends SimpleParent
      Declare Constructor( )
   End Type

   Constructor Child( )
      '' Simple UDT initializer
      Base( 1, 2, 3 )
   End Constructor

   Type ComplexParent
      As Integer i
      Declare Constructor( ByVal As Integer = 0 )
   End Type

   Constructor ComplexParent( ByVal i As Integer = 0 )
      this.i = i
   End Constructor

   Type Child Extends ComplexParent
      Declare Constructor( )
      Declare Constructor( ByRef As Child )
   End Type

   Constructor Child( )
      '' Base UDT constructor call
      Base( 1 )
   End Constructor

   Constructor Child( ByRef rhs As Child )
      '' Base UDT constructor call
      Base( rhs.i )
   End Constructor

Dialect Differences
   * Methods are only supported in the -lang fb dialect, hence Base has no 
     function in other dialects.

Differences from QB
   * New to FreeBASIC

See also
   * Base (Member Access)
   * This
   * Type
   * Extends
   * Extends Zstring
   * Extends Wstring
   * Option Base



------------------------------------------------------------- KeyPgBase ----
Base (Member Access)

Provides explicit access to base type members in non-static methods of a 
Type

Syntax
   Base.member
   Base [ .Base ... ] .member

Description
   Base provides a way to explicitly access members of a specific base 
   type, in the context of non-static methods of a user-defined type 
   derived from another type using Extends.

   By using Base repeatedly, as in base.base.base.member, it is possible to 
   access any desired base type, in case there are multiple levels of 
   inheritance.

   Base is especially useful when a base type's member is shadowed by a 
   local variable or member of a derived type using the same identifier. 
   Base then allows unambiguous access to the base type.

   For virtual methods, base.method() always calls the base method and 
   never the overriding method.

   Note: There is no specific syntax with Base to access a member operator 
   of a specific base type. The only way is to apply the operator on the 
   instance beforehand up-casted to the right type (but for virtual 
   operators, this workaround does not allow to call the base operator when 
   overridden, because that does not modify the run-time type of the 
   instance but only its compile-time type).

Example
   Type Parent
      As Integer a
      Declare Constructor(ByVal As Integer = 0)
      Declare Sub show()
   End Type

   Constructor Parent(ByVal a As Integer = 0)
      This.a = a
   End Constructor

   Sub Parent.show()
      Print "parent", a
   End Sub

   Type Child Extends Parent
      As Integer a
      Declare Constructor(ByVal As Integer = 0)
      Declare Sub show()
   End Type

   Constructor Child(ByVal a As Integer = 0)
      '' Call base type's constructor
      Base(a * 3)
      This.a = a
   End Constructor

   Sub Child.show()
      '' Call base type's show() method, not ours
      Base.show()
      
      '' Show both a fields, the base type's and ours'
      Print "child", Base.a, a
   End Sub

   Type GrandChild Extends Child
      As Integer a
      Declare Constructor(ByVal As Integer = 0)
      Declare Sub show()
   End Type

   Constructor GrandChild(ByVal a As Integer = 0)
      '' Call base type's constructor
      Base(a * 2)
      This.a = a
   End Constructor

   Sub GrandChild.show()
      '' Call base type's show() method, not ours
      Base.show()
      
      '' Show both a fields, the base.base type's, the base type's and ours'
      Print "grandchild", Base.Base.a, Base.a, a
   End Sub

   Dim As GrandChild x = GrandChild(3)
   x.show()

Dialect Differences
   * Methods are only supported in the -lang fb dialect, hence Base has no 
     function in other dialects.

Differences from QB
   * New to FreeBASIC

See also
   * Base (Initializer)
   * This
   * Type
   * Extends
   * Extends Zstring
   * Extends Wstring
   * Option Base



------------------------------------------------------------- KeyPgBeep ----
Beep

Produces a beep sound.

Syntax
   Declare Sub Beep ( )
   Declare Sub Beep ( ByVal duration As Single, ByVal pitch As Single )

Usage
   Beep
   Beep duration, pitch

Parameters
   duration
      Duration in seconds.
   pitch
      Pitch as semitones from middle C, matching the sfxlib pitch form.

Description
   Beep tells the system to sound a beep noise.  The no-argument form keeps 
   the traditional console behavior.  The two-argument form uses sfxlib and 
   produces a generated note with an explicit duration and pitch.

   For more control over generated sound, use the sfxlib commands such as 
   Sound, Tone, Note, and Play.

Example
   Beep

Differences from QB
   *  In QB, this was a single tone noise generated through the PC 
     speaker. Now this might not be the case.

See also
   * Out - producing sound using CPU ports
   * Sound Library Reference
   * Generated Sound Commands



-------------------------------------------------------------- KeyPgBin ----
Bin

Returns a binary (base 2) string representation of an integer

Syntax
   Declare Function Bin ( ByVal number As UByte ) As String
   Declare Function Bin ( ByVal number As UShort ) As String
   Declare Function Bin ( ByVal number As ULong ) As String
   Declare Function Bin ( ByVal number As ULongInt ) As String
   Declare Function Bin ( ByVal number As Const Any Ptr ) As String

   Declare Function Bin ( ByVal number As UByte, ByVal digits As Long ) As 
   String
   Declare Function Bin ( ByVal number As UShort, ByVal digits As Long ) As 
   String
   Declare Function Bin ( ByVal number As ULong, ByVal digits As Long ) As 
   String
   Declare Function Bin ( ByVal number As ULongInt, ByVal digits As Long ) 
   As String
   Declare Function Bin ( ByVal number As Const Any Ptr, ByVal digits As 
   Long ) As String

Usage
   result = Bin[$]( number [, digits ] )

Parameters
   number
      A number or expression evaluating to a number.  A floating-point 
      number will be converted to a LongInt.
   digits
      Desired number of digits in the returned string.

Return Value
   A string containing the unsigned binary representation of number.

Description
   Returns a string representing the unsigned binary value of the integer 
   number. Binary digits range from 0 to 1.

   If you specify digits > 0, the result string will be exactly that 
   length.  It will be truncated or padded with zeros on the left, if 
   necessary.

   The length of the string will not go longer than the maximum number of 
   digits required for the type of number (32 for a Long, 64 for a LongInt)
   .

   If you want to do the opposite, i.e. convert an binary string back into 
   a number, the easiest way to do it is to prepend the string with "&B", 
   and convert it to an integer type, using a function like CInt, similarly 
   to a normal numeric string.  E.g. CInt("&B101")

Example
   Print Bin(54321)
   Print Bin(54321, 5)
   Print Bin(54321, 20)

   will produce the output:

   1101010000110001
   10001
   00001101010000110001

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Bin.
   * The string type suffix "$" is ignored in the -lang fblite dialect, 
     always warn.
   * The string type suffix "$" is ignored in the -lang fb dialect, always 
     warn.

Differences from QB
   * New to FreeBASIC

See also
   * Oct
   * Hex
   * ValInt
   * ValLng



----------------------------------------------------------- KeyPgBinary ----
Binary

Specifies file or device to be opened for binary mode

Syntax
   Open filename for Binary [Access access_type] [Lock lock_type] as [#]
   filenum 

Parameters
   filename
      file name to open
   access_type
      indicates whether the file may be read from, written to or both
   lock_type
      locking to be used while the file is open
   filenum
      unused file number to associate with the open file

Description
   Opens a file or device for reading and/or writing binary data in the 
   file filenum, with free format.
   If the file does not exist, a new file will be created. The file pointer 
   is initialized by Open at byte no. 1. 
   Get # and Put # file operations move the file pointer according to the 
   size of the data, the pointer can be set to any byte in the file.
   The data existing in the file is preserved by Open. 
   This file mode can use any buffer variable to read/write data in the 
   file.   
   The data is saved in binary mode, in the same internal format FreeBASIC 
   uses, by means of Get # and Put #.

   filename must be a string expression resulting in a legal file name in 
   the target OS, without wildcards. The file will be sought for in the 
   present directory, unless a path is given.

   Access_type By default Binary mode allows to both read and write the 
   file, unless an Access type is specified, it must be one of: 
      * Read - the file is opened for input only
      * Write - the file is opened for output only
      * Read Write - the file is opened for input and output (the default)

   Lock_type indicates the way the file is locked  for other processes 
   (users or threads), it is one of:
      * Shared - The file can be freely accessed by other processes     
      * Lock Read - The file can't be opened simultaneously for reading
      * Lock Write - The file can't be opened simultaneously for writing
      * Lock Read Write - The file cannot be opened simultaneously by 
        other processes.
      If no lock type is stated, the file will be Shared for other threads 
      of the program and Lock Read Write for other programs.
      Lock and Unlock can be used to restrict temporally access to parts of 
      a file.

   filenum is a valid file number (in the range 1..255) not being used for 
   any other file presently open. The file number identifies the file for 
   the rest of file operations. A free file number can be found using the 
   FreeFile function.

Example
   '' Create a binary data file with one number in it
   Dim x As Single = 17.164

   Open "MyFile.Dat" For Binary As #1
     '' put without a position setting will put from the last known file position
     '' in this case, the very beginning of the file.
     Put #1, , x
   Close #1

   '' Now read the number from the file
   Dim x As Single = 0

   Open "MyFile.Dat" For Binary As #1
     Get #1, , x
   Close #1

   Print x

   '' Read entire contents of a file to a string
   Dim txt As String

   Open "myfile.txt" For Binary Access Read As #1
     If LOF(1) > 0 Then
      '' our string has as many characters as the file has in bytes
      txt = String(LOF(1), 0)
      '' size of txt is known.  entire string filled with file data
      Get #1, , txt
     End If
   Close #1

   Print txt

Differences from QB
   * None

See also
   * Open
   * Put #
   * Get #
   * Random
   * Append
   * Output
   * Input



-------------------------------------------------------------- KeyPgBit ----
Bit

Gets the state of an individual bit in an integer value.

Syntax
   #define Bit( value, bit_number ) (((value) And (Cast(TypeOf(value), 1) 
   Shl (bit_number))) <> 0)

Usage
   result = Bit( value, bit_number )

Parameters
   value
      The integer value.
   bit_number
      The index of the bit.

Return Value
   Returns an Integer value of -1 if the bit is set, or 0 if the bit is 
   cleared.

Description
   This macro expands to an integer value indicating whether or not the bit 
   specified by bit_number is set in the integer value. Behaves as `(value 
   And 1 Shl bit_number) <> 0`.

   The valid range of values for bit_number depends on the size, in bits, 
   of `TypeOf(value)`, which is `0` (from the lowest bit) through `SizeOf(
   value) * 8 - 1` (up to the highest bit). See Standard Datatype Limits 
   for a table of the standard datatypes and their sizes.
   For the bit_number values outside the valid range, the results of this 
   macro are undefined.

Example
   Print Bit(&B1000, 3)
   Print Bit(4,2)
   Print Bit(5,1)
   Print Bit(&H8000000000000000ULL,63)

   will produce the output:


   -1
   -1
    0
   -1

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Bit.

Differences from QB
   * New to FreeBASIC

See also
   * BitSet
   * BitReset



--------------------------------------------------------- KeyPgBitreset ----
BitReset

Gets the value with a specified bit cleared, from a copied integer.

Syntax
   #define BitReset( value, bit_number ) ((value) And Not (Cast(TypeOf(
   Value), 1) Shl (bit_number)))

Usage
   result = BitReset( value, bit_number )

Parameters
   value
      The integer value.
   bit_number
      The index of the bit to clear.

Return Value
   Returns the integer value with the specified bit cleared.

Description
   This macro expands to a copy of the integer value with the specified 
   bit_number cleared (to off, or `0`). Behaves as `value And Not (1 Shl 
   bit_number)`.
   To clear a specified bit in a variable, the following assignment can be 
   used: variable = BitReset( variable, bit_number )

   The valid range of values for bit_number depends on the size, in bits, 
   of `TypeOf(value)`, which is `0` (from the lowest bit) through `SizeOf(
   value) * 8 - 1` (up to the highest bit). See Standard Datatype Limits 
   for a table of the standard datatypes and their sizes.
   For the bit_number values outside the valid range, the results of this 
   macro are undefined.

Example
   Print Bin(BitReset(&b10101, 2))
   Print BitReset(5,0)
   Print Hex(BitReset(&h8000000000000001,63))

   will produce the output:

   10001
    4
   1

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Bitreset.

Differences from QB
   * New to FreeBASIC.

See also
   * Bit
   * BitSet



----------------------------------------------------------- KeyPgBitset ----
BitSet

Gets the value with a specified bit set, from a copied integer.

Syntax
   #define BitSet( value, bit_number ) ((value) Or (Cast(TypeOf(Value), 1) 
   Shl (bit_number)))

Usage
   result = BitSet( value, bit_number )

Parameters
   value
      The integer value.
   bit_number
      The index of the bit to set.

Return Value
   Returns the integer value with the specified bit set.

Description
   This macro expands to a copy of the integer value with the specified 
   bit_number set (to on, or `1`). Behaves as `value Or (1 Shl bit_number)
   `.
   To set a specified bit in a variable, the following assignment can be 
   used: variable = BitSet( variable, bit_number )

   The valid range of values for bit_number depends on the size, in bits, 
   of `TypeOf(value)`, which is `0` (from the lowest bit) through `SizeOf(
   value) * 8 - 1` (up to the highest bit). See Standard Datatype Limits 
   for a table of the standard datatypes and their sizes.
   For the bit_number values outside the valid range, the results of this 
   macro are undefined.

Example
   Print Bin(BitSet(&b10001,2))
   Print BitSet(4, 0)
   Print Hex(BitSet(1ull, 63))

   will produce the output:

   10101
    5
   8000000000000001

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Bitset.

Differences from QB
   * New to FreeBASIC.

See also
   * Bit
   * BitReset



------------------------------------------------------------ KeyPgBload ----
BLoad

Loads arbitrary data from a file created with BSave, or a compatible BMP 
image file.

Syntax
   Declare Function BLoad ( ByRef filename As Const String, ByVal dest As 
   Any Ptr = 0, ByVal pal As Any Ptr = 0 ) As Long

Usage
   result = BLoad( filename [, [ dest ] [, pal ] ] )

Parameters
   filename
      the name of the file to load the image from; can include a file path
   dest
      the memory location to load the image to, or null (0) to copy the 
      image to the current graphics screen work page
   pal
      the memory location to load the palette to, or null (0) to change the 
      current graphics screen palette, if it uses one

Return Value
   Returns zero (0) if successful, or a non-zero error code to indicate a 
   failure. (throws a runtime error)

Description
   BLoad can be used to load image data or any other data from a file 
   created with BSave, and store that data in an array or paste it to the 
   screen. If dest is absent or null (0), the image data is pasted to the 
   current graphics screen work page.  Otherwise it is loaded as image data 
   to the address given by dest.
   BLoad must be called only if a graphics mode is initialized, else the 
   program crashes (see BLOAD/BSAVE text mode work-around to work in text 
   mode).

   BLoad can load 3 different types of files:
      * Old QB-like data files, saved with BSAVE from QB code, containing 
        "raw" data preceded by a 7-byte header, beginning with &HFD, up to 
        64 KiB in size
      * New FB-like data files, saved with BSave from FB code, containing 
        "raw" data preceded by a 5-byte header, beginning with &HFE. There 
        is no 64 KiB limit with this format
      * BMP image files, supports a subset of valid ("Windows") .BMP 
        files, beginning with "BM", saved from FB code with BSave, or 
        created / saved in a compatible format using a graphics editor / 
        converter.
   QB-like data files and BMP files are converted to an FB-compatible image 
   format when opened.

   Image files with 8-bit per pixel resolution or lower contain a palette 
   that describes the color values used in the images. If pal is not null (
   0), the palette is copied to memory starting at the address specified. 
   Otherwise, if the current graphics screen uses a palette then its 
   palette is changed to match that of the image file.

   When using one of the 2 "non-BMP" file formats to save images, the image 
   files must have been created with BSave in the same graphics screen mode 
   as it is being loaded into. When using the BMP file format, this 
   restriction doesn't apply. 

   When loading a BMP file using BLoad,  the images must be true-color 
   (15-, 16-, 24- or 32-bits per pixel) or palettized/indexed (8-bit or 
   lower). The image data will be converted to the proper pixel format for 
   the current color depth, except that true-color can't be reduced to a 
   palettized image. BLoad doesn't support BMP files using RLE compression 
   or other image file types (PNG, JPG, GIF, ...).  BLoad will load alpha 
   channel information, if available, from 32-bit BMP files with 
   BITMAPV4HEADER or BITMAPV5HEADER file headers.

   The error code returned by BLoad can be checked using Err in the next 
   line. The function version of  BLoad returns directly the error code as 
   a 32 bit Long.

Runtime errors:
   BLoad throws one of the following runtime errors:
      (1) Illegal function call
         * dest was not specified or was null (0), and no graphics screen 
           was set.
         * The Bitmap uses an unsupported BMP file compression type (
           BI_RLE4, BI_RLE8)
         * The Bitmap is true-color (16, 24, or 32 bits per pixel) and the 
           current graphics screen uses a palette (8 bits per pixel or 
           lower).
      (2) File not found
         * The file filename could not be found.
      (3) File I/O error
         * The file doesn't have any of the supported types 
         * A general read error occurred.

   Note: When you use BLoad to load a BMP file into an image buffer, the 
   original dimensions of the image are not changed.  If you want the image 
   buffer to have the same dimensions as the BMP file, you have to find out 
   the dimensions beforehand, and create an image of the right size 
   yourself.  See the example below for an example of how to do this.

Example
   'Load a graphic to current work page
   Screen 18, 32
   Cls
   BLoad "picture.bmp"
   Sleep

   'Load a 48x48 bitmap into an image
   ScreenRes 320, 200, 32
   Dim myImage As Any Ptr = ImageCreate( 48, 48 )
   BLoad "picture.bmp", myImage
   Put (10,10), myImage
   ImageDestroy( myImage )
   Sleep

   ScreenRes 640, 480, 8 '' 8-bit palette graphics mode
   Dim pal(0 To 256-1) As Integer '' 32-bit integer array with room for 256 colors

   '' load bitmap to screen, put palette into pal() array
   BLoad "picture.bmp", , @pal(0)

   WindowTitle "Old palette"
   Sleep

   '' set new palette from pal() array
   Palette Using pal(0)

   WindowTitle "New palette"
   Sleep

   '' A function that creates an image buffer with the same 
   '' dimensions as a BMP image, and loads a file into it.

   Const NULL As Any Ptr = 0

   Function bmp_load( ByRef filename As Const String ) As Any Ptr

      Dim As Long filenum, bmpwidth, bmpheight
      Dim As Any Ptr img

      '' open BMP file
      filenum = FreeFile()
      If Open( filename For Binary Access Read As #filenum ) <> 0 Then Return NULL

         '' retrieve BMP dimensions
         Get #filenum, 19, bmpwidth
         Get #filenum, 23, bmpheight

      Close #filenum

      '' create image with BMP dimensions
      img = ImageCreate( bmpwidth, Abs(bmpheight) )

      If img = NULL Then Return NULL

      '' load BMP file into image buffer
      If BLoad( filename, img ) <> 0 Then ImageDestroy( img ): Return NULL

      Return img

   End Function

   Dim As Any Ptr img

   ScreenRes 640, 480, 32

   img = bmp_load( "picture.bmp" )

   If img = NULL Then
      Print "bmp_load failed"

   Else

      Put (10, 10), img

      ImageDestroy( img )

   End If

   Sleep

Differences from QB
   * Support for loading BMP files is new to FreeBASIC.
   * Support for retrieving the palette from BMP files is new to FreeBASIC
     .
   * FreeBASIC uses a different file format from QBASIC internally, which 
     doesn't have the 64 KiB limit, and is unsupported by QBASIC.

See also
   * BSave
   * Palette
   * ImageCreate
   * ImageDestroy
   * Internal Graphics Formats



---------------------------------------------------------- KeyPgBoolean ----
Boolean

Standard data type

Syntax
   Dim variable As Boolean

Description
   Boolean data type. Can hold the values True or False
   Default value on initialization is False

   Notes on definition of boolean data type:
      - Ideally, the definition of the boolean data type is that it holds 
      the value of True or False, and that's it. However, to make this 
      concept a reality, we need a definition that uses real world 
      connections.
      - A more realistic definition is that the boolean data type is a 
      1-bit integer, having the value 0 to indicate False and 1 to indicate 
      True.
      - For a practical definition, we must consider, yet again, additional 
      factors. The most significant factor is that the hardware (processor) 
      on which code is executed does not directly support a 1-bit data 
      type; the smallest register or memory size we can work with is 8-bits 
      or 1-byte.
      - Assume "false" is 0 in both C/C++ and FB.  C/C++ has logical 'not' 
      operator '!' such that '!0' produces '1'.  FB has a bitwise Not 
      operator such that 'not 0' produces '-1'.
      - Nevertheless the definition under the hood for a FB boolean remains 
      an 1-bit integer, zero extended to fill larger integer types.
      - Therefore when assigning a boolean with an integer value (by 
      implicit conversion and not with the False or True value), '0' 
      induces the False state and '1' or '-1' induces the True state (any 
      other value also induces the True state, but with a warning message).
      - Otherwise when assigning a numeric type with a boolean (by implicit 
      conversion), False induces the '0' value and True induces the '-1' 
      value.
      - However, the purpose and intent of the boolean data type remains, 
      that it should only ever hold a True value or False value, regardless 
      of the underlying details.

Example
   Dim boolvar As Boolean
   boolvar = True
   Print "boolvar = ", boolvar

   Output:

   boolvar =     True

Version
   * Since fbc 1.04.0

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Boolean.

Differences from QB
   * New to FreeBASIC

See also
   * CBool
   * True
   * False
   * Table with variable types overview, limits and suffixes



------------------------------------------------------------ KeyPgBsave ----
BSave

Saves an array of arbitrary data and palette information to a file on disk

Syntax
   Declare Function BSave ( ByRef filename As Const String, ByVal source As 
   Any Ptr, ByVal size As ULong = 0, ByVal pal As Any Ptr = 0, ByVal 
   bitsperpixel As Long = 0 ) As Long

Usage
   result = BSave( filename, source [,[ size ][,{ pal | pal, bitsperpixel 
   }]] )

Parameters
   filename
      the name of the file to create for storing the pixel and palette 
      data.
   source
      the address of the data to store, or null (0) to store pixel data 
      from the current screen work page.
   size
      optional, the total number of bytes of data to store.  This value is 
      needed unless the output is a BMP file.
   pal
      optional, the address of a buffer holding 256 Palette colors, or null 
      (0) for the current screen palette.
   bitsperpixel
      optional, a requested bit depth for the output BMP image. If 
      bitsperpixel is specified, pal must also be specified (at a least 
      null (0) value), otherwise an error is obtained.

Return Value
   Returns zero (0) if successful, or a non-zero error code to indicate a 
   failure. (throws a runtime error)

Description
   BSave is used for saving arbitrary data from memory into a file, using a 
   file format specific to FB, or saving images into a standard BMP image 
   file, replacing an existing file if necessary.
   BSave must be called only if a graphics mode is initialized, else the 
   program crashes (see BLOAD/BSAVE text mode work-around to work in text 
   mode).

   BSave outputs a total of size bytes of arbitrary data located at source 
   to a specified file. If source is null (0), then BSave outputs a maximum 
   of size bytes from the current work page's pixel buffer, which is 
   structured in the current screen mode's internal pixel format. (This 
   data is not compatible with the image buffer format as it has no 
   header.)  For 8-bit images, palette information is obtained from pal if 
   present and non-null, or if pal omitted or null (0), from the current 
   screen palette.

   A BMP image file can be created if filename has a file extension of "
   .bmp" (case insensitive). source is assumed to point to a valid image 
   buffer whose entire pixel data will be stored in the BMP file. If source 
   is null (0), the contents of the current work page will be stored 
   instead. For 8-bit images, palette information is obtained from pal if 
   non-null, or if null (0), from the current screen palette. The size 
   parameter is ignored when saving BMP files.

   The default bit depth for BMP files is 8-bit for 8-bit (palette) images, 
   24-bit for 16-bit images, and 32-bit for 32-bit images.  The 
   bitsperpixel parameter can be used to request 24-bit output for 8-bit 
   images, or 24-bit output for 32-bit images.

   The error code returned by BSave can be checked using Err in the next 
   line. The function version of  BSave returns directly the error code as 
   a 32 bit Long.

Runtime errors:
   BSave throws one of the following runtime errors:

   (1) Illegal function call
      * size is less than zero (0), or size is zero and source is 
        non-null, or a problem is detected with the image buffer.
   (2) File not found
      * The file could not be created.
   (3) File I/O error
      * The file could not be written to.

Example
   ' Set gfx mode
   ScreenRes 320, 200, 32

   ' Clear with black on white
   Color RGB(0, 0, 0), RGB(255, 255, 255)
   Cls

   Locate 13, 15: Print "Hello world!"

   ' Save screen as BMP
   BSave "hello.bmp", 0

Save image buffer to bitmap file:
   'set graphics screen 640 x 480 pixels, 32 bit colors
   Const W = 640, H = 480 'width & hight
   ScreenRes W, H, 32
   'draw a smiley at screen center
   Circle (W \ 2, H \ 2), 180, &h00ffff00, , , , f 'yellow circle
   Circle (W \ 2 - 55, H \ 2 - 70), 35, &h00000000, , , 1.5, f 'left eye
   Circle (W \ 2 + 55, H \ 2 - 60), 35, &h00000000, , , 1.5, f 'right eye
   Circle (W \ 2, H \ 2 + 80), 70, &h00000000, , , 0.4, f 'mouth
   'allocate memory for image buffer
   Dim As Any Ptr pImageBuffer = ImageCreate(250, 250)
   'copy screen section to buffer
   Get (W \ 2 - 125, H \ 2 - 125)-Step(250 - 1, 250 - 1), pImageBuffer
   'save image buffer to file
   Dim As String fileName = "Smiley.bmp"
   If BSave(fileName, pImageBuffer) = 0 Then
      Print "Saved succesful: " + fileName
   Else
      Print "Error saving: " + fileName
   End If
   'free memory for image buffer
   ImageDestroy(pImageBuffer)
   'keep graphics screen open until key press
   Sleep

Differences from QB
   * Support for saving more than 64KiB of arbitrary data is new to 
     FreeBASIC.
   * Support for saving BMP files is new to FreeBASIC.
   * QB cannot use BLoad to load files created with BSave in FreeBASIC, 
     but FreeBASIC can use BLoad to load files created with BSave in QB

See also
   * BLoad
   * Palette



------------------------------------------------------------ KeyPgByref ----
Byref (Parameters)

Declaration specifier to explicitly pass a parameter by reference

Syntax
   ByRef param As datatype

Usage
   [ Declare ] { Sub | Function } proc_name ( ByRef param As datatype  )

Description
   Passes a variable by reference, that is its address, to a subroutine or 
   function. When a variable is passed by reference, the contents of the 
   variable can be changed by the target subroutine or function.

   In -lang qb and -lang fblite dialects, ByRef is the default parameter 
   passing convention, unless Option ByVal is in effect.

   Opposite of ByVal.

   Note: A constant or a literal expression can also be passed to such a 
   procedure (which gets by reference), but they are obviously not 
   modifiable from the procedure body. In that case, the compiler passes by 
   reference a temporary variable initialized with the constant or the 
   literal expression.

   Note: Since fbc version 1.20.0, arguments of STRING*N type are copied to 
   a temporary variable when passed to BYREF ZSTRING (or BYVAL ZSTRING PTR) 
   parameters (since there is no expectation that STRING*N will have it's 
   own terminating null character) and copied back after the call.

   Warning: When passing by reference, it is recommended to pass an 
   argument of the same type (or fully compatible, like a derived type for 
   example) as that of the declared parameter. Although in some cases the 
   compiler accepts to pass a different type, often the result is not the 
   one expected.

Example
   Dim MyVar As Integer

   Sub ChangeVar(ByRef AVar As Integer)
      AVar = AVar + 1
   End Sub

   MyVar = 1
   Print "MyVar: "; MyVar 'output = 1
   ChangeVar MyVar
   Print "MyVar: "; MyVar 'output = 2
   Sleep
   End

Dialect Differences
   * In -lang fb dialect, ByVal is the default parameter passing 
     convention for all built-in types except String and user-defined Type 
     which are passed ByRef by default. The ZString and WString built-in 
     types are also passed ByRef by default, but passing ByVal is 
     forbidden. Arrays are always passed ByRef and the use of the specifier 
     ByRef or ByVal is forbidden.
   * In -lang qb and -lang fblite dialects, ByRef is the default parameter 
     passing convention.

Differences from QB
   * New to FreeBASIC

See also
   * Passing Arguments to Procedures
   * Declare
   * ByVal
   * Byref (Function Results)
   * Byref (Variables)



---------------------------------------------------- KeyPgByrefFunction ----
Byref (Function Results)

Specifies that a function result is returned by reference

Syntax
   Function name ( parameter-list ) ByRef As datatype

Description
   Causes the function result to be returned by reference, rather than by 
   value. A function returning ByRef will return the address of a variable, 
   instead of making a copy like when returning by value. This allows the 
   caller of the function to modify the variable which the function result 
   points to.

   If ByRef is not specified, the default is to return the function result 
   by value.

   Functions with ByRef result should not return local variables from the 
   function, because they will be destroyed upon returning from the 
   function, invalidating any pointer or reference to them. To help with 
   writing safe code, the compiler will show an error message when a local 
   variable is used with Function = x (or name = x) assignments and Return 
   x statements.

   Note: On the left-hand side of an assignment expression using the '=' 
   symbol, the result of the function (returned by reference) must be 
   enclosed in parentheses when the function calls one single argument, in 
   order to solve the parsing ambiguity. '=>' can be used for assignments, 
   in place of '=', same as for initializers, allowing to avoid parsing 
   ambiguity (without parentheses). As for the arguments list, it should 
   always be surrounded with parentheses even if empty.

   Operators (member or global), when used as functions, have also the 
   capability to return results by reference, by using the same syntax.

Example
   Function min( ByRef I As Integer , ByRef J As Integer ) ByRef As Integer
      '' The smallest integer will be returned by reference, no copy will be created.
      If I < J Then
         Return I
      Else
         Return J
      End If
   End Function

   Dim As Integer A = 13, B = 7
   Print A, B
   Print min( A , B )
   min( A , B ) = 0
   Print A, B

   Function f( ) ByRef As Const ZString
      '' This string literal (because statically allocated in memory) will be returned by reference, no copy will be created.
      Function = "abcd"
   End Function

   Print f( )

   Dim Shared As String s

   Function f1( ) ByRef As String
      '' This variable-length string will be returned by reference, no copy will be created.
      Function = s
   End Function

   Function f2( ByRef _s As String ) ByRef As String
      '' This variable-length string will transit by reference (input and output), no copy will be created.
      Function = _s
   End Function

   s = "abcd"
   Print s

   f1( ) = f1( ) & "efgh"
   Print s

   '' The enclosing parentheses are required here on the left-hand side.
   ( f2( s ) ) = f2( s ) & "ijkl"
   Print s

   '' The enclosing parentheses are not required here on the left-hand side.
   f2( s ) => f2( s ) & "mnop"
   Print s

   Function power2( ByRef _I As Integer ) ByRef As Integer
      _I *= _I
      '' This integer will be returned by reference, no copy will be created.
      Function = _I
   End Function

   Dim As Integer I = 2
   power2( power2( power2( I ) ) )  '' Function return-byref cascading is equivalent to ((I*I)*(I*I))*((I*I)*(I*I)) = I^8
   Print I

Differences from QB
   * New to FreeBASIC

See also
   * Returning values
   * Byref (Parameters)
   * Byref (Variables)



--------------------------------------------------- KeyPgByrefVariables ----
Byref (Variables)

Declares a reference

Syntax
      (Dim | Static) [Shared] ByRef name1 As DataType = variable1 [, ByRef 
      name2 As DataType = variable2, ...]
   or
      (Dim | Static) [Shared] ByRef As DataType name1 = variable1 [, name2 
      = variable2, ...]
   or
      [Static] Var [Shared] ByRef name1 = variable1 [, ByRef name2 = 
      variable2, ...]

Parameters
   name
      reference name
   variable
      variable name to refer

Description
   Declares a reference (by name) to a variable.

   A reference is an entity that is a way to access data located in memory. 
   A reference is not the data itself but only information about its 
   location. A reference can be thought of as a pointer that is implicitly 
   dereferenced. In many cases, it can be used as an alternative to 
   pointer.

   A reference must always be initialized with a variable when it is 
   created.
   DataType must be the same type as that of the variable, or a compatible 
   type (for example one from the types of its Bases in case of 
   inheritance):
      * Only when the two types are identical (or using the third syntax 
        with Var), a reference can be considered as an alias of the 
        variable. One can do the same operations through such a reference 
        as one can do with the original variable.
      * Otherwise (types compatible but not identical), one cannot do all 
        same operations than with the original variable:
            For example, a base type reference referring to a derived type 
            object allows to activate polymorphism when a virtual method is 
            called on it, similarly to a base type pointer referring to a 
            derived type object. One can do the same operations through 
            such a reference as one can do with a dereferenced pointer of 
            same type (but for both not the same operations as using 
            directly the derived type instance).

   A reference can be reassigned to refer to another variable (of 
   compatible type) by doing:
      @refname = @othervariable

   NOTE: The arrays of references and the non-static reference fields for 
   UDT are not supported yet.

Example
   '' Comparison between:
   ''   - a copy ('ci') of a variable ('i')
   ''   - a reference ('ri') to a variable ('i')

   Dim As Integer i = 12
   Print @i, i

   Dim As Integer ci = i  '' or Var ci = i
   Print @ci, ci

   Dim ByRef As Integer ri = i  '' or Var Byref ri = i
   Print @ri, ri

   Print

   Print i, ci, ri
   i = 34
   Print i, ci, ri
   ci = 56
   Print i, ci, ri
   ri = 78
   Print i, ci, ri

   Sleep
      

   '' Use reference allows to simplify expressions compared to pointer
   '' (avoid to use operator '@' and especially '*')

   Function fp () As ZString Ptr
      Static As ZString * 256 z
      Return @z
   End Function

   Dim As ZString Ptr pz = fp()
   *pz = "FreeBASIC Zstring Ptr"
   Print *pz
   *pz &= " 1.3.0"
   Print *pz

   Print

   Function fr () ByRef As ZString
      Static As ZString * 256 z
      Return z
   End Function

   Dim ByRef As ZString rz = fr()  '' or Var Byref rz = fr()
   rz = "FreeBASIC Zstring Ref"
   Print rz
   rz &= " 1.4.0"
   Print rz

   Sleep
      

   '' It is possible to reassign a reference.
   '' An example with an UDT to control the successive constructions & destructions of objects handled with one only reference.

   Type UDT
     Declare Constructor ()
     Declare Destructor ()
     Dim As Integer I
   End Type

   Constructor UDT ()
     Static As Integer nb
     nb += 1
     This.I = nb
     Print "UDT.Constructor()"
   End Constructor

   Destructor UDT ()
     Print "UDT.Destructor()"
   End Destructor

   Var ByRef ru = *New UDT  '' or Dim Byref As UDT ru = *New UDT
   Print ru.I
   Delete @ru

   Print

   @ru = New UDT
   Print ru.I
   Delete @ru

   Sleep
      

   '' Polymorphism (by using inheritance and virtuality) can be activated through any of the 3 following kinds of entities:
   ''   - base-type pointers referring to derived-type objects,
   ''   - dereferenced base-type pointers referring to derived-type objects,
   ''   - base-type references referring to derived-type objects.
   '
   '' If in the first line of the below code, FALSE is put instead TRUE, the polymorphism by virtuality is no more activated.

   #define virtuality True

   Type myBase Extends Object
     #if virtuality = True
      Declare Virtual Sub hello()
     #else
      Declare Sub Hello()
     #endif
   End Type

   Sub myBase.hello()
     Print "myBase.hello()"
   End Sub

   Type myDerived Extends myBase
     Declare Sub hello()
   End Type

   Sub myDerived.hello()
     Print "myDerived.hello()"
   End Sub

   Dim As myBase mb
   Dim As myBase Ptr pmb = @mb
   Dim ByRef As myBase rmb = mb  '' or Var Byref rmb = mb
   pmb->hello()    '' pmb is a base-type pointer referring to a base-type object
   (*pmb).hello()  '' *pmb is a dereferenced base-type pointer referring to a base-type object
   rmb.hello()     '' rmb is a base-type reference referring to a base-type object

   Print

   Dim As myDerived md
   Dim As myBase Ptr pmd = @md
   Dim ByRef As myBase rmd = md  '' only syntax because the reference data-type must be different from the one of object
   pmd->hello()    '' pmd is a base-type pointer referring to a derived-type object
   (*pmd).hello()  '' *pmd is a dereferenced base-type pointer referring to a derived-type object
   rmd.hello()     '' rmd is a base-type reference referring to a derived-type object

   Sleep
      

Version
   * Since fbc 1.04.0

Dialect Differences
   * Only supported in -lang fb, -lang fblite and -lang deprecated 
     dialects.

Differences from QB
   * New to FreeBASIC.

See also
   * Dim
   * Static
   * Var
   * Shared
   * Byref (Parameters)
   * Byref (Function Results)



------------------------------------------------------------- KeyPgByte ----
Byte

Standard data type: 8 bit signed

Syntax
   Dim variable As Byte

Description
   8-bit signed whole-number data type. Can hold a value in the range of 
   -128 to 127.

Example
     Dim bytevar As Byte
     bytevar = 100
     Print "bytevar= ", bytevar

   Dim x As Byte = CByte(&H80)
   Dim y As Byte = CByte(&H7F)
   Print "Byte Range = "; x; " to "; y

   Output:
   Byte Range = -128 To  127

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Byte.

Differences from QB
   * New to FreeBASIC

See also
   * UByte
   * CByte
   * Table with variable types overview, limits and suffixes



------------------------------------------------------------ KeyPgByval ----
ByVal

Declaration specifier to explicitly pass a parameter by value

Syntax
   ByVal param As datatype

Usage
   [ Declare ] { Sub | Function } proc_name ( ByVal param As datatype  )

Description
   ByVal in a parameter list of a declare statement causes a copy of the 
   variable to be passed to the procedure (for example, a sub or function) 
   by its value.

   This means that if the value of the variable x is passed, then the 
   original variable x will not be modified in any way; however, if the 
   variable were passed ByRef, the value of the original variable x could 
   be modified by the called function.

   Opposite of ByRef.

   The ByVal keyword is also used in the context of Byref Parameters and 
   Function Results, where it can be used to explicitly override the 
   by-reference semantics in order to pass or assign a pointer as-is to a 
   Byref parameter or function result. For reference:
      * Manually passing pointers to by-reference parameters
      * Manually returning pointers as-is from Byref functions

   Note: ByVal (passing by copy) is good for small objects (4 or 8 bytes, a 
   bit more will still be ok) that are easy to copy, like numeric types. 
   Passing ByVal avoids the overhead of the pointer used by ByRef.
   ByRef is better for passing huge objects like strings or big UDTs that 
   should not be copied. Even though ByRef has some overhead because it has 
   to pass a pointer (and dereference at each access to the object), this 
   is still better than copying a multitude of bytes on to the stack 
   every-time the procedure is called.

Example
   Sub MySub(ByVal value As Integer)
      value += 1
   End Sub

   Dim MyVar As Integer

   MyVar = 1
   Print "MyVar: "; MyVar 'output = 1
   MySub MyVar
   Print "MyVar: "; MyVar 'output = 1, because byval won't change the values passed into it globally.
   Sleep
   End

Dialect Differences
   * In the -lang fb dialect, ByVal is the default parameter passing 
     convention for all built-in types except String and user-defined Type 
     which are passed ByRef by default. The ZString and WString built-in 
     types are also passed ByRef by default, but passing ByVal is 
     forbidden. Arrays are always passed ByRef and the use of the specifier 
     ByRef or ByVal is forbidden.
   * In -lang qb and -lang fblite dialects, ByRef is the default parameter 
     passing convention.

Differences from QB
   * QB only used ByVal in declarations to non-Basic subroutines

See also
   * Passing Arguments to Procedures
   * Declare
   * ByRef




============================================================================
    C

------------------------------------------------------------- KeyPgCall ----
Call

Statement to invoke a subroutine

Syntax
   Call procname ([parameter list])

Description
   Calls a Sub or Function.

   This keyword is a holdover from earlier dialects of BASIC, and is mainly 
   deprecated.

   In -lang qb, it can be used to call Subs in code before they are 
   declared.  The function will be implicitly Declare'd, with any 
   parameters passed ByRef As Any.
   Note: until the function is declared, no type-checking is done on the 
   parameters, so it is up to the programmer to ensure they are of the 
   correct type.

Example
   '' Compile with -lang qb or -lang fblite

   #lang "fblite"

   Declare Sub foobar(ByVal x As Integer, ByVal y As Integer)
   Call foobar(35, 42)

   Sub foobar(ByVal x As Integer, ByVal y As Integer)
   Print x; y
   End Sub

   '' Compile with -lang qb or -lang fblite

   #lang "fblite"

   Function f ( ) As Integer
   f = 42
   End Function

   Call f ' execute function f, but ignore the answer

   '' Compile with -lang qb

   '$lang: "qb"

   Call mysub(15, 16) '' call "mysub" before it has been declared, or even mentioned.

   Sub mysub(ByRef a As Integer, ByRef b As Integer)
      
      Print a, b
      
   End Sub

Dialect Differences
   * The use of Call is not allowed in the -lang fb dialect.
   * The -lang fblite dialect does not allow you to call functions that 
     have not been previously declared.

Differences from QB
   * The procedure must have already been declared.
   * Call in QB will make a copy of all parameters, so changes made to the 
     arguments inside the called Sub will not be reflected in the variables 
     in the caller.

See also
   * Declare
   * Sub



-------------------------------------------------------- KeyPgCallocate ----
CAllocate

Allocates memory for a certain number of elements from the free store and 
clears the contents

Syntax
   Declare Function CAllocate cdecl ( ByVal num_elements As UInteger, ByVal 
   size As UInteger = 1 ) As Any Ptr

Usage
   result = CAllocate( num_elements [, size ] )

Parameters
   num_elements
      The number of elements to allocate memory for.
   size
      The size, in bytes, of each element.

Return Value
   If successful, the address of the start of the allocated memory is 
   returned. Otherwise, the null pointer (0) is returned.

Description
   CAllocate initializes the allocated memory with zeros.
   Consequently, CAllocate can be also directly used with String or Udt 
   containing string, because the string descriptor is cleared (set to 0) 
   first.
   Similarly, CAllocate can also be used directly with ZString or WString 
   because string data is created with null characters.

Example
   ' Allocate and initialize space for 10 integer elements.
   Dim p As Integer Ptr = CAllocate(10, SizeOf(Integer))

   ' Fill the memory with integer values.
   For index As Integer = 0 To 9
      p[index] = (index + 1) * 10
   Next

   ' Display the integer values.
   For index As Integer = 0 To 9
      Print p[index] ;
   Next

   ' Free the memory.
   Deallocate(p)
      
Outputs:

    10 20 30 40 50 60 70 80 90 100
   	

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Callocate.

Differences from QB
   * New to FreeBASIC

See also
   * Allocate
   * Deallocate
   * Reallocate



------------------------------------------------------------- KeyPgCase ----
Case

Control flow statement

Syntax
   Case expression

Example
   See example at Select Case.

Differences from QB
   * None

See also
   * Select Case



------------------------------------------------------------- KeyPgCast ----
Cast

Converts an expression to a specified data type

Syntax
   Cast( datatype, expression )

Parameters
   datatype 
      a built-in data type (standard type)
   expression 
      a variable of another built-in data type

Description
   Converts expression into a different datatype. Useful to be used in 
   macros when datatype is unknown and also when converting to Type Alias.

   This is a general form of conversion operators such as CInt or CDbl.
   Cast is more versatile because it can be used on built-in types that 
   have a built-in Cast Operator, but don't have a built-in keyword for it: 
   e.g. Cast( Byte, boolean ).
   It is also suitable for use in cases where the type of a variable is not 
   fixed in the code - for example, it might be Defined earlier, or may be 
   the Type Of a different variable or expression.

   Note: If you want to use an operator specifically for converting to 
   different types of Pointers, consider using CPtr instead.

   Upcasting: In an inheritance structure, the upcasting is converting a 
   derived type reference or pointer into a base type.
   In this special use, Cast applied on a derived-type instance (expression
   ) can be used to return a base-type (datatype) reference.

   By using a member Operator Cast, Cast can be overloaded for a user 
   defined type expression.
  
Example
   '' will print -128 because the integer literal will be converted to a signed Byte
   '' (this Casting operation is equivalent to using CByte)
   Print Cast( Byte, &h0080 )

   '' will print 3 because the floating-point value will be converted to an Integer
   '' (this Casting operator is equivalent to using CInt)
   Print Cast( Integer, 3.1 )

   Sleep

   '' macro sizeofDerefPtr(): returns the size of the dereferenced pointer
   #define sizeofDerefPtr(ptrToDeref) SizeOf(*Cast(TypeOf(ptrToDeref), 0))

   '' macro typeofDerefPtr(): returns the type of the dereferenced pointer
   #define typeofDerefPtr(ptrToDeref) TypeOf(*Cast(TypeOf(ptrToDeref), 0))

   ' Allocate dynamically memory for a Double by New
   Dim As Double Ptr pd
   pd = New typeofDerefPtr(pd)
   *pd = 3.14159
   Print *pd

   ' Allocate dynamically memory for a Zstring*10 by Callocate
   Dim As ZString Ptr pz
   pz = CAllocate(10, sizeofDerefPtr(pz))
   *pz = "FreeBASIC"
   Print *pz

   Sleep
   Delete pd
   Deallocate(pz)

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Cast.

Differences from QB
   * New to FreeBASIC

See also
   * Cast (Operator)
   * CPtr
   * CInt
   * TypeOf
   * Coercion and Conversion
    


---------------------------------------------------------- KeyPgCapture ----
Capture

Controls sfxlib audio capture.

Syntax
   result = Capture Start()
   Capture Pause
   Capture Resume
   Capture Stop
   status = Capture Status()
   frames = Capture Available()
   result = Capture Save( filename )
   frames = Capture Read( samples, frames )

Description
   Capture records audio input when the active backend supports capture.  
   Capture Start begins recording, pause/resume/stop control the capture 
   state, Capture Available reports how many frames can be read, Capture 
   Read copies captured samples into a Single buffer, and Capture Save 
   writes the buffered capture data to a file.

   Capture Status returns 0 for stopped, 1 for running, and 2 for paused.

Example
   See examples/sfxlib/capture-start.bas, examples/sfxlib/capture-read.bas, 
   examples/sfxlib/capture-save.bas, and examples/sfxlib/showcase.bas.

Differences from QB
   * New to FreeBASIC.

See also
   * Device
   * Audio



------------------------------------------------------------ KeyPgCbool ----
CBool

Converts numeric or string expression to a boolean (Boolean)

Syntax
   Declare Function CBool ( ByVal expression As datatype ) As Boolean

   Type typename
      Declare Operator Cast ( ) As Boolean
   End Type

Usage
   result = CBool( numeric expression )
   result = CBool( string expression )
   result = CBool( user defined type )

Parameters
   expression
      a numeric, string, or user defined type to cast to a Boolean value
   datatype
      any numeric, string, or user defined type
   typename
      a user defined type

Return Value
   A Boolean value.

Description
   The CBool function converts a zero value to False and a non-zero value 
   to True.

   The name can be explained as 'Convert to Boolean'.

   If the argument is a string expression, it is converted to boolean using 
   a case insensitive to the string "false" to return a False value or 
   "true" to return a True value.

Example
   ' Using the CBOOL function to convert a numeric value

   'Create an BOOLEAN variable
   Dim b As Boolean

   'Convert a numeric value
   b = CBool(1)

   'Print the result, should return True
   Print b
   Sleep

Version
   * Since fbc 1.04.0

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Cbool.

Differences from QB
   * New to FreeBASIC

See also
   * CByte
   * CUByte
   * CShort
   * CUShort
   * CInt
   * CUInt
   * CLng
   * CULng
   * CLngInt
   * CULngInt
   * CSng
   * CDbl
   * Str



------------------------------------------------------------ KeyPgCbyte ----
CByte

Converts numeric or string expression to Byte.

Syntax
   Declare Function CByte ( ByVal expression As datatype ) As Byte

   Type typename
      Declare Operator Cast ( ) As Byte
   End Type

Usage
   result = CByte( numeric expression )
   result = CByte( string expression )
   result = CByte( user defined type )

Parameters
   expression
      A numeric, string, or pointer expression to cast to a Byte value.
   datatype
      Any numeric, string, or pointer data type.
   typename
      A user defined type.

Return Value
   A Byte value.

Description
   The CByte function rounds off the decimal part and returns a 8-bit Byte 
   value. The function does not check for an overflow, and results are 
   undefined for values which are less than -128 or larger than 127.

   The name can be explained as 'Convert to Byte'.

   If the argument is a string expression, it is converted to numeric by 
   using ValInt.

Example
   ' Using the CBYTE function to convert a numeric value

   'Create an BYTE variable
   Dim numeric_value As Byte

   'Convert a numeric value
   numeric_value = CByte(-66.30)

   'Print the result, should return -66
   Print numeric_value
   Sleep

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Cbyte.

Differences from QB
   * New to FreeBASIC

See also
   * CUByte
   * CShort
   * CUShort
   * CInt
   * CUInt
   * CLng
   * CULng
   * CLngInt
   * CULngInt
   * CSng
   * CDbl



------------------------------------------------------------- KeyPgCdbl ----
CDbl

Converts numeric or string expression to Double precision floating point

Syntax
   Declare Function CDbl ( ByVal expression As datatype ) As Double

   Type typename
      Declare Operator Cast ( ) As Double
   End Type

Usage
   result = CDbl( numeric expression )
   result = CDbl( string expression )
   result = CDbl( user defined type )

Parameters
   expression
      a numeric, string, or pointer expression to cast to a Double value
   datatype
      any numeric, string, or pointer data type
   typename
      a user defined type

Return Value
   A Double precision value.

Description
   The CDbl function returns a 64-bit Double value. The function does not 
   check for an overflow, so be sure not to pass a value outside the 
   representable range of the Double data type. The name can be explained 
   as 'Convert to DouBLe'.

   If the argument to CDbl is a string expression, it is first converted to 
   numeric by using Val.

Example
   ' Using the CDBL function to convert a numeric value

   'Create an DOUBLE variable
   Dim numeric_value As Double

   'Convert a numeric value
   numeric_value = CDbl(-12345678.123)

   'Print the result, should return -12345678.123
   Print numeric_value
   Sleep

Differences from QB
   * The string argument was not allowed in QB

See also
   * CByte
   * CUByte
   * CShort
   * CUShort
   * CInt
   * CUInt
   * CLng
   * CULng
   * CLngInt
   * CULngInt
   * CSng



------------------------------------------------------------ KeyPgCdecl ----
cdecl

Specifies a cdecl-style calling convention in a procedure declaration

Syntax
   Sub name cdecl [Overload] [Alias "alias"] ( parameters )
   Function name cdecl [Overload] [Alias "alias"] ( parameters ) [ ByRef ] 
   As return_type

Description
   In procedure declarations, cdecl specifies that a procedure will use the 
   cdecl calling convention. In the cdecl calling convention, any 
   parameters are to be passed (pushed onto the stack) in the reverse order 
   in which they are listed, that is, from right to left. The procedures 
   need not preserve the EAX, ECX or EDX registers, and must not clean up 
   the stack (pop any parameters) before it returns - that is left to the 
   calling code.

   cdecl is allowed to be used with variadic procedure declarations (those 
   with the last parameter listed as "...").

   cdecl is the default calling convention on Linux, the *BSDs, and DOS, 
   unless another calling convention is explicitly specified or implied by 
   one of the Extern Blocks. cdecl is typically the default calling 
   convention for C compilers, and it's used almost exclusively on 
   Unix-like systems.

   If a procedure definition has a declaration (with calling convention 
   explicit or by default) and the definition does not explicitly specify a 
   calling convention, then the calling convention is implied by the 
   declaration.

Example
   ' declaring 'strcpy' from the standard C library
   Declare Function strcpy cdecl Alias "strcpy" (ByVal dest As ZString Ptr, ByVal src As ZString Ptr) As ZString Ptr

Differences from QB
   * New to FreeBASIC

See also
   * pascal, stdcall
   * Declare
   * Sub, Function



------------------------------------------------------------ KeyPgChain ----
Chain

Temporarily transfers control to an external program

Syntax
   Declare Function Chain ( ByRef program As Const String ) As Long

Usage
   result = Chain( program )

Parameters
   program
      The file name (including file path) of the program (executable) to 
      transfer control to.

Return Value
      Returns the external program's exit code if executed successfully, or 
      negative one (-1) otherwise.

Description
   Transfers control over to an external program. When the program exits, 
   execution resumes immediately after the call to Chain.

Example
   #ifdef __FB_LINUX__
      Dim As String program = "./program"
   #else
      Dim As String program = "program.exe"
   #endif

   Print "Running " & program & "..."
   If (Chain(program) <> 0) Then
      Print program & " not found!"
   End If

Platform Differences
   * Linux requires the program name case matches the real name of the 
     file. Windows and DOS  are case insensitive. The program  chained may 
     be case sensitive for its command line parameters.
   * Path separators in Linux are forward slashes / . Windows uses 
     backward slashes \ but it allows for forward slashes .  DOS uses 
     backward  \ slashes.
   * Exit code is limited to 8 bits in DOS.

Differences from QB
   * Common does not allow to keep the values of certain variables when 
     chaining programs with Chain.

See also
   * Exec transfer temporarily, with arguments  
   * Run one-way transfer
   * Command pick arguments



----------------------------------------------------- KeyPgSfxGenerated ----
Generated Sound Commands

Commands for generated sound, PLAY strings, and sfxlib mix settings.

Syntax
   Beep [ duration, pitch ]
   Sound frequency, duration
   Sound channel, frequency, duration, volume
   Tone channel, frequency, duration
   Noise channel, duration, volume
   Noise channel, frequency, duration, volume
   Note name, octave, duration
   Note channel, name, octave, duration
   Play music
   Play channel, music
   Play music1, music2
   Play music1, music2, music3
   Tempo bpm
   bpm = Tempo()
   Channel channel
   channel = Channel()
   Octave octave
   octave = Octave()
   Voice instrument
   instrument = Voice()
   Vol level
   Volume level
   level = Volume()
   Volume channel, level
   level = Volume( channel )
   Balance position
   position = Balance()
   Pan channel, position
   position = Pan( channel )
   Wave id, waveform
   Envelope id, attack, decay, sustain, release
   Instrument id, wave_id, envelope_id
   Instrument channel, instrument_id

Description
   These commands synthesize sound directly through sfxlib.  Sound, Tone, 
   Noise, Note, and Play create voices.  Tempo, Channel, Octave, and Voice 
   set defaults used by PLAY-string and generated-sound commands.  Volume, 
   Vol, Balance, and Pan control mix levels and stereo placement.

   Sound accepts the high-impact classic form Sound frequency, duration and
   the explicit channel form Sound channel, frequency, duration, volume.
   When both arguments are integers, duration is interpreted as the PC BASIC
   timer-tick value.

   Wave defines a waveform id.  The currently supported waveform values 
   are:
      * 0 sine
      * 1 square
      * 2 triangle
      * 3 saw
      * 4 noise

   Envelope defines an ADSR envelope using seconds for attack, decay, and 
   release, and a 0.0 to 1.0 sustain level.  Instrument can define an 
   instrument from a waveform and envelope, or assign an instrument to a 
   channel.

   The channel-oriented commands use sfxlib's channel table.  Channels are 
   zero-based.

Example
   See examples/sfxlib/basics-01-generated-sound.bas, 
   examples/sfxlib/basics-02-play-strings.bas, 
   examples/sfxlib/basics-03-channels-mix.bas, 
   examples/sfxlib/basics-04-instruments.bas, and 
   examples/sfxlib/showcase.bas.

Platform Differences
   * On headless or diagnostic runs, SFXLIB_DRIVER=null can be set before 
     program startup to use the null output driver.

Differences from QB
   * New to FreeBASIC.

See also
   * Beep
   * Music
   * Sfx
   * Sound Library Reference



------------------------------------------------------------ KeyPgChdir ----
ChDir

Changes the current drive and directory

Syntax
   Declare Function ChDir ( ByRef path As Const String ) As Long

Usage
   result = ChDir( path )

Parameters
   path
      A String argument specifying the path to change to.

Return Value
   Returns zero (0) on success and negative one (-1) on failure.

Description
   Changes the current drive and directory to that specified.

Example
   Dim pathname As String = $"x:\folder"
   Dim result As Long = ChDir(pathname)

   If result <> 0 Then Print "error changing current directory to " & pathname & "."

Platform Differences
   * Linux requires the filename case matches the real name of the file. 
     Windows and DOS are case insensitive. 
   * Path separators in Linux are forward slashes / . Windows uses 
     backward slashes \ but it allows for forward slashes .  DOS uses 
     backward  \ slashes. 

Differences from QB
   * In QB, the drive could not be specified.

See also
   * CurDir
   * MkDir
   * RmDir



-------------------------------------------------------------- KeyPgChr ----
Chr

Returns a string of characters from one or more ASCII integer values

Syntax
   Declare Function Chr ( ByVal ch As Integer [, ... ] ) As String

Usage
   result = Chr[$]( ch0 [, ch1 ... chN ] )

Parameters
   ch
      The ASCII integer value of a character (up to 32 characters).

Return Value
   Returns a string containing the character(s).

Description
   Chr returns a string containing the character(s) represented by the ASCII
   values passed to it.

   When Chr is used with numerical constants or literals, the result is 
   evaluated at compile-time, so it can be used in variable initializers.

   Asc performs the opposite function, returning the ASCII code of a 
   character represented by a string.

Example
   Print "the character represented by";
   Print " the ASCII code of 97 is: "; Chr(97)

   Print Chr(97, 98, 99) ' prints abc

   ' s initially has the value "abc"
   Dim s As String = Chr(97, 98, 99)

   Print s

Dialect Differences
   * The string type suffix "$" is required in the -lang qb dialect.
   * The string type suffix "$" is optional in the -lang fblite dialect.
   * The string type suffix "$" is ignored in the -lang fb dialect, warn 
     only with the -w suffix compile option (or -w pedantic compile 
     option).

Differences from QB
   * FreeBASIC accepts multiple integer values as arguments, QB accepted 
     only one.
   * FreeBASIC evaluates the CHR function at compile time when used with 
     constants or literals.

See also
   * ASCII Character Codes
   * WChr
   * Asc
   * Str
   * Val



------------------------------------------------------------- KeyPgCint ----
CInt

Converts a numeric or string expression to an Integer or an Integer<bits>

Syntax
   Declare Function CInt ( ByVal expression As datatype ) As Integer
   Declare Function CInt<bits> ( ByVal expression As datatype ) As Integer<
   bits>

   Type typename
      Declare Operator Cast ( ) As Integer
      Declare Operator Cast ( ) As Integer<bits>
   End Type

Usage
   result = CInt( expression )
   result = CInt( string expression )
   result = CInt( user defined type )

Parameters
   bits
      A numeric constant expression indicating the size in bits of integer 
      desired.  The values allowed are 8, 16, 32 or 64.
   expression
      a numeric, string, or pointer expression to cast to a Integer value
   datatype
      any numeric, string, or pointer data type
   typename
      a user defined type

Return Value
   An Integer or Integer<bits> containing the converted value.

Description
   If CInt is passed a numeric expression, it rounds it using using the 
   round-to-even method - i.e. it rounds to the closest integer value, 
   choosing the closest even integer if the number is equidistant from two 
   integers - and returns an Integer, or if a bits value is supplied, an 
   integer type of the given size.

   The function does not check for an overflow; for example, for a 32-bit 
   Integer the results are undefined for values which are less than -2 147 
   483 648 or larger than 2 147 483 647.

   If the argument is a string expression, it is converted to numeric by 
   using ValInt or ValLng, depending on the size of the result type.

   The name "CINT" is derived from 'Convert to INTeger'.

Example
   ' Using the CINT function to convert a numeric value

   'Create an INTEGER variable
   Dim numeric_value As Integer

   'Convert a numeric value
   numeric_value = CInt(300.5)

   'Print the result, should return 300, because 300 is even

   numeric_value = CInt(301.5)

   'Print the result, should return 302, because 301 is odd
   Print numeric_value

Dialect Differences
   * In the -lang qb dialect, CInt will return a 16-bit integer, like in 
     QB.

Differences from QB
   * The string argument was not allowed in QB
   * The <bits> parameter was not allowed in QB

See also
   * Cast
   * CByte
   * CUByte
   * CShort
   * CUShort
   * CUInt
   * CLng
   * CULng
   * CLngInt
   * CULngInt
   * CSng
   * CDbl
   * Integer



----------------------------------------------------------- KeyPgCircle ----
Circle

Graphics statement to draw an ellipse or a circle

Syntax
   Circle [target,] [STEP] (x,y), radius[, [color][, [start][, [end][, 
   [aspect][, F]]]]]

Parameters
   target
      optional; specifies the image buffer to draw on
   STEP
      indicates that coordinates are relative
   (x, y)
      coordinates of the center of the ellipse
   radius
      the radius of the circle - or for an ellipse, the semi-major axis 
      (i.e. the longest radius)
   color
      the color attribute
   start
      starting angle
   end
      ending angle
   aspect
      aspect ratio of the ellipse, the ratio of the height to the width
   F
      fill mode indicator

Description
   Circle will draw a circle, ellipse, or arc based on the parameters given 
   to it. 

   target specifies a buffer to draw on.  target may be an image created 
   with ImageCreate or Get (Graphics).  If omitted, target defaults to the 
   screen's current work page.  (See ScreenSet)

   The center of the shape will be placed on the destination surface at (x, 
   y). 

   Radius denotes the radius of the shape. If aspect ratio is not 1.0, the 
   biggest radius must be given here.

   Color denotes the color attribute, which is mode specific (see Color and 
   Screen (Graphics) for details). If omitted, the current foreground color 
   as set by the Color statement is used.

   The Step option specifies that x and y are offsets relative to the 
   current graphics cursor position.

   start and end are angles are in radians. These can range -2*PI to 2*PI, 
   where PI is the constant &pi;, approximately 3.141593; if you specify a 
   negative angle, its value is changed sign and a line is drawn from the 
   center up to that point in the arc. end angle can be less than start. If 
   you do not specify start and end, a full circle/ellipse is drawn; if you 
   you specify start but not end, end is assumed to be 2*PI; if you specify 
   end but not start, start is assumed to be 0.0.

   aspect is the aspect ratio, or the ratio of the y radius over the x 
   radius. If omitted, the default for ScreenRes modes is 1.0, while for 
   Screen (Graphics) modes the default value is the value required to draw 
   a perfect circle on the screen, keeping the pixel aspect ratio in mind. 
   This value can be calculated as follows:
      ratio = (y_radius / x_radius) * pixel_aspect_ratio
         where pixel_aspect_ratio is the ratio of the current mode width 
         over the current mode height, assuming a 4:3 standard monitor. If 
         aspect ratio is less than 1.0, radius is the x radius; if aspect 
         is more or equal to 1.0, radius is the y radius.

   F is the fill flag. If you specify this flag, the circle/ellipse will be 
   filled with the selected color. This only takes effect if you are 
   drawing a full circle/ellipse.

   Custom coordinates system set up by Window and/or View (Graphics) affect 
   the drawing operation; clipping set by View also applies. When Circle 
   finishes drawing, the current graphics cursor position is set to the 
   supplied center.

   Note: Curves drawn with Circle can induce pixels overdrawn at some 
   locations. Thus, the resultant (blended) color of these overdrawn pixels 
   is affected if a transparent color (in conjunction with the 
   GFX_ALPHA_PRIMITIVES option flag) is used.

Example
   ' Set 640x480 mode, 256 colors
   Screen 18

   ' Draws a circle in the center
   Circle (320, 240), 200, 15

   ' Draws a filled ellipse
   Circle (320, 240), 200, 2, , , 0.2, F

   ' Draws a small arc
   Circle (320, 240), 200, 4, 0.83, 1.67, 3

   Sleep

Differences from QB
   * target is new to FreeBASIC
   * The FreeBASIC implementation uses a different algorithm for 
     ellipse/arc drawing than QB, so the result may not be equal to QB for 
     every pixel.
   * The F flag to draw filled circles/ellipses is new to FreeBASIC.

See also
   * Screen (Graphics)
   * Color



------------------------------------------------------------ KeyPgClass ----
Class

Declares a class object

Syntax
   Class typename ...

Parameters
   typename
      name of the Class

Description
   We would have put something useful here (honest) except this feature 
   isn't implemented in the compiler yet.  But since it will get added in 
   future, and there are several other document pages that need to link 
   here, we thought it safe to include in anyway.

Example
   '' sample code

Output:

   sample Output

Dialect Differences
   * Object-related features are supported only in the -lang fb option

Differences from QB
   * New to FreeBASIC

See also
   * Enum
   * Type



------------------------------------------------------------ KeyPgClear ----
Clear

Clears or initializes some memory

Syntax
   Declare Sub Clear cdecl ( ByRef dst As Any, ByVal value As Long = 0, 
   ByVal bytes As UInteger )

Usage
   Clear( dst, [value], bytes )

Parameters
   dst
      starting address of some memory
   value
      the value to set all bytes equal to
   bytes
      number of bytes to clear

Description
   Clear sets one or more bytes in memory to a certain value (the default 
   value is zero (0) if not specified). The starting address is taken from 
   a reference to a variable or array element.

   NOTE: In order to clear memory referenced by a Pointer, it must be 
   dereferenced first (or else specifying in argument term the ByVal 
   keyword in front of the pointer name). Otherwise, Clear will try to 
   clear the bytes at the pointer variable's memory location.

Example
   'create an array with 100 elements
   Dim array(0 To 99) As Integer

   'clear the contents of the array to 0, starting with the first element
   Clear array(0), , 100 * SizeOf(Integer)

   'allocate 20 bytes of memory
   Dim As Byte Ptr p = Allocate(20)

   'set each of the first ten bytes to 0
   Clear *p, 0, 10

   'set each of the next ten bytes to 42
   Clear p[10], 42, 10

   'check the values of the allocated bytes
   For i As Integer = 0 To 19
      Print i, p[i]
   Next

   'deallocate memory
   Deallocate p

Differences from QB
   * The behavior and usage is new to FreeBASIC
   * The keyword CLEAR was used in QB to erase all variables, close all 
     files, and optionally change the stack size. This use is not supported 
     in FreeBASIC.

See also
   * Erase
   * Reset



------------------------------------------------------------- KeyPgClng ----
CLng

Converts numeric or string expression to Long

Syntax
   Declare Function CLng ( ByVal expression As datatype ) As Long

   Type typename
      Declare Operator Cast ( ) As Long
   End Type

Usage
   result = CLng( numeric expression )
   result = CLng( string expression )
   result = CLng( user defined type )

Parameters
   expression
      a numeric, string, or pointer expression to cast to a Long value
   datatype
      any numeric, string, or pointer data type
   typename
      a user defined type

Return Value
   A Long value.

Description
   The CLng function rounds off the decimal part and returns a 32-bit Long 
   value.  The function does not check for an overflow, and results are 
   undefined for values which are less than -2 147 483 648 or larger than 2 
   147 483 647.

   The name can be explained as 'Convert to LoNG'.

   If the argument is a string expression, it is converted to numeric by 
   using ValInt.

Example

   ' Using the CLNG function to convert a numeric value

   'Create an LONG variable
   Dim numeric_value As Long

   'Convert a numeric value
   numeric_value = CLng(-300.23)

   'Print the result, should return -300
   Print numeric_value
   Sleep

Differences from QB
   * The string argument was not allowed in QB

See also
   * CByte
   * CUByte
   * CShort
   * CUShort
   * CInt
   * CUInt
   * CULng
   * CLngInt
   * CULngInt
   * CSng
   * CDbl



---------------------------------------------------------- KeyPgClngint ----
CLngInt

Converts numeric or string expression to 64-bit integer (LongInt)

Syntax
   Declare Function CLngInt ( ByVal expression As datatype ) As LongInt

   Type typename
      Declare Operator Cast ( ) As LongInt
   End Type

Usage
   result = CLngInt( numeric expression )
   result = CLngInt( string expression )
   result = CLngInt( user defined type )

Parameters
   expression
      a numeric, string, or pointer expression to cast to a LongInt value
   datatype
      any numeric, string, or pointer data type
   typename
      a user defined type

Return Value
   A LongInt value.

Description
   The CLngInt function rounds off the decimal part and returns a 64-bit 
   LongInt value.  The function does not check for an overflow, and results 
   are undefined for values which are less than -9 223 372 036 854 775 808 
   or larger than 223 372 036 854 775 807.

   The name can be explained as 'Convert to LoNG INTeger'.

   If the argument is a string expression, it is converted to numeric by 
   using ValLng.

Example
   ' Using the CLNGINT function to convert a numeric value

   'Create an LONG INTEGER variable
   Dim numeric_value As LongInt

   'Convert a numeric value
   numeric_value = CLngInt(-12345678.123)

   'Print the result, should return -12345678
   Print numeric_value
   Sleep

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Clngint.

Differences from QB
   * New to FreeBASIC

See also
   * CByte
   * CUByte
   * CShort
   * CUShort
   * CInt
   * CUInt
   * CLng
   * CULng
   * CULngInt
   * CSng
   * CDbl



------------------------------------------------------------ KeyPgClose ----
Close

Stream I/O function to terminate access to a device

Syntax
   Close [[#]filenum ] [, [#]filenum ...]
             or 
   result = Close( [#filenum] )

Parameters
   filenum
      List of file numbers to close.

Return Value
   Close returns a 32 bit Long: a zero (0) on success and a non-zero error 
   code otherwise.

Description
   Closes the files whose file numbers are passed as arguments. If an 
   unused file number is passed, Close returns an error.

   Close without arguments closes all the files presently opened.

   Terminating the program using an End statement will automatically close 
   all files.

   The error code returned by Close can be checked using Err in the next 
   line. The function version of  Close returns directly the error code as 
   a 32 bit Long.

Example
   ' Create a string and fill it.
   Dim buffer As String, f As Integer

   buffer = "Hello World within a file."

   ' Find the first free file number.
   f = FreeFile

   ' Open the file "file.ext" for binary usage, using the number "f".
   Open "file.ext" For Binary As #f

     ' Place our string inside the file, using number "f".
     Put #f, , buffer

   ' Close the file.  We could also do 'Close #f', but it's only necessary if more than one number is open.
   Close

   ' End of program. (Check the file "file.ext" upon running to see the output.)

Differences from QB
   * Close can be called as a function that returns an error code.
   * FB throws an error on trying to close an unused file number, if 
     compiled with error checking and if not used with the function-style 
     syntax

See also
   * Open
   * Put (File I/O) 
   * Get (File I/O)
   * FreeFile



-------------------------------------------------------------- KeyPgCls ----
Cls

Clears the screen in both text modes and graphics modes

Syntax
   Declare Sub Cls ( ByVal mode As Long = 1 )

Usage
   Cls mode

Parameters
   mode
      A optional numeric variable with a value from 0 to 2.  If omitted, it 
      defaults to 1.

Description
   An optional mode parameter may be given,

      If omitted, Cls clears either the text or graphics viewport.  If a 
      graphics viewport has been defined using the View (Graphics) 
      statement, the graphics viewport is cleared.  Otherwise, the text 
      viewport, defined by View Print, is cleared.  (If there is no 
      explicit text viewport defined, the entire screen is cleared.)

      If 0, clears the entire screen

      If 1, clears the graphics viewport if defined.  Otherwise, clears the 
      text viewport

      If 2, clears the text viewport

Example
   '' set the color to light grey text on a blue background
   Color 7, 1

   '' clear the screen to the background color
   Cls

   '' print text in the center of the screen
   Locate 12, 33
   Print "Hello Universe!"

In graphics modes, if you want to clear the entire screen to color 0, it 
can be faster using  Clear to write zeroes to the screen memory than 
calling Cls.

   Dim scrbuf As Byte Ptr, scrsize As Integer
   Dim As Long scrhei, scrpitch
   Dim As Integer r = 0, dr = 1

   ScreenRes 640, 480, 8

   scrbuf = ScreenPtr: Assert( scrbuf <> 0 )
   ScreenInfo( , scrhei, , , scrpitch )
   scrsize = scrpitch * scrhei

   Do
      
      '' lock the screen (must do this while working directly on screenbuffer)
      ScreenLock
         
         '' clear the screen (could use Cls here):
         Clear *scrbuf, 0, scrsize
         
         '' draw circle
         Circle (320, 240), r
         
      ScreenUnlock
      
      '' grow/shrink circle radius
      r += dr
      If r <= 0 Then dr = 1 Else If r >= 100 Then dr = -1
      
      '' short pause in each frame (prevents hogging the CPU)
      Sleep 1, 1
      
      '' run loop until user presses a key
   Loop Until Len(Inkey) > 0

Differences from QB
   * None

See also
   * Color
   * Locate
   * Print
   * ?
   * View (Graphics)



------------------------------------------------------------ KeyPgColor ----
Color

Sets the display foreground / background color that is used with console 
output and graphics output of text

Syntax
   Declare Function Color ( ByVal foreground As ULong , ByVal background As 
   ULong ) As ULong

Usage
   Color [foreground] [, background]
   result = Color [( [foreground] [, background] )]

Parameters
   foreground
      the foreground color to set
   background
      the background color to set

Return Value
   Returns a 32-bit value containing the current foreground color in the 
   Low Word and the current background color in the High Word.
   In hi/truecolor modes, only the foreground color is returned, taking up 
   the whole 32 bits. Instead, see ScreenControl to return the current 
   graphics mode color (foreground and background).

   The old color values can be retrieved at the same time as setting new 
   ones.

Description
   The Color statement sets the current foreground and/or background 
   colors. Circle, Draw, Line (Graphics), Cls, Paint, Print, PReset and PSet
   all use the last colors set by this function when you don't specify a 
   color to them, where applicable. The color values that Color accepts 
   depend on the current graphics mode.

      +---------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
      |Mode     |Meaning                                                                                                                                                                                                                             |
      |1        |foreground is screen color (ranging 0-15). background is the emulated CGA palette to be used: 0 (green, red, and brown), 1 (cyan, magenta and white), 2 (same as 0, but with bright colors) or 3 (same as 1, but with bright colors)|
      |2, 11    |foreground is a color index in current palette (ranging 0-1). background is a color index in current palette (ranging 0-1).                                                                                                         |
      |7, 8     |foreground is a color index in current palette (ranging 0-15). background is screen color index in current palette (ranging 0-15).                                                                                                  |
      |9        |foreground is a color index in current palette (ranging 0-63). background is screen color index in current palette (ranging 0-63).                                                                                                  |
      |12       |foreground is a color index in current palette (ranging 0-15). background is a color index in current palette (ranging 0-15).                                                                                                       |
      |13 and up|foreground is a color index in current palette (ranging 0-255). background is a color index in current palette (ranging 0-255).                                                                                                     |
      +---------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

   If you are using a color depth higher than 8bpp, foreground and 
   background are direct RGB color values in the form &hAARRGGBB, where AA, 
   RR, GG and BB are the alpha, red, green and blue components ranging &h00
   -&hFF (0-255 in decimal notation). While in hi/truecolor modes, you can 
   use the RGB or RGBA macro to obtain a valid color value.
   A Default Palette is automatically set when entering a Screen (Graphics) 
   mode. 

Example
   ' Sets 320x240 in 32bpp color depth
   Screen 14, 32

   ' Sets orange foreground and dark blue background color
   Color RGB(255, 128, 0), RGB(0, 0, 64)

   ' Clears the screen to the background color
   Cls                     

   ' Prints "Hello World!" in the middle of the screen
   Locate 15, 14
   Print "Hello World!"

   Sleep

   Dim c As ULong

   'retrieve current color values
   c = Color()

   'extract color values from c using LOWORD and HIWORD
   Print "Console colors:"
   Print "Foreground: " & LoWord(c)
   Print "Background: " & HiWord(c)

   ' In 32-bit color depth, Function Color() returns only the foreground color

   #include "fbgfx.bi"

   '' screencontrol expects integer/uinteger
   Dim As Long fgcolor, bkcolor

   ScreenRes 500, 500, 32
   Width 500\8, 500\16
   Color &HFFFF00, &H0000FF
   Cls

   Print "From Function Color():"
   Print "  Foreground Color: "; Hex(Color(), 8)
   Print

   ScreenControl FB.GET_COLOR, fgcolor, bkcolor
   Print "From Sub ScreenControl():"
   Print "  Foreground Color: "; Hex(fgcolor, 8)
   Print "  Background Color: "; Hex(bkcolor, 8)

   Sleep

Differences from QB
   * Direct color modes were not supported in QB.
   * There is no border argument.

See also
   * RGB
   * RGBA
   * LoWord
   * HiWord
   * Locate
   * Palette
   * Screen (Graphics)



---------------------------------------------------------- KeyPgCommand ----
Command

Returns command line parameters used to call the program

Syntax
   Declare Function Command ( ByVal index As Long = -1 ) As String

Usage
   result = Command[$]( [ index ] )

Parameters
   index
      Zero-based index for a particular command-line argument.

Return Value
     Returns the command-line arguments(s).

Description
   Command returns command-line arguments passed to the program upon 
   execution.

   If index is less than zero (< 0), a space-separated list of all 
   command-line arguments is returned, otherwise, a single argument is 
   returned. A value of zero (0) returns the name of the executable; and 
   values of one (1) and greater return each command-line argument.

   If index is greater than the number of arguments passed to the program, 
   the null string ("") is returned.

   When the command line is parsed for arguments, everything between double 
   quotes in the parameter list will be considered as a single block, and 
   is returned without the double quotes.

   By default, filename globbing for arguments (expansion of wildcards to 
   filenames) is used on all ports of FreeBASIC for compatibility.  
   Arguments on the command line containing wildcards are typically not 
   expanded if when no file is matched or if properly quoted.  Other 
   special characters for redirection are typically not returned unless 
   properly quoted.  Consult the documentation on the shell being used for 
   more information on the proper quoting of command line arguments.
   There may be some strange behavior when using backslash(es) in command 
   line arguments, and the result may even depend on the platform.

   WARNING: By nature of constructor precedence in FreeBASIC and main() 
   initialization, calling Command within a global constructor (module 
   constructor or UDT constructor called for static/shared object) is not 
   safe (may even induce a runtime error).

   Disabling filename globbing under Windows
      Define the following global variable(s) somewhere in the source:
   '' For MinGW.org and Cygwin runtimes:
   Extern _CRT_glob Alias "_CRT_glob" As Long
   Dim Shared _CRT_glob As Long = 0

   '' For MinGW-w64 runtime:
   Extern _dowildcard Alias "_dowildcard" As Long
   Dim Shared _dowildcard As Long = 0

   Disabling filename globbing under Dos
      Define the following function somewhere in the source:
   Function __crt0_glob_function Alias "__crt0_glob_function" ( ByVal arg As UByte Ptr ) As UByte Ptr Ptr
     Return 0
   End Function

   Disabling filename globbing under Linux
      Filename globbing is handled by the command shell.  Quote the 
      argument containing wildcards or disable filename globbing in the 
      shell prior to executing the command.  For example in bash use 'set 
      -f' to disable wildcard expansion

Example
   Print "program launched via: " & Command(0)

   Dim As Long i = 1
   Do
      Dim As String arg = Command(i)
      If Len(arg) = 0 Then
         Exit Do
      End If

      Print "command line argument " & i & " = """ & arg & """"
      i += 1
   Loop

   If i = 1 Then
      Print "(no command line arguments)"
   End If

   Sleep

Dialect Differences
   * The string type suffix "$" is required in the -lang qb dialect.
   * The string type suffix "$" is optional in the -lang fblite dialect.
   * The string type suffix "$" is ignored in the -lang fb dialect, warn 
     only with the -w suffix compile option (or -w pedantic compile 
     option).

Differences from QB
   * The numeric argument was not supported in QB.
   * QB converted the parameter list to uppercase before returning it, 
     FreeBASIC doesn't.
   * By default arguments containing wildcard characters are expanded 
     (filename globbing)

See also
   * __FB_ARGC__
   * __FB_ARGV__
   * Exec
   * Run



----------------------------------------------------------- KeyPgCommon ----
Common

Variable declaration and scope modifier

Syntax
   Common [Shared] symbolname[()] [AS DataType] [, ...]

Description
   Declares a variable which is shared between code modules, including 
   those to be compiled as static and dynamic libraries (DLLs).
   A matching Common statement must appear in all other code modules using 
   the variable. 

   Common variables cannot be initialized.
   Common arrays are always variable-length, and must be defined with an 
   empty parameter list (), and its dimensions set in a later Dim or ReDim 
   statement.
   Common variables cannot be instances of a user-defined type having a 
   constructor or a destructor even implicit.

   The Shared optional parameter makes the variable global so that it can 
   be used inside Subs and Functions, as well as at module level.

Example
   '' common1.bas

   Declare Sub initme()

   Common Shared foo() As Double

   ReDim foo(0 To 2)

   initme()

   Print foo(0), foo(1), foo(2)

   '' common2.bas

   Common Shared foo() As Double

   Sub initme()
     foo(0) = 4*Atn(1)
     foo(1) = foo(0)/3
     foo(2) = foo(1)*2
   End Sub

After compiling the two files like:
fbc common1.bas common2.bas
running common1 produces the output:

    3.141592653589793           1.047197551196598           2.094395102393195

Platform Differences
   * Windows does not support Common with a dynamic library (compiled with 
     -dll or -dylib).

Differences from QB
   * The arrays will be always variable-length.
   * blockname is not needed and must be removed because the order of 
     declaration no longer matters, only the symbol names.
   * Common does not allow to keep the values of certain variables when 
     chaining programs with Chain.

See also
   * Dim
   * Erase
   * Extern
   * LBound
   * ReDim
   * Preserve
   * Shared
   * Static
   * UBound
   * Var



---------------------------------------------------- KeyPgCondBroadcast ----
CondBroadcast

Restarts all threads CondWaiting for the handle

Syntax
   Declare Sub CondBroadcast ( ByVal handle As Any Ptr )

Usage
   CondBroadcast ( handle )

Parameters
   handle
      The handle of a conditional variable.

Description
   Once the conditional is CondCreate and the threads are started, one of 
   more of them (including the implicit main thread executing main program) 
   can be set to CondWait for the conditional, they will be stopped until 
   some other thread CondSignals that the waiting thread can restart. 
   CondBroadcast can be used to restart all threads waiting for the 
   conditional. At the end of the program CondDestroy must be used to avoid 
   leaking resources in the OS.

   Condbroadcast must be used instead of CondSignal to restart all threads 
   waiting on the conditional.

Example
   See also CondCreate

   '' How can all threads wait for each other before continuing to execute their concomitant sections of code ?
   ''
   '' This is the main code that manages the synchronization of concomitant sections of code:
   ''    - Each thread signals to main code that it is waiting for synchronization.
   ''    - The main code waits for each of all threads, then sends the synchronization signal to all threads.
   ''
   '' The synchronization uses the following keywords from threading:
   ''   - In each thread : 'Condsignal' (to send signal to main code) then 'Condwait' (to wait signal from main code).
   ''   - In main code : 'Condwait' (to wait signal from each thread) then 'Condbroadcast' (to send signal to all threads).
   '' With the associated mutexes and conditional variables and flags.
   ''
   '' Test example highlighting the structure of threads and their behaviors, when synchronizing all threads to execute their concomitant sections of code:

   Dim threadnumber As Integer = 4

   '' global data for all threads
      Dim Shared restart As Integer = 0
      Dim Shared threadcount As Integer = 0
      
      Dim Shared hmutexrestart As Any Ptr
      Dim Shared hcondrestart As Any Ptr
      Dim Shared hmutexready As Any Ptr
      Dim Shared hcondready As Any Ptr

   Sub mythread(ByVal p As Any Ptr)
      
      Dim id As Integer = Cast(Integer, p)
      
      '' for visualizing thread status
         Print "   Thread #" & id & " is started..."
         
      '' instead of starting user code
         Sleep id * 40, 1
         
      '' for visualizing thread status
         Print "      Thread #" & id & " is running..."
         Sleep id * 20, 1  '' just to well visualize thread interlacing
         Print "   Thread #" & id & " is waiting for synchronization..."
         
      '' for sending signal to main code
         MutexLock hmutexready
         threadcount += 1
         CondSignal hcondready
         MutexUnlock hmutexready
         
      '' for waiting signal from main code
         MutexLock hmutexrestart
         Do While restart = 0  
            CondWait hcondrestart, hmutexrestart
         Loop
         MutexUnlock hmutexrestart
         
      '' for visualizing thread status
         Print "   Thread #" & id & " is reactivated..."
         
      '' instead of synchronized user code
         Sleep id * 40, 1
         
      '' for visualizing thread status
         Print "      Thread #" & id & " is continuing..."
         Sleep id * 20, 1  '' just to well visualize thread interlacing
         Print "   Thread #" & id & " is finishing execution..."
      
   End Sub

   Dim threads(1 To threadnumber) As Any Ptr

   hcondrestart = CondCreate()
   hmutexrestart = MutexCreate()
   hcondready = CondCreate()
   hmutexready = MutexCreate()

   '' for visualizing main code status
      Print "Start all threads from main code :"
         
   '' for starting all threads
      For i As Integer = 1 To threadnumber
         threads(i) = ThreadCreate(@mythread, Cast(Any Ptr, i))
      Next i

   '' for waiting for all threads waiting for synchronisation
      MutexLock hmutexready
      Do Until threadcount = threadnumber
         CondWait(hcondready, hmutexready)
      Loop
      MutexUnlock hmutexready

   '' for visualizing main code status
      Print "All thread seen waiting from main code"
      Print
      Print "Reactivate all threads from main code :"
         
   '' for reactivating all threads
      MutexLock hmutexrestart
      restart = 1
      CondBroadcast hcondrestart
      MutexUnlock hmutexrestart

   '' for waiting for all threads to be completed
      For i As Integer = 1 To threadnumber
         If threads(i) <> 0 Then
            ThreadWait threads(i)
         End If
      Next i
      
   '' for visualizing main code status
      Print "All thread seen completed from main code"

   MutexDestroy hmutexready
   CondDestroy hcondready
   MutexDestroy hmutexrestart
   CondDestroy hcondrestart

   Sleep

Platform Differences
   * Condbroadcast is not available with the DOS version / target of 
     FreeBASIC, because multithreading is not supported by DOS kernel nor 
     the used extender.
   * In Linux the threads are always started in the order they are 
     created, this can't be assumed in Win32. It's an OS, not a FreeBASIC 
     issue. 

Dialect Differences
   * Threading is not allowed in -lang qb

Differences from QB
   * New to FreeBASIC

See also
   * CondCreate
   * CondDestroy
   * CondSignal
   * CondWait
   * ThreadCreate



------------------------------------------------------- KeyPgCondCreate ----
CondCreate

Creates a conditional variable to be used in synchronizing threads

Syntax
   Declare Function CondCreate ( ) As Any Ptr

Usage
   result = CondCreate

Return Value
   A handle to a newly created conditional variable, or the null pointer 
   (0) on failure.

Description
   Once the conditional is Condcreated and the threads are started, one or 
   more of them (including the implicit main thread executing main program) 
   can be set to CondWait for the conditional, they will be stopped until 
   some other thread CondSignals that the waiting thread can restart. 
   CondBroadcast can be used to restart all threads waiting for the 
   conditional. At the end of the program CondDestroy must be used to avoid 
   leaking resources in the OS.

Example
   See also CondWait and CondSignal and CondBroadcast

   ''
   '' make newly-created threads wait until all threads are ready, then start them all at once
   ''

   Dim Shared hcondstart As Any Ptr
   Dim Shared hmutexstart As Any Ptr
   Dim Shared start As Integer = 0

   Dim Shared threadcount As Integer
   Dim Shared hmutexready As Any Ptr
   Dim Shared hcondready As Any Ptr

   Sub mythread(ByVal id_ptr As Any Ptr)
      Dim id As Integer = Cast(Integer, id_ptr)
     
      '' signal that this thread is ready
      MutexLock hmutexready
      threadcount += 1
      Print "Thread #" & id & " is waiting..."
      CondSignal hcondready
      MutexUnlock hmutexready
      
      '' wait for the start signal
      MutexLock hmutexstart
      Do While start = 0   
         CondWait hcondstart, hmutexstart
      Loop

      '' now this thread holds the lock on hmutexstart
      
      MutexUnlock hmutexstart

      '' print out the number of this thread
      For i As Integer = 1 To 40
         Print id;
      Next i
   End Sub

   Dim threads(1 To 9) As Any Ptr

   hcondstart = CondCreate()
   hmutexstart = MutexCreate()

   hcondready = CondCreate()
   hmutexready = MutexCreate()

   threadcount = 0

   MutexLock(hmutexready)
   For i As Integer = 1 To 9
      threads(i) = ThreadCreate(@mythread, Cast(Any Ptr, i))
      If threads(i) = 0 Then
         Print "unable to create thread"
      End If
   Next i

   Print "Waiting until all threads are ready..."

   Do Until threadcount = 9
      CondWait(hcondready, hmutexready)
   Loop
   MutexUnlock(hmutexready)

   Print
   Print "Go!"

   MutexLock hmutexstart
   start = 1
   CondBroadcast hcondstart
   MutexUnlock hmutexstart

   '' wait for all threads to complete
   For i As Integer = 1 To 9
      If threads(i) <> 0 Then
         ThreadWait threads(i)
      End If
   Next i

   MutexDestroy hmutexready
   CondDestroy hcondready

   MutexDestroy hmutexstart
   CondDestroy hcondstart

   'Visual example of mutual exclusion + mutual synchronization between 2 threads
   'by using Mutex and CondVar:
   'the "user-defined thread" computes the points coordinates on a circle,
   'and the "main thread" plots the points.
   '
   'Principle of mutual exclusion + mutual synchronisation
   '          Thread#A               XOR + <==>             Thread#B
   '.....                                          .....
   'MutexLock(mut)                                 MutexLock(mut)
   '  Do_something_with_exclusion                    Do_something_with_exclusion
   '  While bool#1 <> true <------------------------ bool#1 = true
   '    CondWait(cond#1, mut) <--------------------- CondSignal(cond#1)
   '  Wend <-----------------------------------.     Do_something_with_exclusion
   '  bool#1 = false               .---------- | --> While bool#2 <> true
   '  Do_something_with_exclusion  |   .------ | ----> CondWait(cond#2, mut)
   '  bool#2 = true ---------------'   |   .-- | --> Wend
   '  CondSignal(cond#2) --------------'   |   |     bool#2 = false
   '  Do_something_with_exclusion          |   |     Do_something_with_exclusion
   'MutexUnlock(mut) ----------------------'   '-- MutexUnlock(mut)
   '.....                                          .....
   '
   'Behavior:
   '- Unnecessary to pre-calculate the first point.
   '- Each calculated point is plotted one time only.
   '
   'If you comment out the lines containing "MutexLock" and "MutexUnlock",
   '"CondWait" and "CondSignal", ".ready"
   '(inside "user-defined thread" or/and "main thread"),
   'there will be no longer mutual exclusion nor mutual synchronization
   'between computation of coordinates and plotting of points,
   'and many points will not be plotted on circle (due to non coherent coordinates).

   '-----------------------------------------------------------------------------------------------------

   Type ThreadUDT                                   'Generic user thread UDT
      Dim handle As Any Ptr                        'Any Ptr handle to user thread
      Dim sync As Any Ptr                          'Any Ptr handle to mutex
      Dim cond1 As Any Ptr                         'Any Ptr handle to conditional1
      Dim cond2 As Any Ptr                         'Any Ptr handle to conditional2
      Dim ready1 As Byte                           'Boolean to coordinates ready1
      Dim ready2 As Byte                           'Boolean to coordinates ready2
      Dim quit As Byte                             'Boolean to end user thread
      Declare Static Sub Thread (ByVal As Any Ptr) 'Generic user thread procedure
      Dim procedure As Sub (ByVal As Any Ptr)      'Procedure(Any Ptr) to be executed by user thread
      Dim p As Any Ptr                             'Any Ptr to pass to procedure executed by user thread
      Const False As Byte = 0                      'Constante "false"
      Const True As Byte = Not False               'Constante "true"
   End Type

   Static Sub ThreadUDT.Thread (ByVal param As Any Ptr) 'Generic user thread procedure
      Dim tp As ThreadUDT Ptr = param                  'Casting to generic user thread UDT
      Do
         Static As Integer I
         MutexLock(tp->sync)                          'Mutex (Lock) for user thread
         tp->procedure(tp->p)                         'Procedure(Any Ptr) to be executed by user thread
         I += 1
         Locate 30, 38
         Print I;
         tp->ready1 = True                            'Set ready1
         CondSignal(tp->cond1)                        'CondSignal to send signal1 to main thread
         While tp->ready2 <> True                     'Process loop against spurious wakeups
            CondWait(tp->cond2, tp->sync)            'CondWait to receive signal2 from main-thread
         Wend
         tp->ready2 = False
         If tp->quit = tp->True Then                  'Test for ending user thread
            MutexUnlock(tp->sync)                    'Mutex (Unlock) for user thread
            Exit Do
         End If
         MutexUnlock(tp->sync)                        'Mutex (Unlock) for user thread
         Sleep 5, 1
      Loop
   End Sub

   '-----------------------------------------------------------------------------------------------------

   Type Point2D
      Dim x As Integer
      Dim y As Integer
   End Type

   Const x0 As Integer = 640 / 2
   Const y0 As Integer = 480 / 2
   Const r0 As Integer = 200

   Const pi As Single = 4 * Atn(1)

   Sub PointOnCircle (ByVal p As Any Ptr)
      Dim pp As Point2D Ptr = p
      Dim teta As Single = 2 * pi * Rnd
      pp->x = x0 + r0 * Cos(teta)
      Sleep 5, 1                         'To increase possibility of uncorrelated data occurrence
      pp->y = y0 + r0 * Sin(teta)
   End Sub

   Screen 12
   Locate 30, 2
   Print "<any_key> : exit";
   Locate 30, 27
   Print "calculated:";
   Locate 30, 54
   Print "plotted:";

   Dim Pptr As Point2D Ptr = New Point2D

   Dim Tptr As ThreadUDT Ptr = New ThreadUDT
   Tptr->sync = MutexCreate
   Tptr->cond1 = CondCreate
   Tptr->cond2 = CondCreate
   Tptr->procedure = @PointOnCircle
   Tptr->p = Pptr
   Tptr->handle = ThreadCreate(@ThreadUDT.Thread, Tptr)

   Do
      Static As Integer I
      MutexLock(Tptr->sync)                 'Mutex (Lock) for main thread
      While Tptr->ready1 <> Tptr->True      'Process loop against spurious wakeups
         CondWait(Tptr->cond1, Tptr->sync) 'CondWait to receive signal1 from user-thread
      Wend
      Tptr->ready1 = Tptr->False
      PSet (Pptr->x, Pptr->y)               'Plotting one point
      I += 1
      Locate 30, 62
      Print I;
      Tptr->ready2 = Tptr->True             'Set ready2
      CondSignal(Tptr->cond2)               'CondSignal to send signal2 to user thread
      If Inkey <> "" Then
         Tptr->quit = Tptr->True           'Set quit
         MutexUnlock(Tptr->sync)           'Mutex (Unlock) for main thread
         Exit Do
      End If
      MutexUnlock(Tptr->sync)               'Mutex (Unlock) for main thread
      Sleep 5, 1
   Loop
    

   ThreadWait(Tptr->handle)
   MutexDestroy(Tptr->sync)
   CondDestroy(Tptr->cond1)
   CondDestroy(Tptr->cond2)
   Delete Tptr
   Delete Pptr

   Sleep

   See also the similar MutexCreate example

Platform Differences
   * Condcreate is not available with the DOS version / target of 
     FreeBASIC, because multithreading is not supported by DOS kernel nor 
     the used extender.

Dialect Differences
   * Threading is not allowed in -lang qb

Differences from QB
   * New to FreeBASIC

See also
   * CondBroadcast
   * CondDestroy
   * CondSignal
   * CondWait
   * MutexCreate
   * MutexLock
   * MutexUnlock
   * ThreadCreate



------------------------------------------------------ KeyPgCondDestroy ----
CondDestroy

Destroys a multi-threading conditional variable when it is no more needed

Syntax
   Declare Sub CondDestroy ( ByVal handle As Any Ptr )

Usage
   CondDestroy ( handle )

Parameters
   handle
      The handle of a conditional variable to destroy.

Description
   Once the conditional is CondCreated and the threads are started, one of 
   more of them (including the implicit main thread executing main program) 
   can be set to CondWait for the conditional, they will be stopped until 
   some other thread CondSignals that the waiting thread can restart. 
   CondBroadcast can be used to restart all threads waiting for the 
   conditional. At the end of the program CondDestroy must be used to avoid 
   leaking resources in the OS.

   Conddestroy destroys a condition variable, freeing the resources it 
   might hold. No threads must be waiting on the condition variable on 
   entrance to Conddestroy.

Example
   See CondCreate, CondWait, CondSignal, and CondBroadcast

Platform Differences
   * Conddestroy is not available with the DOS version / target of 
     FreeBASIC, because multithreading is not supported by DOS kernel nor 
     the used extender.

Dialect Differences
   * Threading is not allowed in -lang qb

Differences from QB
   * New to FreeBASIC

See also
   * CondCreate
   * CondBroadcast
   * CondSignal
   * CondWait
   * ThreadCreate



------------------------------------------------------- KeyPgCondSignal ----
CondSignal

Restarts a thread suspended by a call to CondWait

Syntax
   Declare Sub CondSignal ( ByVal handle As Any Ptr )

Usage
   CondSignal ( handle )

Parameters
   handle
      The handle of a conditional variable.

Description
   Once the conditional is created with CondCreate and the threads are 
   started, one of more of them (including the implicit main thread 
   executing main program) can be set to CondWait for the conditional, they 
   will be stopped until some other thread CondSignals that the waiting 
   thread can restart. CondBroadcast can be used to restart all threads 
   waiting for the conditional. At the end of the program CondDestroy must 
   be used to avoid leaking resources in the OS.

   Condsignal restarts one thread waiting. It should be called after mutex 
   is locked (using the same mutex as one used with CondWait). If no 
   threads are waiting on the conditional, nothing happens (the signal is 
   lost forever); if several are waiting, only one is restarted. The caller 
   must then unlock mutex in order for CondWait subroutine to complete.

Example
   See also CondCreate and CondWait and CondBroadcast

   ' This very simple example code demonstrates the use of several condition variable routines.
   ' The main routine initializes a string and creates one thread.
   ' The main routine waits until receive the condition signal from the thread, then print the complemented string.
   ' The thread complements the string, then sends a condition signal.
   '
   'Principle of mutual exclusion + simple synchronization
   '          Thread#A             XOR + ==>            Thread#B
   '.....                                     .....
   'MutexLock(mut)                            MutexLock(mut)
   '  Do_something_with_exclusion               Do_something_with_exclusion
   '  Thread_signal = true -------------------> While Thread_signal <> true
   '  CondSignal(cond) -------------------------> CondWait(cond, mut)
   '  Do_something_with_exclusion      .------> Wend
   'MutexUnlock(mut) ------------------'        Thread_signal = false
   '.....                                       Do_something_with_exclusion
   '.....                                     MutexUnlock(mut)
   '.....                                     .....

   Dim Shared As Any Ptr mutex
   Dim Shared As Any Ptr cond
   Dim Shared As String txt
   Dim As Any Ptr pt
   Dim Shared As Integer ok = 0

   Sub thread (ByVal p As Any Ptr)
      Print "thread is complementing the string"
      MutexLock(mutex)
      Sleep 400, 1
      txt &= " complemented by thread"
      ok = 1
      CondSignal(cond)
      MutexUnlock(mutex)
      Print "thread signals the processing completed"
   End Sub

   mutex = MutexCreate
   cond = CondCreate

   txt = "example of text"
   Print "main() initializes a string = " & txt
   Print "main creates one thread"
   Print
   pt = ThreadCreate(@thread)
   MutexLock(mutex)
   While ok <> 1
      CondWait(cond, mutex)
   Wend
   Print
   Print "back in main(), the string = " & txt
   ok = 0
   MutexUnlock(mutex)

   ThreadWait(pt)
   MutexDestroy(mutex)
   CondDestroy(cond)

Dialect Differences
   * Threading is not allowed in -lang qb

Platform Differences
   * Condsignal is not available with the DOS version / target of 
     FreeBASIC, because multithreading is not supported by DOS kernel nor 
     the used extender.
   * In Linux the threads are always started in the order they are 
     created, this can't be assumed in Win32. It's an OS, not a FreeBASIC 
     issue. 

Differences from QB
   * New to FreeBASIC

See also
   * CondCreate
   * CondDestroy
   * CondBroadcast
   * CondWait
   * ThreadCreate



--------------------------------------------------------- KeyPgCondWait ----
CondWait

Stops execution of current thread until some condition becomes true

Syntax
   Declare Sub CondWait ( ByVal handle As Any Ptr, ByVal mutex As Any Ptr )

Usage
   CondWait ( handle, mutex )

Parameters
   handle
      The handle of a conditional variable.
   mutex
      The mutex associated with this conditional variable, which must be 
      locked when testing the condition and calling CondWait.

Description
   Function that stops the thread where it is called until some other 
   thread  CondSignals or CondBroadcasts  the handle.

   Once the conditional variable is created with CondCreate and the threads 
   are started, one of more of them (including the implicit main thread 
   executing main program) can be set to CondWait for the conditional; they 
   will be stopped until some other thread CondSignals that the waiting 
   thread can restart. CondBroadcast can be used to restart all threads 
   waiting for the conditional. At the end of the program CondDestroy must 
   be used to avoid leaking resources in the OS.

   When calling CondWait, mutex should already be locked (using the same 
   mutex as one used with CondSignal or CondBroadcast). An atomic unlock of 
   the mutex and wait on the conditional variable will occur. The calling 
   thread execution is suspended and does not consume any CPU time until 
   the condition variable is signaled. When the condition variable becomes 
   signaled, mutex will be locked again and then execution will return to 
   the thread after the CondWait call, but with the mutex owned by the 
   caller. The caller is then responsible for unlocking mutex in order to 
   complete CondWait subroutine so that execution after the CondWait call 
   can then resume.

   Note: It is a good habit to use CondWait in a protected way against 
   eventual spurious wakeups.
   For that, CondWait is put within a loop for checking that a Boolean 
   predicate is indeed true (predicate set true by another thread just 
   before executing CondSignal or CondBroadcast) when the thread has 
   finished waiting:
      signal-caller:
         predicate = true
         Condsignal(handle)
      waiting-called:
         While predicate <> true
            Condwait(handle, mutex)
         Wend
         predicate = false
      the loop can terminate only when the predicate is true.
   On the other hand, if the predicate is already true before the thread 
   reaches the loop, CondWait is downright skipped (allowing to take into 
   account a case of CondSignal or CondBroadcast that would have been lost 
   otherwise, because prematurely executed in a second thread before the 
   first thread is really waiting for this).
   See example below for detailed coding.

Example
   See also CondCreate and CondSignal

   ' This simple example code demonstrates the use of several condition variable routines.
   ' The main routine creates three threads.
   ' Two of the threads update a "count" variable.
   ' The third thread waits until the count variable reaches a specified value.

   #define numThread  3
   #define countThreshold 6

   Dim Shared As Integer count = 0
   Dim Shared As Any Ptr countMutex
   Dim Shared As Any Ptr countThresholdCV
   Dim As Any Ptr threadID(0 To numThread-1)
   Dim Shared As Integer ok = 0

   Sub threadCount (ByVal p As Any Ptr)
      Print "Starting threadCount(): thread#" & p
      Do
         Print "threadCount(): thread#" & p & ", locking mutex"
         MutexLock(countMutex)
         count += 1
         ' Check the value of count and signal waiting thread when condition is reached.
         ' Note that this occurs while mutex is locked.
         If count >= countThreshold Then
            If count = countThreshold Then
               Print "threadCount(): thread#" & p & ", count = " & count & ", threshold reached, unlocking mutex"
               ok = 1
               CondSignal(countThresholdCV)
            Else
               Print "threadCount(): thread#" & p & ", count = " & count & ", threshold exceeded, unlocking mutex"
            End If
            MutexUnlock(countMutex)
            Exit Do
         End If
         Print "threadCount(): thread#" & p & ", count = " & count & ", unlocking mutex"
         MutexUnlock(countMutex)
         Sleep 100, 1
      Loop
   End Sub

   Sub threadWatch (ByVal p As Any Ptr)
      Print "Starting threadWatch(): thread#" & p & ", locking mutex, waiting for conditional"
      MutexLock(countMutex)
      ' Note that the Condwait routine will automatically and atomically unlock mutex while it waits.
      While ok = 0
         CondWait(countThresholdCV, countMutex)
      Wend
      Print "threadWatch(): thread#" & p & ", condition signal received"
      Print "threadWatch(): thread#" & p & ", count now = " & count & ", unlocking mutex"
      MutexUnlock(countMutex)
   End Sub

   ' Create mutex and condition variable
   countMutex = MutexCreate
   countThresholdCV = CondCreate
   ' Create threads
   threadID(0) = ThreadCreate(@threadWatch, Cast(Any Ptr, 1))
   threadID(1) = ThreadCreate(@threadCount, Cast(Any Ptr, 2))
   threadID(2) = ThreadCreate(@threadCount, Cast(Any Ptr, 3))
   ' Wait for all threads to complete
   For I As Integer = 0 To numThread-1
      ThreadWait(threadID(I))
      Print "Main(): Waited on thread#" & I+1 & " Done"
   Next I
   MutexDestroy(countMutex)
   CondDestroy(countThresholdCV)

Platform Differences
   * Condwait is not available with the DOS version / target of FreeBASIC, 
     because multithreading is not supported by DOS kernel nor the used 
     extender.
   * In Linux the threads are always started in the order they are 
     created, this can't be assumed in Win32. It's an OS, not a FreeBASIC 
     issue. 

Dialect Differences
   * Threading is not allowed in -lang qb

Differences from QB
   * New to FreeBASIC

See also
   * CondCreate
   * CondDestroy
   * CondBroadcast
   * CondSignal
   * MutexCreate
   * MutexLock
   * MutexUnlock
   * ThreadCreate



------------------------------------------------------------ KeyPgConst ----
Const

Non-modifiable variable declaration.

Syntax
   Const symbolname1 [AS DataType] = value1 [, symbolname2 [AS DataType] = 
   value2, ...]
      or
   Const [AS DataType] symbolname1 = value1 [, symbolname2 = value2, ...]

Description
   Declares non-modifiable constant data that can be integer or decimal 
   (floating-point) numbers or strings. The constant type will be inferred 
   if DataType isn't explicitly given.

   Specifying String * Size, Zstring * Size or Wstring * Size as DataType 
   is not allowed.
   Specifying String as DataType is tolerated but without effect because 
   the resulting type is always a Zstring * Size.

   Constants follow visibility rules similar to those of variables for 
   Namespace blocks, Type blocks, and compound block statements.

Example
   Const Red = RGB(252, 2, 4)
   Const Black As UInteger = RGB(0, 0, 0)
   Const Text = "This is red text on a black bkgnd."

   Locate 1, 1
   Color Red, Black
   Print Text
   Sleep
   End

Differences from QB
   * QB does not support the As datatype syntax.

See also
   * #define
   * Const (Qualifier)
   * Const (Member)
   * Enum
   * Var



------------------------------------------------------ KeyPgConstMember ----
Const (Member)

Specifies that a member procedure is read only.

Syntax
   Type typename
      Declare Const Sub|Function|Property|Operator ...
   End Type

   [Const] Sub|Function|... typename ...
      ...
   End Sub|Function|...

Description
   Specifies that a method does not change the object it is called on. The 
   hidden This parameter will be considered read-only. The declaration can 
   be read as 'invoking a const method promises not to change the object', 
   and the compiler will error if the member procedure tries to change any 
   of the data fields, or calls a non-const member procedure. 

   Read-only (Const) declarations are a measure of type safety that can be 
   read as 'promises not to change.'  The compiler uses the const 
   declarations to check operations on variables and parameters and 
   generate an error at compile time if their data could potentially 
   change.  There is no runtime overhead for using Const qualifiers since 
   all of the checks are made at compile time.

   Constructors and destructors cannot be Const (not useful).
   Member procedures can not be both Const and Static since static member 
   procedures do not have a hidden This parameter.

   For methods with Const in their declaration, Const can also be specified 
   on the corresponding method bodies, for improved code readability.

Example
   '' Const Member Procedures

   Type foo
     x As Integer
     c As Const Integer = 0
     Declare Const Sub Inspect1()
     Declare Const Sub Inspect2()
     Declare Sub Mutate1()
     Declare Sub Mutate2()
   End Type

   ''
   Sub foo.Mutate1()
     '' we can change non-const data fields
     x = 1

     '' but we still can't change const data
     '' fields, they are promised not to change
     '' c = 1 '' Compile error

   End Sub

   ''
   Sub foo.Mutate2()
     '' we can call const members
     Inspect1()

     '' and non-const members
     Mutate1()

   End Sub

   ''
   Sub foo.Inspect1()
     '' can use data members
     Dim y As Integer
     y = c + x

     '' but not change them because Inspect1()
     '' is const and promises not to change foo
     '' x = 10 '' Compile error

   End Sub

   ''
   Sub foo.Inspect2()
     '' we can call const members
     Inspect1()

     '' but not non-const members
     '' Mutate1() '' Compile error

   End Sub

Differences from QB
   * New to FreeBASIC

See also
   * Const
   * Const (Qualifier)
   * Dim
   * Type



--------------------------------------------------- KeyPgConstQualifier ----
Const (Qualifier)

Specifies that a data type or pointer data type is read only.

Syntax
   ... As [Const] datatype [ [Const] Ptr ... ]

Parameters
   datatype
      Name of a standard or user defined data type.

Description
   Specifies that the datatype or Ptr immediately to the right of the Const 
   qualifier is to be considered as read only.  Read-only (Const) 
   declarations are a measure of type safety that can be read as 'promises 
   not to change.'  The compiler uses the const declarations to check 
   operations on variables and parameters and generate an error at compile 
   time if their data could potentially change.  There is no runtime 
   overhead for using Const qualifiers since all of the checks are made at 
   compile time.

   Const can be used anywhere data type declarations are made.  This 
   includes variables, parameters, function return results, user defined 
   type fields, type aliases, and casting.  The datatype can be any 
   built-in standard data type or user defined type.

   Read-only variables must have an initializer since modifying a read-only 
   variable through an assignment will generate a compiler error.  The 
   initializer may appear after the declaration of the variable.

   Both non-const and const variables may be passed to a procedure 
   expecting a const parameter.  However, a const variable may not be 
   passed to a procedure taking a non-const parameter, and will generate a 
   compile error.

   Procedures can be overloaded based on the const-ness of parameters.  For 
   example a procedure can be overloaded where one version of the procedure 
   takes a 'byref foo as bar' parameter and another version of the 
   procedure takes a 'byref foo as const bar' parameter.

   With pointer declarations, Const can be used to indicate which part of 
   the pointer declaration is read-only (all other parts are by default 
   read-write).  The read-only portion of the pointer data type could be 
   the pointer itself (the address), what the pointer points to (the data), 
   or both.  In a declaration with more than one level of Ptr indirection, 
   the right most Ptr indicates the highest order level of indirection and 
   is therefore dereferenced first.

   The compiler has an internal hard-limit of eight (8) levels of pointer 
   indirection with respect to const qualifiers and the behavior of using 
   Const with Ptr data types having greater than eight (8) levels of 
   indirection is undefined.

Example
   '' Const Variables

   '' procedure taking a const parameter
   Sub proc1( ByRef x As Const Integer )

     '' can't change x because it is const
     '' x = 10 '' compile error

     '' but we can use it in expressions and
     '' assign it to other variables
     Dim y As Integer
     y = x
     y = y * x + x

   End Sub

   '' procedure taking a non-const parameter
   Sub proc2( ByRef x As Integer )
     '' we can change the value
     x = 10
   End Sub

   '' declare a non-const and const variable
   Dim a As Integer
   Dim b As Const Integer = 5

   '' proc1() will accept a non-const or const
   '' argument because proc1() promises not to
   '' change the variable passed to it.
   proc1( a )
   proc1( b )

   '' proc2() will accept a non-const argument
   proc2( a )

   '' but not a const argument because proc2()
   '' might change the variable's data and we
   '' promised that 'b' would not change.
   '' proc2( b ) '' compile error

   '' Const Pointers

   '' an integer
   Dim x As Integer = 1
   Dim y As Integer = 2
   Dim z As Integer = 3

   '' To check that the compiler generates errors
   '' when attempting to reassign const variables,
   '' uncomment the assignments below.

   ''
   Scope
     '' a pointer to an integer
     Dim p As Integer Ptr = @x

     p = @y       /' OK - pointer can be changed '/
     *p = z       /' OK - data can be changed '/

   End Scope

   ''
   Scope
     '' a pointer to a constant integer
     Dim p As Const Integer Ptr = @x

     p = @y       /' OK - pointer can be changed '/
     '' *p = z    /' Error - data is const '/

   End Scope

   ''
   Scope
     '' a constant pointer to an integer
     Dim p As Integer Const Ptr = @x

     '' p = @y    /' Error - pointer is const '/
     *p = z       /' OK - data can be changed '/

   End Scope

   ''
   Scope
     '' a constant pointer to a constant integer
     Dim p As Const Integer Const Ptr = @x

     '' p = @y    /' Error - pointer is const '/
     '' *p = z    /' Error - data is const '/

   End Scope

   '' Const Parameters in an Overloaded Procedure

   '' procedure with non-const parameter
   Sub foo Overload( ByRef n As Integer )
     Print "called 'foo( byref n as integer )'"
   End Sub

   '' procedure with const parameter
   Sub foo Overload( ByRef n As Const Integer )
     Print "called 'foo( byref n as const integer )'"
   End Sub

   Dim x As Integer = 1
   Dim y As Const Integer = 2

   foo( x )
   foo( y )

   '' OUTPUT:
   '' called 'foo( byref n as integer )'
   '' called 'foo( byref n as const integer )'

Differences from QB
   * New to FreeBASIC

See also
   * Const
   * Const (Member)
   * Dim
   * Type



------------------------------------------------------ KeyPgConstructor ----
Constructor

Called automatically when a class or user defined type is created

Syntax
   Type typename
      Declare Constructor ( )
      Declare Constructor ( [ ByRef | ByVal ] parameter As datatype [ = 
      default ] [, ... ] )
   End Type

   Constructor typename ( [ parameters ] ) [ Export ]
      statements
   End Constructor

Parameters
   typename 
      name of the Type or Class

Description
   Constructor methods are called when a user defined Type or Class 
   variable is created.

   typename is the name of the type for which the Constructor method is 
   declared and defined.  Name resolution for typename follows the same 
   rules as procedures when used in a Namespace.

   More than one constructor may exist for a Type or Class, but only one 
   will be called when a user defined Type or Class variable is created, 
   and the exact constructor method called depends on the parameter 
   signature matched when the variable is initialized.
   More than one parameter may exist in a constructor method declaration.

   A constructor method is passed a hidden This parameter having the same 
   type as typename.  This is optionally used to access the fields of the 
   Type or Class which is to be initialized in the Constructor method.

   Constructors are called when declaring global or local static instances 
   of typename and when allocating typename dynamically using the 
   New Expression operator. See examples below for different constructor 
   syntaxes.

   A copy Constructor is a special constructor that initializes a new 
   object from an existing object. There are three general cases where the 
   copy Constructor is called: when instantiating one object and 
   initializing it with another object (in one instruction), when passing 
   an object by value, when an object is returned from a function by value 
   (by using Return x statement).
      Note: When an object is returned from a function by value, but by 
      using Function = x (or function_identifier = x) assignment, the 
      Constructor is called once at first, and then the Let (Assign) 
      operator at each assignment.
   A copy Constructor must be defined if the shallow implicit copy 
   constructor is not sufficient. This happens in cases when the object 
   manages dynamically allocated memory or other resources which need to be 
   specially constructed or copied (for example if a member pointer points 
   to dynamically allocated memory, the implicit copy constructor will 
   simply do an implicit pointer construction and a copy of value instead 
   of allocate memory and then perform the copy of data).
      Note: Even if is defined an explicit default Constructor, it is never 
      called by the implicit copy constructor.
   A copy Constructor can not declare its parameter (the object to clone) 
   by value.

   Chaining of constructors in nested types is supported.  Any fields that 
   have their own default constructor are called first.
   Chaining together constructors of a same type is allowed by using the 
   keyword Constructor(parameters) at the top of constructor. It prevents 
   the compiler from emitting field initialization code (instead, it relies 
   on the chained constructor to initialize everything).

   Constructor can be also called directly from the typename instance like 
   the other member methods (Sub) and with the same syntax, i.e. using a 
   member access operator, e.g. obj.Constructor(parameters). In particular, 
   doing this.Constructor(parameters) is not treated as chaining together 
   constructors of a same type, and it is allowed anywhere (not only at the 
   top of constructors). In general it's not safe to manually call the 
   constructor on an object, because no Destructor is called, and the old 
   object state - if any - is overwritten without any of its old members 
   being destroyed, which could cause memory/resource leaks.

Example
   Simple constructor example for beginners:
   Type MyObj
     Foo As Integer Ptr
     
      '' Constructor to create our integer, and set its value.
     Declare Constructor( ByVal DefVal As Integer = 0 )
      '' Destroy our integer on object deletion.
     Declare Destructor()
   End Type

   Constructor MyObj( ByVal DefVal As Integer = 0 )
     Print "Creating a new integer in MyObj!"
     Print "The Integer will have the value of: " & DefVal
     Print ""
     
      '' Create a pointer, and set its value to the one passed to the
      '' Constructor.
     This.Foo = New Integer
     *This.Foo = DefVal
   End Constructor

   Destructor MyObj()
     Print "Deleting our Integer in MyObj!"
     Print ""
     
      '' Delete the pointer we created in MyObj.
     Delete This.Foo
     This.Foo = 0
   End Destructor

   Scope
      '' Create a MyObj type object
      '' Send the value of '10' to the constructor
     Dim As MyObj Bar = 10
     
      '' See if the integer's been created.  Print its value.
     Print "The Value of our integer is: " & *Bar.Foo
     Print ""
     
     Sleep
   End Scope
     '' We've just gone out of a scope.  The Destructor should be called now
     '' Because our objects are being deleted.
   Sleep

   More advanced construction example, showing constructor overloading 
   among other things:
   Type sample

     _text As String

     Declare Constructor ()
     Declare Constructor ( a As Integer )
     Declare Constructor ( a As Single  ) 
     Declare Constructor ( a As String, b As Byte ) 

     Declare Operator Cast () As String

   End Type

   Constructor sample ()
     Print "constructor sample ()"
     Print
     this._text = "Empty"
   End Constructor

   Constructor sample ( a As Integer )
     Print "constructor sample ( a as integer )"
     Print "  a = "; a
     Print
     this._text = Str(a)
   End Constructor

   Constructor sample ( a As Single )
     Print "constructor sample ( a as single )"
     Print "  a = "; a
     Print
     this._text = Str(a)
   End Constructor

   Constructor sample ( a As String, b As Byte )
     Print "constructor sample ( a as string, b as byte )"
     Print "  a = "; a
     Print "  b = "; b
     Print
     this._text = Str(a) + "," + Str(b)
   End Constructor

   Operator sample.cast () As String
     Return this._text
   End Operator

   Print "Creating x1"
   Dim x1 As sample

   Print "Creating x2"
   Dim x2 As sample = 1

   Print "Creating x3"
   Dim x3 As sample = 99.9

   Print "Creating x4"
   Dim x4 As sample = sample( "aaa", 1 )

   Print "Values:"
   Print "  x1 = "; x1
   Print "  x2 = "; x2
   Print "  x3 = "; x3
   Print "  x4 = "; x4

   Example of copy constructor:
   Type UDT
     Dim As String Ptr p                     ''pointer to string
     Declare Constructor ()                  ''default constructor
     Declare Constructor (ByRef rhs As UDT)  ''copy constructor
     Declare Destructor ()                   ''destructor
   End Type

   Constructor UDT ()
     This.p = CAllocate(1, SizeOf(String))
   End Constructor

   Constructor UDT (ByRef rhs As UDT)
     This.p = CAllocate(1, SizeOf(String))
     *This.p = *rhs.p
   End Constructor

   Destructor UDT ()
     *This.p = ""
     Deallocate This.p
   End Destructor

   Dim As UDT u0
   *u0.p = "copy constructor exists"
   Dim As UDT u = u0
   *u0.p = ""  ''to check the independance of the result copy with the object copied
   Print *u.p
   Sleep

Dialect Differences
   * Object-related features are supported only in the -lang fb option

Differences from QB
   * New to FreeBASIC

See also
   * Class
   * Constructor (Module)
   * New Expression
   * Destructor
   * Type
   * Coercion and Conversion



------------------------------------------------ KeyPgModuleConstructor ----
Constructor (Module)

Specifies execution of a procedure before module-level code

Syntax
   [Public | Private] Sub procedure_name [Alias "external_identifier"] [()] 
   Constructor [priority]
      { procedure body }
   End Sub

Description
   The Constructor keyword is used in Sub definitions (forbidden at 
   declaration line level) to force execution of the procedure prior to 
   that of module-level code. Procedures defined as constructors may be 
   used the same way as ordinary procedures, that is, they may be called 
   from within module-level code, as well as other procedures.

   The procedure must have an empty parameter list.  A compile-time error 
   will be generated if the Constructor keyword is used in a Sub definition 
   having one or more parameters. In a set of overloaded procedures, only 
   one (1) constructor may be defined because of the ambiguity of having 
   multiple Subs which take no arguments.

   In a single module, depending on the build and run-time environment of 
   the target system:
      * constructors may execute in which they are defined, or reverse 
        order
      * constructors may execute before or after global static variables 
        having constructors
      * constructors may execute before or after other module constructors 
        having priority attribute
      * constructors with priority attribute may execute before or after 
        global static variables having constructors

   The priority attribute, an integer between 101 and 65535, can be used to 
   force constructors to be executed in a certain order, relative to other 
   constructors also having priority attribute.  The value of priority has 
   no specific meaning, only the relationship of the number with other 
   constructor priorities.  101 is the highest priority and is executed 
   first, relative to other constructors also having priority attribute.

   A module may define multiple constructor procedures, and multiple 
   modules may define additional constructors provided no two Public 
   constructors share the same procedure_name.

   When linking with modules that also define constructors, the order of 
   execution is not guaranteed at link-time unless the priority attribute 
   is used. Therefore, special care should be taken when using constructors 
   that may call on a secondary module also defining a constructor.  In 
   such a case it is advisable to use a single constructor that explicitly 
   calls initialization procedures in those modules.

   Public static member procedures (a Sub having an empty parameter list), 
   of user defined Type can be defined as a module constructor, by adding 
   the Constructor keyword used in the sub procedure definition.

   Initialization of static simple numeric type variables, that have a 
   value that can be determined at compile time (for example, default zero, 
   constants, pointers to static objects, pointers to functions, etc), are 
   initialized before any code is executed.  These values are part of the 
   executable image and have an initial value when the executable is loaded 
   in to memory.  Trivial static globals where no code is needed to 
   initialize, are guaranteed to be initialized and can be reliably used in 
   all code, including global static object constructors and module 
   constructors.

   The module constructor feature exposes a low-level link-time feature of 
   the build and run-time environment.  Accessing global static objects 
   having constructors from module constructors should be avoided due to 
   variations in execution order on different build systems.

   Warning for 64-bit compiler only: See the Identifier Rules page for the 
   choice of user procedure identifier names (and specially the 'Platform 
   Differences' paragraph).

Example
   '' ConDesExample.bas : An example program that defines two sets of
   '' constructors and destructors. Demonstrates when and in what order
   '' they are called when linking a single module.

   Sub Constructor1() Constructor
      Print "Constructor1() called"
   End Sub

   Sub Destructor1() Destructor
      Print "Destructor1() called"
   End Sub

   Sub Constructor2() Constructor
      Print "Constructor2() called"
   End Sub

   Sub Destructor2() Destructor
      Print "Destructor2() called"
   End Sub

      '' ----------------------
      Print "module-level code"

      End 0
      '' ----------------------

   Output:

   Constructor2() called
   Constructor1() called
   module-level code
   Destructor1() called
   Destructor2() called

Differences from QB
   * New to FreeBASIC

See also
   * Constructor (Class)
   * Destructor (Module)
   * Sub



--------------------------------------------------------- KeyPgContinue ----
Continue

Control flow statement to continue next iteration of a loop

Syntax
   Continue {Do | For | While}

Description
   Skips all code until the end clause of a loop structure, i.e. Do...Loop, 
   For...Next, or a While...Wend block, then executes the limit condition 
   check. In the case of a For...Next, the variable is incremented 
   according to the Step specified.

   Where there are multiple Do / For / While blocks nested, it will 
   continue on the innermost block of that type, i.e. the last one entered. 
   You can continue an earlier block of that type by giving the word 
   multiple times, separated by commas.  e.g. continue while, while

Example
   Dim As Integer n

   Print "Here are odd numbers between 0 and 10!"
   Print
   For n = 0 To 10

     If ( n Mod 2 ) = 0 Then 
      Continue For
     End If
     
     Print n
     
   Next n

    '' simple prime number finder

   Print "Here are the prime numbers between 1 and 20!"
   Print

   Dim n As Integer, d As Integer

   For n = 2 To 20
      
      For d = 2 To Int(Sqr(n))
         
         If ( n Mod d ) = 0 Then ' d divides n
            
            Continue For, For ' n is not prime, so try next n
            
         End If
         
      Next d
      
      Print n
      
   Next n

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Continue.

Differences from QB
   * New to FreeBASIC

See also
   * Exit



-------------------------------------------------------------- KeyPgCos ----
Cos

Returns the cosine of an angle

Syntax
   Declare Function Cos ( ByVal angle As Double ) As Double

Usage
   result = Cos( angle )

Parameters
   angle
      the angle (in radians)

Return Value
   Returns the cosine of the argument angle as a Double within the range of 
   -1.0 to 1.0.

Description
   The argument number is measured in radians (not degrees).

   The value returned by this function is undefined for values of angle 
   with an absolute value of 2 ^ 63 or greater.

   Cos can be overloaded as operator to accept user-defined types.

Example
   Const PI As Double = 3.1415926535897932
   Dim a As Double
   Dim r As Double
   Input "Please enter an angle in degrees: ", a
   r = a * PI / 180   'Convert the degrees to Radians
   Print ""
   Print "The cosine of a" ; a; " degree angle is"; Cos ( r ) 
   Sleep

Output:

   Please enter an angle in degrees: 30
   The cosine of a 30 degree angle Is 0.8660254037844387

Differences from QB
   * None

See also
   * Acos
   * Sin
   * Tan
   * A Brief Introduction To Trigonometry



------------------------------------------------------------- KeyPgCptr ----
CPtr

Converts a pointer expression to a specified data type pointer

Syntax
   CPtr( PointerDataType, expression )

Description
   Converts expression to PointerDataType.

   PointerDataType must be a Pointer type (e.g. a DataType Ptr or an Any Ptr
   ), or a Type (Alias) to one.
   expression may have a different pointer type or be an Integer.

   Note: Currently, FB does not actually enforce that PointerDataType must 
   be a pointer.  This will likely change in future versions though.  
   Currently, it may display a warning if you try to convert to a 
   non-pointer (for any conversion type if you compile with the -w pedantic 
   compiler switch).

Example
   Dim intval As Integer
   Dim intptr As Integer Ptr
   intval = &h0080
   intptr = @intval
   '' will print -128 and 128, as the first expression will be "seen" as an signed byte
   Print *CPtr( Byte Ptr, intptr ), *intptr

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Cptr.

Differences from QB
   * New to FreeBASIC

See also
   * Ptr
   * Cast
   * CByte
   * CShort
   * CInt
   * CLngInt
   * CSng
   * CDbl 



----------------------------------------------------------- KeyPgCshort ----
CShort

Converts numeric or string expression to an integer (Short)

Syntax
   Declare Function CShort ( ByVal expression As datatype ) As Short

   Type typename
      Declare Operator Cast ( ) As Short
   End Type

Usage
   result = CShort( numeric expression )
   result = CShort( string expression )
   result = CShort( user defined type )

Parameters
   expression
      a numeric, string, or pointer expression to cast to a Short value
   datatype
      any numeric, string, or pointer data type
   typename
      a user defined type

Return Value
   A Short value.

Description
   The CShort function rounds off the decimal part and returns a 16-bit 
   Short value.  The function does not check for an overflow, and results 
   are undefined for values which are less than -32 768 or larger than 32 
   767.

   The name can be explained as 'Convert to Short'.

   If the argument is a string expression, it is converted to numeric by 
   using ValInt.

Example
   ' Using the CSHORT function to convert a numeric value

   'Create an SHORT variable
   Dim numeric_value As Short

   'Convert a numeric value
   numeric_value = CShort(-4500.66)

   'Print the result, should return -4501
   Print numeric_value
   Sleep

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Cshort.

Differences from QB
   * New to FreeBASIC

See also
   * CByte
   * CUByte
   * CUShort
   * CInt
   * CUInt
   * CLng
   * CULng
   * CLngInt
   * CULngInt
   * CSng
   * CDbl



------------------------------------------------------------ KeyPgCsign ----
CSign

Converts an expression to signed

Syntax
   CSign ( expression )

Usage
   variable = CSign ( expression )

Description
   Converts an unsigned expression to a signed one, useful to force signed 
   behavior of division or multiplication (including with Shl and Shr).

   This is the opposite of CUnsg.

Example
   Dim value As UShort = 65535
   Print CSign(value)  '' will print -1

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Csign.

Differences from QB
   * New to FreeBASIC

See also
   * CUnsg



------------------------------------------------------------- KeyPgCsng ----
CSng

Converts numeric or string expression to Single precision floating point

Syntax
   Declare Function CSng ( ByVal expression As datatype ) As Single

   Type typename
      Declare Operator Cast ( ) As Single
   End Type

Usage
   result = CSng( numeric expression )
   result = CSng( string expression )
   result = CSng( user defined type )

Parameters
   expression
      a numeric, string, or pointer expression to cast to a Single value
   datatype
      any numeric, string, or pointer data type
   typename
      a user defined type

Return Value
   A Single precision value.

Description
   The CSng function returns a 32-bit Single value. The function does not 
   check for an overflow, so be sure not to pass a value outside the 
   representable range of the Single data type. The name can be explained 
   as 'Convert to SiNGle'.

   If the argument to CSng is a string expression, it is first converted to 
   numeric by using Val.

Example
   ' Using the CSNG function to convert a numeric value

   'Create an SINGLE variable
   Dim numeric_value As Single

   'Convert a numeric value
   numeric_value = CSng(-12345.123)

   'Print the result, should return -12345.123
   Print numeric_value
   Sleep

Differences from QB
   * The string argument was not allowed in QB

See also
   * CByte
   * CUByte
   * CShort
   * CUShort
   * CInt
   * CUInt
   * CLng
   * CULng
   * CLngInt
   * CULngInt
   * CDbl



----------------------------------------------------------- KeyPgCsrlin ----
CsrLin

Returns the row position of the cursor

Syntax
   Declare Function CsrLin ( ) As Long

Usage
   result = CsrLin

Return Value
   An Long specifying the current row of the cursor.

Description
   Returns the current row the cursor is on (i.e. the "cursor line").  The 
   topmost row is number 1.

Example
   Print "The cursor is on row:"; CsrLin

Differences from QB
   * None

See also
   * Locate
   * Pos



----------------------------------------------------------- KeyPgCubyte ----
CUByte

Converts numeric or string expression to an unsigned byte (UByte)

Syntax
   Declare Function CUByte ( ByVal expression As datatype ) As UByte

   Type typename
      Declare Operator Cast ( ) As UByte
   End Type

Usage
   result = CUByte( numeric expression )
   result = CUByte( string expression )
   result = CUByte( user defined type )

Parameters
   expression
      a numeric, string, or pointer expression to cast to a UByte value
   datatype
      any numeric, string, or pointer data type
   typename
      a user defined type

Return Value
   A UByte value.

Description
   The CUByte function rounds off the decimal part and returns a 8-bit UByte
   value. The function does not check for an overflow, and results are 
   undefined for values which are less than 0 or larger than 255.

   The name can be explained as 'Convert to Unsigned Byte'.

   If the argument is a string expression, it is converted to numeric by 
   using ValUInt.

Example
   ' Using the CUBYTE function to convert a numeric value

   'Create an UNSIGNED BYTE variable
   Dim numeric_value As UByte

   'Convert a numeric value
   numeric_value = CUByte(123.55)

   'Print the result, should return 124
   Print numeric_value
   Sleep

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Cubyte.

Differences from QB
   * New to FreeBASIC

See also
   * CByte
   * CShort
   * CUShort
   * CInt
   * CUInt
   * CLng
   * CULng
   * CLngInt
   * CULngInt
   * CSng
   * CDbl



------------------------------------------------------------ KeyPgCuint ----
CUInt

Converts numeric or string expression to a UInteger or UInteger<bits>

Syntax
   Declare Function CUInt ( ByVal expression As datatype ) As UInteger
   Declare Function CUInt<bits> ( ByVal expression As datatype ) As UInteger
   <bits>

   Type typename
      Declare Operator Cast ( ) As UInteger
      Declare Operator Cast ( ) As UInteger<bits>
   End Type

Usage
   result = CUInt( numeric expression )
   result = CUInt( string expression )
   result = CUInt( user defined type )

Parameters
   bits
      A numeric constant expression indicating the size in bits of unsigned 
      integer desired.  The values allowed are 8, 16, 32 or 64.
   expression
      a numeric, string, or pointer expression to cast to a UInteger or 
      UInteger<bits> value
   datatype
      any numeric, string, or pointer data type
   typename
      a user defined type

Return Value
   A UInteger or UInteger<bits> containing the converted value.

Description
   The CUInt function rounds off the decimal part and returns a UInteger 
   value, or if a bits value is supplied, an unsigned integer type of the 
   given size.

   The function does not check for an overflow; for example, for a 32-bit 
   UInteger results are undefined for values which are less than 0 or 
   larger than 4 294 967 296.

   The name can be explained as 'Convert to Unsigned INTeger'.

   If the argument is a string expression, it is converted to numeric by 
   using ValUInt or ValULng, depending on the size of the result type.

Example
   ' Using the CUINT function to convert a numeric value

   'Create an UNSIGNED INTEGER variable
   Dim numeric_value As UInteger

   'Convert a numeric value
   numeric_value = CUInt(300.23)

   'Print the result = 300
   Print numeric_value

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Cuint.

Differences from QB
   * New to FreeBASIC

See also
   * CByte
   * CUByte
   * CShort
   * CUShort
   * CInt
   * CLng
   * CULng
   * CLngInt
   * CULngInt
   * CSng
   * CDbl
   * UInteger



------------------------------------------------------------ KeyPgCulng ----
CULng

Converts numeric or string expression to ULong

Syntax
   Declare Function CULng ( ByVal expression As datatype ) As ULong

   Type typename
      Declare Operator Cast ( ) As ULong
   End Type

Usage
   result = CULng( numeric expression )
   result = CULng( string expression )
   result = CULng( user defined type )

Parameters
   expression
      a numeric, string, or pointer expression to cast to a ULong value
   datatype
      any numeric, string, or pointer data type
   typename
      a user defined type

Return Value
   A ULong value.

Description
   The CULng function rounds off the decimal part and returns a 32 bit ULong
   value. The function does not check for an overflow. The name can be 
   explained as 'Convert to Unsigned LoNG'.

   If the argument is a string expression, it is converted to numeric by 
   using ValUInt or ValULng.

Example
   ' Using the CULNG function to convert a numeric value

   'Create an UNSIGNED LONG variable
   Dim numeric_value As ULong

   'Convert a numeric value
   numeric_value = CULng(300.23)

   'Print the result = 300
   Print numeric_value
   Sleep

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Culng.

Differences from QB
   * New to FreeBASIC

See also
   * CByte
   * CUByte
   * CShort
   * CUShort
   * CInt
   * CUInt
   * CLng
   * CLngInt
   * CULngInt
   * CSng
   * CDbl



--------------------------------------------------------- KeyPgCulngint ----
CULngInt

Converts numeric or string expression to 64-bit unsigned integer (ULongInt)

Syntax
   Declare Function CULngInt ( ByVal expression As datatype ) As ULongInt

   Type typename
      Declare Operator Cast ( ) As ULongInt
   End Type

Usage
   result = CULngInt( numeric expression )
   result = CULngInt( string expression )
   result = CULngInt( user defined type )

Parameters
   expression
      a numeric, string, or pointer expression to cast to a ULongInt value
   datatype
      any numeric, string, or pointer data type
   typename
      a user defined type

Return Value
   A ULongInt value.

Description
   The CULngInt function rounds off the decimal part and returns a 64-bit 
   ULongInt value.  The function does not check for an overflow, and 
   results are undefined for values which are less than 0 or larger than 18 
   446 744 073 709 551 615.  Additionally, casts from floating-point 
   expressions are currently not guaranteed to work for values higher than 
   2^63 (9 223 372 036 854 775 808).

   The name can be explained as 'Convert to Unsigned LoNG INTeger'.

   If the argument is a string expression, it is converted to numeric by 
   using ValULng.

Example
   ' Using the CLNGINT function to convert a numeric value

   'Create an UNSIGNED LONG INTEGER variable
   Dim numeric_value As ULongInt

   'Convert a numeric value
   numeric_value = CULngInt(12345678.123)

   'Print the result, should return 12345678
   Print numeric_value
   Sleep

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Culngint.

Differences from QB
   * New to FreeBASIC

See also
   * CByte
   * CUByte
   * CShort
   * CUShort
   * CInt
   * CUInt
   * CLng
   * CULng
   * CLngInt
   * CSng
   * CDbl



------------------------------------------------------------ KeyPgCunsg ----
CUnsg

Converts an expression to unsigned

Syntax
   CUnsg ( expression )

Usage
   variable = CUnsg ( expression )

   Converts a signed expression to an unsigned one, useful to force 
   unsigned behavior of division or multiplication (including with Shl and 
   Shr).

   This is the opposite of CSign.

Example
   Dim value As Short = -1
   Print CUnsg(value)  '' will print 65535

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Cunsg.

Differences from QB
   * New to FreeBASIC

See also
   * CSign



----------------------------------------------------------- KeyPgCurdir ----
CurDir

Returns the current directory/folder

Syntax
   Declare Function CurDir ( ) As String

Usage
   result = CurDir

Return Value
   A String which is set to the name of the current directory/folder.

Description
   Returns the current directory/folder.

Example
   Print CurDir

   output will vary.

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Curdir.

Differences from QB
   * New to FreeBASIC

See also
   * Open
   * Dir
   * ChDir
   * MkDir
   * RmDir



---------------------------------------------------------- KeyPgCushort ----
CUShort

Converts numeric or string expression to an unsigned integer (UShort)

Syntax
   Declare Function CUShort ( ByVal expression As datatype ) As UShort

   Type typename
      Declare Operator Cast ( ) As UShort
   End Type

Usage
   result = CUShort( numeric expression )
   result = CUShort( string expression )
   result = CUShort( user defined type )

Parameters
   expression
      a numeric, string, or pointer expression to cast to a UShort value
   datatype
      any numeric, string, or pointer data type
   typename
      a user defined type

Return Value
   A UShort value.

Description
   The CUShort function rounds off the decimal part and returns a 16-bit 
   UShort value.  The function does not check for an overflow, and results 
   are undefined for values which are less than 0 or larger than 65 535.

   The name can be explained as 'Convert to Unsigned Short'.

   If the argument is a string expression, it is converted to numeric by 
   using ValUInt.

Example
   ' Using the CUSHORT function to convert a numeric value

   'Create an USHORT variable
   Dim numeric_value As UShort

   'Convert a numeric value
   numeric_value = CUShort(36000.4)

   'Print the result, should return 36000
   Print numeric_value
   Sleep

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Cushort.

Differences from QB
   * New to FreeBASIC

See also
   * CByte
   * CUByte
   * CShort
   * CInt
   * CUInt
   * CLng
   * CULng
   * CLngInt
   * CULngInt
   * CSng
   * CDbl



-------------------------------------------------------- KeyPgCustomgfx ----
Custom

Parameter to the Put graphics statement which selects a custom method

Syntax
   Put [ target, ] [ STEP ] ( x,y ), source [ ,( x1,y1 )-( x2,y2 ) ], 
   Custom, custom_function_ptr [, parameter]

Parameters
   Custom
      Required.
   custom_function_ptr
      name of the custom user defined function.
   parameter
      optional Pointer to be passed to the custom function; if omitted, the 
      default value is zero (0).

Description
   Custom selects a custom user defined function as the method for blitting 
   an image buffer.

   The Custom method uses a user-defined function to calculate the final 
   pixel values to be drawn to the destination buffer. This function will 
   be called once for every pixel of the source image, and will receive the 
   source and destination pixel values, and a data pointer passed by the Put
   function. The pixel value returned will be the value used to draw to the 
   destination buffer. The function has the form:

   Declare Function identifier ( _
      ByVal source_pixel As ULong, _
      ByVal destination_pixel As ULong, _
      ByVal parameter As Any Ptr _
      ) As ULong

   identifier is the name of the function.
   source_pixel is the current pixel value of the source image.
   destination_pixel is the current pixel value of the destination image.
   parameter is the parameter that is passed by the Put command.  If it was 
   omitted, its value will be zero.

Example
   Function dither ( ByVal source_pixel As ULong, ByVal destination_pixel As ULong, ByVal parameter As Any Ptr ) As ULong
      
      ''either returns the source pixel or the destination pixel, depending on the outcome of rnd
      
      Dim threshold As Single = 0.5
      If parameter <> 0 Then threshold = *CPtr(Single Ptr, parameter)
      
      If Rnd() < threshold Then
         Return source_pixel
      Else
         Return destination_pixel
      End If
      
   End Function

   Dim img As Any Ptr, threshold As Single

   '' set up a screen
   ScreenRes 320, 200, 16, 2
   ScreenSet 0, 1

   '' create an image
   img = ImageCreate(32, 32)
   Line img, ( 0,  0)-(15,  15), RGB(255,   0,   0), bf
   Line img, (16,  0)-(31,  15), RGB(  0,   0, 255), bf
   Line img, ( 0, 16)-(15,  31), RGB(  0, 255,   0), bf
   Line img, (16, 16)-(31,  31), RGB(255,   0, 255), bf

   '' dither the image with varying thresholds
   Do Until Len(Inkey)
      
      Cls
      
      threshold = 0.2
      Put ( 80 - 16, 100 - 16), img, Custom, @dither, @threshold
      
      '' default threshold = 0.5
      Put (160 - 16, 100 - 16), img, Custom, @dither
      
      threshold = 0.8
      Put (240 - 16, 100 - 16), img, Custom, @dither, @threshold
      
      ScreenCopy
      Sleep 25
      
   Loop

   '' free the image memory
   ImageDestroy img

Dialect Differences
   * Not available in the -lang qb dialect.

Differences from QB
   * New to FreeBASIC

See also
   * Put (Graphics)



----------------------------------------------------------- KeyPgCvaArg ----
Cva_Arg

Macro to obtain the next argument from a variadic argument list object.

Syntax
   variable = Cva_Arg ( argument_list, datatype )

Parameters
   argument_list
      Cva_List data type variable to access for next value
   datatype
      The datatype of the next value in the variable argument list 
      argument_list

Description
   The Cva_Arg macro allows the use of a variable number of arguments 
   within a function:
      * 	Cva_Arg returns the current argument in the list, argument_list, 
        with an expected data type of datatype.
      * 	Before first Cva_Arg use, argument_list must be initialized with 
        the command Cva_Start or Cva_Copy.
      * 	Cva_Arg automatically increments argument_list to the next 
        argument within the list after obtaining the value of the current 
        argument.

Example
   '' Example of a simple custom printf
   Sub myprintf cdecl(ByRef formatstring As String, ...)
      Dim As Cva_List args

      '' Initialize the cva_list object to first var-arg
      Cva_Start( args, formatstring )

      '' For each char in format string...
      Dim As UByte Ptr p = StrPtr(formatstring)
      Dim As Integer todo = Len(formatstring)
      While (todo > 0)
         Dim As Integer char = *p
         p += 1
         todo -= 1

         '' Is it a format char?
         If (char = Asc("%")) Then
            If (todo = 0) Then
               '' % at the end
               Print "%";
               Exit While
            End If

            '' The next char should tell the type
            char = *p
            p += 1
            todo -= 1

            '' Print var-arg, depending on the type
            Select Case char
            '' integer?
            Case Asc("i")
               Print Str(Cva_Arg(args, Integer));

            '' long integer? (64-bit)
            Case Asc("l")
               Print Str(Cva_Arg(args, LongInt));

            '' single or double?
            '' Note: because the C ABI, all singles passed on
            '' var-args are converted to doubles.
            Case Asc( "f" ), Asc( "d" )
               Print Str(Cva_Arg(args, Double));

            '' string?
            Case Asc("s")
               '' Strings are passed byval, so the length is unknown
               Print *Cva_Arg(args, ZString Ptr);

            End Select

         '' Ordinary char, just print as-is
         Else
            Print Chr( char );
         End If
      Wend

      Cva_End( args )

   End Sub

   Dim As String s = "bar"

   myprintf(!"integer=%i, longint=%l single=%f, double=%d, string=%s, string=%s\n", _
          1, 1ll Shl 32, 2.2, 3.3, "foo", s)

Version
   * Since fbc 1.07.0

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __cva_arg.

Differences from QB
   * New to FreeBASIC

See also
   * ... (Ellipsis)
   * Cva_Copy
   * Cva_End
   * Cva_List
   * Cva_Start



---------------------------------------------------------- KeyPgCvaCopy ----
Cva_Copy

Macro to initialize variadic argument list object variable from an already 
initialized variadic argument list object variable

Syntax
   Cva_Copy( dst_list, src_list )

Parameters
   dst_list
      destination Cva_List variable to initialize
   src_list
      source Cva_List variable to copy from

Description
   Copies one Cva_List type variable to another Cva_List type variable.  
   dst_list is initialized using current state of src_list

   src_list must already have been initialized with a previous Cva_Start or 
   Cva_Copy statement.

   Cva_Copy is like a copy constructor for the a variadic argument list 
   object and must eventually have a matching call to Cva_End, which is 
   like the destructor.  After Cva_End for dst_list has been called, 
   dst_list can be reused and reinitialized with another call to Cva_Start 
   or Cva_Copy.  The Cva_Copy and Cva_End calls must both be called in the 
   same procedure (for cross platform compatibility).

Example
   '' example of using cva_copy to create
   '' a copy of the variable argument list

   Sub proc cdecl(count As Integer, ... )
      Dim args1 As Cva_List
      Dim args2 As Cva_List

      '' first list
      Cva_Start( args1, count )

      '' create a copy
      Cva_Copy( args2, args1 )

      For i As Integer = 1 To count
         Print Cva_Arg( args1, Integer ), Cva_Arg( args2, Integer )
      Next
      
      '' clean-up
      Cva_End( args2 )
      Cva_End( args1 )

   End Sub

   proc( 4, 4000, 300, 20, 1 )

   '' example of using cva_copy to create
   '' a copy of the variable argument list
   '' and pass it to another procedure

   Sub vproc cdecl(count As Integer, ByRef args As Cva_List )

      '' if we don't know that caller made a copy
      '' of args, it is safe to make our own copy
      '' and leave the passed in args untouched

      Dim a As Cva_List
      Cva_Copy( a, args )

      Print "vproc"
      For i As Integer = 1 To count
         Print Cva_Arg( a, Integer )
      Next
      
      '' clean-up
      Cva_End( a )

   End Sub

   Sub proc cdecl(count As Integer, ... )

      Dim args As Cva_List
      Cva_Start( args, count )

      '' if don't know that the called procedure
      '' will make it's own copy, it is safe to
      '' make a copy here and pass that instead

      Dim tmp As Cva_List
      Cva_Copy( tmp, args )
      vproc( count, tmp )
      Cva_End( tmp )

      '' args is still valid, we can use it
      Print "proc"
      For i As Integer = 1 To count
         Print Cva_Arg( args, Integer )
      Next
      
      '' clean-up
      Cva_End( args )

   End Sub

   proc( 4, 4000, 300, 20, 1 )

Version
   * Since fbc 1.07.0

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __cva_copy.

Differences from QB
   * New to FreeBASIC

See also
   * ... (Ellipsis)
   * Cva_Arg
   * Cva_End
   * Cva_List
   * Cva_Start



----------------------------------------------------------- KeyPgCvaEnd ----
Cva_End

Macro to clean-up a variadic argument list object variable

Syntax
   Cva_End( argument_list )

Parameters
   argument_list
      Cva_List variable to clean up

Description
   Cleans-up a Cva_List type variable that was previously initialized with 
   Cva_Start or Cva_Copy, like a destructor.

   argument_list must already have been initialized with a previous 
   Cva_Start or Cva_Copy statement in the same procedure as Cva_End (for 
   cross platform compatibility).

Example
   Sub proc cdecl(count As Integer, ... )
      Dim args As Cva_List

      Cva_Start( args, count )

      For i As Integer = 1 To count
         Print Cva_Arg( args, Integer )
      Next
      
      Cva_End( args )
   End Sub

   proc( 4, 4000, 300, 20, 1 )

Version
   * Since fbc 1.07.0

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __cva_end.

Differences from QB
   * New to FreeBASIC

See also
   * ... (Ellipsis)
   * Cva_Arg
   * Cva_Copy
   * Cva_List
   * Cva_Start



---------------------------------------------------------- KeyPgCvaList ----
Cva_List

Variadic argument list object type

Syntax
   Dim variable As Cva_List

Description
   Cva_List is a built in data type for working with the variable length 
   argument list in a variadic procedure.

   Use Cva_Start to initialize the Cva_List variable (constructor).
   Use Cva_Copy to copy a Cva_List variable (copy constructor).
   Use Cva_Arg to obtain the value of the next argument.
   Use Cva_End when finished with a Cva_List variable (destructor).

   The exact type and size of Cva_List varies depending on the target 
   platform.  This builtin type provides a layer of abstraction over the 
   underlying mechanism for obtaining the values passed to a variadic 
   procedure.

   fbc will select a default Cva_List type depending on -target, -arch, and 
   -gen command line options, as described in the following code.
   #if (__FB_BACKEND__ = "gcc")
      #if defined( __FB_64BIT__ ) 
         #if defined( __FB_ARM__ )
            Type __va_list Alias "__va_list"
               As Any Ptr __stack
               As Any Ptr __gr_top
               As Any Ptr __vr_top
               As Long __gr_offs
               As Long __vr_offs
            End Type
            Type Cva_List As __va_list Alias "__builtin_va_list"
         #elseif defined( __FB_WIN32__ )
            Type Cva_List As Any Alias "__builtin_va_list" Ptr
         #else
            Type __va_list_tag Alias "__va_list_tag"
               As ULong gp_offset
               As ULong fp_offset
               As Any Ptr overflow_arg_area
               As Any Ptr reg_save_area
            End Type  
            Type Cva_List As __va_list_tag Alias "__builtin_va_list[]"
         #endif   
      #else
         Type Cva_List As Any Alias "__builtin_va_list" Ptr
      #endif
   #else
      Type Cva_List As Any Alias "char" Ptr
   #endif

Example
   Function average cdecl(count As Integer, ... ) As Double

      Dim sum As Double = 0
      Dim i As Integer

      Dim args As Cva_List '' argument list object
      Cva_Start( args, count ) '' constructor
      For i = 1 To count
         sum += Cva_Arg(args, Double)
      Next
      Cva_End( args ) '' destructor
      
      Return sum / count
   End Function

   Print average(4, 3.4 ,5.0, 3.2, 4.1) '' all passed variable arguments must be of type double
   Print average(2, 65.2, 454.65481)    '' all passed variable arguments must be of type double

The output would look like:

    3.925
    259.927405

   '' pass the args list to a function taking an cva_list type argument
   #include "crt/stdio.bi"

   Sub myprintf cdecl( fmt As ZString Ptr, ... )
      Dim args As Cva_List
      Cva_Start( args, fmt )
      vprintf( fmt, args )
      Cva_End( args )
   End Sub

   Dim As String s = "bar"

   myprintf( !"integer=%i, longint=%lli float=%f\n", _
      1, 1ll Shl 32, 3.3 )

   myprintf( !"string=%s, string=%s\n", "foo", s )

Version
   * Since fbc 1.07.0

Platform Differences
   * The exact type and size of Cva_List depends on -target, -arch, -gen 
     command line options.
   * In -gen gas, Cva_List is a pointer
   * In -gen gcc, Cva_List is a pointer, a struct, or a struct array.  The 
     Cva_List type is replaced by "__builtin_va_list" in gcc.
   * On 32-bit targets, gas backend: type Cva_List as any alias "char" ptr
     .
   * On 32-bit targets, gcc backend: type Cva_List as any alias 
     "__builtin_va_list" ptr
   * On Windows 64-bit, gcc backend: type Cva_List as any alias 
     "__builtin_va_list" ptr
   * On Linux x86_64, gcc backend: type Cva_List as __va_list_tag alias 
     "__builtin_va_list[]"
   * On arm64, gcc backend: type Cva_List as __va_list alias 
     "__builtin_va_list"

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __cva_list.

Differences from QB
   * New to FreeBASIC

See also
   * ... (Ellipsis)
   * Cva_Arg
   * Cva_Start
   * Cva_Copy
   * Cva_End



--------------------------------------------------------- KeyPgCvaStart ----
Cva_Start

Macro to initialize variadic argument list object variable

Syntax
   Cva_Start( argument_list, last_param )

Parameters
   argument_list
      Cva_List data type variable to initialize
   last_param
      The last parameter in the procedures parameter list before the 
      Ellipsis ...

Description
   In a variadic procedure definition, argument_list is a variable having 
   the Cva_List type and must be initialized with Cva_Start to work with 
   the variable length argument list passed to the procedure.

   last_param is the last parameter before the Ellipsis ... in the variadic 
   procedure definition.

   Cva_Start can only be used in variadic procedures.  A variadic procedure 
   is declared or defined by specifying the Ellipsis ... as the last 
   parameter, and will accept a variable number of arguments when calling 
   the procedure.

   Cva_Start is like a constructor for the variadic argument_list object 
   and must eventually have a matching call to Cva_End, which is like a 
   destructor.  After Cva_End for argument_list has been called, 
   argument_list can be reused and reinitialized with another call to 
   Cva_Start.  The Cva_Start and Cva_End calls must both be called in pairs 
   in the same procedure (for cross platform compatibility).

   Cva_Copy is similar to Cva_Start except it initializes a variadic 
   argument_list object from an already initialized variadic argument_list 
   object, like a copy constructor.

Example
   '' typical usage of iterating through all arguments

   Sub proc cdecl(count As Integer, ... )
      Dim args As Cva_List
      Cva_Start( args, count )
      For i As Integer = 1 To count
         Print Cva_Arg( args, Integer )
      Next
      Cva_End( args )
   End Sub

   proc( 4, 4000, 300, 20, 1 )

   '' example of using cva_start to get the first argument
   '' then restarting to get all the arguments

   Sub proc cdecl(count As Integer, ... )
      Dim args As Cva_List

      '' get the first argument only
      Cva_Start( args, count )
      Print Cva_Arg( args, Integer )
      Cva_End( args )

      '' restart and get all the arguments
      Cva_Start( args, count )
      For i As Integer = 1 To count
         Print Cva_Arg( args, Integer )
      Next
      Cva_End( args )

   End Sub

   proc( 4, 4000, 300, 20, 1 )

Version
   * Since fbc 1.07.0

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __cva_start.

Differences from QB
   * New to FreeBASIC

See also
   * ... (Ellipsis)
   * Cva_Arg
   * Cva_Copy
   * Cva_End
   * Cva_List



-------------------------------------------------------------- KeyPgCvd ----
CVD

Converts a 64-bit integer or 8-byte string to a double-precision value

Syntax
   Declare Function CVD ( ByVal l As LongInt ) As Double
   Declare Function CVD ( ByRef str As Const String ) As Double

Usage
   result = CVD( l )
   result = CVD( str )

Parameters
   l
      A 64-bit LongInt with a binary copy of a double-precision variable 
      stored in it.
   str
      A String at least 8 bytes in length with a binary copy of a 
      double-precision variable stored in it.

Return Value
      Returns a Double value holding a binary copy of the input value.

Description
   Does a binary copy from a 64-bit LongInt or 8-byte String to a Double 
   variable.  A value of zero (0.0) is returned if the string is less than 
   8 bytes in length.  The result will make sense only if the parameter 
   contained a IEEE-754 formatted double-precision value, such as one 
   generated by CVLongInt or MKD.

   This function is useful to read numeric values from buffers without 
   using a Type definition.

Example
   Dim d As Double, l As LongInt
   d = 1.125
   l = CVLongInt(d)

   Print Using "l = _&H&"; Hex(l)
   Print Using "cvd(i) = &"; CVD(l)

Differences from QB
   * QB did not support integer arguments.

See also
   * MKD
   * CVS
   * CVLongInt



-------------------------------------------------------------- KeyPgCvi ----
CVI

Converts a floating-point number or string to an integer variable using a 
binary copy

Syntax
   32-bit:
   Declare Function CVI ( ByVal f As Single ) As Integer
   64-bit:
   Declare Function CVI ( ByVal f As Double ) As Integer

   Declare Function CVI ( ByRef str As Const String ) As Integer
   Declare Function CVI<bits> ( expr As DataType ) As Integer<bits>

Usage
   result = CVI( sng )
   result = CVI( str )
   result = CVI<bits>( expr )

Parameters
   f
      A floating-point number with a binary copy of an integer variable 
      stored in it.  Its precision (Single or Double) depends on the size 
      of Integer on the current platform
   str
      A String with a binary copy of an integer variable stored in it.
   bits
      Specifies a size of integer type to return.  The types and sizes of 
      expr accepted will depend on the corresponding function called.
   expr
      An expression that will be copied into an Integer<bits>.

Return Value
   An Integer or Integer<bits> variable containing a binary copy of the 
   input expression.

Description
   Returns an integer value using the binary data contained in a 
   floating-point value, or a String.  A value of zero (0) is returned if 
   the string contains fewer characters than the size of the return type.

   CVI can be used to convert strings created with MKI.

   This function can also be used to convert Integer-sized values from a 
   memory or file buffer without the need for a Type structure.  However, 
   just as with the type structure, special care should be taken when using 
   CVI to convert strings that have been read from a buffer.

   CVI supports an optional <bits> parameter before the argument.  If bits 
   is 16, CVShort will be called instead; if bits is 32, CVL will be 
   called; if bits is 64, CVLongInt will be called.  The return type and 
   accepted argument types will depend on which function is called.  See 
   each function's page for more information.

   CVI's behaviour changes depending on the size of the Integer data type 
   on the current platform.
   * For 16-bit Integer (-lang qb), a 16-bit value is returned, and no 
     floating-point types are accepted.
   * For 32-bit Integer, a 32-bit value is returned, and numeric arguments 
     are interpreted as Single precision values.
   * For 64-bit Integer, a 64-bit value is returned, and numeric arguments 
     are interpreted as Double precision values.

Example
   Dim i As Integer, s As String
   s = "ABCD"
   i = CVI(s)
   Print Using "s = ""&"""; s
   Print Using "i = _&H&"; Hex(i)

Dialect Differences
   * In the -lang qb dialect, CVI expects a 2-byte string, since a QB 
     integer is only 16 bits.  Only the first two bytes of the string are 
     used, even if the string happens to be longer than two bytes.
   * In the -lang qb dialect, CVI will not take a floating-point argument, 
     since a QB integer is only 16 bits and there is no 16-bit 
     floating-point data type.  Instead, CVI<32>/CVI<64> or CVL/CVLongInt 
     may be used.

Differences from QB
   * In QB an error occurs if the string passed is fewer than two bytes in 
     length.
   * QB did not support floating-point arguments.
   * QB did not support a <bits> parameter.

See also
   * MKI
   * CVShort
   * CVL
   * CVLongInt
   * Integer



-------------------------------------------------------------- KeyPgCvl ----
CVL

Converts a single-precision floating-point number or four-byte string to an 
integer (Long) variable

Syntax
   Declare Function CVL ( ByVal sng As Single ) As Long
   Declare Function CVL ( ByRef str As Const String ) As Long

Usage
   result = CVL( sng )
   result = CVL( str )

Parameters
   sng
      A Single floating-point number with a binary copy of an integer 
      variable stored in it.
   str
      A String at least four bytes in length with a binary copy of an 
      integer variable stored in it.

Return Value
      A Long variable to copy the binary copy of a integer to.

Description
   Returns a 32-bit Long integer value using the binary data contained in a 
   Single, or a String of at least four bytes in length.  A value of zero (
   0) is returned if the string is less than four bytes in length.

   CVL is used to convert 4-byte strings created with MKL.

   This function can also be used to convert 32-bit integer values from a 
   memory or file buffer without the need for a Type structure.  However, 
   just as with the type structure, special care should be taken when using 
   CVL to convert strings that have been read from a buffer.

Example
   Dim l As Long, s As String
   s = "ABCD"
   l = CVL(s)
   Print Using "s = ""&"""; s
   Print Using "l = &"; l

Differences from QB
   * In QB an error occurs if the string passed is less than four bytes in 
     length.
   * QB did not support floating-point arguments.

See also
   * MKL
   * CVShort
   * CVI
   * CVLongInt



-------------------------------------------------------- KeyPgCvlongint ----
CVLongInt

Converts a double-precision floating-point number or eight-byte string to a 
LongInt variable

Syntax
   Declare Function CVLongInt ( ByVal dbl As Double ) As LongInt
   Declare Function CVLongInt ( ByRef str As Const String ) As LongInt

Usage
   result = CVLongInt( dbl )
   result = CVLongInt( str )

Parameters
   dbl
      A Double floating-point number with a binary copy of a LongInt 
      variable stored in it.
   str
      A String at least eight bytes in length with a binary copy of a 
      LongInt variable stored in it.

Return Value
      A LongInt variable holding a binary copy of the input variable.

Description
   Returns a 64-bit LongInt value using the binary data contained in a 
   Double, or a String of at least eight bytes in length.  A value of zero 
   (0) is returned if the string is less than eight bytes in length.

   CVLongInt is used to convert 8-byte strings created with MKLongInt.

   This function can also be used to convert 64-bit integer values from a 
   memory or file buffer without the need for a Type structure.  However, 
   just as with the type structure, special care should be taken when using 
   CVLongInt to convert strings that have been read from a buffer.

Example
   Dim ll As LongInt, s As String
   s = "ABCDEFGH"
   ll = CVLongInt(s)
   Print Using "s = ""&"""; s
   Print Using "ll = _&H&"; Hex(ll)

Differences from QB
   * In QB an error occurs if the string passed is less than eight bytes 
     in length.
   * QB did not support floating-point arguments.

See also
   * MKLongInt
   * CVShort
   * CVI
   * CVL



-------------------------------------------------------------- KeyPgCvs ----
CVS

Converts a 32-bit integer or 4-byte string to a single-precision variable

Syntax
   Declare Function CVS ( ByVal i As Integer ) As Single
   Declare Function CVS ( ByRef str As Const String ) As Single

Usage
   result = CVS( i )
   result = CVS( str )

Parameters
   i
      A 32-bit Integer with a binary copy of a single-precision variable 
      stored in it.
   str
      A String at least 4 bytes in length with a binary copy of a 
      single-precision variable stored in it.

Return Value
      Returns a Single value holding a binary copy of the input value.

Description
   Does a binary copy from a 32-bit Integer or 4-byte String to a Single 
   variable.  A value of zero (0.0) is returned if the string is less than 
   4 bytes in length.  The result will make sense only if the parameter 
   contained a IEEE-754 formatted single-precision value, such as one 
   generated by CVI or MKS.

   This function is useful to read numeric values from buffers without 
   using a Type definition.

Example
   Dim f As Single, i As Integer
   f = 1.125
   i = CVI(f)

   Print Using "i = _&H&"; Hex(i)
   Print Using "cvs(i) = &"; CVS(i)

Differences from QB
   * QB did not support integer arguments.

See also
   * MKS
   * CVD
   * CVI



---------------------------------------------------------- KeyPgCvshort ----
CVShort

Converts a two-byte string to a Short integer variable

Syntax
   Declare Function CVShort ( ByRef str As Const String ) As Short

Usage
   result = CVShort( str )

Parameters
   str
      A String at least two bytes in length with a binary copy of a Short 
      integer variable stored in it.

Return Value
    Short variable holding the binary copy of a Keypgshort.

Description
   Returns a 16-bit Short integer value using the binary data contained in 
   a String of at least two bytes in length.  A value of zero (0) is 
   returned if the string is less than two bytes in length.

   CVShort is used to convert 2-byte strings created with MKShort.

   This function can also be used to convert 16-bit integer values from a 
   memory or file buffer without the need for a Type structure.  However, 
   just as with the type structure, special care should be taken when using 
   CVShort to convert strings that have been read from a buffer.

Example
   Dim si As Short, s As String
   s = "AB"
   si = CVShort(s)
   Print Using "s = ""&"""; s
   Print Using "si = _&H&"; Hex(si)

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Cvshort.

Differences from QB
   * In QB this function is called CVI

See also
   * MKShort
   * CVI
   * CVL
   * CVLongInt




============================================================================
    D

------------------------------------------------------------- KeyPgData ----
Data

Statement to store data at compile time.

Syntax
   Data constant_expression1 [,constant_expression2]...

Description
   Data stores a list of constant numeric or alphabetical expressions that 
   are evaluated at compile time (except with -lang qb) and stored as 
   constants that can be read into variables by using Read.

   All the Data statements in the program behave as a single chained list; 
   after the last element of one Data statement is read, the first element 
   of the following Data statement will be read.
   The program should not attempt to Read after the last Data element.  The 
   results are (in all dialects) undefined,  and the program may crash 
   (Page Fault).

   Data statements are only visible from within the module in which they 
   are defined; they must be only entered in module-level code.

   Data constants can only be of simple types (numeric or string).  A 
   numeric value can be read as a numeric literal into a string. A string 
   read into a numeric variable will be evaluated by the Val function.  
   Consts can be used as items of data except in the -lang qb dialect, 
   where their names are considered as normal text.

   The "Restore label" statement makes the first Data item after the label 
   the next item to be read, allowing the user to choose specific sections 
   of data to read.

   Data is normally used to initialize variables. FreeBASIC also allows the 
   initialization of static variables when they are Dimensioned - see 
   Variable Initializers for more information.

Example
   ' Create an array of 5 integers and a string to hold the data.
   Dim As Integer h(4)
   Dim As String hs
   Dim As Integer readindex

   ' Set up to loop 5 times (for 5 numbers... check the data)
   For readindex = 0 To 4

     ' Read in an integer.
     Read h(readindex)

     ' Display it.
     Print "Number" ; readindex ; " = " ; h(readindex)

   Next readindex

   ' Spacer.
   Print

   ' Read in a string.
   Read hs

   ' Print it.
   Print  "String = " + hs

   ' Await a keypress.
   Sleep

   ' Exit program.
   End

   ' Block of data.
   Data 3, 234, 435/4, 23+433, 87643, "Good" + "Bye!"

Dialect Differences
   * -lang fb and -lang fblite considers data items as constant 
     expressions that are evaluated during compilation and its result 
     stored in the program.
   * -lang qb considers unquoted words, including names of variables and 
     constants, as literal strings, and stores them without change, as in 
     QBASIC.  Unquoted strings are delimited by commas, and a colon or a 
     line-break signifies the end of the Data statement.  Unquoted strings 
     are trimmed of whitespace at the beginning and end.

Differences from QB
   * Outside of the -lang qb dialect, alphabetic string literals must be 
     enclosed within quotation marks, in QBASIC this was optional.
   * In QBASIC empty items evaluated to number 0 or to empty strings, in 
     FreeBASIC they give a compile error. In QBASIC a comma at the end of 
     the statement made an additional, empty item, evaluated to 0 or an 
     empty string. In FreeBASIC they give a compile error.

See also
   * Read
   * Restore



------------------------------------------------------------- KeyPgDate ----
Date

Returns the current system date as a string

Syntax
   Declare Function Date ( ) As String

Usage
   result = Date[$]

Return Value
   Returns the current system date, in the format mm-dd-yyyy

Description
   None

Example
   Print Date ' prints the current date

Differences from QB
   * The QB DATE statement (to set the system date) is now called SetDate.
   * The string type suffix "$" is required in the -lang qb dialect.
   * The string type suffix "$" is optional in the -lang fblite dialect.
   * The string type suffix "$" is ignored in the -lang fb dialect, warn 
     only with the -w suffix compile option (or -w pedantic compile 
     option).

See also
   * SetDate
   * Time
   * Timer



---------------------------------------------------------- KeyPgDateAdd ----
DateAdd

Offset a date with a specified interval

Syntax
   Declare Function DateAdd ( ByRef interval As Const String, ByVal number 
   As Double, ByVal date_serial As Double ) As Double

Usage
   #include "vbcompat.bi"
   result = DateAdd( interval, number, date_serial )

Parameters
   interval
      string indicating which period of time corresponds to one unit of 
      number
   number
      the number of intervals to add to the base date.  The number will be 
      rounded to the nearest integer.
   date_serial
      the base date

Return Value
   Returns a Date Serial corresponding to the received date_serial plus the 
   number of intervals.

Description
   Interval is specified as follows:

      +-----+---------------------+
      |value|interval             |
      |yyyy |years                |
      |q    |quarter(three months)|
      |m    |months               |
      |ww   |weeks                |
      |d,w,y|days                 |
      |h    |hours                |
      |n    |minutes              |
      |s    |seconds              |
      +-----+---------------------+
  

   The compiler will not recognize this function unless vbcompat.bi or 
   datetime.bi is included.

Example
   #include "vbcompat.bi"

   Const fmt = "ddddd ttttt"
   Dim d As Double
   d = Now()

   Print "1 hour from now is ";
   Print Format( DateAdd( "h", 1, d ), fmt )

   Print "1 day from now is ";
   Print Format( DateAdd( "d", 1, d ), fmt )

   Print "1 week from now is ";
   Print Format( DateAdd( "ww", 1, d ), fmt )

   Print "1 month from now is ";
   Print Format( DateAdd( "m", 1, d ), fmt )

Differences from QB
   * Did not exist in QB. This function appeared in Visual Basic.

See also
   * Date Serials

   


--------------------------------------------------------- KeyPgDateDiff ----
DateDiff

Gets the difference of two dates measured by a specified interval

Syntax
   Declare Function DateDiff ( ByRef interval As Const String, ByVal 
   serial1 As Double, ByVal serial2 As Double, ByVal firstdayofweek As Long 
   = fbUseSystem, ByVal firstdayofyear As Long = fbUseSystem ) As LongInt

Usage
   #include "vbcompat.bi"
   result = DateDiff( interval, date_serial1, date_serial2 [, 
   firstdayofWeek [, firstweekofyear ] ] )

Parameters
   interval
      the unit of time (interval) with which to measure the difference
   date_serial1
      starting date serial
   date_serial2
      end date serial
   firstdayofweek
      first day of the week
   firstdayofyear
      first day of the year

Return Value
   Returns a LongInt corresponding to the number of intervals found between 
   two Date Serials.

   If date_serial1 > date_serial2, the result is negative.

Description
   interval is specified as follows:

         +-----+---------------------+
         |value|interval             |
         |yyyy |years                |
         |q    |quarter(three months)|
         |m    |months               |
         |w    | seven day periods   |
         | ww  |calendar weeks       |
         |d,y  |days                 |
         |h    |hours                |
         |n    |minutes              |
         |s    |seconds              |
         +-----+---------------------+
  

   first_dayofweek Affects the counting when 'ww' interval is used.

         +-------+-----------------+-----------+
         |value  |first day of week|constant   |
         |omitted|sunday           |           |
         |0      |local settings   |fbUseSystem|
         |1      |sunday           |fbSunday   |
         |2      |monday           |fbMonday   |
         |3      |tuesday          |fbTuesday  |
         |4      |wednesday        |fbWednesday|
         |5      |thursday         |fbThursday |
         |6      |friday           |fbFriday   |
         |7      |saturday         |fbSaturday |
         +-------+-----------------+-----------+

   first_weekofyear specifies which year (previous or next) that the week 
   which spans the end of one year and the beginning of the next should 
   included with.

         +-----+-------------------------------------+---------------+
         |value|first week of year                   |constant       |
         |0    |local settings                       |fbUseSystem    |
         |1    |January 1's week                     |fbFirstJan1    |
         |2    |first weeks having 4 days in the year|fbFirstFourDays|
         |3    |first full week of year              |fbFirstFullWeek|
         +-----+-------------------------------------+---------------+

   Notice if you do an arithmetical subtraction of two date serials you get 
   the difference in days.

   The compiler will not recognize this function unless vbcompat.bi or 
   datetime.bi is included.

Example
   #include "vbcompat.bi"

   Dim s As String, d1 As Double, d2 As Double

   Line Input "Enter your birthday: ", s

   If IsDate( s ) Then
     d1 = DateValue( s )
     d2 = Now()

     Print "You are " & DateDiff( "yyyy", d1, d2 ) & " years old."
     Print "You are " & DateDiff( "d", d1, d2 ) & " days old."
     Print "You are " & DateDiff( "s", d1, d2 ) & " seconds old."

   Else
     Print "Invalid date"

   End If

Differences from QB
   * Did not exist in QB. This function appeared in Visual Basic.

See also
   * Date Serials



--------------------------------------------------------- KeyPgDatePart ----
DatePart

Gets an interval from a date

Syntax
   Declare Function DatePart ( ByRef interval As Const String, ByVal 
   date_serial As Double, ByVal firstdayofweek As Long = fbUseSystem, ByVal 
   firstdayofyear As Long = fbUseSystem ) As Long

Usage
   #include "vbcompat.bi"
   result = DatePart( interval, date_serial, first_dayofWeek [, 
   first_week_of_year ] )

Parameters
   interval
      string indicating which part of the date is required
   date_serial
      the date serial to decode 
   firstdayofweek
      first day of the week
   firstdayofyear
      first day of the year

Return Value
   Return an integer representing  the interval in the Date Serial.

Description

   interval string indicating which part of the date is required is 
   specified as follows:

         +-----+---------------------+
         |value|interval             |
         |yyyy |years                |
         |q    |quarter(three months)|
         |m    |months               |
         | w   | weekday             |
         | ww  | week of the year    |
         |y    |day of the year      |
         |d    |day of the month     |
         |h    |hours                |
         |n    |minutes              |
         |s    |seconds              |
         +-----+---------------------+
  

   first_dayofweek Affects the output when 'w' interval is required.

         +-------+-----------------+-----------+
         |value  |first day of week|constant   |
         |omitted|sunday           |           |
         |0      |local settings   |fbUseSystem|
         |1      |sunday           |fbSunday   |
         |2      |monday           |fbMonday   |
         |3      |tuesday          |fbTuesday  |
         |4      |wednesday        |fbWednesday|
         |5      |thursday         |fbThursday |
         |6      |friday           |fbFriday   |
         |7      |saturday         |fbSaturday |
         +-------+-----------------+-----------+

   first_weekofyear  specifies which year (previous or next) that the week 
   which spans the end of one year and the beginning of the next should 
   included with. Affects the output when 'ww' interval is required.

         +-----+-------------------------------------+---------------+
         |value|first week of year                   |constant       |
         |0    |local settings                       |fbUseSystem    |
         |1    |January 1's week                     |fbFirstJan1    |
         |2    |first weeks having 4 days in the year|fbFirstFourDays|
         |3    |first full week of year              |fbFirstFullWeek|
         +-----+-------------------------------------+---------------+

   The compiler will not recognize this function unless vbcompat.bi or 
   datetime.bi is included.

Example
   #include "vbcompat.bi"

   Dim d As Double

   d = Now()

   Print "Today is day " & DatePart( "y", d );
   Print " in week " & DatePart( "ww", d );
   Print " of the year " & DatePart( "yyyy", d )

Differences from QB
   * Did not exist in QB. This function appeared in Visual Basic.

See also
   * Date Serials



------------------------------------------------------- KeyPgDateSerial ----
DateSerial

Creates a date serial

Syntax
   Declare Function DateSerial ( ByVal year As Long, ByVal month As Long, 
   ByVal day As Long ) As Long

Usage
   #include "vbcompat.bi"
   result = DateSerial( year, month, day )

Parameters
   year
      the year
   month
      the month of the year
   day
      the day of the month

Return Value
   Returns a date serial containing the date formed by the values in the 
   year, month and day parameters.The date serial returned has no decimal 
   part.

Description
   The compiler will not recognize this function unless vbcompat.bi or 
   datetime.bi is included.

Example
   #include "vbcompat.bi"

   Dim a As Long = DateSerial(2005, 11, 28)

   Print Format(a, "yyyy/mm/dd hh:mm:ss") 

Differences from QB
   * Did not exist in QB. This function appeared in PDS and VBDOS

See also
   * Date Serials
   * DateSerial
   * TimeValue
   * DateValue



-------------------------------------------------------- KeyPgDateValue ----
DateValue

Returns a Date Serial from a string

Syntax
   Declare Function DateValue ( ByRef date_string As String ) As Long

Usage
   #include "vbcompat.bi"
   result = DateValue( date_string )

Parameters
   date_string
      the string to convert to a date serial

Return Value
   Returns a Date Serial from a date string.

Description
   The date string must be in the format set in the regional settings of 
   the Operating System. 

   DateValue( Date() ) will work correctly only if the regional settings 
   specify the same short date format QB used (mm-dd-yyyy).  Consider using 
   the Now function in the expression Fix(Now()) to obtain the current date 
   as a date serial.

   The compiler will not recognize this function unless vbcompat.bi or 
   datetime.bi is included.

Example
   #include "vbcompat.bi"

   Dim As Long v1, v2
   Dim As String  s1, s2

   Print "Enter first date: ";
   Line Input s1

   If IsDate( s1 ) = 0 Then
     Print "not a date"
     End
   End If

   Print "Enter second date: ";
   Line Input s2

   If IsDate( s2 ) = 0 Then
     Print "not a date"
     End
   End If

   '' convert the strings to date serials
   v1 = DateValue( s1 )
   v2 = DateValue( s2 )

   Print "Number of days between dates is " & Abs( v2 - v1 )

Differences from QB
   * Did not exist in QB. This function appeared in PDS and VBDOS

See also
   * Date Serials
   * DateSerial
   * TimeValue



-------------------------------------------------------------- KeyPgDay ----
Day

Gets the day of the month from a Date Serial

Syntax
   Declare Function Day ( ByVal date_serial As Double ) As Long

Usage
   #include "vbcompat.bi"
   result = Day( date_serial )

Parameters
   date_serial
      the date

Return Value
   Returns the day of the month from a  variable containing a date in  
   Date Serial  format. 

Description

   The compiler will not recognize this function unless vbcompat.bi is 
   included.

Example
   #include "vbcompat.bi"

   Dim ds As Long = DateSerial(2005, 11, 28)

   Print Format(ds, "yyyy/mm/dd "); Day(ds)

Differences from QB
   * Did not exist in QB. This function appeared in PDS and VBDOS

See also
   * Date Serials



------------------------------------------------------- KeyPgDeallocate ----
Deallocate

Frees previously allocated memory

Syntax
   Declare Sub Deallocate cdecl ( ByVal pointer As Any Ptr )

Usage
   Deallocate( pointer )

Parameters
   pointer
      the address of the previously allocated buffer.

Description
   This procedure frees memory that was previously allocated with Allocate. 
   pointer must be a valid pointer. After the procedure returns, pointer 
   will be rendered invalid (pointing to an invalid memory address), and 
   its use (dereferencing or calling Deallocate again) will result in 
   undefined behavior.

   When memory was allocated to hold a string descriptor, the string must 
   always be destroyed (setting to "") before deallocate the string 
   descriptor (allowing to deallocate the memory taken up by the string 
   data), otherwise, it is not possible to deallocate it later, and it may 
   induce memory leak in the program continuation.

   Calling Deallocate on a null pointer induces no action.

Example
   The following example shows how to free previously allocated memory. 
   Note that the pointer is set to null following the deallocation:
   Sub DeallocateExample1()
      Dim As Integer Ptr integerPtr = Allocate( Len( Integer ) )  '' initialize pointer to
                                                   '' new memory address

      *integerPtr = 420                                     '' use pointer
      Print *integerPtr

      Deallocate( integerPtr )                              '' free memory back to system
      integerPtr = 0                                        '' and zero the pointer
   End Sub

      DeallocateExample1()
      End 0
      

   Although in this case it is unnecessary since the function immediately 
   exits afterwards, setting the pointer to null is a good habit to get 
   into. If the function deallocated memory from a pointer that was passed 
   in by reference, for instance, the pointer that was used in the function 
   call will be rendered invalid, and it is up to the caller to either 
   reassign the pointer or set it to null. Example 3 shows how to correctly 
   handle this kind of situation, and the next example shows the effects of 
   deallocating memory with multiple references.

   In the following example, a different pointer is used to free previously 
   allocated memory:
   '' WARNING: "evil" example showing how things should NOT be done

   Sub DeallocateExample2()
      Dim As Integer Ptr integerPtr = Allocate( Len( Integer ) )  
      '' initialize ^^^ pointer to new memory

      Dim As Integer Ptr anotherIntegerPtr = integerPtr
      '' initialize ^^^ another pointer to the same memory

      *anotherIntegerPtr = 69                     '' use other pointer
      Print *anotherIntegerPtr

      Deallocate( anotherIntegerPtr )             '' free memory back to system
      anotherIntegerPtr = 0                       '' and zero other pointer

   '' *integerPtr = 420                           '' undefined behavior; original
                                       '' pointer is invalid
   End Sub

      DeallocateExample2()
      End 0
      

   Note that after the deallocation, both pointers are rendered invalid. 
   This illustrates another one of the ways that bugs can arise when 
   working with pointers. As a general rule, only deallocate memory 
   previously allocated when you know that there is only one (1) pointer 
   currently pointing at it.

   Function createInteger() As Integer Ptr
      Return Allocate( Len( Integer ) )                     '' return pointer to newly
   End Function                                             '' allocated memory

   Sub destroyInteger( ByRef someIntegerPtr As Integer Ptr )
      Deallocate( someIntegerPtr )                          '' free memory back to system
      someIntegerPtr = 0                                    '' null original pointer
   End Sub

   Sub DeallocateExample3()
      Dim As Integer Ptr integerPtr = createInteger()       '' initialize pointer to
                                              '' new memory address

      *integerPtr = 420                                     '' use pointer
      Print *integerPtr

      destroyInteger( integerPtr )                          '' pass pointer by reference
      Assert( integerPtr = 0 )                              '' pointer should now be null
   End Sub

      DeallocateExample3()
      End 0
      

   In the program above, a reference pointer in a function is set to null 
   after deallocating the memory it points to. An Assert macro is used to 
   test if the original pointer is in fact null after the function call. 
   This example implies the correct way to pass pointers to functions that 
   deallocate the memory they point to is by reference.

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Deallocate.

Differences from QB
   * New to FreeBASIC

See also
   * Allocate
   * Reallocate



---------------------------------------------------------- KeyPgDeclare ----
Declare

Declares a module-level or member procedure

Syntax
   Declare Sub name [ param_list ]
   Declare Function name [ param_list ] [ ByRef ] As return_type
   Declare Operator op_symbol param_list [ [ ByRef ] As return_type ]

   Type T
      Declare Constructor [ param_list ]
      Declare Destructor
      Declare Sub name [ param_list ]
      Declare Function name [ param_list ] [ ByRef ] As return_type
      Declare Operator name [ param_list ] [ [ ByRef ] As return_type ]
      Declare Property name [ ( [ param_list ] ) ] [ [ ByRef ] As 
      return_type ]
   End Type

Parameters
   param_list
      Parenthesized comma-separated list of parameters.
   return_type
      The return type of a Function, Operator, or Property procedure.
   name
      The name or symbol of the procedure.
   op_symbol
      The name or symbol of an operator.
   T
      The name of a new user-defined type.

Description
   The Declare statement declares a Sub, Function, Operator, Constructor, 
   or Destructor.
   The procedure can be referred to in code without seeing its definition, 
   although it must be defined somewhere. Essentially, the Declare 
   statement introduces a procedure, and states that its definition is 
   elsewhere. For example, a function can be declared at the top of a 
   source module, called, then defined at the bottom of the source file, as 
   shown below the example.

   A procedure's declaration is almost identical to the first line of its 
   definition, except the declaration is preceded by the Declare keyword 
   and has no body. Also, attributes such as Export are left off the 
   declaration.

   FreeBASIC, as QB, does not require the declaration of the functions 
   unless they are defined in a different source file or in the same file 
   past the point where they are called. This is no longer true for 
   procedures declared inside a Type body, which must always be declared 
   first in the Type's body before use. If you do not declare Type 
   procedures you will receive an error.

    As every file using a function must have its declaration, declarations 
   are usually kept in one or more include files to allow usage of the 
   function by any module that needs it using the #include statement. 

Example
Module-level Function:
   '' declare the function sum which takes two integers and returns an integer
   Declare Function sum( As Integer, As Integer ) As Integer

      Print "the sum of 420 and 69 is: " & sum( 420, 69 )    '' call the function sum

   '' define the function sum which takes two integers and returns an integer
   Function sum( a As Integer, b As Integer ) As Integer
      Return a + b
   End Function

Type-level Sub:
   Type my_type
      my_data As Integer
      Declare Sub increment_data( )
   End Type

   Sub my_type.increment_data( )
      my_data += 1
   End Sub

   Dim As my_type an_instance

   an_instance.my_data = 68

   an_instance.increment_data( )

   Print an_instance.my_data

Dialect Differences
   * In the -lang fb dialect, ByVal is the default parameter passing 
     convention.
   * In the -lang qb and -lang deprecated dialects, ByRef is the default 
     parameter passing convention.
   * Type-level Sub/Function/Operator/Constructor/Destructor's are only 
     allowed in -lang fb

Differences from QB
   * In FreeBASIC, the parameter names are optional.

See also
   * Sub
   * Function
   * Operator
   * Property
   * Constructor
   * Destructor
   * Constructor (Module)
   * Destructor (Module)
   * Type
   * Dim
   * Alias (Name)
   * Alias (Modifier)

   

---------------------------------------------------------- KeyPgDefbyte ----
DefByte

Specifies a default data type for a range of variable names

Syntax
   DefByte start_letter[-end_letter ][, ...]

Parameters
   start_letter
      the first letter in the range
   end_letter
      the last letter in the range

Description
   DefByte specifies that variables and arrays which aren't declared with a 
   data type - or not declared at all - are implicitly declared of type Byte
   if the first letter of their names matches a certain letter or lies 
   within an inclusive range of letters.

Example
   This will make bNumber a Byte number since it's first letter starts with 
   b:
   '' Compile with -lang fblite or qb

   #lang "fblite"

   DefByte b
   Dim bNumber

Dialect Differences
   * Available in the -lang fblite dialect.
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Defbyte.

Differences from QB
   * New to FreeBASIC

See also
   * Byte
   * DefInt
   * DefUByte
   * Dim



----------------------------------------------------------- KeyPgDefdbl ----
DefDbl

Specifies a default data type for a range of variable names

Syntax
   DefDbl start_letter[-end_letter ][, ...]

Parameters
   start_letter
      the first letter in the range
   end_letter
      the last letter in the range

Description
   DefDbl specifies that variables and arrays which aren't declared with a 
   data type - or not declared at all - are implicitly declared of type 
   Double if the first letter of their names matches a certain letter or 
   lies within an inclusive range of letters.

Example
   This will make aNum a Double-precision decimal number since it is in the 
   range of a-d:
   '' Compile with -lang fblite or qb

   #lang "fblite"

   DefDbl a-d
   Dim aNum 'implicit: As Double

   Print Len(aNum) ' Prints 8, the number of bytes in a double.

Dialect Differences
   * Only available in the -lang qb and -lang fblite dialects.

Differences from QB
   * None

See also
   * DefInt
   * DefSng
   * Dim
   * Double



---------------------------------------------------------- KeyPgDefined ----
defined

Preprocessor function to test if a symbol has been defined

Syntax
   defined (symbol_name)

Parameters
   symbol_name
      Name of the symbol to test

Return Value
   Returns non-zero (-1) if the symbol has been defined, otherwise returns 
   zero (0).

Description
   Given the symbol name, the defined() preprocessor function returns true 
   if the symbol has been defined - or false if the symbol is unknown.

   This is used mainly with #if (or #elseif).
   Similar to #ifdef (or #elseifdef) except it allows more than one check 
   to occur because of its flexibility.

Example
   'e.g. - which symbols are defined out of a, b, c, and d ?

   Const a = 300
   #define b 12
   Dim c As Single

   #if defined(a)
    Print "a is defined"
   #endif
   #if defined(b)
    Print "b is defined"
   #endif
   #if defined(c)
    Print "c is defined"
   #endif
   #if defined(d)
    Print "d is defined"
   #endif

Differences from QB
   * New to FreeBASIC

See also
   * #define
   * #macro
   * #if
   * #else 
   * #elseif 
   * #elseifdef 
   * #elseifndef 
   * #endif 
   * #ifdef
   * #ifndef
   * #undef



----------------------------------------------------------- KeyPgDefint ----
DefInt

Specifies a default data type for a range of variable names

Syntax
   DefInt start_letter[-end_letter ][, ...]

Parameters
   start_letter
      the first letter in the range
   end_letter
      the last letter in the range

Description
   DefInt specifies that variables and arrays which aren't declared with a 
   data type - or not declared at all - are implicitly declared of type 
   Integer if the first letter of their names matches a certain letter or 
   lies within an inclusive range of letters.

Example
   This will make iNumber an Integer number since its first letter starts 
   with i.
   '' Compile with -lang fblite or qb

   #lang "fblite"

   DefInt i
   Dim iNumber

Dialect Differences
   * Only available in the -lang qb and -lang fblite dialects.

Differences from QB
   * None

See also
   * DefByte
   * DefDbl
   * DefLng
   * DefLongInt
   * DefShort
   * DefSng
   * DefStr
   * Integer



----------------------------------------------------------- KeyPgDeflng ----
DefLng

Specifies a default data type for a range of variable names

Syntax
   DefLng start_letter[-end_letter ][, ...]

Parameters
   start_letter
      the first letter in the range
   end_letter
      the last letter in the range

Description
   DefLng specifies that variables and arrays which aren't declared with a 
   data type - or not declared at all - are implicitly declared of type Long
   if the first letter of their names matches a certain letter or lies 
   within an inclusive range of letters.

Example
   This will make lNumber a Long integer number since it starts with l.
   '' Compile with -lang fblite or qb

   #lang "fblite"

   DefLng l
   Dim lNumber ' implicit: As Long

   Print Len(lNumber) ' Displays 4, the number of bytes in a long.

Dialect Differences
   * Only available in the -lang qb and -lang fblite dialects.

Differences from QB
   * None

See also
   * DefInt
   * Defulongint
   * Dim
   * LongInt



------------------------------------------------------- KeyPgDeflongint ----
DefLongInt

Specifies a default data type for a range of variable names

Syntax
   DefLongInt start_letter[-end_letter ][, ...]

Parameters
   start_letter
      the first letter in the range
   end_letter
      the last letter in the range

Description
   DefLongInt specifies that variables and arrays which aren't declared 
   with a data type - or not declared at all - are implicitly declared of 
   type LongInt if the first letter of their names matches a certain letter 
   or lies within an inclusive range of letters.

Example
   This will make lNumber a LongInt number since it's first letter starts 
   with l.
   '' Compile with -lang fblite

   #lang "fblite"

   DefLongInt l
   Dim lNumber

Dialect Differences
   * Available in the -lang fblite dialect.
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Deflongint.

Differences from QB
   * New to FreeBASIC

See also
   * DefInt
   * Defulongint
   * Dim
   * LongInt



--------------------------------------------------------- KeyPgDefshort ----
DefShort

Specifies a default data type for a range of variable names

Syntax
   DefShort start_letter[-end_letter ][, ...]

Parameters
   start_letter
      the first letter in the range
   end_letter
      the last letter in the range

Description
   DefShort specifies that variables and arrays which aren't declared with 
   a data type - or not declared at all - are implicitly declared of type 
   Short if the first letter of their names matches a certain letter or 
   lies within an inclusive range of letters.

Example
   This will make sNumber a Short number since its first letter starts with 
   s.
   '' Compile with -lang fblite or qb

   #lang "fblite"

   DefShort s
   Dim sNumber

Dialect Differences
   * Available in the -lang fblite dialect.
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Defshort.

Differences from QB
   * New to FreeBASIC
   * In QBasic, to make variables default to a 2 byte integer, DEFINT is 
     used.

See also
   * DefInt
   * DefUShort
   * Dim
   * Integer
   * Short



----------------------------------------------------------- KeyPgDefsng ----
DefSng

Specifies a default data type for a range of variable names

Syntax
   DefSng start_letter[-end_letter ][, ...]

Parameters
   start_letter
      the first letter in the range
   end_letter
      the last letter in the range

Description
   DefSng specifies that variables and arrays which aren't declared with a 
   data type - or not declared at all - are implicitly declared of type 
   Single if the first letter of their names matches a certain letter or 
   lies within an inclusive range of letters.

Example
   This will make sNumber and yNumber a Single-precision decimal number 
   since it is in the range of s-z.
   '' Compile with -lang fblite or qb

   #lang "fblite"

   DefSng s-z
   Dim sNumber, yNumber

Dialect Differences
   * Only available in the -lang qb and -lang fblite dialects.

Differences from QB
   * None

See also
   * DefInt
   * DefDbl
   * Single



----------------------------------------------------------- KeyPgDefstr ----
DefStr

Specifies a default data type for a range of variable names

Syntax
   DefStr start_letter[-end_letter ][, ...]

Parameters
   start_letter
      the first letter in the range
   end_letter
      the last letter in the range

Description
   DefStr specifies that variables and arrays which aren't declared with a 
   data type - or not declared at all - are implicitly declared of type 
   String if the first letter of their names matches a certain letter or 
   lies within an inclusive range of letters.

Example
   This will make sMessage a String since it starts with s.
   '' Compile with -lang fblite or qb

   #lang "fblite"

   DefStr s
   Dim sMessage

Dialect Differences
   * Only available in the -lang qb and -lang fblite dialects.

Differences from QB
   * None

See also
   * DefInt
   * DefSng
   * DefLng
   * DefDbl
   * Dim
   * String



--------------------------------------------------------- KeyPgDefubyte ----
DefUByte

Specifies a default data type for a range of variable names

Syntax
   DefUByte start_letter[-end_letter ][, ...]

Parameters
   start_letter
      the first letter in the range
   end_letter
      the last letter in the range

Description
   DefUByte specifies that variables and arrays which aren't declared with 
   a data type - or not declared at all - are implicitly declared of type 
   UByte if the first letter of their names matches a certain letter or 
   lies within an inclusive range of letters.

Example
   This will make uNumber a UByte number since it's first letter starts 
   with u.
   '' Compile with -lang fblite

   #lang "fblite"

   DefUByte u
   Dim uNumber

Dialect Differences
   * Available in the -lang fblite dialect.
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Defubyte.

Differences from QB
   * New to FreeBASIC

See also
   * DefByte
   * DefInt
   * Dim
   * UByte



---------------------------------------------------------- KeyPgDefuint ----
DefUInt

Specifies a default data type for a range of variable names

Syntax
   DefUInt start_letter[-end_letter ][, ...]

Parameters
   start_letter
      the first letter in the range
   end_letter
      the last letter in the range

Description
   DefUInt specifies that variables and arrays which aren't declared with a 
   data type - or not declared at all - are implicitly declared of type 
   UInteger if the first letter of their names matches a certain letter or 
   lies within an inclusive range of letters.

Example
   This will make uNumber a UInteger number since its first letter starts 
   with u.
   '' Compile with -lang fblite

   #lang "fblite"

   DefInt u
   Dim uNumber

Dialect Differences
   * Available in the -lang fblite dialect.
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Defuint.

Differences from QB
   * New to FreeBASIC

See also
   * DefInt
   * Dim
   * UInteger



------------------------------------------------------ KeyPgDefulongint ----
Defulongint

Specifies a default data type for a range of variable names

Syntax
   Defulongint start_letter[-end_letter ][, ...]

Parameters
   start_letter
      the first letter in the range
   end_letter
      the last letter in the range

Description
   Defulongint specifies that variables and arrays which aren't declared 
   with a data type - or not declared at all - are implicitly declared of 
   type ULongInt if the first letter of their names matches a certain 
   letter or lies within an inclusive range of letters.

Example
   This will make lNumber a ULongInt number since its first letter starts 
   with l.
   '' Compile with -lang fblite

   #lang "fblite"

   defulongint l
   Dim lNumber

Dialect Differences
   * Available in the -lang fblite dialect.
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Defulongint.

Differences from QB
   * New to FreeBASIC

See also
   * DefInt
   * DefLongInt
   * Dim
   * ULongInt



-------------------------------------------------------- KeyPgDefushort ----
DefUShort

Specifies a default data type for a range of variable names

Syntax
   DefUShort start_letter[-end_letter ][, ...]

Parameters
   start_letter
      the first letter in the range
   end_letter
      the last letter in the range

Description
   DefUShort specifies that variables and arrays which aren't declared with 
   a data type - or not declared at all - are implicitly declared of type 
   UShort if the first letter of their names matches a certain letter or 
   lies within an inclusive range of letters.

Example
   This will make uNumber a UShort number since its first letter starts 
   with u.
   '' Compile with -lang fblite

   #lang "fblite"

   DefUShort u
   Dim uNumber

Dialect Differences
   * Available in the -lang fblite dialect.
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Defushort.

Differences from QB
   * New to FreeBASIC

See also
   * DefInt
   * DefShort
   * Dim
   * UShort



--------------------------------------------------------- KeyPgOpDelete ----
Operator Delete Statement

Operator to destroy data and free memory allocated with the 
Operator New Expression

Usage
   Delete buf
      or
   Delete[] buf

Parameters
   buf 
      A pointer to memory that has been allocated by New Expression 
      operator or New[] Expression operator, the array-version of 
      New Expression operator (a typed pointer must be provided in 
      accordance to the data type to delete).

Description
   The Delete Statement operator is used to destroy and free the memory of 
   an object created with New Expression operator. When deleting a TYPE, 
   its destructor will be called. Delete Statement operator should only be 
   used with addresses returned from New Expression operator.

   The array version of Delete Statement operator, Delete[] Statement 
   operator, is used to destroy an array of objects previously created with 
   New[] Expression operator, the array-version of New Expression operator. 
   Destructors will be called here as well.

   Delete Statement operator must be used with addresses returned from 
   New Expression operator, and Delete[] Statement operator with New[] 
   Expression operator, the array-version of New Expression operator. You 
   cannot mix and match the different versions of the operators.

   After the memory is deleted, the buf pointer will be pointing at invalid 
   memory. Calling Delete Expression twice on the same pointer value leads 
   to undefined behavior. It may be a good idea to set the buf pointer to 
   null (0), in order to guard against later code using it accidentally, 
   since null pointer dereferences are easier to find and debug.

   Calling Delete Statement operator on a null pointer induces no action.

   The memory deallocation process part provided by the Delete Statement 
   operator can be overloaded for user-defined types as a member operator 
   Delete Overload. The previous process part for data destruction can 
   never be modified.

   Note: Any operator Delete[] (Statement or Overload) and the only 
   Overload operator Delete are not compatible with sub-type polymorphism, 
   even using Override Virtual Destructor that may in addition induce 
   crashing.
   Instead of having to call such an operator Delete([]) Statement on 
   derived-type pointer, the safest way is to simply call (on base-type 
   pointer) an overridden user Virtual member procedure that will 
   automatically launch the operator Delete([]) Statement at derived-type 
   level.

Example
   Type Rational
      As Integer numerator, denominator
   End Type

   ' Create and initialize a Rational, and store its address.
   Dim p As Rational Ptr = New Rational(3, 4)

   Print p->numerator & "/" & p->denominator

   ' Destroy the rational and give its memory back to the system. 
   Delete p

   ' Set the pointer to null to guard against future accesses
   p = 0

   ' Allocate memory for 100 integers, store the address of the first one.
   Dim p As Integer Ptr = New Integer[100]

   ' Assign some values to the integers in the array.
   For i As Integer = 0 To 99
      p[i] = i
   Next

   ' Free the entire integer array.
   Delete[] p

   ' Set the pointer to null to guard against future accesses
   p = 0

Dialect Differences
   * Only available in the -lang fb dialect.

Differences from QB
   * New to FreeBASIC

See also
   * New Expression
   * Delete Overload
   * Deallocate



------------------------------------------------------- KeyPgDestructor ----
Destructor

Called automatically when a class or user defined type goes out of scope or 
is destroyed

Syntax
   Type typename
      field declarations
      Declare Destructor ( )
   End Type

   Destructor typename ( ) [ Export ]
      statements
   End Destructor

Parameters
   typename 
      name of the Type of Class

Description
   The destructor method is called when a user defined Type or Class 
   variable goes out of scope or is destroyed explicitly with the 
   Delete Statement operator.

   typename is the name of the type for which the Destructor method is 
   declared and defined.  Name resolution for typename follows the same 
   rules as procedures when used in a Namespace.

   The Destructor method is passed a hidden This parameter having the same 
   type as typename.

   The destructor in a type is called before the destructors on any of its 
   fields.  Therefore, all fields are accessible with the hidden This 
   parameter in the destructor body.

   Only one destructor may be declared and defined per type (but several 
   destructors can be called in a chained way if the type contains or 
   inherits other types with their own destructors).

   Since the End statement does not close any scope, object destructors 
   will not automatically be called if the End statement is used to 
   terminate the program.

   Destructor can be also called directly from the typename instance like 
   the other member methods (Sub) and with the same syntax, i.e. using a 
   member access operator, e.g. obj.Destructor(). The object, and all its 
   members, are assumed to be constructed and in a valid state, otherwise 
   its effects are undefined and may cause crashes.  This syntax is useful 
   in cases where obj has been constructed manually, e.g. with obj.
   Constructor() or Placement New.

Example
   Type T
     value As ZString * 32
     Declare Constructor ( init_value As String )
     Declare Destructor ()
   End Type

   Constructor T ( init_value As String )
     value = init_value
     Print "Creating: "; value
   End Constructor

   Destructor T ()
     Print "Destroying: "; value
   End Destructor

   Sub MySub
     Dim x As T = ("A.x")
   End Sub

   Dim x As T = ("main.x")

   Scope
     Dim x As T = ("main.scope.x")
   End Scope

   MySub

Output:

   Creating: main.x
   Creating: main.scope.x
   Destroying: main.scope.x
   Creating: A.x
   Destroying: A.x
   Destroying: main.x

Dialect Differences
   * Object-related features are supported only in the -lang fb dialect.

Differences from QB
   * New to FreeBASIC

See also
   * Class
   * Constructor
   * Delete Statement
   * Destructor (Module)
   * Type



------------------------------------------------- KeyPgModuleDestructor ----
Destructor (Module)

Specifies execution of a procedure at program termination

Syntax
   [Public | Private] Sub identifier [Alias "external_identifier"] [()] 
   Destructor [priority] [Static]
      { procedure body }
   End Sub

Description
   Defines a procedure to be automatically called from a compiled program's 
   end-code.  End-code is generated by the compiler and is executed when 
   the program terminates normally.  Procedures defined as destructors may 
   be used the same way as ordinary procedures, that is, they may be called 
   from within module-level code, as well as other procedures.  

   The procedure must have an empty parameter list.  A compile-time error 
   will be generated if the Destructor keyword is used in a Sub definition 
   having one or more parameters. In a set of overloaded procedures, only 
   one (1) destructor may be defined because of the ambiguity of having 
   multiple Subs which take no arguments.

   In a single module, depending on the build and run-time environment of 
   the target system:
      * destructors may execute in which they are defined, or reverse 
        order
      * destructors may execute before or after global static variables 
        having dstructors
      * destructors may execute before or after other module destructors 
        having priority attribute
      * destructors with priority attribute may execute before or after 
        global static variables having destructors

   The priority attribute, an integer between 101 and 65535, can be used to 
   force destructors to be executed in a certain order.  The value of 
   priority has no specific meaning, only the relationship of the number 
   with other destructor priorities. 101 is the lowest priority and is 
   executed last, relative to other destructors also having priority 
   attribute.

   A module may define multiple destructor procedures.  Destructor 
   procedures may also appear in more than one module. All procedures 
   defined with the syntax shown above will be added to the list of 
   procedures to be called during the program's termination.

   The order in which destructors defined in multiple modules are executed 
   is known only at link time.  Therefore, special care should be taken 
   when using destructors that may call on a secondary module also defining 
   a destructors.  In such a case it is advisable to use a single 
   destructor that explicit calls termination procedures in multiple 
   modules to ensure a graceful termination of the application.

   Destructors will be called if the program terminates normally or if 
   error-checking is enabled and the program terminates abnormally.

   Public static member procedures (a Sub having an empty parameter list), 
   of user defined Type can be defined as a module destructor, by adding 
   the Constructor keyword used in the sub procedure definition.

   The module destructor feature exposes a low-level link-time feature of 
   the build and run-time environment.  Accessing global static objects 
   having destructors from module destructors should be avoided due to 
   variations in execution order on different build systems.

   Warning for 64-bit compiler only: See the Identifier Rules page for the 
   choice of user procedure identifier names (and specially the 'Platform 
   Differences' paragraph).

Example
   Sub pauseonexit Destructor
      
      '' If the program reaches the end, or aborts with an error, 
      '' it will run this destructor before closing
      
      Print "Press any key to end the program..."
      Sleep
      
   End Sub

   Dim array(0 To 10, 0 To 10) As Integer
   Dim As Integer i = 0, j = 11

   '' this next line will cause the program to abort with an 
   '' error if you compile with array bounds checking enabled (fbc -exx ...)
   Print array(i, j)

Differences from QB
   * New to FreeBASIC

See also
   * Destructor (Class)
   * Constructor (Module)
   * Sub



----------------------------------------------------------- KeyPgDevice ----
Device

Lists, selects, and queries sfxlib output devices.

Syntax
   Device List
   result = Device Select( device )
   Device Info [ device ]

Description
   Device List asks sfxlib to enumerate the output drivers compiled into 
   the runtime.  Device Select selects a device by index.  Device Info 
   prints diagnostic information for the current device or for the supplied 
   device index.

   Device availability is platform dependent.  The null output driver may 
   be selected for headless tests and diagnostics.

Example
   See examples/sfxlib/device-list.bas, examples/sfxlib/device-select.bas, 
   and examples/sfxlib/device-info.bas.

Differences from QB
   * New to FreeBASIC.

See also
   * Audio
   * Capture



-------------------------------------------------------------- KeyPgDim ----
Dim

Declares a variable

Syntax
      Dim [Shared] name1 As DataType [, name2 As DataType, ...]
   or
      Dim [Shared] As DataType name1 [, name2, ...]

   Arrays:
      Dim name ( [lbound To] ubound [, ...] ) As DataType
      Dim name ( Any [, Any...] ) As DataType
      Dim name ( ) As DataType

   Initializers:
      Dim scalar_symbol As DataType = expression | Any
      Dim array_symbol (arraybounds) As DataType = { expression [, ...] } | 
      Any
      Dim udt_symbol As DataType = ( expression [, ...] ) | Any

Description
   Declares a variable by name and reserves memory to accommodate it.

   Variables must be declared before they can be used in the -lang fb 
   dialect or when using Option Explicit in the other dialects.  Only in 
   the -lang qb and -lang fblite dialects variables may be used without 
   first declaring them, in such a case they are called implicit variables.

   Dim can be used to declare and assign variables of any of the supported 
   data types, user defined types, or enumerations.

   Depending on where and how a variable or array is declared can change 
   how it is allocated in memory.  See Storage Classes.

   More than one variable may be declared in a single Dim statement by 
   separating each variable declaration with a comma.

   '' Variable declaration examples

   '' One variable per DIM statement
   Dim text As String
   Dim x As Double

   '' More than one variable declared, different data types
   Dim k As Single, factor As Double, s As String

   '' More than one variable declared, all same data types
   Dim As Integer mx, my, mz ,mb

   '' Variable having an initializer
   Dim px As Double Ptr = @x

Explicit Variables with Implicit Data Types
   In the -lang qb and -lang fblite dialects, even if the variable is 
   declared explicitly, it will be given a default data type if the data 
   type is not explicitly given either by name or by type suffix.  The 
   default data type is Single in the -lang qb dialect and Integer in the 
   -lang fblite dialect.  The default data type can be changed throughout a 
   source listing by use of the Def### statements. (for example, DefInt, 
   DefStr, DefSng)

   '' Compile with -lang qb

   '$lang: "qb"

   '' All variables beginning with A through N will default to the INTEGER data type
   '' All other variables default to the SINGLE data type
   DefInt I-N

   Dim I, J, X, Y, T$, D As Double
   '' I and J are INTEGERs
   '' X and Y are SINGLEs
   '' T$ is STRING
   '' D is DOUBLE

Arrays
   As with most BASIC dialects, FreeBASIC supports arrays with indexes 
   ranging from a lower bound to an upper bound.  In the syntaxes shown, 
   lbound refers to the lower bound, or the smallest index.  ubound refers 
   to the upper bound, or the largest index.  If a lower bound is not 
   specified, it is assumed to be zero by default, unless Option Base is 
   used.

   Const upperbound = 10

   '' Declare an array with indexes ranging from 0 to upperbound, 
   '' for a total of (upperbound + 1) indexes.
   Dim array(upperbound) As Single

   Multidimensional arrays can be declared as well, and are stored in this 
   definite order: values differing only in the last index are contiguous 
   (row-major order).
   The maximum number of dimensions of a multidimensional array is 8. 

   '' declare a three-dimensional array of single 
   '' precision floating-point numbers.
   Dim array(1 To 2, 6, 3 To 5) As Single

   '' The first dimension of the declared array 
   '' has indices from 1 to 2, the second, 0 to 6, 
   '' and the third, 3 to 5.

			

   For more information on arrays see Arrays Overview.

   If the values used  with Dim to declare the dimensions of an array are 
   all constants, the array will be created fixed length (of Static size, 
   unless Option Dynamic is specified), while using one or more variables 
   to declare the dimensions of an array makes it variable length, even if 
   Option Static is in effect.

   Arrays can be declared as variable length in several ways: Using Dim 
   with an empty set of indexes (Dim x()), using Dim with indexes that are 
   variables or using the keyword ReDim, or using Any in place of the array 
   bounds, or declaring it past the metacommand $Dynamic. Variable length 
   arrays can't use initializers.

   Arrays declared with Dim having constant indexes and not preceeded by 
   Option Dynamic are fixed length (not resizable at runtime) and can use 
   initializers.

   The upper bound can be an ellipsis (..., 3 dots).  This will cause to 
   upper bound to be set automatically based on the number of elements 
   found in the initializer.  When ellipsis is used in this manner, an 
   initializer must be used, and it may not be Any.  See the Ellipsis page 
   for a short example.

   See also Fixed-Length Arrays and Variable-Length Arrays.

Initializers
   Arrays, variables, strings, and user defined types (UDTs) are 
   initialized to zero (or False for Boolean) or null strings by default 
   when they are created, except since fbc version 1.20.0 where 
   fixed-length strings of STRING*N type are padded with spaces (because 
   such a string field no longer has terminal null character).

   To avoid the overhead of default variable initialization, the Any 
   initializer can be used with Dim to tell the compiler to only reserve 
   the place for the variable in memory but not initialize it, so the 
   variable will contain garbage. In this case the programmer should not 
   make assumptions about the initial values.

   Fixed-length arrays, variables, zstrings and UDTs may be given a value 
   at the time of their declaration by following the variable declaration 
   with an initializer.  Arrays, variables and UDTs are initialized as they 
   would in a normal assignment, using an equal ( = ) sign.  The => sign 
   can also be used, allowing to avoid the declaration resembling an 
   expression for example when declaring fixed length strings.

   Array values are given in comma-delimited values enclosed by curly 
   brackets, and UDT values are given in comma delimited values enclosed by 
   parenthesis.  These methods of initializing variables can be nested 
   within one another for complex assignments. Nesting allows for arrays of 
   any dimension to be initialized.

   '' Declare an array of 2 by 5 elements
   '' and initialize
   Dim array(1 To 2, 1 To 5) As Integer => {{1, 2, 3, 4, 5}, {1, 2, 3, 4, 5}}

			

   '' declare a simple UDT
   Type mytype
      var1 As Double
      var2 As Integer
   End Type

   '' declare a 3 element array and initialize the first
   '' 2 mytype elements
   Dim myvar(0 To 2) As mytype => {(1.0, 1), (2.0, 2)}

	
   For module-level, fixed-length, or global variables, initialized values 
   must be constant expressions.  FreeBASIC will report a compile-time 
   error if otherwise.

   Note: Initializing UDT's with strings is not supported at this time. 
   Initializing UDT containing data-field initializer or string is not 
   valid.  Initializing UDT derived directly or indirectly from the the 
   built-in Object type is not valid.

Explicit Variables with Type Suffixes
   In the -lang qb and -lang fblite dialects, the data type of a variable 
   may be indicated with a type suffix ( $ % # ! & ).

   '' Compile with -lang qb or fblite

   '$lang: "qb"

   '' A string variable using the $ type suffix
   Dim strVariable$

   '' An integer variable using the % type suffix
   Dim intVariable%

   '' A long variable using the & type suffix
   Dim lngVariable&

   '' A single precision floating point variable using the ! type suffix
   Dim sngVariable!

   '' A double precision floating point variable using the # type suffix
   Dim dblVariable#

Example
   Dim a As Byte
   Dim b As Short
   Dim c As Integer
   Dim d As LongInt
   Dim au As UByte
   Dim bu As UShort
   Dim cu As UInteger
   Dim du As ULongInt
   Dim e As Single
   Dim f As Double
   Dim g As Integer Ptr
   Dim h As Byte Ptr
   Dim s1 As String * 10   '' fixed length string
   Dim s2 As String        '' variable length string
   Dim s3 As ZString Ptr   '' zstring

   s1 = "Hello World!"
   s2 = "Hello World from FreeBASIC!"
   s3 = Allocate( Len( s2 ) + 1 )
   *s3 = s2

   Print "Byte: "; Len(a)
   Print "Short: "; Len(b)
   Print "Integer: "; Len(c)
   Print "Longint: "; Len(d)
   Print "UByte: "; Len(au)
   Print "UShort: "; Len(bu)
   Print "UInteger: "; Len(cu)
   Print "ULongint: "; Len(du)
   Print "Single: "; Len(e)
   Print "Double: "; Len(f)
   Print "Integer Pointer: "; Len(g)
   Print "Byte Pointer: "; Len(h)
   Print "Fixed String: "; Len(s1)
   Print "Variable String: "; Len(s2)
   Print "ZString: "; Len(*s3)

   Deallocate(s3)

Version
   * Since fbc version 1.20.0, fixed-length strings of STRING*N type are 
     initialized to space value (zero value previously).

Dialect Differences
   * In the -lang qb and -lang fblite dialects, variables have procedure 
     scope if the variable is defined inside a procedure, and for the 
     entire module if the variable is defined with Dim Shared.
   * In the -lang qb dialect, variables cannot be initialised.  In the 
     -lang fblite dialect, the variable is initialised with a default value 
     at the start of the procedure/module, and assigned its initial value 
     if/when the Dim statement is executed at runtime.
   * In the -lang fb and -lang deprecated dialects, variables declared 
     inside compound block statements (For..Next, While..Wend, Do..Loop, 
     If..Then, Select..End Select, With..End With, Scope..End Scope) have 
     local working scopes, and are visible only within these blocks. To 
     access duplicated symbols defined as global outside these blocks, add 
     one or preferably two dot(s) as prefix: .SomeSymbol or preferably ..
     SomeSymbol (or only ..SomeSymbol if inside a With..End With block).
   * In the -lang fb dialect, Option statements (e.g. Option Base, 
     Option Dynamic), metacommands(e.g. $Static) and Def### statements 
     (e.g. DefInt) are not allowed.

Differences from QB
   * Variable Initializers are new to FreeBASIC.
   * The alternate syntax Dim As DataType symbolname, [...] is new to 
     FreeBASIC.
   * Multidimensional arrays are stored in this definite order: values 
     differing only in the last index are contiguous (row-major order), 
     they were stored in opposite order in QB by default: values differing 
     only in the first index were contiguous (column-major order).
   * Variable length arrays up to 2 GiB in size are possible in FreeBASIC. 
     In QB, $STATIC arrays were limited to 64 KiB , or to the DOS memory 
     available (several 100 KiB at best) if made $DYNAMIC and /AH was used.
   * The ellipsis form for upper bounds is new to FreeBASIC.

See also
   * Var
   * Common
   * Extern
   * ReDim
   * Preserve
   * Shared
   * Static
   * Byref (Variables)
   * Erase
   * LBound
   * UBound
   * ... (Ellipsis)
   * Any
   * Pointers to Procedures



-------------------------------------------------------------- KeyPgDir ----
Dir

Searches for and returns information about an item in the filesystem; 
performs a directory searchattrib

Syntax
   # Include "dir.bi"

   Declare Function Dir ( ByRef item_spec As Const String, ByVal 
   attrib_mask As Integer = fbNormal, ByRef out_attrib As Integer ) As 
   String
   Declare Function Dir ( ByRef item_spec As Const String, ByVal 
   attrib_mask As Integer = fbNormal, ByVal p_out_attrib As Integer Ptr = 0 
   ) As String
   Declare Function Dir ( ByRef out_attrib As Integer ) As String
   Declare Function Dir ( ByVal p_out_attrib As Integer Ptr = 0 ) As String

Usage
   result = Dir( item_spec, [ attrib_mask ], out_attrib )
   result = Dir( item_spec [, [ attrib_mask ] [, p_out_attrib ] ] )
   result = Dir( out_attrib )
   result = Dir( [ p_out_attrib ] )

Parameters
   item_spec
      The pattern to match an item's name against.
   attrib_mask
      The bit mask to match an item's attributes against.
   out_attrib
      Reference to a bit mask that's assigned each of the found item's 
      attributes, if any.
   p_out_attrib
      Pointer to a bit mask that's assigned each of the found item's 
      attributes, if any.

Return Value
   If no item matching the name item_spec or the attribute mask attrib_mask 
   was found, then out_attrib (or *p_out_attrib) is assigned to zero and an 
   empty string is returned. Otherwise, out_attrib (or *p_out_attrib) is 
   assigned the attribute mask of the item, and the item name, without a 
   path, is returned.

Description
   Dir returns the first filesystem item that matches the item_spec passed 
   as an argument. To retrieve the next file items that match this 
   item_spec pattern, call Dir again without this argument (or with an 
   empty string).
   So to obtain a list of items in a directory, Dir needs to be invoked 
   multiple times returning one item per invocation.

   If item_spec contains an absolute path, then the first procedure 
   searches the filesystem for an item that matches the name item_spec and 
   whose attributes are all contained in attrib_mask (fbNormal by default). 
   Otherwise, it searches relative to the current directory (see CurDir). 
   In any case, if a matching item is not found, out_attrib is assigned to 
   zero and an empty string is returned. Otherwise, out_attrib is assigned 
   with the attribute flags of the item, and the name of the item, without 
   a path, is returned.
   item_spec may include an asterisk (*, for matching any adjacent 
   characters) or one or more question marks (?, for matching any 
   individual character). If it does, the procedure searches for the first 
   such item.

   If an item is found, subsequent calls with item_spec omitted, or set to 
   an empty string, will return the next item matching the name item_spec 
   until no more such items are found. If attrib_mask is omitted from these 
   subsequent calls, the procedure searches for items with the same 
   attributes as in the previous call.

   The second syntax behaves the same as Dir( item_spec, attrib_mask, *
   p_out_attrib ).
   The third syntax behaves the same as Dir( "", , out_attrib ).
   The fourth syntax behaves the same as Dir( "", , *p_out_attrib ).

File Attributes:
   Files and directories and other items can be said to possess so-called 
   file attributes; metadata that describes the item. The meaning of this 
   metadata may vary depending on the operating system and the file system 
   it uses.
   The following defined constants are used as bit-flags in attrib_mask and 
   in out_attrib or *p_out_attrib. Their values can be combined to form a 
   mask using Operator Or. These values are the metadata that the returned 
   files are allowed to have. To access the defined flags, you must #include
   "dir.bi".

   Assuming the reader understands 'file' to mean any file system entry: 
   normal file, directory, etc.
   attrib_mask specifies the set of file attributes that are permitted for 
   file names returned (if a file has an attribute that is not specified in 
   attrib_mask, then it is excluded from file names returned).
   For example:
      fbDirectory will only allow the directory attribute not to be set, 
      meaning that only files or directories with no other attributes set 
      will be matched.
      (fbReadOnly Or fbDirectory) will allow read-only directories and 
      files, and writable directories and files.
      fbArchive Or fbDirectory will match against archived files, archived 
      directories, non-archived files and non-archived directories (it will 
      not match against, for example, read-only files).
   Logic condition:
         file name returned by Dir if the equality '((attrib_mask) OR 
         (file_attrib)) = (attrib_mask)' is true
      or
         file name returned by Dir if ((file_attrib) AND (Not attrib_mask)) 
         = 0

   More powerful filtering can be done by checking the returned out_attrib 
   for specifc flags using Operator And.

    # define fbReadOnly &h01 
      The item cannot be written to or deleted.
      DOS & Windows: The item has the "read-only" attribute set.
      Linux:The item has no write permissions associated with the current 
      user or group, nor is it globally writable.  (Whether or not the user 
      has root permissions is ignored.)

    # define fbHidden &h02 
      The item is hidden in ordinary directory listings.
      DOS & Windows: The item has the "hidden" attribute set.
      Linux: The item's name has a period (.) as the first character.

    # define fbSystem &h04 
      The item is used almost exclusively by the system.
      DOS & Windows: The item has the "system" attribute set.
      Linux: The item is either a character device, block device, named 
      pipe (FIFO) or Unix socket.

    # define fbDirectory &h10  
      The item is a directory. Includes the current (.) and parent (..) 
      directories as well.
      DOS & Windows & Linux: The item is a directory.

    # define fbArchive &h20 
      The item may be backed up after some automated operations.
      DOS & Windows: The item has the "archive" attribute set 
      (automatically set after every write access to a file).
      Linux: The item is not a directory; typical filesystems do not 
      support this metadata.

    # define fbNormal (fbReadOnly or fbArchive) 
      The item is read-only or "archived".

   (If attrib_mask does not include fbArchive, then Dir may widen the check 
   to include fbDirectory, but it is recommended to add fbDirectory 
   explicitly, if that is the behaviour sought.)

   Items found having no attributes are always matched, regardless of the 
   value of attrib_mask.
   An item will not be matched if it has one or more attributes that aren't 
   specified in attrib_mask.

   In general it is not possible to use attrib_mask to include a 
   file/folder with one set of attributes while excluding a file/folder 
   with a different set. For example, it is not possible to scan for 
   read-only directories while excluding read-only files (unless the files 
   also have other attributes).
   Finer control can be gained by checking the out_attrib value for the 
   desired set of attributes.

Example
   ' Number of files in the current directory.

   Dim As Integer FileCount

   If Dir("*") <> "" Then  ' Start a file search with no specified filespec/attrib *AND* get the first filename.
      Filecount = 1
      While Dir() <> ""  ' If dir() is "", exit the loop: no more filenames are left to be read.
         FileCount += 1  ' Increment the counter of number of files
      Wend
   End If

   Print FileCount & " files in the current directory."

   Sleep

	

   #include "dir.bi" 'provides constants to use for the attrib_mask parameter

   Sub list_files (ByRef filespec As String, ByVal attrib As Integer)
      Dim As String filename = Dir(filespec, attrib) ' Start a file search with the specified filespec/attrib *AND* get the first filename.
      Do While Len(filename) > 0 ' If len(filename) is 0, exit the loop: no more filenames are left to be read.
         Print filename
         filename = Dir() ' Search for (and get) the next item matching the initially specified filespec/attrib.
      Loop
   End Sub

   Print "directories:"
   list_files "*", fbDirectory

   Print
   Print "archive files:"
   list_files "*", fbArchive

	

   '' show any files that have directory attribute and don't care if it is system, hidden, read-only, or archive

   #include Once "dir.bi"

   '' allow everything
   Var mask = fbDirectory Or fbHidden Or fbSystem Or fbArchive Or fbReadOnly

   Var attrib = 0
   Var f = Dir( "*.*", mask, attrib )
   While( f > "" )
      '' show any files that have at least a directory attribute
      If( attrib And fbDirectory ) Then
         Print f
      End If
      f = Dir( attrib )
   Wend

	

   '' Example of using DIR function and retrieving attributes

   #include "dir.bi" '' provides constants to match the attributes against

   '' set input attribute mask to allow files that are normal, hidden, system or directory
   Const attrib_mask = fbNormal Or fbHidden Or fbSystem Or fbDirectory ' = &h37

   Dim As UInteger out_attr '' unsigned integer to hold retrieved attributes

   Dim As String fname '' file/directory name returned with
   Dim As Integer filecount, dircount

   fname = Dir("*.*", attrib_mask, out_attr) '' Get first file name/attributes, according to supplied file spec and attribute mask

   Print "File listing in " & CurDir & ":"

   Do Until Len(fname) = 0 '' loop until Dir returns empty string

      If (fname <> ".") And (fname <> "..") Then '' ignore current and parent directory entries

         Print fname,

         If (out_attr And fbDirectory) <> 0 Then
            Print "- directory";
            dircount += 1
         Else
            Print "- file";
            filecount += 1
         End If
         If (out_attr And fbReadOnly) <> 0 Then Print ", read-only";
         If (out_attr And fbHidden  ) <> 0 Then Print ", hidden";
         If (out_attr And fbSystem  ) <> 0 Then Print ", system";
         If (out_attr And fbArchive ) <> 0 Then Print ", archived";
         Print

      End If

      fname = Dir(out_attr) '' find next name/attributes

   Loop

   Print
   Print "Found " & filecount & " files and " & dircount & " subdirs"

Platform Differences
   * Linux requires the filename case to match the real name of the file. 
     Windows and DOS are case insensitive.
   * Path separators in Linux are forward slashes /. Windows uses 
     backslashes \ but it allows for forward slashes.  DOS uses 
     backslashes.
   * In DOS, the attrib mask value of &h37 (&h3F usually works also, but 
     &h37 is safer) returns all files and directories, including "." and 
     "..", but no Volume: the value 8 returns the Volume, even if current 
     directory is not the main directory.

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Dir.

Differences from QB
   * Not found in QBasic but present in Visual Basic.  The out_attrib 
     parameter is new to FreeBASIC.

See also
   * Open
   * CurDir
   * ChDir
   * MkDir
   * RmDir



--------------------------------------------------------------- KeyPgDo ----
Do

Control flow statement for looping.

Syntax
   Do [ { Until | While } condition ]
      [ statement block ]
   Loop

   Do
      [ statement block ]
   Loop [ { Until | While } condition ]

Example
   See example at Do...Loop.

Differences from QB
   * None

See also
   * Do...Loop

   

----------------------------------------------------------- KeyPgDoloop ----
Do...Loop

Control flow statement for looping

Syntax
   Do [ { Until | While } condition ]
      [ statement block ]
   Loop
or
   Do
      [ statement block ]
   Loop [ { Until | While } condition ]

Description
   The Do statement executes the statements in the following statement 
   block until/while the condition, if any,  evaluates to true.

   If Until is used, the Do statement stops repetition of the statement 
   block when condition evaluates to true. The While keyword has opposite 
   effect, stopping the loop if condition evaluates to false. If both 
   condition and either Until or While are omitted, the Do statement loops 
   indefinitely.

   If an Exit Do statement is encountered inside the statement block, the 
   loop is terminated, and execution resumes immediately following the 
   enclosing Loop statement. If a Continue Do statement is encountered, the 
   rest of the statement block is skipped and execution resumes at the Do 
   statement.

   In the first syntax, the condition is checked when the Do statement is 
   first encountered, and if the condition is met, the statement block will 
   be skipped. In the second syntax, condition is initially checked after 
   the statement block is executed. This means that the statement block is 
   always guaranteed to execute at least once.

   condition may be any valid expression that evaluates to False (zero) or 
   True (non-zero).

Example
   In this example, a Do loop is used to count the total number of odd 
   numbers from 1 to 10. It will repeat until its n > 10 condition is met:
   Dim As Integer n = 1                            '' number to check
   Dim As Integer total_odd = 0                    '' running total of odd numbers
   Do Until( n > 10 )
     If( ( n Mod 2 ) > 0 ) Then total_odd += 1    '' add to total if n is odd (has remainder from division by 2)
     n += 1
   Loop
   Print "total odd numbers: " ; total_odd         '' prints '5'

   End 0

   Here, an infinite DO loop is used to count the total number of evens. We 
   place the conditional check inside the loop via an If...Then statement, 
   which exits the loop if and when n > 10 becomes true:
      Dim As Integer n = 1                            '' number to check
      Dim As Integer total_even = 0                   '' running total of even numbers
      Do
        If( n > 10 ) Then Exit Do                    '' exit if we've scanned our 10 numbers
      
        If( ( n Mod 2 ) = 0 ) Then total_even += 1   '' add to total if n is even (no remainder from division by 2)
        n += 1
      Loop
      Print "total even numbers: " ; total_even       '' prints '5'

      End 0

Dialect Differences
   * In the -lang qb and -lang fblite dialects, variables declared inside 
     a Do..Loop block have a function-wide scope  as in QB 
   * In the -lang fb and -lang deprecated dialects, variables declared 
     inside a Do..Loop block are visible only inside the block, and can't 
     be accessed outside it. To access duplicated symbols defined as global 
     outside this block, add one or preferably two dot(s) as prefix: .
     SomeSymbol or preferably ..SomeSymbol (or only ..SomeSymbol if inside 
     a With..End With block).

Differences from QB
   * None

See also
   * Continue
   * Exit
   * For...Next
   * While...Wend



----------------------------------------------------------- KeyPgDouble ----
Double

Standard data type: 64 bit floating point

Syntax
   Dim variable As Double

Description
   Double is a 64-bit, floating-point data type used to store more precise 
   decimal numbers. They can hold positive values in the range 
   4.940656458412465e-324 to 1.797693134862316e+308, or negative values in 
   the range -4.940656458412465e-324 to -1.797693134862316e+308, or zero (0)
   . They contain at most 53 bits of precision, or about 15 decimal digits.

   Doubles have a greater range and precision than Singles, they still have 
   limited accuracy which can lead to significant inaccuracies if not used 
   properly.  They are dyadic numbers - i.e. they can only accurately hold 
   multiples of powers of two, which will lead to inaccuracies in most 
   base-10 fractions.

Example
   'Example of using a double variable.

   Dim a As Double
   a = 1.985766472453666
   Print a

   Sleep

Differences from QB
   * None

See also
   * Single Less precise float type
   * CDbl
   * Table with variable types overview, limits and suffixes



------------------------------------------------------------- KeyPgDraw ----
Draw

Statement for sequenced pixel plotting

Syntax
   Draw [target,] cmd

Parameters
   target
      the buffer to draw on
   cmd
      a string containing the sequence of commands

Description
   Drawing will take place onto the current work page set via ScreenSet or 
   onto the target Get/Put buffer if specified.
   The Draw statement can be used to issue several drawing commands all at 
   once; it is useful to quickly draw figures. The command string accepts 
   the following commands:

   Commands to plot pixels:
      +-------+--------------------------------------------------------------------------------------------------------------------------------------------------------------+
      |Command|Description                                                                                                                                                   |
      |       |Commands to plot pixels:                                                                                                                                      |
      |B      |Optional prefix: move but do not draw.                                                                                                                        |
      |N      |Optional prefix: draw but do not move.                                                                                                                        |
      |M x,y  |Move to specified screen location. if a '+' or '-' sign precedes x, movement is relative to current cursor position.  x's sign has no effect on the sign of y.|
      |U [n]  |Move n units up. If n is omitted, 1 is assumed.                                                                                                               |
      |D [n]  |Move n units down. If n is omitted, 1 is assumed.                                                                                                             |
      |L [n]  |Move n units left. If n is omitted, 1 is assumed.                                                                                                             |
      |R [n]  |Move n units right. If n is omitted, 1 is assumed.                                                                                                            |
      |E [n]  |Move n units up and right. If n is omitted, 1 is assumed.                                                                                                     |
      |F [n]  |Move n units down and right. If n is omitted, 1 is assumed.                                                                                                   |
      |G [n]  |Move n units down and left. If n is omitted, 1 is assumed.                                                                                                    |
      |H [n]  |Move n units up and left. If n is omitted, 1 is assumed.                                                                                                      |
      |       |Commands to color:                                                                                                                                            |
      |C n    |Changes current foreground color to n.                                                                                                                        |
      |P p,b  |PAINTs (flood fills) region of border color b with color p.                                                                                                   |
      |       |Commands to scale and rotate:                                                                                                                                 |
      |S n    |Sets the current unit length, default is 4.  A unit length of 4 is equal to 1 pixel.                                                                          |
      |A n    |Rotate n*90 degrees (n ranges 0-3).                                                                                                                           |
      |TA n   |Rotate n degrees (n ranges 0-359).                                                                                                                            |
      |       |Extra commands:                                                                                                                                               |
      |X p    |Executes commands at p, where p is a STRING PTR.                                                                                                              |
      +-------+--------------------------------------------------------------------------------------------------------------------------------------------------------------+

   Commands to set the color, size and angle will take affect all 
   subsequent Draw operations.

Draw respects the current clipping region as set by the View (Graphics) 
statement, but its coordinates are not affected by the custom coordinates 
system.

Example
   Screen 13

   'Move to (50,50) without drawing
   Draw "BM 50,50"

   'Set drawing color to 2 (green)
   Draw "C2"

   'Draw a box
   Draw "R50 D30 L50 U30"

   'Move inside the box
   Draw "BM +1,1"

   'Flood fill with color 1 (blue) up to border color 2 
   Draw "P 1,2"

   Sleep

   '' Draws a flower on-screen

   Dim As Integer i, a, c
   Dim As String fill, setangle

   '' pattern for each petal
   Dim As Const String petal = _
      _
      ("X" & VarPtr(setangle)) _ '' link to angle-setting string
      _
      & "C15" _       '' set outline color (white)
      & "M+100,+10" _ '' draw outline
      "M +15,-10" _
      "M -15,-10" _
      "M-100,+10" _
      _
      & "BM+100,0" _              '' move inside petal
      & ("X" & VarPtr(fill)) _    '' flood-fill petal (by linking to fill string)
      & "BM-100,0"                '' move back out

   '' set screen
   ScreenRes 320, 240, 8

   '' move to center
   Draw "BM 160, 120"

   '' set initial angle and color number
   a = 0: c = 32

   For i = 1 To 24

      '' make angle-setting and filling command strings
      setangle = "TA" & a
      fill = "P" & c & ",15"

      '' draw the petal pattern, which links to angle-setting and filling strings
      Draw petal
      
      '' short delay
      Sleep 100

      '' increment angle and color number
      a += 15: c += 1

   Next i

   Sleep

Differences from QB
   * target is new to FreeBASIC
   * QB used the special pointer keyword VARPTR$ with the X p command.
   * FB does not currently allow sub-pixel movements: all movements are 
     rounded to the nearest integer coordinate.

See also
   * Draw String
   * Screen (Graphics)
   * VarPtr
   * Paint



------------------------------------------------------- KeyPgDrawString ----
Draw String

Graphics statement to render text to an image or screen.

Syntax
   Draw String [buffer,] [STEP] (x, y), text [,color [, font [, method [, (
   alpha|blender) [, parameter] ] ] ] ]

Usage
   Draw String [buffer,] [STEP] (x, y), text [, color]
   Draw String [buffer,] [STEP] (x, y), text , , font [, method [, alpha ] 
   ]
   Draw String [buffer,] [STEP] (x, y), text , , font, Custom, blender [, 
   parameter]

Parameters
   buffer
      the sprite to draw the string on. If this is not supplied, it will be 
      drawn to the screen.
   STEP
      use relative coordinates. If STEP is added, the x and y coordinates 
      are translated relative to the last drawn point.
   x, y
      the horizontal / vertical position to draw to, relative to the top 
      left hand corner of the screen (unless STEP is used - see above).  
      The top left corner of the text will be drawn at this position.
   text
      the string containing the text to draw
   color
      if no font is supplied, this allows you to choose the color of the 
      text.  If omitted, the default foreground Color is used.
      If a font is supplied, color is ignored, and the font itself 
      specifies the color for each pixel.
   font
      an image buffer containing a custom font. If no font is supplied, the 
      standard font for the current text resolution is used, and the 
      following parameters are ignored.
   method | Custom
      specifies how the font characters are drawn on top of the target 
      surface. The same methods as found for the Put statement are allowed, 
      with the only difference that the default method is Trans for this 
      function.  This parameter only applies to custom fonts.
   alpha
      alpha value, ranging 0-255.  This parameter only applies to the Add 
      or Alpha methods.
   blender
      custom blender function for the Custom drawing method; see 
      Put (Graphics) statement description for details.  This parameter 
      only applies to the Custom method.
   parameter
      optional Pointer to be passed to the custom blender function; if 
      omitted, the default value is zero (0).

Description
   This graphics keyword prints a string to the screen with pixel 
   positioning, transparent background, and can use an user-supplied font. 
   Draw String does not update any text or graphics cursor.  It doesn't 
   wrap at the end of line.  Tabs, carriage returns and other special 
   characters have no special behavior in Draw String, and are treated as 
   normal characters.

   In graphics mode, this function provides a flexible alternative to Print
   .  It has several key advantages:
      * Draw String can print text to any coordinate on the screen, while 
        Print is constrained to the character grid accessible by Locate.
      * Print will override the background behind the text with the 
        current background color.  Draw String does not do this: it leaves 
        the pixels in the background untouched.
      * Like Put, Draw String has several different methods for printing 
        text, such as Alpha and Custom.
      * Draw String isn't limited to a single character set: it is 
        possible to supply a custom font to be used instead.

   Note: If a custom font isn't supplied, Draw String will default to the 
   standard font, as used by Print, with character size dictated by Width.  
   method - if passed - will be ignored, and the text will be drawn using 
   the color supplied, with a transparent background.

   Draw String coordinates are affected by custom coordinates system set 
   via Window and View (Graphics) statements, and the drawn text respects 
   clipping rectangle set by View (Graphics).

   The custom font format:
   The font is stored in a standard Get/Put buffer; the font has to be 
   stored in a buffer using the same depth as the current color depth, 
   otherwise Draw String will bump out with an illegal function call 
   runtime error.

   The first line of pixels in the font buffer holds the header of the 
   font, on a byte (not pixel) basis. The very first byte identifies the 
   font header version; currently this must be 0. The second byte gives the 
   ascii code of the first supported character in the font; the third byte 
   gives the ascii code of the last supported character. So if the font 
   supports the full range 0-255, 0 and 255 will be the contents of these 
   two bytes.
   Next comes the width of each of the supported characters, each in a 
   byte. Supposing the font holds 96 characters, ranging from 32 to 127 
   (inclusive), the header would have the first three bytes holding 0, 32 
   and 127, followed by 96 bytes giving the widths of the corresponding 
   chars.

   The font height is obtained by subtracting 1 from the buffer height, 
   that is, while the first buffer line of pixels acts as a font header, 
   the remaining lines define the glyphs' layout. The buffer must be as 
   wide as necessary to hold all the supported character sprites in the 
   same row, one after another.

Example
   This gives an example of basic Draw String usage: it uses it to print 
   "Hello world" in the center of the screen:
   Const w = 320, h = 200 '' screen dimensions

   Dim x As Integer, y As Integer, s As String

   '' Open a graphics window
   ScreenRes w, h

   '' Draw a string in the centre of the screen:

   s = "Hello world"
   x = (w - Len(s) * 8) \ 2
   y = (h - 1 * 8) \ 2

   Draw String (x, y), s

   '' Wait for a keypress before ending the program
   Sleep

   This example shows you how to create and use your own custom font.  For 
   simplicity, it uses Draw String with the default font to create the 
   glyphs.
   '' Define character range
   Const FIRSTCHAR = 32, LASTCHAR = 127

   Const NUMCHARS = (LASTCHAR - FIRSTCHAR) + 1
   Dim As UByte Ptr p, myFont
   Dim As Integer i

   '' Open a 256 color graphics screen (320*200)
   ScreenRes 320, 200, 8

   '' Create custom font into PUT buffer

   myFont = ImageCreate(NUMCHARS * 8, 9)

    '' Put font header at start of pixel data

   #ifndef ImageInfo '' older versions of FB don't have the ImageInfo feature
   p = myFont + IIf(myFont[0] = 7, 32, 4)
   #else
   ImageInfo( myFont, , , , , p )
   #endif

   p[0] = 0
   p[1] = FIRSTCHAR
   p[2] = LASTCHAR

    '' PUT each character into the font and update width information
   For i = FIRSTCHAR To LASTCHAR
      
      '' Here we could define a custom width for each letter, but for simplicity we use
      '' a fixed width of 8 since we are reusing the default font glyphs
      p[3 + i - FIRSTCHAR] = 8
      
      '' Create character onto custom font buffer by drawing using default font
      Draw String myFont, ((i - FIRSTCHAR) * 8, 1), Chr(i), 32 + (i Mod 24) + 24
      
   Next i

   '' Now the font buffer is ready; we could save it using BSAVE for later use
   Rem BSave "myfont.bmp", myFont

   '' Here we draw a string using the custom font
   Draw String (10, 10), "ABCDEFGHIJKLMNOPQRSTUVWXYZ", , myFont
   Draw String (10, 26), "abcdefghijklmnopqrstuvwxyz", , myFont
   Draw String (66, 58), "Hello world!", , myFont

   '' Free the font from memory, now we are done with it
   ImageDestroy myFont

   Sleep

Differences from QB
   * New to FreeBASIC

See also
   * Print
   * ?
   * Draw
   * ImageCreate
   * ImageDestroy
   * ImageInfo
   * Put (Graphics)
   * Width



-------------------------------------------------------- KeyPgDylibfree ----
DyLibFree

Unloads a dynamic link library from memory

Syntax
   Declare Sub DyLibFree ( ByVal libhandle As Any Pointer )

Usage
   DyLibFree( libhandle )

Parameters
   libhandle
      The handle of a library to unload.

Description
   DyLibFree is used to release at runtime libraries previously linked to 
   your program with DyLibLoad. The argument is the handle to the library 
   returned by DyLibLoad.

Example
   See the dynamic loading example on the Shared Libraries page.

Platform Differences
   * DOS: see specific Shared Libraries - DOS page

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Dylibfree.

Differences from QB
   * New to FreeBASIC

See also
   * DyLibSymbol
   * DyLibLoad
   * Export



-------------------------------------------------------- KeyPgDylibload ----
DyLibLoad

Loads to a Dynamic Link Library (DLL) into memory at runtime

Syntax
   Declare Function DyLibLoad ( ByRef libname As String ) As Any Pointer

Usage
   result = DyLibLoad ( libname )

Parameters
   libname
      A String containing the name of the library to load.

Return Value
   The Pointer handle of the library loaded. Zero on error

Description
   DyLibLoad is used to link at runtime libraries to your program. This 
   function does the link and returns a handle that must be used with 
   DyLibSymbol when calling a function in the library and with DyLibFree 
   when releasing the library.

   Note: If the libname string (without extension) already includes a 
   character dot (.), it may be mandatory to explicitly specify the 
   filename extension to avoid any parser ambiguity.

Example
   See the dynamic loading example on the Shared Libraries page.

Platform Differences
   * DOS: dynamic link libraries have ".dxe" file name extension and the 
     full libname must be specified: "<name>.dxe".
   * DOS: calling dylibload( "" ), using an empty file name will 
     initialize the run time library exports.
   * DOS: see specific Shared Libraries - DOS page

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Dylibload.

Differences from QB
   * New to FreeBASIC

See also
   * DyLibSymbol
   * DyLibFree
   * Export



------------------------------------------------------ KeyPgDylibsymbol ----
DyLibSymbol

Returns the address of a function or variable in a dll

Syntax
   Declare Function DyLibSymbol ( ByVal libhandle As Any Ptr, ByRef symbol 
   As String ) As Any Ptr
   Declare Function DyLibSymbol ( ByVal libhandle As Any Ptr, ByVal symbol 
   As Short ) As Any Ptr

Usage
   result = DyLibSymbol ( libhandle, symbol )

Parameters
   libhandle
      The Any Ptr handle of a DLL returned by DyLibLoad
   symbol
      A String containing name of the function, or variable in the library 
      to return the address of.  In Windows only, can also be a Short 
      containing the ordinal of the function/variable.

Return Value
   A Pointer to the function or variable in the library.

   If the function fails, the return value is 0.

Description
   DyLibSymbol returns a pointer to the variable or function named symbol , 
   in the dll pointed by libhandle. libhandle is obtained by loading the 
   dll with DyLibLoad. The symbol must have been Exported in the dll.
   If libhandle is 0, the symbol is searched in the current executable or 
   dll.

   If using cdecl functions, only the name of the procedure needs to be 
   specified. If dynamically linking to a function created using STDCALL 
   (default in windows), then the function must be decorated. To decorate a 
   function, use its name, '@', then the number of bytes passed as 
   arguments. For instance if the function FOO takes 3 integer arguments, 
   the decorated function would be 'FOO@12'. Remember, without an explicit 
   Alias, the procedure name will be uppercase.

   If linking to a dll created in Visual C++(tm), decoration need not be 
   used. For GCC, decoration is needed.

   Note: The dylibsymbol, if failing, will attempt to automatically 
   decorate the procedure, from @0 to @256, in 4 byte increments.

Example
   See the dynamic loading example on the Shared Libraries page.

Platform Differences
   * Ordinals are not supported on Linux, 0 is always returned.
   * Ordinals are not supported on DOS, 0 is always returned.
   * Windows does not support DyLibSymbol use with variables (only with 
     procedures).
   * DOS: see specific Shared Libraries - DOS page

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Dylibsymbol.

Differences from QB
   * New to FreeBASIC

See also
   * DyLibLoad
   * DyLibFree
   * Export




============================================================================
    E

------------------------------------------------------------- KeyPgElse ----
Else

Control flow statement for conditional branching

Syntax
   If expression Then [statement(s)] [Else [statement(s)]] [End If]
or
   If expression Then : [statement(s)] [Else [statement(s)]] : End If
or
   If expression Then
      [statement(s)]
   [ ElseIf expression Then ]
      [statement(s)]
   [ Else ]
      [statement(s)]
   End If

   Remark: EndIf (without blank) is also supported like in QB for backward 
   compatibility.

Example
   See example at If...Then.

Differences from QB
   * None

See also
   * If...Then



----------------------------------------------------------- KeyPgElseif ----
ElseIf

Control flow statement for conditional branching

Syntax
   If expression Then
      [statement(s)]
   [ ElseIf expression Then ]
      [statement(s)]
   [ Else ]
      [statement(s)]
   End If

   Remark: EndIf (without blank) is also supported like in QB for backward 
   compatibility.

Example
   See example at If...Then.

Differences from QB
   * None

See also
   * If...Then



--------------------------------------------------------- KeyPgEncoding ----
Encoding

Specifies character format of a text file

Syntax
   Open filename for {Input|Output|Append} Encoding "utf-8"|"utf-16"|"
   utf-32"|"ascii" as [#]filenum 

Parameters
   filename for {Input|Output|Append}
      file name to open for Input, Output, or Append
   Encoding "utf-8"|"utf-16"|"utf-32"|"ascii"
      indicates encoding type for the file
   filenum
      unused file number to associate with the open file

Description
   Encoding specifies the format for an Unicode text file, so Winput # and 
   Print # use the correct encoding.  If omitted from an Open statement, 
   "ascii" encoding is the default.

   Only little endian character encodings are supported at the moment. 
      *"utf8", 
      *"utf16" 
      *"utf32" 
      *"ascii" (the default)

Example
   '' This example will:
   '' 1) Write a string to a text file with utf-16 encoding
   '' 2) Display the byte contents of the file
   '' 3) Read the text back from the file
   ''
   '' WSTRING's will work as well but STRING has been
   '' used in this example since not all consoles support
   '' printing WSTRING's.

   '' The name of the file to use in this example
   Dim f As String
   f = "sample.txt"

   ''
   Scope
     Dim s As String
     s = "FreeBASIC"

     Print "Text to write to " + f + ":"
     Print s
     Print

     '' open a file for output using utf-16 encoding
     '' and print a short message
     Open f For Output Encoding "utf-16" As #1

     '' The ascii string is converted to utf-16
     Print #1, s
     Close #1
   End Scope

   ''
   Scope
     Dim s As String, n As LongInt

     '' open the same file for binary and read all the bytes
     Open f For Binary As #1
     n = LOF(1)
     s = Space( n )
     Get #1,,s
     Close #1
     
     Print "Binary contents of " + f + ":"
     For i As Integer = 1 To n
      Print Hex( Asc( Mid( s, i, 1 )), 2); " ";
     Next
     Print
     Print

   End Scope

   ''
   Scope
     Dim s As String
     
     '' open a file for input using utf-16 encoding
     '' and read back the message
     Open f For Input Encoding "utf-16" As #1

     '' The ascii string is converted from utf-16
     Line Input #1, s
     Close #1

     '' Display the text
     Print "Text read from " + f + ":"
     Print s
     Print
   End Scope

   Output:

   Text To Write To sample.txt:
   FreeBASIC

   Binary contents of sample.txt:
   FF FE 46 00 72 00 65 00 65 00 42 00 41 00 53 00 49 00 43 00 0D 00 0A 00 

   Text Read from sample.txt:
   FreeBASIC

Platform Differences
   * Unicode (w)strings are not supported in the DOS port of FreeBASIC

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Encoding.

Differences from QB
   * QB had no support for Unicode

See also
   * Open



--------------------------------------------------------- KeyPgEndblock ----
End (Block)

Indicates the end of a compound statement block.

Syntax
   End { Sub | Function | If  | Select  | Type  | Enum  | Scope  | With  | 
   Namespace  | Extern  | Constructor  | Destructor  | Operator | Property 
   }

Description
   Used to indicate the end of the most recent code block.

   The type of the block must be included in the command: one of Sub, 
   Function, If, Select, Type, Enum, Scope, With, Namespace, Extern, 
   Constructor, Destructor, Operator, or Property.

   Ending a Sub, Function, If, Select, Scope, Constructor, Destructor, 
   Operator, or Property block also closes the scope for variables defined 
   inside that block.  When the scope is closed, variables defined inside 
   the scope are destroyed, calling their destructors as needed.

   To end a program, see End (Statement).

Example
   Declare Sub checkvalue( n As Integer )

   Dim variable As Integer

   Input "Give me a number: ", variable
   If variable = 1 Then
   Print "You gave me a 1"
   Else
   Print "You gave me a big number!"
   End If
   checkvalue(variable)

   Sub checkvalue( n As Integer )
   Print "Value is: " & n
   End Sub

Differences from QB
   * none

See also
   * Constructor
   * Destructor
   * End (Statement)
   * Enum
   * Extern
   * Function
   * If...Then
   * Namespace
   * Operator
   * Property
   * Scope
   * Select Case
   * Sub
   * Type
   * With



-------------------------------------------------------------- KeyPgEnd ----
End (Statement)

Control flow statement to end the program.

Syntax
   Declare Sub End ( ByVal retval As Long = 0 )

Usage
   End [ retval ]

Parameters
   retval
      Error code returned to system.

Description
   Used to exit the program, and return to the operating system. An 
   optional integer return value can be specified to indicate an error code 
   to the system. If no return value is given, a value of 0 is 
   automatically returned at the end of the program.

   Usage of this statement does not cleanly close scope. Local variables 
   will not have their destructors called automatically, because FreeBASIC 
   does not do stack unwinding. Only the destructors of global variables 
   will be called in this case.

   For this reason, it is discouraged to use End simply to mark the end of 
   a program; the program will come to an end automatically, and in a 
   cleaner fashion, when the last line of module-level code has executed.

Example
   '' This program requests a string from the user, and returns an error
   '' code to the OS if the string was empty

   Function main() As Integer

      '' assign input to text string
      Dim As String text
      Line Input "Enter some text ( try ""abc"" ): " , text

      '' If string is empty, print an error message and
      '' return error code 1 (failure)
      If( text = "" ) Then
         Print "ERROR: string was empty"
         Return 1
      End If

      '' string is not empty, so print the string and
      '' return error code 0 (success)
      Print "You entered: " & text
      Return 0

   End Function

   '' call main() and return the error code to the OS
   End main()

Platform Differences
   * In Linux, the retval parameter is a Byte.

Differences from QB
   * The END statement supports specifying a custom return value to be 
     returned to the operating system.

See also
   * End (Block)
   * Return (From Procedure)
   * Return (From Gosub)
   * System



------------------------------------------------------------ KeyPgEndif ----
End If

Control flow statement for conditional branching.

Syntax
   If expression Then [statement(s)] [Else [statement(s)]] [End If]
or
   If expression Then : [statement(s)] [Else [statement(s)]] : End If
or
   If expression Then
      [statement(s)]
   [ ElseIf expression Then ]
      [statement(s)]
   [ Else ]
      [statement(s)]
   End If

   Remark: EndIf (without blank) is also supported like in QB for backward 
   compatibility.

Example
   See example at If...Then.

Differences from QB
   * END IF was not supported in single-line IFs in QBASIC.

See also
   * If...Then

   


------------------------------------------------------------- KeyPgEnum ----
Enum

Declares an enumerated type.

Syntax
   Enum [typename [ Explicit ] ]
      symbolname [= expression] [, ...]
      ...
   End Enum

Parameters
   typename
      Name of the Enum
   symbolname
      Name of the constant
   expression
      A constant expression
   Explicit
      Requires that symbols must be explicitly referred to by typename.
      symbolname

Description
   Enum, short for enumeration, declares a list of symbol names that 
   correspond to discrete values. If no initial value is given, the first 
   item will be set to 0.  Each subsequent symbol has a value one more than 
   the previous unless expression is given.

   Symbols may be each on their own line, or separated on a single line by 
   commas.

   An Enum is a useful way of grouping together a set of related Constants. 
   A symbol can be accessed like a constant, e.g: a = symbolname.  But if 
   the name clashes with another symbol, it must be resolved using typename
   .symbolname.  This resolution method is always required if you make the 
   enum Explicit.

   A non-Explicit Enum declared inside an Extern ... End Extern block will 
   add its constants to the parent namespace directly, as in C, instead of 
   acting as a namespace on its own. It disallows the typename.symbolname 
   style of access, and the constants may conflict with other symbols from 
   the parent namespace.

   Enum can not contain any member procedure or member data (only symbols), 
   but it can be included (named or unnamed) in a Type by having.

   An Enum instance can be passed, as any user defined instance, to a 
   procedure (including for the definition of Overloaded operators).
   The size of an Enum instance will be always that of an Integer (no 
   matter how many defined symbols are just declarations for the compiler 
   assignment).

Example
   Enum MyEnum
      option1 = 1
      option2
      option3
   End Enum

   Dim MyVar As MyEnum

   MyVar = option1

   Select Case MyVar
      Case option1
         Print "Option 1"
      Case option2
         Print "Option 2"
      Case option3
         Print "Option 3"
   End Select

   You can reference formerly declared symbol names within the same enum:
   Enum MyEnum
      option1 = 1
      option2
      option3
      __
      MAX_VALUE = __ -1
   End Enum

   Print "Option #1:", MyEnum.option1
   Print "Option #2:", MyEnum.option2
   Print "Option #3:", MyEnum.option3
   Print "Max Value:", MyEnum.MAX_VALUE

	Output:

   Option #1:     1
   Option #2:     2
   Option #3:     3
   Max Value:     3

Dialect Differences
   * Explicit Enum not available in the -lang qb dialect unless referenced 
     with the alias __Explicit.

Differences from QB
   * New to FreeBASIC

See also
   * Const
   * Operator
   * Table with variable types overview, limits and suffixes



------------------------------------------------------- KeyPgSetenviron ----
SetEnviron

Sets a system environment variable

Syntax
   Declare Function SetEnviron ( ByRef varexpression As String ) As Long

Usage
   result = SetEnviron( varexpression )

Parameters
   varexpression
      Name and setting of an environment variable in the following (or 
      equivalent) form: varname=varstring.
      (varname being the name of the environment variable, and varstring 
      being its text value to set)

Return Value
   Return zero (0) if successful, non-zero otherwise.

Description
   Modifies system environment variables.  There are several variables 
   available for editing other than the default ones on your system.  An 
   example of this would be fbgfx, where you can choose the form of 
   graphics driver the FreeBASIC graphics library will use.

Example
   'e.g. to set the system variable "path" to "c:":

   Shell "set path" 'shows the value of path
   SetEnviron "path=c:"
   Shell "set path" 'shows the new value of path

     '' WINDOWS ONLY EXAMPLE! - We just set the graphics method to use
     '' GDI rather than DirectX (or Direct2D added on new systems).
     '' You may note a difference in FPS.
   SetEnviron("fbgfx=GDI")

     '' Desktop width/height
   Dim As Long ScrW, ScrH, BPP
   ScreenInfo ScrW, ScrH, BPP

     '' Create a screen at the half width/height of your monitor.
     '' Normally this would be slow, but GDI is fairly fast for this kind
     '' of thing.
   ScreenRes ScrW/2, ScrH/2, BPP

     '' Start our timer/
   Dim As Double T = Timer

     '' Lock our page
   ScreenLock
   Do
     
      '' Print time since last frame
     Locate 1, 1
     Print "FPS: " & 1 / ( Timer - T )
     T = Timer
     
      '' Flip our screen
     ScreenUnlock
     ScreenLock
      '' Commit a graphical change to our screen.
     Cls
     
   Loop Until Len(Inkey)

     '' unlock our page.
   ScreenUnlock

Platform Differences
   * In Linux, varexpression  must be permanent (a literal, a variable 
     declared in the main code or a static variable declared in a 
     procedure), because Linux does not memorize the string but only a 
     pointer to its data characters.

Differences from QB
   * In QB, SetEnviron was called Environ.

See also
   * Environ
   * Shell



---------------------------------------------------------- KeyPgEnviron ----
Environ

Returns the value of a system environment variable

Syntax
   Declare Function Environ ( ByRef varname As Const String ) As String

Usage
   result = Environ[$]( varname )

Parameters
   varname
      The name of an environment variable.

Return Value
   Returns the text value of the environmental variable, or the empty 
   string ("") if the variable does not exist.

Description
   Environ returns the text value of a system environment variable.

Example
   'e.g. to show the system variable "path":

   Print Environ("path")

Differences from QB
   * The QB ENVIRON statement is now called SetEnviron.
   * The string type suffix "$" is required in the -lang qb dialect.
   * The string type suffix "$" is optional in the -lang fblite dialect.
   * The string type suffix "$" is ignored in the -lang fb dialect, warn 
     only with the -w suffix compile option (or -w pedantic compile 
     option).

See also
   * SetEnviron
   * Shell



----------------------------------------------------- KeyPgSfxGenerated ----
Generated Sound Commands

Commands for generated sound, PLAY strings, and sfxlib mix settings.

Syntax
   Beep [ duration, pitch ]
   Sound frequency, duration
   Sound channel, frequency, duration, volume
   Tone channel, frequency, duration
   Noise channel, duration, volume
   Noise channel, frequency, duration, volume
   Note name, octave, duration
   Note channel, name, octave, duration
   Play music
   Play channel, music
   Play music1, music2
   Play music1, music2, music3
   Tempo bpm
   bpm = Tempo()
   Channel channel
   channel = Channel()
   Octave octave
   octave = Octave()
   Voice instrument
   instrument = Voice()
   Vol level
   Volume level
   level = Volume()
   Volume channel, level
   level = Volume( channel )
   Balance position
   position = Balance()
   Pan channel, position
   position = Pan( channel )
   Wave id, waveform
   Envelope id, attack, decay, sustain, release
   Instrument id, wave_id, envelope_id
   Instrument channel, instrument_id

Description
   These commands synthesize sound directly through sfxlib.  Sound, Tone, 
   Noise, Note, and Play create voices.  Tempo, Channel, Octave, and Voice 
   set defaults used by PLAY-string and generated-sound commands.  Volume, 
   Vol, Balance, and Pan control mix levels and stereo placement.

   Sound accepts the high-impact classic form Sound frequency, duration and
   the explicit channel form Sound channel, frequency, duration, volume.
   When both arguments are integers, duration is interpreted as the PC BASIC
   timer-tick value.

   Wave defines a waveform id.  The currently supported waveform values 
   are:
      * 0 sine
      * 1 square
      * 2 triangle
      * 3 saw
      * 4 noise

   Envelope defines an ADSR envelope using seconds for attack, decay, and 
   release, and a 0.0 to 1.0 sustain level.  Instrument can define an 
   instrument from a waveform and envelope, or assign an instrument to a 
   channel.

   The channel-oriented commands use sfxlib's channel table.  Channels are 
   zero-based.

Example
   See examples/sfxlib/basics-01-generated-sound.bas, 
   examples/sfxlib/basics-02-play-strings.bas, 
   examples/sfxlib/basics-03-channels-mix.bas, 
   examples/sfxlib/basics-04-instruments.bas, and 
   examples/sfxlib/showcase.bas.

Platform Differences
   * On headless or diagnostic runs, SFXLIB_DRIVER=null can be set before 
     program startup to use the null output driver.

Differences from QB
   * New to FreeBASIC.

See also
   * Beep
   * Music
   * Sfx
   * Sound Library Reference



-------------------------------------------------------------- KeyPgEoc ----
Eoc

Checks whether a TCP connection has been closed by the peer.

Syntax
   Declare Function Eoc ( ByVal filenum As Long ) As Long

Usage
   result = Eoc( filenum )

Parameters
   filenum
      A file number bound to an Open Tcp connection or an accepted TCP 
      client.

Return Value
   Returns true (-1) if the connection has ended, zero (0) otherwise.

Description
   Eoc means "end of connection".  It is intended for TCP file numbers, 
   where EOF only says that no byte is immediately available to read.  A 
   TCP program can poll Eof to decide whether a read is ready and Eoc to 
   decide whether the remote endpoint has closed the socket.

   Calling Eoc on a non-TCP file number is an illegal function call.

Example
   See examples/network/opentcp/http-get.bas.

Differences from QB
   * New to FreeBASIC.

See also
   * Open Tcp
   * Tcp Accept
   * EOF



-------------------------------------------------------------- KeyPgEof ----
EOF

Checks to see if the end of an open file has been reached

Syntax
   Declare Function EOF ( ByVal filenum As Long ) As Long

Usage
   result = EOF( filenum )

Parameters
   filenum
      File number of an open file.

Return Value
   Returns true (-1) if end-of-file has been reached, zero (0) otherwise.

Description
   When reading from files opened for Input (File Mode), it is useful to 
   know when the end of the file has been reached, thus avoiding errors 
   caused by reading past the ends of files. Use EOF to determine this. EOF 
   expects a valid file number from an already opened file. Use FreeFile to 
   retrieve an available file file number.

   For file numbers bound to files opened for Output, EOF always returns 0.

   For TCP file numbers opened by Open Tcp or returned by Tcp Accept, EOF 
   indicates whether a byte is immediately available to read.  Use Eoc to 
   test whether the remote endpoint has closed the connection.

Example
   '' This code finds a free file number to use and attempts to open the file
   '' "file.ext" and if successful, binds our file number to the opened file. It
   '' reads the file line by line, outputting it to the screen. We loop until eof()
   '' returns true, in this case we ignore the loop if file is empty.

   Dim As String file_name
   Dim As Long file_num

   file_name = "file.ext"
   file_num = FreeFile( )                 '' retrieve an available file number

   '' open our file and bind our file number to it, exit on error
   If( Open( file_name For Input As #file_num ) ) Then
      Print "ERROR: opening file " ; file_name
      End -1
   End If

   Do Until EOF( file_num )               '' loop until we have reached the end of the file
      Dim As String text
      Line Input #file_num, text               '' read a line of text ...
      Print text                             '' ... and output it to the screen
   Loop

   Close #file_num                        '' close file via our file number

   End 0

Differences from QB
   * In QB the comm port signaled an EOF when there were no chars waiting 
     to be read.
   * In QB, for files opened in RANDOM or BINARY mode, EOF returned 
     non-zero only after a read past the end of file has been attempted.  
     In FreeBASIC, EOF returns true after the last item is read.

See also
   * LOF
   * LOC
   * FreeFile
   * Eoc



------------------------------------------------------------ KeyPgOpEqv ----
Operator Eqv (Equivalence)

Returns the bitwise-and (equivalence) of two numeric values

Syntax
   Declare Operator Eqv ( ByRef lhs As T1, ByRef rhs As T2 ) As Ret

Usage
   result = lhs Eqv rhs

Parameters
   lhs
      The left-hand side expression.
   T1
      Any numeric or boolean type.
   rhs
      The right-hand side expression.
   T2
      Any numeric or boolean type.
   Ret
      A numeric or boolean type (varies with T1 and T2).

Return Value
   Returns the bitwise-equivalence of the two operands.

Description
   This operator returns the bitwise-equivalence of its operands, a logical 
   operation that results in a value with bits set depending on the bits of 
   the operands (for conversion of a boolean to an integer, false or true 
   boolean value becomes 0 or -1 integer value).

   The truth table below demonstrates all combinations of a 
   boolean-equivalence operation:

      +-------+-------+------+
      |Lhs Bit|Rhs Bit|Result|
      |0      |0      |1     |
      |1      |0      |0     |
      |0      |1      |0     |
      |1      |1      |1     |
      +-------+-------+------+

   No short-circuiting is performed - both expressions are always 
   evaluated.

   The return type depends on the types of values passed. Byte, UByte and 
   floating-point type values are first converted to Integer. If the left 
   and right-hand side types differ only in signedness, then the return 
   type is the same as the left-hand side type (T1), otherwise, the larger 
   of the two types is returned. Only if the left and right-hand side types 
   are both Boolean, the return type is also Boolean.

   This operator can be overloaded for user-defined types.

Example
   Dim As UByte a = &b00110011
   Dim As UByte b = &b01010101, c
   c = a Eqv b '' c = &b10011001

Dialect Differences
   * In the -lang qb dialect, this operator cannot be overloaded.

Differences from QB
   * None

See also
   * Operator Truth Tables



------------------------------------------------------------ KeyPgErase ----
Erase

Statement to erase arrays

Syntax
   Declare Sub Erase ( array As Any [, ... ] )

Usage
   Erase( array0 [, array1 ... arrayN ] )

Parameters
   array
      An array to be erased.

Description
   Using Erase on a fixed-length array resets all elements without freeing 
   the allocated memory.
   In case of objects, there is destruction then re-construction.

   Using Erase on a variable-length array (array already sized) frees the 
   memory allocated for the array elements, but the array remains declared 
   at its same scope level (with the same datatype and number of 
   dimensions), only the high/low bounds values of each dimension are reset 
   (-1/0).
   In case of objects, there is destruction before freeing memory.

Example
   Dim MyArray1(1 To 10) As Integer
   ReDim MyArray2(1 To 10) As Integer 

   Erase MyArray1, MyArray2
      

   Example showing the before and after results of single-dimension arrays:
   Dim MyArray1(1 To 10) As Integer
   ReDim MyArray2(1 To 10) As Integer

   Print "MyArray1", LBound( MyArray1 ), UBound( MyArray1 ) ' prints: MyArray1       1             10
   Print "MyArray2", LBound( MyArray2 ), UBound( MyArray2 ) ' prints: MyArray2       1             10

   Erase MyArray1, MyArray2

   Print "MyArray1", LBound( MyArray1 ), UBound( MyArray1 ) ' prints: MyArray1       1             10
   Print "MyArray2", LBound( MyArray2 ), UBound( MyArray2 ) ' prints: MyArray2       0            -1
         

   Example showing the before and after results of multi-dimension arrays:
   Dim MyArray1(1 To 3, 4 To 9) As Integer
   ReDim MyArray2(1 To 3, 4 To 9) As Integer

   Print , "LOWER", "UPPER"
   Print "MyArray1", _
        LBound( MyArray1, 1 ); ", "; LBound( MyArray1, 2 ), _
        UBound( MyArray1, 1 ); ", "; UBound( MyArray1, 2 )
   Print "MyArray2", _
        LBound( MyArray2, 1 ); ", "; LBound( MyArray2, 2 ), _
        UBound( MyArray2, 1 ); ", "; UBound( MyArray2, 2 )

   Erase MyArray1, MyArray2

   Print
   Print "MyArray1", _
        LBound( MyArray1, 1 ); ", "; LBound( MyArray1, 2 ), _
        UBound( MyArray1, 1 ); ", "; UBound( MyArray1, 2 )
   Print "MyArray2", _
        LBound( MyArray2, 1 ); ", "; LBound( MyArray2, 2 ), _
        UBound( MyArray2, 1 ); ", "; UBound( MyArray2, 2 )
         
The above example will output:
                 LOWER         UPPER
   MyArray1       1,  4         3,  9
   MyArray2       1,  4         3,  9

   MyArray1       1,  4         3,  9
   MyArray2       0,  0        -1, -1
   			

Differences from QB
   * None

See also
   * Common
   * Dim
   * Extern
   * LBound
   * ReDim
   * Static
   * UBound
   * Var



------------------------------------------------------------- KeyPgErfn ----
Erfn

Error reporting function

Syntax
   Declare Function Erfn ( ) As ZString Ptr

Usage
   result = Erfn ( ) 

Return Value
   Returns a pointer to the string identifying the function where the error 
   occurred.

   Returns NULL if the source is not compiled with the -exx compiler 
   option.

Description
   An error reporting function returning a pointer to the name of the 
   function.

Example
   '' test.bas
   '' compile with fbc -exx -lang fblite test.bas

   #lang "fblite"

   Sub Generate_Error
     On Error Goto Handler
     Error 1000
     Exit Sub
   Handler:
     Print "Error Function: "; *Erfn()
     Print "Error Module  : "; *Ermn()
     Resume Next
   End Sub

   Generate_Error

Output:
   Error Function: GENERATE_ERROR
   Error Module  : test.bas

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Erfn.

Differences from QB
   * New to FreeBASIC

See also 
   * Erl
   * Ermn
   * On...Error



-------------------------------------------------------------- KeyPgErl ----
Erl

Error handling function to return the line where the error occurred

Syntax
   Declare Function Erl ( ) As Long

Usage
   result = Erl

Return Value
   An Long return value containing the line number where the last error 
   occurred.

Description
   Erl will return the line number where the last error occurred. If no 
   error has occurred, Erl will return 0.

   Erl cannot always be used effectively -- QB-like error handling must be 
   enabled.

   Erl is reset by RESUME and RESUME NEXT

Example
   ' compile with -lang fblite or qb

   #lang "fblite"

   ' note: compilation with '-ex' option is required

   On Error Goto ErrorHandler

   ' Generate an explicit error
   Error 100

   End

   ErrorHandler:
     Dim num As Long = Err
     Print "Error "; num; " on line "; Erl
     Resume Next

   ' Expected output is
   ' Error  100 on line  6

Differences from QB
   * FreeBASIC returns the source code line number and ignores the values 
     of all explicit line numbers, where as QB returns the last encountered 
     explicit line number, and will return zero (0) when explicit line 
     numbers are not used.

See also
   * Error Handling
   * Err



------------------------------------------------------------- KeyPgErmn ----
Ermn

Error reporting function

Syntax
   Declare Function Ermn ( ) As ZString Ptr

Usage
   result = Ermn ( ) 

Return Value
   Returns a pointer to the string identifying the module where the error 
   occurred.

   Returns NULL if the source is not compiled with the -exx compiler 
   option.

Description
   An error reporting function returning a pointer to the name of the 
   module.

Example
   '' test.bas
   '' compile with fbc -exx -lang fblite test.bas

   #lang "fblite"

   Sub Generate_Error
     On Error Goto Handler
     Error 1000
     Exit Sub
   Handler:
     Print "Error Function: "; *Erfn()
     Print "Error Module  : "; *Ermn()
     Resume Next
   End Sub

   Generate_Error

Output:
   Error Function: GENERATE_ERROR
   Error Module  : test.bas

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Ermn.

Differences from QB
   * New to FreeBASIC

See also 
   * Erfn
   * Erl
   * On...Error



-------------------------------------------------------------- KeyPgErr ----
Err

Get or set the run-time error number

Usage
   result = Err( )
      or
   Err = number

Description
   The Err() function returns the FreeBASIC run-time error number (a 32 bit 
   Long) which can be set by the built-in statements and functions, or by 
   the program through Err = number or Error. Unlike Error, Err = number 
   sets the error number without invoking an error handler.

   See Runtime Error Codes for a listing of the predefined runtime error 
   numbers and their associated meaning. The program may use additional 
   custom error numbers.

   Err can always be used, even if QB-like error handling is not enabled. 
   Err is reset by Resume and Resume Next.

   Note: Care should be taken when calling an internal function (such as 
   Print) after an error occurred, because it will reset the error value 
   with its own error status. To preserve the Err value, it is a good idea 
   to store it in a variable as soon as the error handler is entered.

   Remark: Some procedures used in their function version return directly 
   the error code (a 32 bit Long).
   That is the case for: BLoad, BSave, Close, FileCopy, GetJoystick, 
   GetMouse, ImageInfo, Kill, Open, Open Com, Open Cons, Open Err, Open Lpt
   , Open Pipe, Open Scrn, ScreenRes, ScreenSync, SetDate, SetMouse, SetTime
   .

Example
An example using QBasic style error handling (compile with -ex option)
   '' Compile with -lang fblite or qb

   #lang "fblite"

   On Error Goto Error_Handler
   Error 150
   End

   Error_Handler:
     n = Err()
     Print "Error #"; n
     Resume Next

An example using inline error handling (note: Open can also return its own 
error status when called as a function)
   '' compile without -e switch

   Dim filename As String

   Do
      Line Input "Input filename: ", filename
      If filename = "" Then End
      Open filename For Input As #1
   Loop Until Err() = 0

   Print Using "File '&' opened successfully"; filename
   Close #1

Differences from QB
   * Error numbers are not the same as in QB.

See also
   * On Error
   * Error
   * Error Handling
   * Runtime Error Codes



------------------------------------------------------------ KeyPgError ----
Error

Error handling statement to force an error to be generated

Syntax
   Declare Sub Error ( errno As Long )

Usage
   Error number

Parameters
   number
      The error number to generate

Description
   Error invokes the error handler specified with On Error or, in case 
   there was none set, aborts the program, printing an error message 
   similar to those generated by the compiler's -exx run-time error 
   checking. It's possible to use the built-in run-time error numbers 
   and/or other custom error numbers for number. This can be used to 
   simulate custom error numbers.

Example
   To send an error alert of error 150 (just some arbitrary error code) one 
   would do the following:
   Error 150

Differences from QB
   * Error numbers are not the same as in QB.

See also
   * Err
   * Error Handling
   * Runtime Error Codes



------------------------------------------------------------ KeyPgEvent ----
Event (Message Data From Screenevent)

Pre-defined structure (UDT) from fbgfx.bi used by ScreenEvent to return 
event data 

Syntax
   #include once "fbgfx.bi"
   using fb
   Dim variable As Event

Description
   Here we report the EVENT structure for clarity:

   Type Event Field = 1
      Type As Long
      Union
         Type
            scancode As Long
            ascii As Long
         End Type
         Type
            x As Long
            y As Long
            dx As Long
            dy As Long
         End Type
         button As Long
         z As Long
         w As Long
      End Union
   End Type

   The Type field will contain the event type ID, while the remaining 4 
   integers will hold sensitive data to the event type. 

   Event types
      The event type is identified by an ID number returned into the first 
      integer of the event buffer (the .type field in the EVENT structure). 
      Known event type IDs - and their values at time of writing - are:

      * EVENT_KEY_PRESS (1) A key was pressed on the keyboard. The 
        .scancode field contains the platform independent scancode value 
        for the key; if the key has an ascii representation, it is held 
        into the .ascii field, which otherwise has a value of 0.
      * EVENT_KEY_RELEASE (2) A key was released on the keyboard. The 
        .scancode and .ascii fields have the same meaning as with the 
        EVENT_KEY_PRESS event.
      * EVENT_KEY_REPEAT (3) A key is being held down repeatedly. The 
        .scancode and .ascii fields have the same meaning as with the 
        EVENT_KEY_PRESS event.
      * EVENT_MOUSE_MOVE (4) The mouse was moved while it was on the 
        program window. The .x and .y fields contain the new mouse position 
        relative to the upper-left corner of the screen, while the .dx and 
        .dy fields contain the motion deltas.
      * EVENT_MOUSE_BUTTON_PRESS (5) One of the mouse buttons was pressed. 
        The .button field has one bit set identifying the button that was 
        pressed; bit 0 identifies the left mouse button, bit 1 the right 
        mouse button and bit 2 the middle mouse button.
      * EVENT_MOUSE_BUTTON_RELEASE (6) One of the mouse buttons was 
        released. The .button field has the same meaning as with the 
        EVENT_MOUSE_BUTTON_PRESS event.
      * EVENT_MOUSE_DOUBLE_CLICK (7)  One of the mouse buttons was double 
        clicked. The .button field has the same meaning as with the 
        EVENT_MOUSE_BUTTON_PRESS event.
      * EVENT_MOUSE_WHEEL (8) The mouse wheel was used; the new wheel 
        position is returned into the .z field.
      * EVENT_MOUSE_ENTER (9) The mouse was moved into the program window.
      * EVENT_MOUSE_EXIT (10) The mouse was moved out of the program 
        window.
      * EVENT_WINDOW_GOT_FOCUS (11) The program window has got focus.
      * EVENT_WINDOW_LOST_FOCUS (12) The program window has lost focus.
      * EVENT_WINDOW_CLOSE (13) The user attempted to close the program 
        window.
      * EVENT_MOUSE_HWHEEL (14) The horizontal mouse wheel was used; the 
        new horizontal wheel position is returned into the .w field.

   The fbgfx.bi header file contains a definition of the EVENT user data 
   type, so it is not necessary to declare it manually.

Example
   See example at ScreenEvent.

Dialect Differences
   * In lang fb, the structure and constants are stored in the FB Namespace
     . This is not the case in other dialects.

Differences from QB
   * New to FreeBASIC

See also
   * ScreenEvent
   * Event Handling
   * Keyboard scancodes
   * Keyboard Input



------------------------------------------------------------- KeyPgExec ----
Exec

Temporarily transfers execution to an external program

Syntax
   Declare Function Exec ( ByRef program As Const String, ByRef arguments As
   Const String ) As Long

Usage
   result = Exec( program, arguments )

Parameters
   program
      The file name (including file path) of the program (executable) to 
      transfer control to.
   arguments
      The command-line arguments to be passed to the program.

Return Value
   The exit status of the program, or negative one (-1) if the program 
   could not be executed.

Description
   Transfers control over to an external program. When the program exits, 
   execution resumes immediately after the call to Exec.

Example
   'A Windows based example but the same idea applies to Linux
   Const exename = "NoSuchProgram.exe"
   Const cmdline = "arg1 arg2 arg3"
   Dim result As Long
   result = Exec( exename, cmdline )
   If result = -1 Then
      Print "Error running "; exename
   Else
      Print "Exit code:"; result
   End If

Platform Differences
   * Linux requires the program case matches the real name of the file. 
     Windows and DOS  are case insensitive. The program being executed may 
     be case sensitive for its command line parameters.
   * Path separators in Linux are forward slashes / . Windows uses 
     backward slashes \ but it allows for forward slashes .  DOS uses 
     backward  \ slashes. 
   * Exit code is limited to 8 bits in DOS.

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Exec.

Differences from QB
   * New to FreeBASIC

See also
   * Chain transfer temporarily, without arguments
   * Run one-way transfer
   * Command pick arguments



---------------------------------------------------------- KeyPgExepath ----
ExePath

Returns the path of the running program

Syntax
   Declare Function ExePath ( ) As String

Usage
   result = ExePath

Return Value
   A String variable set to the path of the running program.

Description
   Returns the path (the location) of the calling program. This is not 
   necessarily the same as CurDir.

Example
   Dim pathname As String = ExePath
   Print "This program's initial directory is: " & pathname

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Exepath.

Differences from QB
   * New to FreeBASIC

See also
   * CurDir



------------------------------------------------------------- KeyPgExit ----
Exit

Control flow statement to exit a compound statement block

Syntax
   Exit {Do | For | While | Select }
   Exit {Sub | Function | Operator | Constructor | Destructor | Property }

   Exit {Do [, Do [ , ...] ] |
         For [, For [ , ...] ] | 
         While [, While, [...] ] | 
         Select [, Select [ , ...] ] }

Description
   Leaves a code block such as a Sub, Function, Operator, Constructor, 
   Destructor, Property, Do...Loop, For...Next, While...Wend, or a  
   Select Case block. The execution skips the rest of the block and goes to 
   the line after its end.

   Where there are multiple Do / For / While / Select blocks nested, it 
   will skip to the end of the innermost block of that type.  You can skip 
   to the end of multiple blocks of that type by giving the word multiple 
   times, separated by commas.
   For example: Exit While, While

Example
   'e.g. the print command will not be seen

   Do
      Exit Do ' Exit the Do...Loop and continues to run the code after Loop
      Print "I will never be shown"
   Loop

   Dim As Integer i, j
   For i = 1 To 10
      
      For j = 1 To 10
         
         Exit For, For
         
      Next j
      
      Print "I will never be shown"
      
   Next i

Differences from QB
   * EXIT OPERATOR, EXIT CONSTRUCTOR, EXIT DESTRUCTOR, EXIT PROPERTY, EXIT 
     WHILE and EXIT SELECT are new to FreeBASIC.

See also
   * Sub
   * Function
   * Do...Loop
   * For...Next
   * While...Wend
   * Continue



-------------------------------------------------------------- KeyPgExp ----
Exp

Returns e raised to the power of a given number

Syntax
   Declare Function Exp cdecl ( ByVal number As Double ) As Double

Usage
   result = Exp( number )

Parameters
   number
      The Double number that e is raised to the power of.

Return Value
   Returns the Double value of e raised to power of number.

Description
   The mathematical constant e, also called Euler's constant, is the base 
   of the Exp and Log and is an irrational and transcendental number. The 
   value of e to twenty significant figures is: 2.7182818284590452354. The 
   required number argument can be any valid numeric expression within 
   range of the function. If number is too large, Exp returns infinity.  If 
   number is too small, Exp returns zero (0.0).  If number is zero, 1.0 is 
   returned. The exact limit on number is based on the math processor.

   Exp can be overloaded as operator to accept user-defined types.

Example
   'Compute Continuous Compound Interest
   Dim r As Double
   Dim p As Double
   Dim t As Double
   Dim a As Double

   Input "Please enter the initial investment (principal amount): "; p
   Input "Please enter the annual interest rate (as a decimal): "; r
   Input "Please enter the number of years to invest: "; t

   a = p * Exp ( r * t )
   Print ""
   Print "After";t;" years, at an interest rate of"; r * 100; "%, your initial investment of"; p; " would be worth";a

The output would look like:

   Please enter the initial investment (principal amount): 100
   Please enter the annual interest rate (As a decimal): .08
   Please enter the number of years To invest: 20
   After 20 years, at an interest rate of 8%, your initial investment of 100 would be worth 495.3032424395115

Differences from QB
   * None

See also
   * Log
   * Operator ^ (Exponentiate)



----------------------------------------------------------- KeyPgExport ----
Export

Definition specifier to indicate that a procedure in a DLL should be 
visible from other programs

Syntax
   { Sub | Function } proc_name ( argumentlist ) [ [ ByRef ] As datatype ] 
   Export

Description
   If a function is defined with this clause in a DLL, it is added to the 
   public export table, so external programs can dynamically link to it 
   using DyLibSymbol.
   (specifier to be put at the level of the first line of procedure 
   definition, forbidden at procedure declaration line level)

Example
   See the examples on the Shared Libraries page.

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Export.

Platform Differences
   * Export has no effect in DOS dynamic link libraries (DXE's); all 
     public procedures are exported.

Differences from QB
   * New to Freebasic

See also
   * DyLibLoad
   * DyLibSymbol
   * Alias



---------------------------------------------------------- KeyPgExtends ----
Extends

Specifies a base type from which to derive a new type

Syntax
   Type|Union typename Extends base_typename
      ...
   End Type|Union

Description
   Extends declares typename to be derived from base_typename. The derived 
   user-defined type, typename, inherits fields and methods of the 
   base_typename base type. typename objects may be used in place of 
   base_typename objects. Fields and methods inherited from base_typename 
   will be implicitly accessible like members of typename.
   However, a member will shadow an inherited member if they have the same 
   identifier. The Base (Member Access) keyword can be used to explicitly 
   access members of the base type shadowed by local members.

   User-defined types that extend another type will include the base type 
   structure at their beginning, and their size as reported by Sizeof() is 
   the sum of their base type's size plus the size needed for any regular 
   data fields (non-static data fields). Since the inherited members make 
   sure that the structure is not empty, a derived type is not required to 
   have regular data fields of its own.

   In typename (the derived user-defined type), the fields can share the 
   same memory space than the base_typename only if typename is a Union. 
   Here it does not matter whether base_typename is a Union or not.
   If only base_typename is a Union, then it will not be affected by fields 
   from typename (the derived user-defined type).
   As a Union is not allowed to have complex fields (i.e. user-defined 
   types with constructor/destructor, or dynamic strings), a derived Union 
   cannot be allowed to have (contain) a complex base_typename.

   The Base (Initializer) keyword can be used at the top of constructor of 
   derived user-defined type. It allows to specify an initializer or 
   constructor call for the base type.

   Extending the built-in Object type allows a user-defined type to be used 
   with Operator Is to perform run-time type checks, to support Virtual and 
   Abstract methods, and to use the Override method attribute.

    Note: UDT pointer can only be cast to pointer types of "widened 
   compatibility" (up or even down in the inheritance hierarchy), or to Any 
   Ptr. Otherwise, cast to Any Ptr first (or to Object Ptr first if both 
   types are directly or indirectly derived from Object).

Example
   Type SchoolMember 'Represents any school member'
      Declare Constructor ()
      Declare Sub Init (ByRef _name As String, ByVal _age As Integer)
      As String Name
      As Integer age
   End Type

   Constructor SchoolMember ()
      Print "Initialized SchoolMember"
   End Constructor

   Sub SchoolMember.Init (ByRef _name As String, ByVal _age As Integer)
      This.name = _name
      This.age = _age
      Print "Name: "; This.name; "   Age:"; This.age
   End Sub

   Type Teacher Extends SchoolMember 'Represents a teacher derived from SchoolMember'
      Declare Constructor (ByRef _name As String, ByVal _age As Integer, ByVal _salary As Integer)
      As Integer salary
      Declare Sub Tell ()
   End Type

   Constructor Teacher (ByRef _name As String, ByVal _age As Integer, ByVal _salary As Integer)
      Print "Initialized Teacher"
      This.Init(_name, _age) 'implicit access to base member procedure'
      This.salary = _salary
   End Constructor

   Sub Teacher.Tell ()
      Print "Salary:"; This.salary
   End Sub

   Type Student Extends SchoolMember 'Represents a student derived from SchoolMember'
      Declare Constructor (ByRef _name As String, ByVal _age As Integer, ByVal _marks As Integer)
      As Integer marks
      Declare Sub Tell ()
   End Type

   Constructor Student (ByRef _name As String, ByVal _age As Integer, ByVal _marks As Integer)
      Print "Initialized Student"
      This.Init(_name, _age) 'implicit access to base member procedure'
      This.marks = _marks
   End Constructor
      
   Sub Student.Tell ()
      Print "Marks:"; This.marks
   End Sub

   Dim As Teacher t = Teacher("Mrs. Shrividya", 40, 30000)
   t.Tell()
   Print
   Dim As Student s = Student("Swaroop", 22, 75)
   s.Tell()

   ' Example using all eight keywords of inheritance:
   '   'Extends', 'Base.', 'Base()', 'Object', 'Is' operator, 'Virtual', 'Abstract', 'Override'

   Type root Extends Object ' 'Extends' to activate RTTI by inheritance of predefined Object type
     Declare Function ObjectHierarchy () As String
     Declare Abstract Function ObjectRealType () As String ' 'Abstract' declares function without local body
                                             '    which must be overriden
     Dim Name As String
     Declare Virtual Destructor () ' 'Virtual' declares destructor with body ('Abstract' forbidden)
   Protected:
     Declare Constructor () ' to avoid user construction from root
     Declare Constructor (ByRef rhs As root) '' to avoid user copy-construction from root
   End Type ' derived type may be member data empty

   Constructor root ()
   End Constructor

   Function root.ObjectHierarchy () As String
     Return "Object(forRTTI) <- root"
   End Function

   Virtual Destructor root ()
     Print "root destructor"
   End Destructor

   Type animal Extends root ' 'Extends' to inherit of root
     Declare Constructor (ByRef _name As String = "")
     Declare Function ObjectHierarchy () As String
     Declare Virtual Function ObjectRealType () As String Override ' 'Virtual' declares function with local
                                                   '    body which can be overriden
                                                   ' 'Override' to check if the function is
                                                   '    well an override
     Declare Virtual Destructor () Override ' 'Virtual' declares destructor with local body
                                  ' 'Override' to check if the destructor is well an override
   End Type

   Constructor animal (ByRef _name As String = "")
     This.name = _name
   End Constructor

   Function animal.ObjectHierarchy () As String
     Return Base.ObjectHierarchy & " <- animal" ' 'Base.' allows to access to parent member function
   End Function

   Virtual Function animal.ObjectRealType () As String
     Return "animal"
   End Function

   Virtual Destructor animal ()
     Print "  animal destructor: " & This.name
   End Destructor

   Type dog Extends animal ' 'Extends' to inherit of animal
     Declare Constructor (ByRef _name As String = "")
     Declare Function ObjectHierarchy () As String
     Declare Function ObjectRealType () As String Override ' 'Override' to check if the function is well an
                                             '    override
     Declare Destructor () Override ' 'Override' to check if the destructor is well an override
   End Type ' derived type may be member data empty

   Constructor dog (ByRef _name As String = "")
     Base(_name) ' 'Base()' allows to call parent constructor
   End Constructor

   Function dog.ObjectHierarchy () As String
     Return Base.ObjectHierarchy & " <- dog" ' 'Base.' allows to access to parent member function
   End Function

   Function dog.ObjectRealType () As String
     Return "dog"
   End Function

   Destructor dog ()
     Print "    dog destructor: " & This.name
   End Destructor

   Type cat Extends animal ' 'Extends' to inherit of animal
     Declare Constructor (ByRef _name As String = "")
     Declare Function ObjectHierarchy () As String
     Declare Function ObjectRealType () As String Override ' 'Override' to check if the function is well an
                                             '    override
     Declare Destructor () Override ' 'Override' to check if the destructor is well an override
   End Type ' derived type may be member data empty

   Constructor cat (ByRef _name As String = "")
     Base(_name) ' 'Base()' allows to call parent constructor
   End Constructor

   Function cat.ObjectHierarchy () As String
     Return Base.ObjectHierarchy & " <- cat" ' 'Base.' allows to access to parent member function
   End Function

   Function cat.ObjectRealType () As String
     Return "cat"
   End Function

   Destructor cat ()
     Print "    cat destructor: " & This.name
   End Destructor

   Sub PrintInfo (ByVal p As root Ptr) ' must be put after definition of animal type, dog type and cat type
     Print "  " & p->Name, "  " & p->ObjectRealType, "           ";
     If *p Is dog Then ' 'Is' allows to check compatibility with type symbol
      Print  Cast(dog Ptr, p)->ObjectHierarchy
     ElseIf *p Is cat Then ' 'Is' allows to check compatibility with type symbol
      Print Cast(cat Ptr, p)->ObjectHierarchy
     ElseIf *p Is animal Then ' 'Is' allows to check compatibility with type symbol
      Print Cast(animal Ptr, p)->ObjectHierarchy
     End If
   End Sub

   Print "Name:", "Object (real):         Hierarchy:"
   Dim a As root Ptr = New animal("Mouse")
   PrintInfo(a)
   Dim d As root Ptr = New dog("Buddy")
   PrintInfo(d)
   Dim c As root Ptr = New cat("Tiger")
   Printinfo(c)
   Print
   Delete a
   Delete d
   Delete c

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Extends.

Differences from QB
   * New to FreeBASIC

See also
   * Type
   * Union
   * Base (Initializer)
   * Base (Member Access)
   * Object
   * Operator Is
   * Virtual
   * Abstract
   * Override
   * Extends Zstring
   * Extends Wstring



--------------------------------------------------- KeyPgExtendsWstring ----
Extends Wstring

Specifies a type which inherits a Wstring behavior

Syntax
   Type|Union typename Extends Wstring [, base_typename]
      ...
   End Type|Union

Description
   Extends Wstring declares typename to inherit properties and behaviors of 
   a WString. Purpose is to allow users to create custom string types (with 
   i.e. dynamic memory management) that can integrate well in to existing 
   fbc compiler built ins (good interoperability with fbc's WString type).

   This declaration of such a UDT with a suitable Cast operator will 
   instruct compiler to convert the UDT to a WString (in addition, other 
   suitable operators as Let, [] (Pointer Index), Len, ..., can be also 
   declared).

   WString behaviour can be inherited directly, or indirectly and singly 
   from a base-type.
   WString behaviour can be inherited by a UDT also extending base_typename 
   (a kind of pseudo multiple-inheritance).

   By declaring a type (directly or indirectly) as Extends Wstring (in 
   addition to defining a suitable Cast operator only), this promotes it 
   fully WString type compatible, even with StrPtr/SAdd, LSet/RSet, and 
   Select Case.

Example
   See Extends Zstring for similar examples.

Version
   * Before fbc 1.09.0, this promotion was not yet fully WString type 
     compatible with the built in functions Val/ValInt/ValLng/ValUInt/
     Valunlg and Left/Right.
   * Since fbc 1.07.0

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Extends __Wstring, but unusable because no member procedure is 
     allowed in this dialect.

Differences from QB
   * New to FreeBASIC

See also
   * Type
   * Union
   * Extends
   * WString
   * Extends Zstring



--------------------------------------------------- KeyPgExtendsZstring ----
Extends Zstring

Specifies a type which inherits a Zstring behavior

Syntax
   Type|Union typename Extends Zstring [, base_typename]
      ...
   End Type|Union

Description
   Extends Zstring declares typename to inherit properties and behaviors of 
   a ZString. Purpose is to allow users to create custom string types (with 
   i.e. dynamic memory management) that can integrate well in to existing 
   fbc compiler built ins (good interoperability with fbc's ZString type).

   This declaration of such a UDT with a suitable Cast operator will 
   instruct compiler to convert the UDT to a ZString (in addition, other 
   suitable operators as Let, [] (Pointer Index), Len, ..., can be also 
   declared).

   ZString behaviour can be inherited directly, or indirectly and singly 
   from a base-type.
   ZString behaviour can be inherited by a UDT also extending base_typename 
   (a kind of pseudo multiple-inheritance).

   By declaring a type (directly or indirectly) as Extends Zstring (in 
   addition to defining a suitable Cast operator only), this promotes it 
   fully ZString type compatible, even with StrPtr/SAdd, LSet/RSet, and 
   Select Case.

Example
   Type myZstring Extends ZString
     Public:
      Declare Constructor (ByRef z As Const ZString = "")
      Declare Operator Cast () ByRef As Const ZString
      Declare Operator Let (ByRef z As Const ZString)
     Private:
      Dim As String s
   End Type

   Constructor myZstring (ByRef z As Const ZString = "")
     This.s = z
   End Constructor

   Operator myZstring.Cast () ByRef As Const ZString
     Return *StrPtr(This.s)
   End Operator

   Operator myZstring.Let (ByRef z As Const ZString)
     This.s = z
   End Operator

   Dim As myZstring z = "FreeBASIC"
   Print "'" & z & "'"

   z &= " compiler"
   Print "'" & z & "'"

   Sleep

   Type vZstring Extends ZString
     Public:
      Declare Constructor (ByVal pz As Const ZString Ptr = 0)
      Declare Operator Cast () ByRef As ZString
      Declare Operator Let (ByVal pz As Const ZString Ptr)
      Declare Operator [] (ByVal index As Integer) ByRef As UByte
      Declare Destructor ()
     Private:
      Dim As ZString Ptr p
      Dim As UInteger l
   End Type

   Constructor vZstring (ByVal pz As Const ZString Ptr = 0)
     This.l = Len(*pz)
     This.p = CAllocate(This.l + 1, SizeOf(ZString))
     *This.p = *pz
   End Constructor

   Operator vZstring.Cast () ByRef As ZString
     Return *This.p
   End Operator

   Operator vZstring.Let (ByVal pz As Const ZString Ptr)
     If This.l < Len(*pz) Then
      Deallocate(This.p)
      This.l = Len(*pz)
      This.p = CAllocate(This.l + 1, SizeOf(ZString))
     End If
     *This.p = *pz
   End Operator

   Operator vZstring.[] (ByVal index As Integer) ByRef As UByte
     Return This.p[index]
   End Operator

   Destructor vZstring ()
     Deallocate(This.p)
   End Destructor

   Operator Len (ByRef v As vZstring) As Integer
     Return Len(Type<String>(v))        '' found nothing better than this
   End Operator                         ''     (or: 'Return Len(Str(v))')

   Dim As vZstring v = "FreeBASIC"
   Print "'" & v & "'", Len(v)

   Dim As ZString * 256 z
   z = *StrPtr(v)                       '' 'error 24: Invalid data types' without 'Extends Zstring'
   Print "'" & z & "'", Len(z)

   v &= Space(2)
   Print "'" & v & "'", Len(v)
   RSet v, "FreeBASIC"                  '' 'error 24: Invalid data types' without 'Extends Zstring'
   Print "'" & v & "'", Len(v)          ''     ('Cast' must return a modifiable reference)

   Select Case v                        '' 'error 24: Invalid data types' without 'Extends Zstring'
   Case Type<vZstring>(Trim(v) & "  ")
     Print "Left justified"
   Case Type<vZstring>("  " & Trim(v))
     Print "Right justified"
   End Select

   v[0] = Asc("-")
   Print "'" & v & "'", Len(v)

   Print "'" & Right(v, 5) & "'"        '' since fbc 1.09.0, 'Right' supports types with 'Extends Zstring'
   'Print "'" & Right(Str(v), 5) & "'"  '' before fbc 1.09.0, use this workaround (or: 'Right(Type<String>(v), 5)')

   Sleep

Version
   * Before fbc 1.09.0, this promotion was not yet fully ZString type 
     compatible with the built in functions Val/ValInt/ValLng/ValUInt/
     Valunlg and Left/Right.
   * Since fbc 1.07.0

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Extends __Zstring, but unusable because no member procedure is 
     allowed in this dialect.

Differences from QB
   * New to FreeBASIC

See also
   * Type
   * Union
   * Extends
   * ZString
   * Extends Wstring



----------------------------------------------------------- KeyPgExtern ----
Extern

Declares a variable, array or object having external linkage

Syntax
   Extern [ Import ] symbolname[ (subscripts) ] [ Alias "aliasname" ] As 
   DataType [, ...]

Parameters
   symbolname
      The name of the variable, array or object.
   aliasname
      An alternate external name for the variable, array or object.

Description
   Declares symbolname as an external name, meaning it is global to 
   external modules including those to be compiled as static and dynamic 
   libraries (DLLs).
   Extern only declares variables, arrays and objects, and does not define 
   them (different from Common or Dim). It also has the effect of making 
   symbolname a shared name, meaning it is visible within procedures (see 
   Shared). A symbolname declared as external name can be (re)defined 
   (using Dim or Redim) only in a single external module.

   If Alias is used, aliasname will be used as the external name rather 
   than symbolname, and its case will be preserved.

   Extern was added in order to support the C libraries.

   If Import is used, the name will be added to the dynamic library import 
   list so its address can be fixed at run-time.

Example
   '' extern1.bas

   Extern Foo Alias "foo" As Integer

   Sub SetFoo
      foo = 1234
   End Sub

   '' extern2.bas

   Declare Sub SetFoo

   Extern Foo Alias "foo" As Integer

   Dim foo As Integer = 0

   SetFoo

   Print Foo

Output:

    1234

Platform Differences
   * Windows does not support Extern with a dynamic library (compiled with 
     -dll or -dylib).

Dialect Differences
   * Not available in the -lang qb dialect.

Differences from QB
   * New to FreeBASIC

See also
   * Extern...End Extern
   * Common
   * Dim
   * Shared
   * Alias (Name)
   * Alias (Modifier)



------------------------------------------------------ KeyPgExternBlock ----
Extern...End Extern

Statement block to allow calling of functions compiled for specific 
languages or platforms.

Syntax
   Extern { "C" | "C++" | "Windows" | "Windows-MS" | "rtlib" } [ Lib "
   libname" ]
      declarative statements
   End Extern

Description
   Extern blocks provide default calling conventions for procedures and 
   mandate a certain name decoration.

   Extern "C" blocks provide a default cdecl calling convention to 
   procedures, and also preserve the case of all names declared within 
   them. The same effect can be achieved without the EXTERN block by using 
   cdecl together with an Alias string containing the exact procedure name.

   Extern "C++" blocks are exactly like Extern "C" blocks but they also 
   mangle the names declared within them in a way compatible to that of g++
   -4.x.

   Extern "Windows" blocks provide a default stdcall calling convention to 
   procedures, preserve the case of all names declared within them, and on 
   the Windows platform, append an "@N" suffix to procedure names, where N 
   is the total size in bytes of any procedure parameters. Similar to the 
   Extern "C" block, the same effect can be achieved by using stdcall and 
   Alias.

   Extern "Windows-MS" blocks are exactly like Extern "Windows" blocks but 
   do not append the "@N" suffix to procedure names on Windows.

   Extern "rtlib" blocks combine the name decoration of Extern "c" and the 
   default calling convention of fbc.  When used in a namespace, the symbol 
   respects the scope of the namespace, however, the name decoration (name 
   mangling) links the symbol to a regular C library.  This behaviour may 
   be desired when declaring procedures that exist in the fb run-time 
   library; where calling convention is based on the target, but we would 
   like to have the compile time name respect the namespace.

   Lib "libname" can be used to specify a library which will be linked in 
   as if #Inclib "Libname" or -l libname had been used. Additionally, all 
   procedure declarations inside the Extern block will use the specified Lib
   "libname" as if it was specified as part of their declarations (but it 
   can still be overridden with an explicit Lib "libname").

Example
   '' This procedure uses the default calling convention for the system, which is
   '' STDCALL on Win32 and CDECL on Linux/DOS/*BSD, and is seen externally as
   '' "MYTEST1@4" on Win32 and "MYTEST1" on Linux/DOS/*BSD (following FB's default
   '' ALL-UPPER-CASE name mangling).
   Sub MyTest1 ( ByVal i As Integer )
   End Sub

   Extern "C"
      '' This procedure uses the CDECL convention and is seen externally
      '' as "MyTest2".
      Sub MyTest2 ( ByVal i As Integer )
      End Sub
   End Extern

   Extern "C++"
      '' This procedure uses the CDECL convention and its name is mangled
      '' compatible to g++-4.x, specifically: "_Z7MyTest3i"
      Sub MyTest3 ( ByVal i As Integer )
      End Sub
   End Extern

   Extern "Windows"
      '' This procedure uses the STDCALL convention and is seen externally
      '' as "MyTest4@4" on Windows, and "MyTest4" on Linux, *BSD and DOS.
      Sub MyTest4 ( ByVal i As Integer )
      End Sub
   End Extern

   Extern "Windows-MS"
      '' This procedure uses the STDCALL convention and is seen externally
      '' as "MyTest5".
      Sub MyTest5 ( ByVal i As Integer )
      End Sub
   End Extern

   MyTest1( 0 )
   MyTest2( 0 )
   MyTest3( 0 )
   MyTest4( 0 )

Dialect Differences
   * Extern blocks are only available in the -lang fb dialect.

Differences from QB
   * New to FreeBASIC

Platform Differences
   * On Linux, *BSD and DOS platforms, Extern "Windows" blocks never 
     append a "@N" suffix to procedure names, and thus are equal to Extern 
     "Windows-MS".

See also
   * cdecl
   * stdcall
   * Extern




============================================================================
    F

------------------------------------------------------------ KeyPgFalse ----
False

Intrinsic constant set by the compiler

Syntax
   Const False As Boolean

Description
   Gives the False Boolean value where used.

Example
   Dim b As Boolean = False
   If b Then
      Print "b is True"
   Else
      Print "b is False"
   End If


   b Is False

Version
   * Since fbc 1.04.0

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __False.

Differences from QB
   * New to FreeBASIC

See also
   * True
   * Boolean



--------------------------------------------------------- KeyPgFastcall ----
__Fastcall

Specifies the Fastcall calling convention in a procedure declaration

Syntax
   declare Sub name __Fastcall [Overload] [Alias "alias"] ( parameters )
   declare Function name __Fastcall [Overload] [Alias "alias"] ( parameters 
   ) [ ByRef ] As return_type

   Sub name [__Fastcall] [Overload] [Alias "alias"] ( parameters )
   Function name [__Fastcall] [Overload] [Alias "alias"] ( parameters ) [ 
   ByRef ] As return_type

Description
   Fastcall is a calling convention for x86 targets where the first and 
   second integer arguments are passed in the in ECX and EDX registers 
   respectively instead of on the stack. All other arguments are passed 
   right to left and callee cleans up the stack (like Stdcall).

   Fastcall can be specified at both the declaration and the definition.
   If a procedure definition has a declaration (with calling convention 
   explicit or by default) and the definition does not explicitly specify a 
   calling convention, then the calling convention is implied by the 
   declaration.

   Note: Default calling convention on win32 x86 inside an extern "c++" 
   block for non-static member procedures is Thiscall.

Example
   Extern "c++"
      Declare Function Example __Fastcall (param1 As Long, param2 As Byte, param3 As LongInt, param4 As String) As Integer
   End Extern

Version
   * Since fbc 1.10.0.

Differences from QB
   * New to FreeBASIC

See also
   * cdecl, stdcall, Thiscall
   * Declare
   * Sub, Function



-------------------------------------------------------- KeyPgFBMemcopy ----
Fb_Memcopy

Copies a block of memory from a location to another

Syntax
   Declare Function fb_memcopy cdecl ( ByRef dst As Any, ByRef src As Any, 
   ByVal bytes As UInteger ) As Any Ptr

Usage
   [result =] fb_memcopy( dst, src, bytes )

Parameters
   dst
      starting address of destination memory
   src
      starting address of source memory
   bytes
      number of bytes to copy

Return Value
   The starting address of destination memory is returned.

Description
   fb_memcopy copies a given number of bytes from the memory location src 
   to the memory location dst.
   Each starting address is taken from a reference to a variable or array 
   element.
   The memory areas must not overlap (otherwise, the copying is not 
   guaranteed to work properly, especially depending on the platform). Use 
   Fb_Memmove preferably when the memory areas do overlap (safer approach).
   To avoid overflows, the valid memory areas pointed to by both src and 
   dst must be at least equal in size to the number of bytes to be copied.

   The underlying type of the objects pointed to by both the source and 
   destination pointers are irrelevant for this function.
   The function does not check for any terminating null character in the 
   source area. It always copies exactly the given number of bytes.
   The result is a binary copy of the data.

   Note: In order to copy from/to memory referenced by a Pointer, it must 
   be dereferenced first (or else specify in argument term the ByVal 
   keyword in front of the pointer name). Otherwise, fb_memcopy will try to 
   copy the bytes from/to the pointer variable's memory location.

Example
   Type Person
      Dim As ZString * 40 Name
      Dim As Integer age
   End Type

   Dim As ZString Ptr mynameptr = @"Pierre de Fermat"

   Dim As Person person1, person2

   ' using fb_memcopy to copy string
   fb_memcopy(person1.name, *mynameptr, Len(*mynameptr) + 1)
   person1.age = 46

   ' using fb_memcopy to copy structure
   fb_memcopy(person2, person1, SizeOf(Person))

   Print person2.name, person2.age

   Sleep
      
Output:

   Pierre de Fermat             46
   		

Version
   * Since fbc 1.08.0

Differences from QB
   * The behavior and usage is new to FreeBASIC.

See also
   * fb_MemCopyClear
   * Fb_Memmove



--------------------------------------------------- KeyPgFBMemcopyclear ----
fb_MemCopyClear

Copies the first part of a block of memory from a location to another and 
clears the rest

Syntax
   Declare Sub fb_MemCopyClear ( ByRef dst As Any, ByVal dstlen As UInteger
   , ByRef src As Any, ByVal srclen As UInteger )

Usage
   fb_memcopy( dst, dstlen, src, srclen )

Parameters
   dst
      starting address of destination memory
   dstlen
      number of bytes to write
   src
      starting address of source memory
   srclen
      number of first bytes to copy (other are cleared)

Description
   fb_memcopycopy copies a given number of bytes (dstlen) from the memory 
   location src to the memory location dst, but only the first srclen bytes 
   are really copied and the rest is cleared ((dstlen - srclen) bytes).
   Each starting address is taken from a reference to a variable or array 
   element.
   The memory areas must not overlap (otherwise, the copying is not 
   guaranteed to work properly, especially depending on the platform).
   To avoid overflows, the valid memory areas pointed to by both src and 
   dst must be at least equal in size to the number of bytes to be copied 
   (including the bytes cleared).

   The underlying type of the objects pointed to by both the source and 
   destination pointers are irrelevant for this function.
   The function does not check for any terminating null character in the 
   source area. It always copies exactly the given number of bytes.
   The result is a binary copy of the data for the first srclen bytes and a 
   zeroing for the rest ((dstlen - srclen) bytes).

   Note: In order to copy from/to memory referenced by a Pointer, it must 
   be dereferenced first (or else specify in argument term the ByVal 
   keyword in front of the pointer name). Otherwise, fb_MemCopyClear will 
   try to copy the bytes from/to the pointer variable's memory location.

Example
   Dim src As ZString * 10 = "FreeBASIC"
   Dim dst As ZString * 10 = "012345678"

   Print "before:"
   Print "src = " & src
   Print "dst = " & dst
   Print

   '' copy first 4 bytes and clear the rest
   fb_MemCopyClear(dst, SizeOf(dst), src, 4)

   Print "after:"
   Print "src = " & src
   Print "dst = " & dst

   Sleep
      
Output:

   before:
   src = FreeBASIC
   dst = 012345678

   after:
   src = FreeBASIC
   dst = Free
   		

Version
   * Since fbc 1.08.0

Differences from QB
   * The behavior and usage is new to FreeBASIC.

See also
   * Fb_Memcopy
   * Fb_Memmove



-------------------------------------------------------- KeyPgFBMemmove ----
Fb_Memmove

Copies a block of memory from a location to another

Syntax
   Declare Function fb_memmove cdecl ( ByRef dst As Any, ByRef src As Any, 
   ByVal bytes As UInteger ) As Any Ptr

Usage
   [result =] fb_memmove( dst, src, bytes )

Parameters
   dst
      starting address of destination memory
   src
      starting address of source memory
   bytes
      number of bytes to copy

Return Value
   The starting address of destination memory is returned.

Description
   fb_memmove copies a given number of bytes from the memory location src 
   to the memory location dst. Each starting address is taken from a 
   reference to a variable or array element.
   Copying takes place as if an intermediate buffer were used, allowing the 
   destination and source areas to overlap in any way (safer approach, and 
   for any platform). Using Fb_Memcopy is sufficient (and may induce 
   greater speed) when the memory areas do not overlap.
   To avoid overflows, the valid memory areas pointed to by both src and 
   dst must be at least equal in size to the number of bytes to be copied.

   The underlying type of the objects pointed to by both the source and 
   destination pointers are irrelevant for this function.
   The function does not check for any terminating null character in the 
   source area. It always copies exactly the given number of bytes.
   The result is a binary copy of the data.

   Note: In order to copy from/to memory referenced by a Pointer, it must 
   be dereferenced first (or else specify in argument term the ByVal 
   keyword in front of the pointer name). Otherwise, fb_memmove will try to 
   copy the bytes from/to the pointer variable's memory location.

Example
   Dim As ZString * 33 z = "memmove can be very useful......"

   Print z

   fb_memmove(z[20], z[15], 11)

   Print z

   Sleep
      
Output:

   memmove can be very useful......
   memmove can be very very useful.
   		

Version
   * Since fbc 1.08.0

Differences from QB
   * The behavior and usage is new to FreeBASIC.

See also
   * Fb_Memcopy
   * fb_MemCopyClear



---------------------------------------------------------- KeyPgFBArray ----
Fbarray (Array Descriptor Structure And Access)

Pre-defined structure (UDT) and procedure declarations from the fbc-int/arra
y.bi include file, usable to access the array descriptor data fields.

Syntax
   From ./inc/fbc-int/array.bi:
   # If __FB_LANG__ = "fb"
   Namespace FBC
   # endif

   Const FB_MAXDIMENSIONS As Integer = 8

   Type FBARRAYDIM
      Dim As UInteger elements     '' number of elements
      Dim As Integer LBound        '' dimension lower bound
      Dim As Integer UBound        '' dimension upper bound
   End Type

   Const FBARRAY_FLAGS_DIMENSIONS = &h0000000f    '' number of entries allocated in dimTb()
   Const FBARRAY_FLAGS_FIXED_DIM  = &h00000010    '' array has fixed number of dimensions
   Const FBARRAY_FLAGS_FIXED_LEN  = &h00000020    '' array points to fixed-length memory
   Const FBARRAY_FLAGS_RESERVED   = &hffffffc0    '' reserved, do not use

   Type FBARRAY
      Dim As Any Ptr index_ptr     '' @array(0, 0, 0, ... )
      Dim As Any Ptr base_ptr      '' start of memory at array lowest bounds
      Dim As UInteger size         '' byte size of allocated contents
      Dim As UInteger element_len  '' byte size of single element
      Dim As UInteger dimensions   '' number of dimensions
      Dim As UInteger flags        '' FBARRAY_FLAGS_*

      '' take care with number of dimensions; fbc may allocate
      '' a smaller descriptor with fewer than FB_MAXDIMENSIONS
      '' in dimTb() if it is known at compile time that they
      '' are never needed.  Always respect number of 
      '' dimensions when accessing dimTb()

      Dim As FBARRAYDIM dimTb(0 To FB_MAXDIMENSIONS-1)
   End Type

   Extern "rtlib"
      Declare Function ArrayDescriptorPtr Alias "fb_ArrayGetDesc" _
         ( array() As Any ) As FBC.FBARRAY Ptr
      Declare Function ArrayConstDescriptorPtr Alias "fb_ArrayGetDesc" _
         ( array() As Const Any ) As Const FBC.FBARRAY Ptr
   End Extern

   # If __FB_LANG__ = "fb"
   End Namespace
   # endif
         

Usage
   #include once "fbc-int/array.bi"
   using FBC

   ' then:
      Dim pd As FBARRAY Ptr
      ...
      pd = ArrayDescriptorPtr ( array() )

   ' or safer:
      Dim pd As Const FBARRAY Ptr
      ...
      pd = ArrayConstDescriptorPtr ( array() )

Parameters
   pd 
      The name of a pointer to the array descriptor
   array 
      The name of the array for which one want to access its descriptor

Description
   At compile time, fbc allocates an array descriptor to store and track 
   information about the array.

   If the number of dimensions is unknown at compile time, then the full 
   FB_MAXDIMENSIONS is allocated in the dimTb() field.  Otherwise, if the 
   number dimensions is known at compile time, then only the number of 
   dimensions needed are allocated.
   Therefore the allocated FBARRAY data may be smaller than the declared 
   FBARRAY structure:
      allocated FBARRAY data size (in bytes) = Sizeof(FBARRAY) - 
      (FB_MAXDIMENSIONS - (FBARRAY.flags And FBARRAY_FLAGS_DIMENSIONS)) * 
      Sizeof(FBARRAYDIM)

   If an array is passed as argument to a procedure, an array descriptor is 
   allocated.  However, if the array is static, fixed length, and never 
   passed as an argument, then all information about the array is known at 
   compile time, including memory locations, and the allocation of a 
   descriptor is optimized out, since all expressions involving the array 
   are compile time constant.

   The array descriptor may also be allocated at run time, as would be in 
   the case of allocating a new UDT containing a variable-length array 
   field member.

   WARNING: It is inadvisable (especially for a non advanced user) to 
   change the data values â€‹â€‹of the array descriptor (internal structure 
   of the compiler).
   For that, it is safer to use rather the function 
   ArrayConstDescriptorPtr() initializing a pointer declared As Const 
   FBARRAY Ptr (or implicitly declared in this way by Var).

   FBARRAY.index_ptr
      Pointer to the array data @array(0, 0, ...).  This pointer may be 
      outside of the actual array data as a kind of virtual pointer to use 
      when calculating offsets using indexes in to the array.

   FBARRAY.base_ptr
      Pointer to the array's memory at the array's lowest bound.  For 
      variable-length arrays allocated at run time, this points to the 
      allocated memory region (i.e. malloc)

   FBARRAY.size
      Total size in bytes of the array data.  Size is equal to total number 
      of elements in the array (all dimensions) multiplied by element 
      length.  i.e. size = dimTb(0).elements * element_len + 
      dimTb(1).elements * element_len + ...

   FBARRAY.element_len
      Size in bytes of an individual element.  Must be set to non-zero 
      value.

   FBARRAY.dimensions
      Number of valid dimensions in the dimTb() table.  A value of zero (0) 
      indicates that dimTb() has FB_MAXDIMENSIONS avaiable, but the array 
      does not yet have number of dimensions defined.  On first REDIM, the 
      number of dimensions will be set.

   FBARRAY.flags
      The flags field contains information about the array descriptor that 
      needs to be known at run time.

         FBARRAY_FLAGS_DIMENSIONS : a 4 bit field to indicate the number of 
         elements allocated in dimTb().  If fbc can determine at compile 
         time that less than FB_MAXDIMENSIONS are needed to represent the 
         array, then only the number of dimensions needed are allocated in 
         dimTb().
         The real size allocated for the array descriptor can be calculated 
         by:
            Sizeof(FBC.FBARRAY) - (FBC.FB_MAXDIMENSIONS - (FBC.
            ArrayDescriptorPtr(array())->flags And 
            FBC.FBARRAY_FLAGS_DIMENSIONS)) * Sizeof(FBC.FBARRAYDIM)

         FBARRAY_FLAGS_FIXED_DIM : if this bit is set, indicates that the 
         number of dimensions are set and are given in dimTb() and must not 
         be changed.

         FBARRAY_FLAGS_FIXED_LEN : if this bit is set, indicates that the 
         array data is fixed length and must not be resized or reallocated

         FBARRAY_FLAGS_RESERVED : all other bits are reserved for future 
         use

   FBARRAY.dimTb()
      dimTb() is an array of FBARRAYDIM to indicate the bounds of each 
      dimension.

      If the number of dimensions is unknown at compile time, then the full 
      FB_MAXDIMENSIONS is allocated in the dimTb() field. Otherwise, if the 
      number dimensions is known at compile time, then only the number of 
      dimensions needed are allocated. Therefore the allocated FBARRAY data 
      may be smaller than the declared FBARRAY structure.

   FBARRAYDIM.elements
      Number of elements in the dimension.  i.e. (ubound-lbound+1)

   FBARRAYDIM.lbound
      Lower bound is the lowest valid index in this dimension.

   FBARRAYDIM.ubound
      Upper bound is the highest valid index in this dimension.

   ArrayDescriptorPtr( array() as any ) as FBC.FBARRAY ptr
      Retrieves a pointer to the array descriptor, returning a pointer to 
      FBC.ARRAY that can be modified (the array descriptor thus referenced 
      is valid until the end of the scope where it is created).

   ArrayConstDescriptorPtr( array() as const any ) as const FBC.FBARRAY ptr
      Retrieves a pointer to the array descriptor, returning a pointer to 
      FBC.ARRAY that is read only (the array descriptor thus referenced is 
      valid until the end of the scope where it is created).

Example
   Very simple syntaxic example highlighting the access capabilities to the 
   data fields of an array descriptor:
   #include "fbc-int/array.bi"

   Sub printArrayDescriptor (ByVal p As Any Ptr, ByVal tabulation As Integer = 0, ByRef title As String = "")
      Dim As FBC.FBARRAY Ptr pd = p
      Dim As Integer t = 0
      If title <> "" Then
         Print title
         t = 1
      End If
      Print Space((t    ) * tabulation) & "[@array descriptor: @&h"; Hex(pd, 2 * SizeOf(Any Ptr)) & " / "; _
                                                      SizeOf(FBC.FBARRAY) - (8 - pd->dimensions) * 3 * SizeOf(Integer) & " bytes]"'
      Print Space((t + 1) * tabulation) & "@array(all_null_indexes)      =&h"; Hex(pd->index_ptr, 2 * SizeOf(Any Ptr))
      Print Space((t + 1) * tabulation) & "@array(all_min_indexes)       =&h"; Hex(pd->base_ptr, 2 * SizeOf(Any Ptr))
      Print Space((t + 1) * tabulation) & "array_total_size_in_bytes     ="; pd->size
      Print Space((t + 1) * tabulation) & "array_element_size_in_bytes   ="; pd->element_len
      Print Space((t + 1) * tabulation) & "number_of_array_dimensions    ="; pd->dimensions
      Print Space((t + 1) * tabulation) & "fixed_len/fixed_dim/dimensions="; (pd->flags And FBC.FBARRAY_FLAGS_FIXED_LEN) Shr 5 & "/"; _
                                                            (pd->flags And FBC.FBARRAY_FLAGS_FIXED_DIM) Shr 4 & "/"; _
                                                            (pd->flags And FBC.FBARRAY_FLAGS_DIMENSIONS)
      For i As Integer = 0 To pd->dimensions - 1
         Print Space((t + 1) * tabulation) & "[dimension number:"; i + 1; "]"
         Print Space((t + 2) * tabulation) & "number_of_elements="; pd->dimTb(i).elements
         Print Space((t + 2) * tabulation) & "min_index         ="; pd->dimTb(i).LBound
         Print Space((t + 2) * tabulation) & "max_index         ="; pd->dimTb(i).UBound
      Next i
   End Sub

   Screen 0
   Width , 35

   Dim As LongInt test1(0 To 9, 1 To 100)
   printArrayDescriptor(FBC.ArrayDescriptorPtr(test1()), 4, "'Dim As Longint test1(0 to 9, 1 to 100)':")
   Sleep
   Cls
   Dim As LongInt test2()
   printArrayDescriptor(FBC.ArrayDescriptorPtr(test2()), 4, "'Dim As Longint test2()':")
   Print
   ReDim test2(0 To 9, 1 To 100)
   printArrayDescriptor(FBC.ArrayDescriptorPtr(test2()), 4, "'Redim test2(0 to 9, 1 to 100)':")
   Sleep
   Cls
   Dim As LongInt test3(Any, Any)
   printArrayDescriptor(FBC.ArrayDescriptorPtr(test3()), 4, "'Dim As Longint test3(Any, Any)':")
   Print
   ReDim test3(0 To 9, 1 To 100)
   printArrayDescriptor(FBC.ArrayDescriptorPtr(test3()), 4, "'Redim test3(0 to 9, 1 to 100)':")

   Sleep
         
Output example (32-bit):

   'Dim As Longint test1(0 to 9, 1 to 100)':
   	[@array descriptor: @&h0019DE70 / 48 bytes]
   		@array(all_null_indexes)      =&h0019DE98
   		@array(all_min_indexes)       =&h0019DEA0
   		array_total_size_in_bytes     =8000
   		array_element_size_in_bytes   =8
   		number_of_array_dimensions    =2
   		fixed_len/fixed_dim/dimensions=1/1/2
   		[dimension number: 1]
   			number_of_elements=10
   			min_index         = 0
   			max_index         = 9
   		[dimension number: 2]
   			number_of_elements=100
   			min_index         = 1
   			max_index         = 100
   			


   'Dim As Longint test2()':
   	[@array descriptor: @&h0019DDF8 / 24 bytes]
   		@array(all_null_indexes)      =&h00000000
   		@array(all_min_indexes)       =&h00000000
   		array_total_size_in_bytes     =0
   		array_element_size_in_bytes   =8
   		number_of_array_dimensions    =0
   		fixed_len/fixed_dim/dimensions=0/0/8

   'Redim test2(0 to 9, 1 to 100)':
   	[@array descriptor: @&h0019DDF8 / 48 bytes]
   		@array(all_null_indexes)      =&h01FD2AB8
   		@array(all_min_indexes)       =&h01FD2AC0
   		array_total_size_in_bytes     =8000
   		array_element_size_in_bytes   =8
   		number_of_array_dimensions    =2
   		fixed_len/fixed_dim/dimensions=0/0/8
   		[dimension number: 1]
   			number_of_elements=10
   			min_index         = 0
   			max_index         = 9
   		[dimension number: 2]
   			number_of_elements=100
   			min_index         = 1
   			max_index         = 100
   			


   'Dim As Longint test3(Any, Any)':
   	[@array descriptor: @&h0019DDC8 / 48 bytes]
   		@array(all_null_indexes)      =&h00000000
   		@array(all_min_indexes)       =&h00000000
   		array_total_size_in_bytes     =0
   		array_element_size_in_bytes   =8
   		number_of_array_dimensions    =2
   		fixed_len/fixed_dim/dimensions=0/1/2
   		[dimension number: 1]
   			number_of_elements=0
   			min_index         = 0
   			max_index         = 0
   		[dimension number: 2]
   			number_of_elements=0
   			min_index         = 0
   			max_index         = 0

   'Redim test3(0 to 9, 1 to 100)':
   	[@array descriptor: @&h0019DDC8 / 48 bytes]
   		@array(all_null_indexes)      =&h01FD4C20
   		@array(all_min_indexes)       =&h01FD4C28
   		array_total_size_in_bytes     =8000
   		array_element_size_in_bytes   =8
   		number_of_array_dimensions    =2
   		fixed_len/fixed_dim/dimensions=0/1/2
   		[dimension number: 1]
   			number_of_elements=10
   			min_index         = 0
   			max_index         = 9
   		[dimension number: 2]
   			number_of_elements=100
   			min_index         = 1
   			max_index         = 100
   			

Version
   * Since fbc 1.08.0

Dialect Differences
   * Only available in the -lang fb dialect.

Differences from QB
   * New to FreeBASIC.

See also
   * Arrays
   * Arraylen
   * Arraysize
    


------------------------------------------------------- KeyPgFbNoGfxlib ----
Fb_No_Gfxlib

User-defined compiler control symbol

Syntax
   #define FB_NO_GFXLIB

Description
   Defining FB_NO_GFXLIB tells the compiler not to treat selected 
   graphics-library command words as built-in gfxlib command keywords.

   This is useful in larger programs or libraries that do not use the 
   legacy graphics command surface and need names such as Screen, Paint, or
   Window to be available as normal identifiers.

   The affected gfxlib command words are PSET, PRESET, POINT, CIRCLE, 
   WINDOW, PALETTE, SCREEN, SCREENQB, PAINT, DRAW, and IMAGECREATE.

   FB_NO_GFXLIB affects parsing only after the symbol has been defined.  It 
   does not remove libraries that are explicitly requested through other 
   code, and it does not change the behavior of already-parsed source.

Example
   #define FB_NO_GFXLIB

   Type Window
      As Integer id
   End Type

   Dim As Window main_window
   main_window.id = 1

Version
   * Since fbc 1.20.1

Differences from QB
   * New to FreeBASIC

See also
   * #define
   * Compiler Option: -d
   * Graphics Keyword List



------------------------------------------------------- KeyPgFbNoSfxlib ----
Fb_No_Sfxlib

User-defined compiler control symbol

Syntax
   #define FB_NO_SFXLIB

Description
   Defining FB_NO_SFXLIB tells the compiler not to treat selected 
   sound-library command words as built-in sfxlib command keywords.

   This is useful in larger programs or libraries that do not use the sound 
   command surface and need names such as Music, Sfx, or Device to be
   available as normal identifiers.

   The affected sfxlib command words are MUSIC, SFX, MIDI, DEVICE, and
   CAPTURE.

   FB_NO_SFXLIB affects parsing only after the symbol has been defined.  It 
   does not remove libraries that are explicitly requested through other 
   code, and it does not change the behavior of already-parsed source.

Example
   #define FB_NO_SFXLIB

   Type Music
      As Integer id
   End Type

   Dim As Music song
   song.id = 1

Version
   * Since fbc 1.20.1

Differences from QB
   * New to FreeBASIC

See also
   * #define
   * Compiler Option: -d
   * Sound Library Reference



------------------------------------------------------------ KeyPgField ----
Field

Specifies field alignment.

Syntax
   Type|Union typename Field = { 1 | 2 | 4 }
      ...
   End Type|Union

Description
   Field can be used to pack Types or Unions more tightly than 
   the default layout. The most commonly used value is Field = 1, which 
   causes the Type or Union to be packed as tightly as possible, without 
   any padding bytes being added between the fields or at the end of the 
   Type. Field can only be used to decrease field alignment, but it cannot 
   be used to increase it. In order to add padding bytes, a Union with 
   appropriate members could be used instead.

Example
   Type bitmap_header Field = 1
      bfType          As UShort
      bfsize          As ULong
      bfReserved1     As UShort
      bfReserved2     As UShort
      bfOffBits       As ULong
      biSize          As ULong
      biWidth         As ULong
      biHeight        As ULong
      biPlanes        As UShort
      biBitCount      As UShort
      biCompression   As ULong
      biSizeImage     As ULong
      biXPelsPerMeter As ULong
      biYPelsPerMeter As ULong
      biClrUsed       As ULong
      biClrImportant  As ULong
   End Type

   Dim bmp_header As bitmap_header

   'Open up bmp.bmp and get its header data:
   'Note: Will not work without a bmp.bmp to load . . .
   Open "bmp.bmp" For Binary As #1

      Get #1, , bmp_header
      
   Close #1

   Print bmp_header.biWidth, bmp_header.biHeight

   Sleep

Dialect Differences
   *In the -lang qb dialect, the compiler assumes Field = 1 by default, if 
     no other Field was specified, causing all structures to be tightly 
     packed, without added padding, as in QB.

Differences from QB
   * In QB Field was used to define fields in a file buffer at run time. 
     This feature is not implemented in FB, so the keyword has been 
     redefined. To define fields in a file buffer, Types must be used.

See also
   * Type
   * Union
   * Structure packing/field alignment



--------------------------------------------------------- KeyPgFileattr ----
FileAttr

Returns information about an open file number

Syntax
   Declare Function FileAttr ( ByVal filenum As Long, ByVal returntype As 
   Long = 1 ) As Integer

Usage
   #include "file.bi"
   result = FileAttr( filenum, [ returntype ] )

or

   #include "vbcompat.bi"
   result = FileAttr( filenum, [ returntype ] )

Parameters
   filenum
      The file number of a file or device opened with Open
   returntype
      An integer value indicating the type of information to return.

Return Value
   A value associated with the return type, otherwise 0 on error.

Description
   Information about the file number is returned based on the supplied 
   returntype
         +-----+-----------+------------------+
         |Value|Description|constant          |
         |1    |File Mode  |fbFileAttrMode    |
         |2    |File Handle|fbFileAttrHandle  |
         |3    |Encoding   |fbFileAttrEncoding|
         +-----+-----------+------------------+

   For File Mode, returntype = 1 (fbFileAttrMode) the return value is the 
   sum of one or more of the following values: 
         +-----+---------+----------------+
         |Value|File Mode|Constant        |
         |1    |Input    |fbFileModeInput |
         |2    |Output   |fbFileModeOutput|
         |4    |Random   |fbFileModeRandom|
         |8    |Append   |fbFileModeAppend|
         |32   |Binary   |fbFileModeBinary|
         +-----+---------+----------------+

   For File Handle, returntype = 2 (fbFileAttrHandle), the return value is 
   the file handle as supplied by the C Runtime for file-type devices.  

   On Windows only: For File Handle, returntype = 2 (fbFileAttrHandle), the 
   value returned for COM devices is the handle returned by CreateFile() 
   when the device was first opened.  The value returned for LPT devices is 
   the handle returned by OpenPrinter() when the device was first opened.  
   This handle value can be passed to other Windows API functions.

   On Linux only: For File Handle, returntype = 2 (fbFileAttrHandle), the 
   value returned for COM devices is the file descriptor returned by open() 
   when the device was first opened.

   For Encoding, returntype = 3 (fbFileAttrEncoding), the return value is 
   one of the following values:
         +-----+--------+----------------+
         |Value|Encoding|Constant        |
         |0    |Ascii   |fbFileEncodASCII|
         |1    |UTF-8   |fbFileEncodUTF8 |
         |2    |UTF-16  |fbFileEncodUTF16|
         |3    |UTF-32  |fbFileEncodUTF32|
         +-----+--------+----------------+

Example
   #include "vbcompat.bi"
   #include "crt.bi"

   Dim f As FILE Ptr, i As Integer

   '' Open a file and write some text to it

   Open "test.txt" For Output As #1
   f = Cast( FILE Ptr, FileAttr( 1, fbFileAttrHandle ))
   For i = 1 To 10
     fprintf( f, !"Line %i\n", i )
   Next i
   Close #1

   '' re-open the file and read the text back

   Open "test.txt" For Input As #1
   f = Cast( FILE Ptr, FileAttr( 1, fbFileAttrHandle ))
   While feof(f) = 0
     i = fgetc(f)
     Print Chr(i);
   Wend
   Close #1

Differences from QB
   * None for returntype = 1
   * QBasic and 16-bit Visual Basic returned DOS file handle for 
     returntype = 2
   * returntype = 3 is new to FreeBASIC

See also
   * Open



--------------------------------------------------------- KeyPgFilecopy ----
FileCopy

Copies a file

Syntax
   Declare Function FileCopy ( ByVal source As ZString Ptr, ByVal 
   destination As ZString Ptr ) As Long

Usage
   #include "file.bi"
   FileCopy source, destination

or

   #include "file.bi"
   result = FileCopy( source, destination )

Parameters
   source
      A String argument specifying the filename of the file to copy from.  
      This file must exist.
   destination
      A String argument specifying the filename of the file to copy to.  
      This file will be overwritten if it exists.  This file should not be 
      currently referenced by any open file handles.

Return Value
   Returns 0 on success, or 1 if an error occurred.

Description
   Copies the contents of the source file into the destination file, 
   overwriting the destination file if it already exists.
   It is necessary to #include either "file.bi" or "vbcompat.bi" in order 
   to gain access to this function.

   The error code returned by FileCopy can be checked using Err in the next 
   line. The function version of  FileCopy returns directly the error code 
   as a 32 bit Long.

Example
   #include "file.bi"
   FileCopy "source.txt", "destination.txt"

Platform Differences
   * Linux requires the filename case matches the real name of the file. 
     Windows and DOS are case insensitive. 
   * Path separators in Linux are forward slashes /. Windows uses backward 
     slashes \ but it allows forward slashes.  DOS uses backward  slashes \
     . 

Differences from QB
   * New to FreeBASIC.  Existed in Visual Basic.

See also



----------------------------------------------------- KeyPgFiledatetime ----
FileDateTime

Returns the last modified date and time of a file as Date Serial 

Syntax
   Declare Function FileDateTime ( ByVal filename As ZString Ptr ) As Double

Usage
   #include "file.bi"
   result = FileDateTime( filename )

or

   #include "vbcompat.bi"
   result = FileDateTime( filename )

Parameters
   filename
      Filename to retrieve date and time for.

Return Value
   Returns a Date Serial.

Description
   Returns the file's last modified date and time as Date Serial.

Example
   #include "vbcompat.bi"

   Dim filename As String, d As Double

   Print "Enter a filename: "
   Line Input filename

   If FileExists( filename ) Then

     Print "File last modified: ";

     d = FileDateTime( filename )

     Print Format( d, "yyyy-mm-dd hh:mm AM/PM" )

   Else

     Print "File not found"

   End If

Platform Differences
   * Linux requires the filename case matches the real name of the file. 
     Windows and DOS are case insensitive. 
   * Path separators in Linux are forward slashes / . Windows uses 
     backward slashes \ but it allows forward slashes.  DOS uses backward 
     slashes \.

Differences from QB
   * New to FreeBASIC

See also
   * Date Serials



------------------------------------------------------- KeyPgFileexists ----
FileExists

Tests the existence of a file

Syntax
   Declare Function FileExists ( ByVal filename As ZString Ptr ) As Long

Usage
   #include "file.bi"
   result = FileExists( filename )

or

   #include "vbcompat.bi"
   result = FileExists( filename )

Parameters
   filename
      Filename to test for existence.

Return Value
   Returns non-zero (-1) if the file exists, otherwise returns zero (0).

Description
   FileExists tests for the existence of a file.
   Internally, it may issue an Open() and a Close() function, which may 
   have consequences - eg, any existing Lock(s) on the file may be 
   released.
   Depending on the exact requirements, alternative methods of checking for 
   file existence may be to use the Dir() function (being careful of 
   attributes and ensuring the path doesn't contain wildcards), or to try 
   Opening the file and checking the return value for success.

Example
   #include "vbcompat.bi"

   Dim filename As String

   Print "Enter a filename: "
   Line Input filename

   If FileExists( filename ) Then
     Print "File found: " & filename
   Else
     Print "File not found: " & filename
   End If

Platform Differences
   * Linux requires the filename case matches the real name of the file. 
     Windows and DOS are case insensitive. 
   * Path separators in Linux are forward slashes /. Windows uses backward 
     slashes \ but it allows for forward slashes.  DOS uses backward \ 
     slashes. 

Differences from QB
   * New to FreeBASIC

See also
   * Dir



-------------------------------------------------------- KeyPgFileflush ----
FileFlush

Flush application stream buffers to system, or system buffers to file

Syntax
   Declare Function FileFlush ( ByVal filenum As Long = -1, ByVal 
   systembuffers As Long = 0 ) As Long

Usage
   #include "file.bi"
   result = FileFlush()
   result = FileFlush( filenum )
   result = FileFlush( filenum, systembuffers )

Parameters
   filenum
      File number of bound file or device.  If not given, or -1, then flush 
      all open files.
   systembuffers
      If non-zero, flush system buffers to physical device.  Default is 
      zero (0).

Return Value
   Returns zero (0) for success or an error code if file buffers could not 
   be flushed.

Description
   FileFlush writes application buffered output to the underlying stream, 
   and if systembuffers is non-zero, to the underlying physical device as 
   well.

   In the form FileFlush(filenum), the application output buffer for a 
   specific file are written.  And in the form FileFlush, all application 
   buffers are written to the system.  Typically, when a file is opened, 
   the stream will be block buffered for binary and random files, and line 
   buffered for append and output files.  The FileFlush function overrides 
   the normal buffering of the application and immediately writes buffered 
   output to the system.  The system may have it's own buffers as well.

   In the form FileFlush(filenum,1), both the application buffer is flushed 
   and the underlying system buffer is flushed to physical device.  In the 
   form FileFlush(,1), all application buffers are flushed and all 
   underlying system buffers are flushed to physical device.

Example
   #include "file.bi"

   Dim As Long f1, f2
   Dim As String s

   Print "File length", "File string"

   f1 = FreeFile
   Open "fileflushtest.txt" For Output As #f1
   Print #f1, "successful file flush"

   f2 = FreeFile
   Open "fileflushtest.txt" For Input As #f2
   Line Input #f2, s
   Print FileLen("fileflushtest.txt"), "'" & s & "'"  '' the string is not yet physically written to the file

   FileFlush(f1)
   Line Input #f2, s
   Print FileLen("fileflushtest.txt"), "'" & s & "'"  '' the string is now physically written to the file

   Close #f2
   Close #f1

   Sleep
      
Output (Windows):

   File length   File String
    0            ''
    23           'successful file flush'
   		

Version
   * Since fbc 1.08.0

Differences from QB
   * New to FreeBASIC.

See also
   * Close



---------------------------------------------------------- KeyPgFilelen ----
FileLen

Finds the length of a file given its filename

Syntax
   Declare Function FileLen ( filename As String ) As LongInt

Usage
   #include "file.bi"
   result = FileLen(filename)

or

   #include "vbcompat.bi"
   result = FileLen(filename)

Parameters
   filename
      A String argument specifying the filename of the file whose length to 
      return.

Description
   Returns the size in bytes of the file specified by filename.

Example
   #include "file.bi"
   Dim length As LongInt
   length = FileLen("file.txt")

Platform Differences
   * Linux requires the filename case matches the real name of the file. 
     Windows and DOS are case insensitive. 
   * Path separators in Linux are forward slashes / . Windows uses 
     backward slashes \ but it allows for forward slashes .  DOS uses 
     backward  \ slashes. 

Differences from QB
   * New to FreeBASIC.  Existed in Visual Basic.

See also
   * LOF



------------------------------------------------------- KeyPgFileseteof ----
FileSetEof

Sets the length of a open file bound to a file number

Syntax
   Declare Function FileSetEof ( ByVal filenum As Long ) As Long

Usage
   #include "file.bi"
   result = FileSetEof(fnum)

Parameters
   filenum
      File number of bound file or device.

Return Value
   Returns zero (0) for success or an error code if the end of file (file 
   size) could not be set.

Description
   FileSetEof Sets the end of file based on the current file position.  
   File position as in Seek is one based.

   When the current file position is before the end of the file, the file 
   is truncated.  File contents before the the current file position are 
   kept, and file contents on or after the current file position are 
   deleted.  When the current position is beyond the end of file, the file 
   is extended with zero value bytes.  After FileSetEof completes, the 
   current file position is at the end of the file.

   To set a file having a length of N-bytes where the file is opened for 
   binary, output, or append, it is necessary to Seek to position N-bytes + 
   1.  To set a file having a length of N-records where the file is opened 
   for random, it is necessary to Seek to position N-records + 1.

Example
   #include "file.bi"

   '' create a zero length file
   Open "file.dat" For Binary As #1
   FileSetEof 1
   Close #1

   '' open same file and extend to 10000 bytes size
   Open "file.dat" For Binary As #1
   Seek #1, (10000 + 1)
   FileSetEof 1
   Close #1

   '' open same file and truncate to 5000 bytes size
   Open "file.dat" For Binary As #1
   Seek #1, (5000 + 1)
   FileSetEof 1
   Close #1

   '' clean-up
   Kill "file.dat"

Version
   * Since fbc 1.08.0

Differences from QB
   * New to FreeBASIC.

See also
   * EOF
   * LOF
   * Seek



-------------------------------------------------------------- KeyPgFix ----
Fix

Returns the integer part of a number, rounding towards zero

Syntax
   Declare Function Fix ( ByVal number As Single ) As Single
   Declare Function Fix ( ByVal number As Double ) As Double
   Declare Function Fix ( ByVal number As Integer ) As Integer
   Declare Function Fix ( ByVal number As UInteger ) As UInteger

Usage
   result = Fix( number )

Parameters
   number
      the floating-point number to truncate

Return Value
   Returns the integer part of number, rounding towards zero.

Description
   Equivalent to: Sgn(number) * Int(Abs(number)).  For example, Fix(1.3) 
   will return 1.0, and Fix(-4.9) will return -4.0.  For integer types, the 
   number is returned unchanged.

   Note: this function is also equivalent to number - Frac(number).

   The Fix unary Operator can be overloaded with user defined types.

Example
   Print Fix(1.9)  '' will print  1
   Print Fix(-1.9) '' will print -1 

Dialect Differences
   * In the -lang qb dialect, this operator cannot be overloaded.

Differences from QB
   * None

See also
   * Int
   * Frac
   * CInt
   * Operator



------------------------------------------------------------- KeyPgFlip ----
Flip

Changes the current video display page

Syntax
   Declare Function Flip ( ByVal frompage As Long = -1, ByVal topage As Long
   = -1 ) As Long

Usage
   Flip [ frompage ] [, topage ]

Parameters
   frompage
      previous page
   topage
      new page to display

Return Value
   Returns zero (0) if successful, or a non-zero error code to indicate a 
   failure.

Description
   In normal graphics mode, Flip is an alias for PCopy and ScreenCopy. See 
   ScreenCopy for details.

   In OpenGL mode, Flip does a hardware page flip and displays the contents 
   of the backbuffer. It is recommended that you call Flip regularly while 
   in OpenGL mode, otherwise your app may also become unresponsive.

   The error code returned by Flip can be checked using Err in the next 
   line. The function version of  Flip returns directly the error code as a 
   32 bit Long.

Example
   ScreenRes 320, 240, 32, 2    'Sets up the screen to be 320x240 in 32-bit color with 2 video pages.
   ScreenSet 1,0                'Sets the working page to 1 and the displayed page to 0

   For n As Integer = 50 To 270

      Cls
      Circle (n, 50),50 ,RGB(255,255,0) 'Draws a circle with a 50 pixel radius in yellow on page 1
      Flip 1,0    'Copies our circle from page 1 to page 0

      Sleep 25
   Next

   Print "Now wasn't that neat!"
   Print "Push any key."
   Flip 1,0    'Copies our text from page 1 to page 0
   Sleep

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Flip.

Differences from QB
   * New to FreeBASIC



-------------------------------------------------------------- KeyPgFor ----
For

Control flow statement, open statement clause, or operator depending on 
context.

Syntax
   For iterator = startvalue To endvalue [ Step increment ]
or
   Open [ device ] "filename" For filemode As #handle
or
   declare operator For ( byref stp as datatype )

Example
   See example at For...Next.

See also
   * For...Next
   * Open
   * Operator

   


---------------------------------------------------------- KeyPgFornext ----
For...Next

Control flow statement for looping

Syntax
   For iterator [ As datatype ] = startvalue To endvalue [ Step stepvalue ]
      [ statement block ]
   Next [ iterator ]

Parameters
   iterator
      a variable identifier that is used to iterate from an initial value 
      to an end value
   datatype
      If specified, the variable iterator will automatically be declared 
      with the type datatype
   startvalue
      an expression that denotes the starting value of the iterator
   endvalue
      an expression used to compare with the value of the iterator
   stepvalue
      an expression that is added to the iterator after every iteration

Description
   A For...Next loop initializes iterator to startvalue, then executes the 
   statement block, incrementing iterator by stepvalue until it exceeds 
   endvalue. If stepvalue is not explicitly given it will set to 1.

   The values of stepvalue and endvalue are stored internally immediately 
   following execution of the For statement and thus neither can be changed 
   inside the For loop.  Comparison operators such as < and > will not be 
   effective as stepvalue or endvalue because the expressions will not be 
   re-evaluated while the loop is running. (The results of the expressions 
   used to define them may be changed, but these changes will not affect 
   the execution of the For loop.) See examples.

   Note: In some dialects, the temporary variables holding stepvalue and 
   endvalue go out of scope at the end of the loop, and their values are 
   not guaranteed to remain unchanged once any code following the loop has 
   been executed.  For this reason, it is recommended never to branch out 
   of a For...Next loop (using Goto or similar), and then jump back into 
   the middle of it later when in the -lang fb or -lang deprecated dialect.

   The iterator must be an intrinsic scalar: only Static/Shared variables 
   and local variables can be used; no other kind can be used, including 
   array elements, UDT members, ByRef parameters or any kind of 
   dereferenced address.

   The iterator may be defined having the same scope as the For statement 
   by using the As datatype syntax.  With this syntax, iterator is created 
   and destroyed within the For...Next scope. See dialect differences 
   below.

   If endvalue is less than startvalue then a negative stepvalue must be 
   specified or the statement block will not execute at all, since 
   startvalue compares greater than endvalue.

   The For statement causes the execution of the statements in the 
   statement block until iterator compares greater than endvalue (or less 
   than endvalue if stepvalue < 0). iterator will be incremented the amount 
   of stepvalue following each execution of the statement block. If an 
   increment is not given, iterator will be implicitly incremented by 1.

   If an Exit For statement is encountered inside the statement block, the 
   loop is terminated, and execution resumes immediately following the 
   enclosing Next statement. If a Continue For statement is encountered, 
   the rest of the statement block is skipped until the block's 
   corresponding Next statement.  The counter's value is incremented and 
   the loop restarted if it is still within the bounds given by endvalue.

   Note: for integer data types, it is not possible to loop up to the 
   highest possible value (or down to the lowest possible value) that can 
   be stored in the variable type, because the loop only breaks when the 
   incremented variable exceeds endvalue, which can never happen.  For 
   example, if you try to iterate an variable from 0 to 255, the loop will 
   only break once the variable reaches 256 or more.  Using a UByte 
   variable for the counter wouldn't work, because although it can hold the 
   numbers 0 to 255, it cannot hold 256.  See Standard Data Type Limits to 
   find the upper and lower limits for the standard data types.

   Like all control flow statements, the For statement can be nested, that 
   is, it can be used in a statement block of another For statement.

   For, Next, and Step are operators that can be overloaded inside user 
   defined types. See Operator For, Operator Next, Operator Step

Example
   Print "counting from 3 to 0, with a step of -0.5"
   For i As Single = 3 To 0 Step -0.5
      Print "i is " & i
   Next i

   Dim As Integer i, j, k, toTemp, stepTemp
   j = 9: k = 1

   For i = 0 To j Step k
      
      j = 0: k = 0 '' Changing j and k has no effect on the current loop.
      Print i;
      
   Next i
   Print

   ' Internally, this is what the above example does:
   j = 9: k = 1

   i = 0: toTemp = j: stepTemp = k
   Do While IIf(stepTemp >= 0, i <= toTemp, i >= toTemp)
      
      j = 0: k = 0 '' Changing j and k has no effect on the current loop.
      Print i;
      
      i += stepTemp
   Loop
   Print

Example of infinite For...Next loop in case of loop up to the highest value 
of an Ubyte iterator (255):
   For ub As UByte = 240 To 255 '' Infinite loop because the end criterion value (255+1=256) can never be reached by the UByte iterator
      Print ub
      If Inkey <> "" Then Exit For
      Sleep 10
   Next ub
The same applies to lowest value of an UByte iterator (0) in case of loop 
down (negative stepvalue).

Dialect Differences
   * In the -lang fb and -lang deprecated dialects, variables declared 
     inside a For..Next block are visible only inside the block, and cannot 
     be accessed outside it. To access duplicated symbols defined as global 
     outside this block, add one or preferably two dot(s) as prefix: .
     SomeSymbol or preferably ..SomeSymbol (or only ..SomeSymbol if inside 
     a With..End With block).
   * In the -lang qb and -lang fblite dialects, variables declared inside 
     a For..Next block (including the counter if declared, and any 
     temporary variables used to hold endvalue or stepvalue), have a 
     procedure-wide scope  as in QB

Differences from QB
   * ByRef arguments cannot be used as counters.

See also
   * Continue
   * Do...Loop
   * Exit



----------------------------------------------------------- KeyPgFormat ----
Format

Formats a number in a specified format

Syntax
   Declare Function Format ( ByVal numerical_expression As Double, ByRef 
   formatting_expression As Const String = "" ) As String

Usage
   #include "string.bi"
   result = Format[$]( numerical_expression, formatting_expression )

Parameters
   numerical_expression
      number to format
   formatting_expression
      formatting pattern

Return Value
   Format returns a string with the result of the numerical expression 
   formatted as indicated in the formatting expression.
   The formatting expression is a string that can yield numeric or 
   date-time values.

Description
   To recover meaningful date-time values the numerical expression must be 
   a date serial obtained from the appropriate functions.
   This function is part of FreeBASIC, however it is not recognized by the 
   compiler unless vbcompat.bi is included.

   "Numeric Formats"
         +--------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
         |Symbol                    | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
         | Null string              | General format (no formatting)                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
         |0                         | Digit placeholder: If the number has fewer digits than there are           zeros (on either side of the decimal) in the format expression, leading or trailing zeros are displayed. If there are more digits to the right of the decimal than zeros in the format, the number is rounded. If there are more digits to the left of the decimal than zeros in the format the digits are all displayed                                                                                      |
         | #                        | Digit placeholder: Follows the same rules as for the 0 digit except the leading or trailing zeros are not displayed                                                                                                                                                                                                                                                                                                                                                                      |
         |.                         | Placeholder for decimal point.If the format contains only #'s to the left of . then numbers smaller than 1  are begun with a decimal point.                                                                                                                                                                                                                                                                                                                                              |
         | %                        | Percentage :The expression is multiplied by 100 and the % character is inserted.                                                                                                                                                                                                                                                                                                                                                                                                         |
         |,                         | Thousands separator. Two adjacent commas, or a comma immediately to the left of the decimal point location (whether there is a decimal specified or not) means 'Omit the three digits that fall between these  commas, or between the comma and the decimal point, rounding as needed.'                                                                                                                                                                                                  |
         | E- E+ e- e+              |Scientific format: If a format contains one digit placeholder (0 or #) to the right of an E-, E+, e-, or e+, the number is displayed in scientific  format and an E or e is inserted between the number and its exponent.The number of 0's or #'s to the right determines the number of digits in the exponent. Use E- or e- to place a minus sign next to negative exponents. Use a E+ or e+ to place a minus sign next to negative exponents and a plus sign next to positive exponents.|
         | : ? + $ () space         |   Display literal character  To display a character other than one of these, precede the character with a backslash (\) or enclose the character(s) in double quotation marks                                                                                                                                                                                                                                                                                                            |
         |\                         | Display next character in format string as it is                                                                                                                                                                                                                                                                                                                                                                                                                                         |
         |text between double quotes|  Displays the text inside the double quotes.                                                                                                                                                                                                                                                                                                                                                                                                                                             |
         | :                        | Time separator is used to separate hours, minutes, and seconds when time values are formatted.                                                                                                                                                                                                                                                                                                                                                                                           |
         | /                        | The date separator is used to separate day,month, and year when date values are formatted.                                                                                                                                                                                                                                                                                                                                                                                               |
         +--------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

   "Date-Time formats:"
         +----------------------+------------------------------------------------------------------------------------------------------------------------------------------------------+
         |Symbol                | Description                                                                                                                                          |
         |d, dd                 | Display the day as a one-digit/two-digit number (1-31/01-31)                                                                                         |
         |ddd                   | Display the day as an abbreviation (Sun-Sat)                                                                                                         |
         |dddd                  | Display the day as a full name (Sunday-Saturday)                                                                                                     |
         |ddddd                 |  Display a serial date number as a complete date (including day, month and year)                                                                     |
         |m, mm                 | Display the month as a one-digit/two-digit number (1-12/01-12).  If immediately following h or hh, the minute rather than the month is displayed     |
         |M, MM                 | Display the month as a one-digit/two-digit number (1-12/01-12), even if immediately following h or hh                                                |
         |mmm                   | Display the month as an abbreviation (Jan-Dec)                                                                                                       |
         |mmmm                  | Display the month as a full name (January-December)                                                                                                  |
         |y, yy                 | Display the year as a two-digit number (00-99)                                                                                                       |
         |yyyy                  | Display the year as a four-digit number (1900-2040)                                                                                                  |
         |h, hh                 | Display the hour as a one-digit/two-digit number (0-23/00-23)                                                                                        |
         |m, mm                 | Display the minute as a one-digit/two-digit number (0-59/00-59).  If not immediately following h or hh, the month rather than the minute is displayed|
         |n, nn                 | Display the minute as a one-digit/two-digit number (0-59/00-59), even if not immediately following h or hh                                           |
         |s, ss                 | Display the second as a one-digit/two-digit number (0-59/00-59)                                                                                      |
         |ttttt                 | Display a time serial number as a complete time, including hour, minute and second                                                                   |
         |AM/PM (Default), am/pm| Use the 12-hour clock displaying AM or am with any hour before noon, PM or pm with any hour between noon and 11:59                                   |
         |A/P, a/p              |  Use the 12-hour clock displaying A or a with any hour before noon, P or p with any hour between noon and 11:59                                      |
         +----------------------+------------------------------------------------------------------------------------------------------------------------------------------------------+

   The representation of time and date separators may be determined from 
   the operating system if regional or localized settings are supported by 
   the target platform.  This determination is made at run-time so that 
   output may be localized to the system the program is running on.

Example
Numeric formats
   #include "string.bi"

   Dim As Double numberVal(...) = {5, -5, .5}
   Dim As String formatStr(...) = {"","0","0.00","#,##0","#,##0.00","0%", "0.00%", "0.00E+00", "0.00E-00"}

   ? "Format string",, Str(numberVal(0)), Str(numberVal(1)), Str(numberVal(2))
   ?
   For iFormat As Integer = 0 To UBound(formatStr)
      ? formatStr(iFormat),,
      For iNumber As Integer = 0 To UBound(numberVal)
         ? Format(numberVal(iNumber), formatStr(iFormat)),
      Next
      ?
   Next

Output:

   Format String               5             -5            0.5

   '                           5             -5            .5            
   0                           5             -5            0             
   0.00                        5.00          -5.00         0.50          
   #,##0                       5             -5            0             
   #,##0.00                    5.00          -5.00         0.50          
   0%                          500%          -500%         50%           
   0.00%                       500.00%       -500.00%      50.00%        
   0.00E+00                    5.00E+00      -5.00E+00     5.00E-01      
   0.00E-00                    5.00E00       -5.00E00      5.00E-01      

Example
Date and time formats
   #include "vbcompat.bi"

   Dim As Double dateTimeVal = DateValue("12/05/1958") + TimeValue("20:50:35")
   Dim As String formatStr(...) = {"yyyy-mm-dd","d-mmmm-yy","d-mmm","mmmm-yyyy","h:mm AM/PM","h:mm:ss AM/PM","h:mm","h:mm:ss","m/d/yy h:mm"}

   ? "Format",, "Display"
   ?
   For iFormat As Integer = 0 To UBound(formatStr)
      ? formatStr(iFormat),, Format(dateTimeVal, formatStr(iFormat))
   Next

Output:

   Format                      Display

   yyyy-mm-dd                  1958-12-05
   d-mmmm-yy                   5-December-58
   d-mmm                       5-Dec
   mmmm-yyyy                   December-1958
   h:mm AM/PM                  8:50 PM
   h:mm:ss AM/PM               8:50:35 PM
   h:mm                        20:50
   h:mm:ss                     20:50:35
   m/d/yy h:mm                 12/5/58 20:50

Dialect Differences
   None

Differences from QB
   * Does not exist in QB 4.5. This function appeared first in PDS 7.1

See also
   * Print Using
   * ? Using
   * Str



------------------------------------------------------------- KeyPgFrac ----
Frac

Returns the decimal part of a number

Syntax
   Declare Function Frac ( ByVal number As Double ) As Double
   Declare Function Frac ( ByVal number As Integer ) As Integer
   Declare Function Frac ( ByVal number As UInteger ) As UInteger

Usage
   result = Frac( number )

Parameters
   number
      the number or expression to get the fraction part of.

Return Value
   Returns the fractional part of a number or expression.

Description
   Equivalent to: (number - Fix(number)).
   For example, Frac(4.25) will return 0.25, and Frac(-1.75) will return 
   -0.75.  For integer types, the value 0 is always returned.

   The Frac unary Operator can be overloaded with user defined types.

Example
   Print Frac(10.625)  '' will print  0.625
   Print Frac(-10.625) '' will print -0.625 

Dialect Differences
   * In the -lang qb dialect, this operator cannot be overloaded.

Differences from QB
   * New to FreeBASIC

See also
   * Fix
   * Operator



-------------------------------------------------------------- KeyPgFre ----
Fre

Returns the amount of free memory available

Syntax
   Declare Function Fre ( ByVal value As Long = 0 ) As UInteger

Usage
   result = Fre( [ value ] )

Parameters
   value
      Unused dummy parameter kept for backward compatibility; can be 
      ignored.

Return Value
   Returns the amount of free memory, in bytes.

Description
   Returns the free memory (ram) available, in bytes.

Example
   Dim mem As UInteger = Fre

   Print "Free memory:"
   Print
   Print mem; " bytes"
   Print mem  \ 1024; " kilobytes"
   Print mem  \ (1024 * 1024); " megabytes"

Differences from QB
   * The "value" argument is not checked, Fre will always return the free 
     physical memory available

See also
   * Dim
   * ReDim
   * Allocate



--------------------------------------------------------- KeyPgFreefile ----
FreeFile

Returns a free file number

Syntax
   Declare Function FreeFile ( ) As Long

Usage
   result = FreeFile

Return Value
   The next available file number, if any, otherwise zero (0).

Description
   Returns the number of the next free file number with valid values 1 to 
   255, or 0 if there are already 255 files opened. This value is a 
   required argument to Open a file. FreeFile is useful when opening files 
   in complex programs where the programmer can't keep track of the used 
   file numbers.

   Make sure to always close files when no longer needed, otherwise you 
   will get a file number leak, and won't be able to open any files anymore 
   after 255 filenumbers are exhausted while your program is running.

   FreeFile will always return the smallest free file number. The file 
   number returned by FreeFile will not change until that file number is 
   Opened, or until a smaller file number is Closed:
      - For this reason, it is wise to use FreeFile immediately before its 
      corresponding Open, to ensure that the same file number is not 
      returned and opened elsewhere first.
      - In case of potential conflict with other threads, this non-breaking 
      'FreeFile...Open' sequence must additionally be considered as a 
      critical section of code and therefore must be protected, for example 
      by mutual exclusion (using a mutex locking).

Example
   ' Create a string and fill it.
   Dim buffer As String, f As Long
   buffer = "Hello World within a file."

   ' Find the first free file number.
   f = FreeFile

   ' Open the file "file.ext" for binary usage, using the file number "f".
   Open "file.ext" For Binary As #f

   ' Place our string inside the file, using file number "f".
   Put #f, , buffer

   ' Close the file.
   Close #f

   ' End the program. (Check the file "file.ext" upon running to see the output.)
   End

   When using multiple FreeFile statements, FreeFile should be used 
   immediately before the Open statement:
   Dim As Long fr, fs
   ' The CORRECT way:
   fr = FreeFile
   Open "File1" For Input As #fr

   fs = FreeFile
   Open "File2" For Input As #fs

   As opposed to:
   Dim As Long fr, fs
   ' The WRONG way:
   fr = FreeFile
   fs = FreeFile '' fs has taken the same file number as fr

   Open "file1" For Input As #fr
   Open "file2" For Input As #fs '' error: file number already opened

Platform Differences
   * On Windows, a file number used in a dynamic link library is not the 
     same as an identical file number used in the main program.  File 
     numbers can not be passed or returned and then used between a DLL and 
     an executable.
   * Besides FreeBASIC's limit of 255 files per program opened at same 
     time, there is an OS limit of total amount of opened files, but 
     usually you won't touch it except in DOS, where the limit may be as 
     low as 15 files total.

Differences from QB
   * None

See also
   * Open
   * Put (File I/O)
   * Get (File I/O)
   * FileAttr



--------------------------------------------------------- KeyPgFunction ----
Function

Defines a procedure returning a value

Syntax
   [Public|Private] Function identifier [cdecl|pascal|stdcall] [Overload] [
   Alias external_identifier] [([parameter_list])] [ ByRef ] As return_type 
   [Static] [Export]
      statements
      ...
      { {Return [return_value]}|{Function = return_value}|{identifier = 
      return_value} }
      ...
   End Function

Parameters
   identifier: the name of the function
   external_identifier: externally visible (to the linker) name enclosed in 
   quotes
   parameter_list: parameter[, parameter[, ...]]
   parameter: [ByRef|ByVal] identifier [As type] [= default_value]
      identifier: the name of the variable referenced in the function.  If 
      the argument is an array then the identifier must be followed by an 
      empty parenthesis. 
      type: the type of variable
      default_value: the value of the argument if none is specified in the 
      call (default_value can be a literal, or a constant, or a shared 
      variable)
   return_type: the type of variable returned by the function
   statements: one or more statements that make up the function body
   return_value: the value returned from the function

Description
   A function defines a block of code which can be executed with a single 
   statement (a function call), and provide a value back to the caller when 
   finished (a return value). 	There are several reasons to use functions:
   * Reduces redundancy in your program
   * Enables reuse of code in many programs
   * Improves readability of the program
   * Improves maintainability of the program
   * Makes it easy to extend your program

   Access Rights : The Public and Private keywords specify public or 
   private intra module-level access rights, respectively. If neither is 
   given, the function defaults to public access (Public).

   Calling Convention : Calling convention, or the order in which arguments 
   are pushed and popped from the stack during function calls, is specified 
   with the cdecl, pascal and stdcall keywords. If none is given, the 
   function uses the standard convention by default (stdcall).

   Passing Arguments : Functions may receive one or more variables, or 
   arguments, when called. These arguments are listed as parameters in the 
   parameter_list. The ByRef and ByVal keywords specify whether the 
   argument will be passed by reference or by value, respectively. The 
   argument's type is given by "As type" following the parameter. If a 
   parameter in the declaration is given a default value, the parameter is 
   optional.  Array parameters are specified by following an identifier 
   with an empty parenthesis.  Note that array parameters are always ByRef 
   and the ByRef keyword is neither required nor allowed for array 
   parameters.  When calling a function with an array argument the 
   parenthesis must be supplied there too; see the examples.

   Overloaded Functions : An overloaded function may share the same name (
   identifier) as another with a different signature. The Overload keyword 
   specifies that a function may be overloaded. A function must be defined 
   - or declared - using the Overload keyword prior to any functions that 
   overload them.

   Returning values : return_type specifies the data type returned by a 
   function upon exit. If no data type is specified, then the function will 
   return the default data type, which will be Integer unless set to 
   another data type using DefSng, DefDbl, DefStr, etc. Functions can 
   return values using three methods: the Return keyword followed by a 
   value exits the function immediately, and returns that value to the 
   caller. Functions can also return values by assigning the Function 
   keyword or the function's identifier to the desired return value (but 
   Function keyword or function's identifier does not allow to evaluate the 
   current assigned value). The latter two methods do not cause the 
   function to exit, however. Return keyword mixed with Function= keyword 
   or function's identifier= or Exit Function keyword in a same function is 
   unsupported when returning objects with constructors. Since functions 
   return values, function calls evaluate to expressions. Thus, function 
   calls can be made wherever an expression is expected, like in Assignments
   or If statements. Functions can also return references by specifying 
   Byref As return_type.
   Warning: Whatever the output branch used, the return value must be 
   always defined, otherwise an unexpected behavior may occur.

   Local Variable Preservation : The Static keyword specifies that a 
   function's locally declared variables are preserved between function 
   calls. Upon entering a function defined with Static, local variables 
   have the same value as when the function was last called.

   Global Variable Access: To access duplicated symbols defined as global 
   outside the function body, add one or preferably two dot(s) as prefix: .
   SomeSymbol or preferably ..SomeSymbol (or only ..SomeSymbol if inside a 
   With..End With block).

   When calling a function, parentheses surrounding the argument list (if 
   any) are required only for function calls in expressions. If there is no 
   argument to pass, the parentheses become optional, but it is a common 
   convention to place empty parentheses '()' after the function name, to 
   signify a function call.

   Warning for 64-bit compiler only: See the Identifier Rules page for the 
   choice of user procedure identifier names (and specially the 'Platform 
   Differences' paragraph).

Example

   '' This program demonstrates the declaration of a function 
   '' and returning a value using Return command

   Declare Function ReturnTen () As Integer

   Print ReturnTen () '' ReturnTen returns an integer by default.

   Function ReturnTen() As Integer
      Return 10
   End Function

   '' This program demonstrates the declaration of a function 
   '' and returning a value using assignment to function name

   Declare Function ReturnTen () As Integer

   Print ReturnTen () '' ReturnTen returns an integer by default.

   Function ReturnTen() As Integer
      ReturnTen = 10
   End Function

   '' This program demonstrates function overloading.

   '' The overloaded functions must be FIRST.
   Declare Function ReturnTen Overload (a As Single) As Integer
   Declare Function ReturnTen Overload (a As String) As Integer
   Declare Function ReturnTen (a As Integer) As Integer

   Print ReturnTen (10.000!) '' ReturnTen will take a single and return an integer
   Print ReturnTen (10)      '' ReturnTen will take an integer and return an integer
   Print ReturnTen ("10")    '' ReturnTen will take a string and return an integer

   Function ReturnTen Overload (a As Single) As Integer
      Return Int(a)
   End Function

   Function ReturnTen Overload (a As String) As Integer
      Return Val(a)
   End Function

   Function ReturnTen (a As Integer) As Integer
      Return a
   End Function

   '' The following example demonstrates optional parameters.

   Function TestFunc(P As String = "Default") As String
      Return P
   End Function

   Print TestFunc("Testing:")
   Print TestFunc

   '' This example shows how to declare and call 
   '' functions taking array arguments.

   Function x(b() As Double) As Integer
     x = UBound(b)-LBound(b)+1
   End Function

   Dim a(1 To 10) As Double
   Print x(a())
   Dim c(10 To 20) As Double 
   Print x(c())

Dialect Differences
   * In the -lang fb dialect, ByVal is the default parameter passing 
     convention for all built-in types except String; String and 
     user-defined Types are passed ByRef by default.
   * In the -lang qb and -lang fblite dialects, ByRef is the default 
     parameter passing convention.
   * In the -lang qb dialect, the name of the function must be used in an 
     assignment to specify the return value.  Using Function = ..." to 
     specify the return value may not be used.
   * In the -lang qb and -lang fblite dialects, Return may only be used to 
     return a value when Option Gosub is off.  In -lang qb, this must be 
     done explicitly using the Option Nogosub statement.

Differences from QB
   * Parameters can be optional in FreeBASIC.
   * In QBASIC, the return type could only specified with a suffix, not 
     with AS TYPE, and only allowed functions to return a built-in type.
   * Return value can now be specified by a Return statement.
   * Function Overloading is supported in FreeBASIC.
   * The return value of functions can be ignored in the calling code.

See also
   * Sub
   * Exit
   * Return (From Procedure)
   * Declare
   * Public
   * Private



--------------------------------------------------- KeyPgMemberFunction ----
Function (Member)

Declares or defines a member procedure returning a value

Syntax
   { Type | Class | Union } typename
      Declare [ Static | Const ] Function fieldname [calling convention 
      specifier] [ Alias external_name ] ( [ parameters ] ) [ ByRef ] As 
      datatype [ Static ]
   End { Type | Class | Union }

   Function typename.fieldname ( [ parameters ] ) [ ByRef ] As datatype [ 
   Export ]
      statements
   End Function

Parameters
   typename 
      name of the Type, Class, or Union
   fieldname 
      name of the procedure
   external_name
      name of field as seen when externally linked
   parameters 
      the parameters to be passed to the procedure
   calling convention specifier	
      can be one of: cdecl, stdcall or pascal

Description
   Function members are accessed with Operator . (Member Access) or 
   Operator -> (Pointer To Member Access) to call a member procedure that 
   returns a value (a reference can also be returned by specifying Byref As 
   return_type).  The procedure may optionally accept parameters either 
   ByVal or ByRef.  typename be overloaded  without explicit use of the 
   Overload keyword.

   typename is the name of the type for which the Function method is 
   declared and defined.  Name resolution for typename follows the same 
   rules as procedures when used in a Namespace.

   A hidden This parameter having the same type as typename is passed to 
   non-static member procedures.  This is used to access the fields of the 
   Type, Class, or Union.
   To access duplicated symbols defined as global outside the Type, add one 
   or preferably two dot(s) as prefix: .SomeSymbol or preferably ..
   SomeSymbol (or only ..SomeSymbol if inside a With..End With block).

   A Static (Member) may be declared using the Static specifier.  A 
   Const (Member) may be declared using the Const specifier.

   As for a normal Function, the return value of a Function member can be 
   ignored in the calling code.

Example
   #include "vbcompat.bi"

   Type Date

     value As Double

     Declare Static Function Today() As Date

     Declare Function Year() As Integer
     Declare Function Month() As Integer
     Declare Function Day() As Integer

   End Type

   Function Date.Today() As Date
     Return Type(Now())
   End Function

   Function Date.Year() As Integer
     Return ..Year(value)
   End Function

   Function Date.Month() As Integer
     Return ..Month(value)
   End Function

   Function Date.Day() As Integer
     Return ..Day(value)
   End Function

   Dim d As Date = Date.Today

   Print "Year  = "; d.Year
   Print "Month = "; d.Month
   Print "Day   = "; d.Day

Dialect Differences
   * Only available in the -lang fb dialect.

See also
   * Class
   * Function
   * Sub (Member)
   * Type



------------------------------------------------------ KeyPgFunctionPtr ----
Function Pointer

Data type that stores a pointer to a Function procedure returning a value

Syntax
   Dim variable As Function [cdecl|pascal|stdcall] [( [parameter_list] )] [ 
   ByRef ] [As return_type] [= initializer]

Parameters
   parameter_list: parameter[, parameter[, ...]]
   parameter: [ByRef|ByVal] identifier [As type] [= default_value]
      identifier: the name of the variable referenced in the function
      type: the type of variable
      default_value: the value of the argument if none is specified in the 
      call
   return_value: the value returned from the function
   intializer: address of a function to set as the initial value

Description
   A Function pointer is a procedure pointer that stores the memory 
   location of compiled code that returns a value.  If no intializer is 
   given the default initial value is zero (0).

   The memory address for the Function procedure can be assigned to the 
   variable by taking the address of a function with ProcPtr or 
   Operator @ (Address Of).

   The procedure must match the same Function declaration as the declared 
   Function pointer.

   To call the function assigned, use the variable name as if it were a 
   normal declared Function, always with parentheses around the parameter 
   list even empty (without parentheses, only the pointer value, ie the 
   address of the function, would be accessed).

   One of the primary uses for Function pointers is to create callback 
   procedures:
      - A callback Function is a Function that is passed through an 
      argument (a Function pointer) to another procedure which is expected 
      to call back (execute) the "argument" at a convenient time.
      - If the callback Function is completely executed before the 
      invocation returns to the caller code, then the callback process is 
      said to be "synchronous".
      - If the invocation immediately returns to the caller code, and the 
      callback Function and the caller's next code are running in parallel, 
      then the callback process is said to be "asynchronous".

Example
   Function ConcatSelf( x As String ) As String
      Return x & x
   End Function

   Dim x As Function( x As String ) As String = ProcPtr( ConcatSelf )

   Print x( "Hello" )

   Function x2 (ByVal i As Integer) As Integer
     Return i * 2
   End Function

   Function x3 (ByVal i As Integer) As Integer
     Return i * 3
   End Function

   Function operation (ByVal i As Integer, ByVal op As Function (ByVal As Integer) As Integer) As Integer
     Return op(i)
   End Function

   Print operation(4, @x2)
   Print operation(4, @x3)

   ' Example of basic callback Function mechanism (asynchronous) to implement a key pressed event:
   ' (the user callback Function address cannot be modified while the event thread is running)
   '   - An asynchronous thread tests the keyboard in a loop, and calls a user callback Function each time a key is pressed.
   '   - The callback Function address is passed to the thread.
   '   - The callback Function prints the character of the key pressed,
   '       but if the key pressed is <escape> it orders the thread to finish by using the function return value.
   '   - As the user callback address is passed to the thread as argument, it cannot be modified while the thread is running.

   '' thread Sub definition
     Sub threadInkey (ByVal p As Any Ptr)
      If p > 0 Then                                                '' test condition callback Function defined
        Dim As Function (ByRef As String) As Integer callback = p  '' convert the any ptr to a callback Function pointer
        Do
         Dim As String s = Inkey
         If s <> "" Then                                          '' test condition key pressed
           If callback(s) Then                                    '' test condition to finish thread
            Exit Do
           End If
         End If
         Sleep 50, 1
        Loop
      End If
     End Sub

   '' user callback Function definition
     Function printInkey (ByRef s As String) As Integer
      If Asc(s) = 27 Then                                        '' test condition key pressed = <escape>
        Print
        Return -1                                                '' order thread to finish
      Else
        Print s;
        Return 0                                                 '' order thread to continue
      End If
     End Function

   '' user main code
     Dim As Any Ptr p = ThreadCreate(@threadInkey, @printInkey)   '' launch the thread, passing the callback Function address
     ThreadWait(p)                                                '' wait for the thread finish

Differences from QB
   * New to FreeBASIC

See also
   * Function
   * ProcPtr
   * Operator @ (Address Of)




============================================================================
    G

------------------------------------------------------ KeyPgGetgraphics ----
Get (Graphics)

Gets a copy of a portion of the current work page or an image buffer

Syntax
   Get [source,] [STEP](x1, y1) - [STEP](x2, y2), dest

Parameters
   source
      the address of an image buffer. If it's omitted, the current work 
      page is copied.
   STEP
      indicates that the following co-ordinates are not absolute 
      co-ordinates.
   [STEP](x1, y1)
      co-ordinates of the upper-left corner of the sub-image to copy.  STEP 
      indicates that (x1, y1) offsets are relative to the current graphics 
      cursor position.
   [STEP](x2, y2)
      co-ordinates of the lower-right corner of the sub-image to copy.  
      STEP indicates that x2 and y2 are relative to x1 and y1, 
      respectively.
   dest
      the address of a previously allocated buffer to store the image data.

Description
   Get copies a rectangular portion of the current work page specified by 
   the co-ordinates (x1,  y1) and (x2,  y2), which represent the upper-left 
   and lower-right corners of the rectangle, respectively. STEP specifies 
   that the upper-left co-ordinates are relative to the current graphics 
   pen location, and/or that the lower-right co-ordinates are relative to 
   the upper-left co-ordinates. The new image buffer is formatted to match 
   the current screen mode pixel format.

   dest can be an address, an array (name not followed by empty 
   parentheses), or a reference to the first element in an array that will 
   receive the new image buffer. This memory must be sufficiently allocated 
   to hold the image buffer (the number of bytes required varies with the 
   -lang dialect used to compile the program). Valid image buffers can be 
   created simply by using preferably the ImageCreate statement.

   source can be an address, an array (name not followed by empty 
   parentheses), or a reference to the first element in an array that holds 
   an image buffer to retrieve a portion of. x1,  y1, x2,  y2, Step and 
   dest have the same meaning in this case.

   The co-ordinates of the rectangle are affected by the most recent Window 
   and View (Graphics) statements, and must both be within the current 
   clipping region set by View (Graphics) (or within the default viewport), 
   otherwise an illegal function call runtime error will be triggered, and 
   the function will have no effect.

Runtime errors:
   Get throws one of the following runtime errors:

   (1) Illegal function call
      * dest is an array, but is not big enough to hold the image buffer.
      * The upper-left or lower-right co-ordinates of the rectangle are 
        outside the current clipping region (set or default). See 
        View (Graphics).

Dialect Differences
   There are 2 types of buffers (details see GfxInternalFormats) depending 
   from FB dialect used:

   * In the -lang fb dialect, dest receives a new-style image buffer, 
     which consists of a 32-byte image header followed by pixel data which 
     is row-padded to the next paragraph boundary (16 bytes). Use the 
     following formula to calculate the total size, in bytes, required to 
     store the image buffer, where w and h are the respective width and 
     height of the rectangular portion of the current work page or source 
     image buffer, and bpp is the number of bytes per pixel of the current 
     screen mode:
      size = 32 + (((w * bpp + &hF) and not &hF) * h)

   * In the -lang qb and -lang fblite dialects, dest receives a QB-style 
     image buffer, which consists of a 4-byte image header followed by 
     pixel data which is not row-padded. Use the following formula to 
     calculate the total size, in bytes, required to store the image 
     buffer, where w and h are the respective width and height of the 
     rectangular portion of the current work page or source image buffer, 
     and bpp is the number of bytes per pixel of the current screen mode:
      size = 4 + (w * h * bpp)

Example
   #include Once "fbgfx.bi"

   '' Setup a 400x300 32bit screen
   ScreenRes 400, 300, 32

   '' First draw funny stuff...
   Line (10,10)-(140,30), RGB(255,255,0), bf
   Draw String (30, 20), "Hello there!", RGB(255,0,0)

   '' Now capture a 150x50 block from the top-left of the screen into an image
   '' buffer with GET...
   Dim As fb.Image Ptr image = ImageCreate(150, 50)
   Get (0,0)-(150-1,50-1), image

   '' And duplicate it all over the place!
   Put (0,50), image
   Put (0,100), image
   Put (0,150), image
   Put (0,200), image
   Put (0,250), image
   Put (150,0), image
   Put (150,50), image
   Put (150,100), image
   Put (150,150), image
   Put (150,200), image
   Put (150,250), image

   ImageDestroy(image)

   '' And a frame around a whole screen..
   Line (0,0)-(400-1,300-1), RGB(255,255,0), b

   '' Now get the whole screen...
   Dim As fb.Image Ptr big = ImageCreate(400, 300)
   Get (0,0)-(400-1,300-1), big

   '' And display that "screenshot" as if it was scrolling by...
   Dim As Integer x = -350
   While ((Inkey() = "") And (x < 350))
      ScreenLock
         Cls
         Put (x,0), big
      ScreenUnlock

      Sleep 100, 1

      x += 10
   Wend

   ImageDestroy(big)

See also
   * Put (Graphics)
   * ImageCreate
   * Get (File I/O)
   * Screen (Graphics)
   * Window
   * View (Graphics)
   * Internal graphics formats



-------------------------------------------------------- KeyPgGetfileio ----
Get (File I/O)

Reads data from a file to a buffer

Syntax
   Get #filenum As Long, [position As LongInt], ByRef data As Any [, [
   amount As UInteger] [, ByRef bytesread As UInteger] ]
   Get #filenum As Long, [position As LongInt], data As String [, , ByRef 
   bytesread As UInteger ]
   Get #filenum As Long, [position As LongInt], data() As Any [, , ByRef 
   bytesread As UInteger ]

Usage
   Get #filenum, position, data [, [amount] [, bytesread ] ]
   varres = Get (#filenum, position, data [, [amount] [, bytesread ] ] )

Parameters
   filenum
      The value passed to Open when the file was opened.
   position
      The position where the read must start. If the file was opened 
      For Random, the position is in records; otherwise, it is in bytes. If 
      omitted, reading starts at the present file pointer position.  The 
      position is 1-based: i.e. first record or byte of a file is at 
      position 1.
      If position is omitted or zero (0), file reading will start from the 
      current file position.
   data
      The buffer where data is written. It can be a numeric variable, a 
      string, an array, a user defined type (including referenced by This), 
      or a dereferenced pointer. The read operation will try to fill 
      completely the variable, unless the EOF is reached. For a 
      user-defined type instance, the data impacted is only the non-static 
      data members.
      When getting arrays, data should be followed by an empty pair of 
      brackets: "()".  Get will read data for all of the values in the 
      array.  amount is not allowed.
      When getting Strings, the number of bytes read is the same as the 
      number of bytes in the string data. amount is not allowed.
      Note: If you want to read values into a buffer, you should NOT pass a 
      pointer to the buffer; instead you should pass the first variable in 
      the buffer (this can be done by dereferencing the pointer with 
      Operator * (Value Of)). If you pass a pointer directly, then Get will 
      overwrite the pointer variable, not the memory it points to.
   amount
      Makes Get read amount consecutive variables from file to memory, i.e. 
      it reads (amount * SizeOf(data) ) bytes of data from file into the 
      memory starting at data's memory location.  If amount is omitted it 
      defaults to 1, meaning that Get just reads a single variable.
   bytesread
      An unsigned integer variable to accept the result of the number of 
      bytes read successfully from the file.

Return Value
   Get() returns a 32 bit Long: a zero (0) on success; non-zero on error.
   Note: if EOF (end of file) is reached while reading, Get will return 
   success.  The amount of bytes actually read can be checked by passing a 
   bytesread variable.

Description
   Reads binary data from a file to a buffer variable

   Get can be used as a function, and will return 0 on success or an error 
   code on failure.	

   For files opened in Random mode, the size in bytes of the data to read 
   must match the specified record size.

   Note:
      - If a real [w/z]string variable is passed to Get, the amount 
      parameter should be forbidden as it is when passing a string. Do not 
      use. Otherwise, it is ignored (except for the '0' value).
      - If a dereferenced [w/z]string pointer is passed to Get, the amount 
      parameter is not taken into account as it is when passing a 
      dereferenced numeric pointer. Do not use. But instead of respecting 
      the amount parameter, the pointed buffer must begin with at least as 
      many non-zero elements as the number of elements to read.
      - For finer granularity, any [w/z]string variable can be safely 
      passed to Get as a numeric buffer by providing the first numeric 
      element (an indexed [w/z]string variable, or a dereferenced 
      [w/z]string pointer then indexed) and the number of numeric elements 
      to be processed.

   Note:
      - Using Get # is naturally dedicated to Binary/Random Access file 
      mode.
      - It is also allowed in Input Access file mode, but this was never 
      well tested and results may vary.

Example
   Dim Shared f As Integer

   Sub get_long()

      Dim buffer As Long ' Long variable

      ' Read a Long (4 bytes) from the file into buffer, using file number "f".
      Get #f, , buffer

      ' print out result
      Print buffer
      Print

   End Sub

   Sub get_array()

      Dim an_array(0 To 10-1) As Long ' array of Longs

      ' Read 10 Longs (10 * 4 = 40 bytes) from the file into an_array, using file number "f".
      Get #f, , an_array()

      ' print out result
      For i As Integer = 0 To 10-1
         Print an_array(i)
      Next
      Print

   End Sub

   Sub get_mem

      Dim pmem As Long Ptr

      ' allocate memory for 5 Longs
      pmem = Allocate(5 * SizeOf(Long))

      ' Read 5 Longs (5 * 4 = 20 bytes) from the file into allocated memory
      Get #f, , *pmem, 5 ' Note pmem must be dereferenced (*pmem, or pmem[0])

      ' print out result using [] Pointer Indexing
      For i As Integer = 0 To 5-1
         Print pmem[i]
      Next
      Print

      ' free pointer memory to prevent memory leak
      Deallocate pmem

   End Sub

   ' Find the first free file file number.
   f = FreeFile

   ' Open the file "file.ext" for binary usage, using the file number "f".
   Open "file.ext" For Binary As #f

     get_long()

     get_array()

     get_mem()

   ' Close the file.  
   Close #f

   ' Load a small text file to a string

   Function LoadFile(ByRef filename As String) As String
      
      Dim h As Integer
      Dim txt As String
      
      h = FreeFile
      
      If Open( filename For Binary Access Read As #h ) <> 0 Then Return ""
      
      If LOF(h) > 0 Then
         
         txt = String(LOF(h), 0)
         If Get( #h, ,txt ) <> 0 Then txt = ""
         
      End If
      
      Close #h
      
      Return txt
      
   End Function

   Dim ExampleStr As String
   ExampleStr = LoadFile("smallfile.txt")
   Print ExampleStr

   ' 'THIS' can be used as argument for writing/filling all non-static data of an UDT instance to/from a file

   Type UDT
      Dim As String * 32 s
      Dim As Double d
      Declare Sub Save(ByRef filename As String)
      Declare Sub Load(ByRef filename As String)
   End Type

   Sub UDT.Save(ByRef filename As String)
      Dim As Integer f
      f = FreeFile()
      Open filename For Binary As #f
      Put #f, , This  '' writes all non-static data of the UDT instance to the file
      Close #f
   End Sub

   Sub UDT.Load(ByRef filename As String)
      Dim As Integer f
      f = FreeFile()
      Open filename For Binary As #f
      Get #f, , This  '' fills all non-static data of the UDT instance from the file
      Close #f
   End Sub

   Dim As UDT u1
   u1.s = "PI number"
   u1.d = 3.14159
   u1.Save("file.ext")

   Dim As UDT u2
   u2.Load("file.ext")
   Print u2.s
   Print u2.d

Differences from QB
   * Get in FB can read full arrays as in VB or, alternatively, read a 
     multiple of the data size into the memory.
   * Get can be used as a function in FB, to find the success/error code 
     returned without having to use error handling procedures.
   * FB allows the bytesread parameter, to check how many bytes have been 
     successfully read in.

See also
   * Get (Graphics) different usage of same keyword 
   * Put (File I/O)
   * Open
   * Close
   * Binary
   * Random
   * FreeFile
   * File I/O methods comparison



------------------------------------------------------ KeyPgGetjoystick ----
GetJoystick

Reads buttons and axis information from attached gaming devices

Syntax
   Declare Function GetJoystick ( ByVal id As Long, ByRef buttons As Integer
   = 0, ByRef a1 As Single = 0, ByRef a2 As Single = 0, ByRef a3 As Single 
   = 0, ByRef a4 As Single = 0, ByRef a5 As Single = 0, ByRef a6 As Single 
   = 0, ByRef a7 As Single = 0, ByRef a8 As Single = 0 ) As Long

Usage
   result = GetJoystick( id[, buttons[, a1[, a2[, a3[, a4[, a5[, a6[, a7[, 
   a8]]]]]]]]] )

Parameters
   id
      the device id number (0 - 15)
   buttons
      the button status
   a1
      first axis value
   a2
      second axis value
   a3
      third axis value
   a4
      fourth axis value
   a5
      fifth axis value
   a6
      sixth axis value
   a7
      seventh axis value
   a8
      eighth axis value

Return Value
   0 on success or 1 on failure.  All of the axis positions are returned in 
   floating point format.

Description
   GetJoystick will retrieves the button state, and the axis positions for 
   up to 8 axes, for the joystick determined by id, a number between 0 and 
   15. Buttons are stored in a similar manner to GetMouse, with each bit in 
   buttons representing a button.

   A single precision value between -1.0 and 1.0 is returned for each valid 
   axis.  If the axis does not exist for the controller, a value of 
   -1000.00 is returned.

   GetJoystick will return 0 upon successful completion; It will return 1 
   upon failure. Failure can be caused by specifying an illegal joystick 
   number, specifying a joystick which doesn't exist, or a failure in the 
   joystick API.

   The error code returned by GetJoystick can be checked using Err in the 
   next line. The function version of  Getjoystick returns directly the 
   error code as a 32 bit Long.

Example
   Screen 12

   Dim x As Single
   Dim y As Single
   Dim buttons As Integer
   Dim result As Long
   Dim a As Integer

   Const JoystickID = 0

   'This line checks to see if the joystick is ok.

   If GetJoystick(JoystickID,buttons,x,y) Then 
      Print "Joystick doesn't exist or joystick error."
      Print
      Print "Press any key to continue."
      Sleep
      End
   End If

   Do
      result = GetJoystick(JoystickID,buttons,x,y)

      Locate 1,1
      Print ;"result:";result;" x:" ;x;" y:";y;" Buttons:";buttons,"","",""
      
      'This tests to see which buttons from 1 to 27 are pressed. 
      For a = 0 To 26 
         If (buttons And (1 Shl a)) Then 
            Print "Button ";a;" pressed.    "
         Else 
            Print "Button ";a;" not pressed."
         End If
      Next a
   Loop

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Getjoystick.

Differences from QB
   * New to FreeBASIC

See also
   * Screen (Graphics)
   * SetMouse
   * GetMouse
   * MultiKey
   * Event
   * ScreenEvent



----------------------------------------------------------- KeyPgGetkey ----
GetKey

Returns the ascii code of the first key in the keyboard buffer

Syntax
   Declare Function GetKey ( ) As Long

Usage
   result = GetKey

Return Value
   The value of the ascii code returned.

Description
   It returns the ascii code of the first key in the keyboard buffer. The 
   key is removed from the buffer. If no key is present, GetKey waits for 
   it.

   For extended keys (returning two characters), the extended code is 
   returned in the first byte (255), and the scancode for keyboard is 
   returned in the second byte (the third and fourth bytes always being 
   null at least in console mode).

   For FB's built-in functionality of getting keyboard input, see 
   Keyboard Input (Basics).

   WARNING: In graphics mode and depending on the key pressed,   Getkey   
   may not always return the exact same value as in console mode (for a 
   non-extended key, the most significant bit of the ascii code byte may be 
   propagated to the higher 3 bytes of the return value, such as a sign 
   bit).
   For a compatible code of the 2 screen modes, see the example below.

   The key read is not echoed to the screen.

   For a keyword not stopping the program if no key is at the buffer see 
   Inkey or MultiKey.

Example
   Dim As Long foo
   Do
      foo = GetKey
      Print "total return: " & foo
      
      If( foo > 255 ) Then
         Print "extended code: " & (foo And &hff)
         Print "regular code: " & (foo Shr 8)
      Else
         Print "regular code: " & (foo And &hff)
      End If
      Print 
   Loop Until foo = 27

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Getkey.

Differences from QB
   * New to FreeBASIC

See also
   * GetMouse
   * Inkey
   * Input()
   * MultiKey
   * Keyboard scancodes
   * Keyboard Input



--------------------------------------------------------- KeyPgGetmouse ----
GetMouse

Retrieves the status of the mouse pointing device

Syntax
   Declare Function GetMouse ( ByRef x As Long, ByRef y As Long, ByRef 
   wheel As Long = 0, ByRef buttons As Long = 0, ByRef clip As Long = 0 ) As
   Long
   Declare Function GetMouse ( ByRef x As LongInt, ByRef y As LongInt, ByRef
   wheel As LongInt = 0, ByRef buttons As LongInt = 0, ByRef clip As LongInt
   = 0 ) As Long

Usage
   result = GetMouse (x, y [, [ wheel ] [, [ buttons ] [, [ clip ]]]])

Parameters
   x
      x coordinate value
   y
      y coordinate value
   wheel
      scroll wheel value
   buttons
      button status
   clip
      clip status

Return Value
   0 on success, or 1 on error (for example because the mouse is outside 
   the graphic window) or on failure. (sets a runtime error)

Description
   GetMouse retrieves the mouse position and buttons status; information is 
   returned in the variables passed to this function by reference. If a 
   mouse is not available, all variables will contain the -1 value. 

   If in console mode, the x and y coordinates are the character cell 
   coordinates the mouse is currently on; the upper left corner of the 
   screen is at coordinates 0, 0. If the mouse moves out of the console 
   window, GetMouse returns the last coordinate on the window that the 
   mouse was on. If in console mode and fullscreen, the scroll wheel value 
   is not returned. 

   If in graphics mode, x and y will always be returned in pixel 
   coordinates still relative to the upper left corner of the screen, which 
   is at 0,0 in this case; custom coordinates system set via View or Window 
   do not affect the coordinates returned by GetMouse.
   If the mouse runs off the graphic window, all values are set to -1 and 
   the return value of the function is set to 1. This may result in 
   misinterpretation for the buttons and wheel if the return value of the 
   function is not also tested.

   Wheel is the mouse wheel counter; rotating the wheel away from you makes 
   the count to increase, rotating the wheel toward you makes it to 
   decrease. At program startup or when a new graphics mode is set via 
   Screen (Graphics), wheel position is reset to 0. FreeBASIC may not 
   always support mouse wheels for a given platform, in which case 0 is 
   always returned.

   Buttons stores the buttons status as a bitmask: bit 0 is set if left 
   mouse button is down; bit 1 is set if right mouse button is down; bit 2 
   is set if middle mouse button / wheel is down.

   Clip stores the mouse clipping status; if 1, the mouse is currently 
   clipped to the graphics window; if 0, the mouse is not clipped.

   The error code returned by GetMouse can be checked using Err in the next 
   line. The function version of  GetMouse returns directly the error code 
   as a 32 bit Long.

   Warning: When the flag GFX_SHAPED_WINDOW is set (see ScreenRes), 
   GetMouse is only active in any colored area, ie there where color <> 
   RGBA(255, 0, 255, alpha).

Example
   Dim As Long x, y, buttons, res 
   ' Set video mode and enter loop
   ScreenRes 640, 480, 8
   Do
      ' Get mouse x, y and buttons. Discard wheel position.
      res = GetMouse (x, y, , buttons)
      Locate 1, 1
      If res <> 0 Then '' Failure

   #ifdef __FB_DOS__
         Print "Mouse or mouse driver not available"
   #else
         Print "Mouse not available or not on window"
   #endif

      Else
         Print Using "Mouse position: ###:###  Buttons: "; x; y;
         If buttons And 1 Then Print "L";
         If buttons And 2 Then Print "R";
         If buttons And 4 Then Print "M";
         Print "   "
      End If
   Loop While Inkey = ""
   End

   'Example 2: type-union-type structure
   Type mouse
      As Long res
      As Long x, y, wheel, clip
      Union
         buttons As Long
         Type
            Left:1 As Long
            Right:1 As Long
            middle:1 As Long
         End Type
      End Union
   End Type
    
   Screen 11
   Dim As mouse m

   Do
      m.res = GetMouse( m.x, m.y, m.wheel, m.buttons, m.clip )
      ScreenLock
      Cls
      Print Using "res = #"; m.res
      Print Using "x = ###; y = ###; wheel = +###; clip = ##"; m.x; m.y; m.wheel; m.clip
      Print Using "buttons = ##; left = #; middle = #; right = #"; m.buttons; m.left; m.middle; m.right
      ScreenUnlock
      Sleep 10, 1
   Loop While Inkey = ""

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Getmouse.  The variables passed must also be of type Long 
     instead of Integer.

Platform Differences
   * On Win32, scroll wheel changes are not guaranteed to be detected in 
     full-screen console mode.  Confirmed on WinXP: In windowed mode, mouse 
     wheel changes are seen, but in full-screen console mode they are not.
   * In DOS, the "clip" value has no relevance.  Additionally the wheel 
     and middle button will not work unless supported and enabled by the 
     mouse driver. See also FaqDOS.

Differences from QB
   * New to FreeBASIC

See also
   * ScreenRes setting graph mode by resolution
   * Screen (Graphics) setting mode the QB-like way
   * SetMouse
   * MultiKey
   * GetJoystick
   * Event
   * ScreenEvent



---------------------------------------------------------- KeyPgGetxpad ----
Getxpad

Reads Xbox-style controller state from the graphics library.

Syntax
   Declare Function Getxpad ( ByVal id As Long, ByRef buttons As Integer = 
   0, ByRef leftx As Single = 0, ByRef lefty As Single = 0, ByRef rightx As 
   Single = 0, ByRef righty As Single = 0, ByRef lefttrigger As Single = 0, 
   ByRef righttrigger As Single = 0, ByRef dpad As Integer = 0 ) As Long

Usage
   status = Getxpad( id[, buttons[, leftx[, lefty[, rightx[, righty[, 
   lefttrigger[, righttrigger[, dpad]]]]]]]] )

Parameters
   id
      The controller number to query.  The valid range is platform 
      dependent.
   buttons
      A bit mask of XPAD_BUTTON_* values.
   leftx, lefty, rightx, righty
      Analog stick positions in the range -1.0 to 1.0.
   lefttrigger, righttrigger
      Trigger positions in the range 0.0 to 1.0.
   dpad
      A bit mask of XPAD_DPAD_* values.

Return Value
   Returns one of the XPAD_STATUS_* constants from fbgfx.bi:
      * XPAD_STATUS_MISSING (0)
      * XPAD_STATUS_CONNECTED (1)
      * XPAD_STATUS_DISCONNECTED (2)

Description
   Getxpad provides a stable Xbox-style controller layout across supported 
   backends.  It is separate from GetJoystick because modern gamepads have 
   a conventional button, trigger, stick, and d-pad shape that maps poorly 
   to a generic axis list.

   The named XPAD_BUTTON_*, XPAD_DPAD_*, and XPAD_STATUS_* constants are 
   declared in fbgfx.bi under the FB namespace.  The function itself is an 
   intrinsic and does not require an include file to call.

Example
   See examples/xpad/first-pad.bas, examples/xpad/active-state.bas, and 
   examples/xpad/stick-view.bas.

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Getxpad.

Differences from QB
   * New to FreeBASIC.

See also
   * GetJoystick
   * MultiKey
   * GetMouse



----------------------------------------------------- KeyPgSfxGenerated ----
Generated Sound Commands

Commands for generated sound, PLAY strings, and sfxlib mix settings.

Syntax
   Beep [ duration, pitch ]
   Sound frequency, duration
   Sound channel, frequency, duration, volume
   Tone channel, frequency, duration
   Noise channel, duration, volume
   Noise channel, frequency, duration, volume
   Note name, octave, duration
   Note channel, name, octave, duration
   Play music
   Play channel, music
   Play music1, music2
   Play music1, music2, music3
   Tempo bpm
   bpm = Tempo()
   Channel channel
   channel = Channel()
   Octave octave
   octave = Octave()
   Voice instrument
   instrument = Voice()
   Vol level
   Volume level
   level = Volume()
   Volume channel, level
   level = Volume( channel )
   Balance position
   position = Balance()
   Pan channel, position
   position = Pan( channel )
   Wave id, waveform
   Envelope id, attack, decay, sustain, release
   Instrument id, wave_id, envelope_id
   Instrument channel, instrument_id

Description
   These commands synthesize sound directly through sfxlib.  Sound, Tone, 
   Noise, Note, and Play create voices.  Tempo, Channel, Octave, and Voice 
   set defaults used by PLAY-string and generated-sound commands.  Volume, 
   Vol, Balance, and Pan control mix levels and stereo placement.

   Sound accepts the high-impact classic form Sound frequency, duration and
   the explicit channel form Sound channel, frequency, duration, volume.
   When both arguments are integers, duration is interpreted as the PC BASIC
   timer-tick value.

   Wave defines a waveform id.  The currently supported waveform values 
   are:
      * 0 sine
      * 1 square
      * 2 triangle
      * 3 saw
      * 4 noise

   Envelope defines an ADSR envelope using seconds for attack, decay, and 
   release, and a 0.0 to 1.0 sustain level.  Instrument can define an 
   instrument from a waveform and envelope, or assign an instrument to a 
   channel.

   The channel-oriented commands use sfxlib's channel table.  Channels are 
   zero-based.

Example
   See examples/sfxlib/basics-01-generated-sound.bas, 
   examples/sfxlib/basics-02-play-strings.bas, 
   examples/sfxlib/basics-03-channels-mix.bas, 
   examples/sfxlib/basics-04-instruments.bas, and 
   examples/sfxlib/showcase.bas.

Platform Differences
   * On headless or diagnostic runs, SFXLIB_DRIVER=null can be set before 
     program startup to use the null output driver.

Differences from QB
   * New to FreeBASIC.

See also
   * Beep
   * Music
   * Sfx
   * Sound Library Reference



------------------------------------------------------------ KeyPgGosub ----
GoSub

Control flow statement to use a section of code and return.

Syntax
   GoSub label

Description
   Execution jumps to a subroutine marked by a line label. Always use Return
   to exit a GoSub,  execution will continue  on next statement after GoSub
   . 

   The line label where GoSub jumps must be in the same main/function/sub 
   block as GoSub. All the variables in the subroutine are shared with the 
   block, no arguments can be used. For this reason Gosub is considered bad 
   programming practice as it can generate unreadable and untraceable code. 
   It is better to use Sub or Function instead.

Example
   '' Compile with -lang qb

   '$lang: "qb"

   GoSub message
   End

   message:
   Print "Welcome!"
   Return

Dialect Differences
   * Only available in the -lang qb and -lang fblite dialects.
   * GoSub support is disabled by default in the -lang fblite unless the 
     Option Gosub statement is used.

Differences from QB
   * None when using the -lang qb dialect.

See also
   * Goto
   * Return (From Gosub)
   * Sub
   * Function
   * Option Gosub
   * Labels



------------------------------------------------------------- KeyPgGoto ----
Goto

Control flow statement to jump to another part of the program

Syntax
   Goto label

Description
   Jumps code execution to a line label.

   When using Goto label to exit a scope, any local variables defined in 
   that scope are destroyed (destructors are called).

   Usage of Goto label may be disallowed when it skips a variable 
   definition but not the end of the variable's scope. If the variable 
   requires construction, a compiler error is shown. For other variables, a 
   compiler warning is shown. This is intended to prevent potential 
   accesses to uninitialized variables, and ensures that automatic 
   destruction never happens to an uninitialized variable.

   For better source code readability, overuse of Goto should be avoided in 
   favor of more modern structures such as Do...Loop, For...Next, Sub, and 
   Function.

Example
      Goto there

   backagain:
      End

   there:
      Print "Welcome!"
      Goto backagain

   '' Compile with -lang qb or fblite

   '$lang: "qb"

   1 Goto 3
   2 End
   3 Print "Welcome!"
   4 Goto 2

Dialect Differences
   * Line numbers are allowed only in the -lang qb and -lang deprecated 
     dialects.
   * In the -lang qb and -lang fblite dialects, Goto label is allowed to 
     skip any variable definitions, because nested scopes are not supported 
     and all variable definitions are moved to the top of their procedure.

Differences from QB
   * None

See also
   * GoSub
   * Sub
   * Function
   * Labels




============================================================================
    H

-------------------------------------------------------------- KeyPgHex ----
Hex

Returns the hexadecimal of the given number

Syntax
   Declare Function Hex ( ByVal number As UByte ) As String
   Declare Function Hex ( ByVal number As UShort ) As String
   Declare Function Hex ( ByVal number As ULong ) As String
   Declare Function Hex ( ByVal number As ULongInt ) As String
   Declare Function Hex ( ByVal number As Const Any Ptr ) As String

   Declare Function Hex ( ByVal number As UByte, ByVal digits As Long ) As 
   String
   Declare Function Hex ( ByVal number As UShort, ByVal digits As Long ) As 
   String
   Declare Function Hex ( ByVal number As ULong, ByVal digits As Long ) As 
   String
   Declare Function Hex ( ByVal number As ULongInt, ByVal digits As Long ) 
   As String
   Declare Function Hex ( ByVal number As Const Any Ptr, ByVal digits As 
   Long ) As String

Usage
   result = Hex[$]( number [, digits ] )

Parameters
   number
      A number or expression evaluating to a number.  A floating-point 
      number will be converted to a LongInt.
   digits
      Optional number of digits to return.

Return Value
   A String containing the unsigned hexadecimal representation of number.

Description
   Returns the unsigned hexadecimal string representation of the integer 
   number. Hexadecimal digits range from 0-9, or A-F.

   If you specify digits > 0, the result string will be exactly that 
   length.  It will be truncated or padded with zeros on the left, if 
   necessary.

   The length of the string will not go longer than the maximum number of 
   digits required for the type of number (8 for a Long, 16 for a LongInt).

   If you want to do the opposite, i.e. convert a hexadecimal string back 
   into a number, the easiest way to do it is to prepend the string with 
   "&H", and convert it to an integer type, using a function like CInt, 
   similarly to a normal numeric string.  E.g. CInt("&HFF")

Example
   '54321 is D431 in hex
   Print Hex(54321)
   Print Hex(54321, 2)
   Print Hex(54321, 5)

   will produce the output:

   D431
   31
   0D431

Dialect Differences
   * The string type suffix "$" is required in the -lang qb dialect.
   * The string type suffix "$" is optional in the -lang fblite dialect.
   * The string type suffix "$" is ignored in the -lang fb dialect, warn 
     only with the -w suffix compile option (or -w pedantic compile 
     option).

Differences from QB
   * In QBASIC, there was no way to specify the number of digits returned.
   * The size of the string returned was limited to 32 bits, or 8 
     hexadecimal digits.

See also
   * Bin
   * Oct
   * ValInt
   * ValLng



----------------------------------------------------------- KeyPgHibyte ----
HiByte

Gets the second byte of the operand.

Syntax
   #define HiByte( expr ) ((Cast(UInteger, expr) And &h0000FF00) Shr 8)

Usage
   result = HiByte( expr )

Parameters
   expr
      A numeric expression, converted to an UInteger value.

Return Value
   Returns the value of the high byte of the low 16bit word of expr.

Description
   This macro converts the numeric expression expr to an UInteger value, 
   then expands to an UInteger representing the value of its second byte - 
   that is the most-significant (high) byte of the least-significant (low) 
   16bit word of expr.

Example
   Dim N As UInteger

   'Note there are 16 bits
   N = &b1010101110000001
   Print "N is                                       "; N
   Print "The binary representation of N is          "; Bin(N)
   Print "The most significant byte (MSB) of N is    "; HiByte(N)
   Print "The least significant byte (LSB) of N is   "; LoByte(N)
   Print "The binary representation of the MSB is    "; Bin(HiByte(N))
   Print "The binary representation of the LSB is    "; Bin(LoByte(N))
   Sleep

The output would look like:

   N Is                                       43905
   The Binary representation of N Is          1010101110000001
   The most significant Byte (MSB) of N Is    171
   The least significant Byte (LSB) of N Is   129
   The Binary representation of the MSB Is    10101011
   The Binary representation of the LSB Is    10000001

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __HIBYTE.

Differences from QB
   * New to FreeBASIC

See also
   * LoByte
   * LoWord
   * HiWord



----------------------------------------------------------- KeyPgHiword ----
HiWord

Gets the second 16bit word of the operand.

Syntax
   #define HiWord( expr ) ((Cast(UInteger, expr) and &hFFFF0000) Shr 16)

Usage
   result = HiWord( expr )

Parameters
   expr
      A numeric expression, converted to an UInteger value.

Return Value
   Returns the value of the high 16bit word of the low 32bit dword of expr.

Description
   This macro converts the numeric expression expr to an UInteger value, 
   then expands to an UInteger representing the value of its second 16bit 
   word - that is the most-significant (high) 16bit word of the 
   least-significant (low) 32bit dword of expr.

Example
   Dim N As UInteger

   'Note there are 32 bits
   N = &b10000000000000011111111111111111

   Print "N is                                       "; N
   Print "The binary representation of N is          "; Bin(N)
   Print "The most significant word (MSW) of N is    "; HiWord(N)
   Print "The least significant word (LSW) of N is   "; LoWord(N)
   Print "The binary representation of the MSW is    "; Bin(HiWord(N))
   Print "The binary representation of the LSW is    "; Bin(LoWord(N))

   Sleep

The output would look like:

   N Is                                       2147614719
   The Binary representation of N Is          10000000000000011111111111111111
   The most significant word (MSW) of N Is    32769
   The least significant word (LSW) of N Is   65535
   The Binary representation of the MSW Is    1000000000000001
   The Binary representation of the LSW Is    1111111111111111

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __HIWORD.

Differences from QB
   * New to FreeBASIC

See also
   * LoByte
   * HiByte
   * LoWord



------------------------------------------------------------- KeyPgHour ----
Hour

Gets the hour of day from a Date Serial 

Syntax
   Declare Function Hour ( ByVal date_serial As Double ) As Long

Usage
   #include "vbcompat.bi"
   result = Hour( dateserial )

Parameters
   date_serial
      the date serial

Return Value
   Returns the hour from a variable containing a date in Date Serial 
   format.

Description
   The compiler will not recognize this function unless vbcompat.bi is 
   included.

Example
   #include "vbcompat.bi"

   Dim ds As Double = DateSerial(2005, 11, 28) + TimeSerial(7, 30, 50)

   Print Format(ds, "yyyy/mm/dd hh:mm:ss "); Hour(ds)

Differences from QB
   * Did not exist in QB. This function appeared in PDS and VBDOS

See also
   * Date Serials




============================================================================
    I

----------------------------------------------------------- KeyPgIfthen ----
If...Then

Control flow statement for conditional branching

Syntax
      If expression Then [statement(s)] [Else [statement(s)]] [End If]
   or
      If expression Then : [statement(s)] [Else [statement(s)]] : End If
   or
      If expression Then
         [statement(s)]
      [ ElseIf expression Then ]
         [statement(s)]
      [ Else ]
         [statement(s)]
      End If

      Remark: EndIf (without blank) is also supported like in QB for 
      backward compatibility.

Description
   If...Then is a way to make decisions.
   It is a mechanism to execute code only if a condition is true, and can 
   provide alternative code to execute based on more conditions:
      * Execute code (just behind Then) if a condition is true.
      * Execute certain code (just behind Then) if a condition is true and 
        execute other (just behind Else) if it's false.
      * Test other conditions (with ElseIf) if the first condition is 
        false.

   expression can be one of several forms:
      * a conditional expression, for example:
         x = 5
      * multiple conditions separated by logical bit-wise operators, for 
        example:
         x >= 5 And x <= 10
      * multiple conditions separated by logical short-circuit operators, 
        for example:
         y <> 0 AndAlso x \ y = 1
         (in this case, "x \ y = 1" will only be evaluated if "y <> 0" is 
         True)
      * any numerical expression, in which case a value of zero (0) 
        represents False, and a non-zero value represents True

   Both multi-line and single-line Ifs can be nested.  In the latter case, 
   the optional End Ifs can be useful to control where nested Ifs begin and 
   end.

   The multi-line syntax allows several Elseifs (but none after a Else) and 
   tests can be nested (there must be in this case as many End Ifs as Ifs).
   If the condition of the If is not true, those of Elseifs blocks are 
   tested in succession:
      * If either of these is true, the corresponding code is executed, 
        then the program skips the following blocks to continue after the 
        End If.
      * If none are true, the code following the Else (if exists) is 
        executed alone.

   In the -lang fb and -lang fblite dialects, colons (:) can be used 
   instead of newlines to construct multi-line If blocks on a single line.

   Note: The single-line syntax If...Goto, as shortcut for If...Then Goto, 
   is deprecated and it only exists for compatibility with QB.

Example
   '' Here is a simple "compute the square root" code using a single-line if...then for the decision,
   '' but with multiple statements extended with colons (:)

   Dim As Double d , r
   r = -1
   d = 2
   'd = -3

   If d > 0 Then r = Sqr(d) : Print "square root computed:" Else r = 0 : Print "square root not computed:"
   Print r

   Sleep
      

   '' Here is a simple "guess the number" game using a multi-line if...then for a decision.

   Dim As Integer num, guess

   Randomize
   num = Int(Rnd * 10) + 1 'Create a random number between 1 and 10...
               
   Print "guess the number between 1 and 10 (or CTRL-C to abort)"

   Do 'Start a loop

      Input "Guess"; guess 'Input a number from the user

      If guess > 10 OrElse guess < 1 Then  'The user's guess is out of range
         Print "The number can't be greater then 10 or less than 1!"
      ElseIf guess > num Then  'The user's guess is too high
         Print "Too high"
      ElseIf guess < num Then  'The user's guess is too low
         Print "Too low"
      Else                     'The user guessed the right number!
         Print "Correct!"
         Exit Do   'Exit the loop
      End If

   Loop 'Go back to the start of the loop

   Sleep
      

Dialect Differences
   * In the -lang qb and -lang fblite dialects, variables declared inside 
     an If..Then block have a procedure-wide scope  as in QB 
   * In the -lang fb and -lang deprecated dialects, variables declared 
     inside an If..Then block are visible only inside the block, and cannot 
     be accessed outside it. To access duplicated symbols defined as global 
     outside this block, add one or preferably two dot(s) as prefix: .
     SomeSymbol or preferably ..SomeSymbol (or only ..SomeSymbol if inside 
     a With..End With block).
   * In the -lang qb dialect, if there is a new line or a single-line 
     comment (') directly after THEN, then the IF will be multi-line.  A 
     colon, a Rem or any other statement will result in a single-line IF.
   * In the -lang fb and -lang fblite dialects, if there is a new line, a 
     single-line comment ('), a colon (:), or a Rem statement directly 
     after THEN, then the IF will be multi-line.  Any other statement will 
     result in a single-line IF.

Differences from QB
   * END IF was not supported in single-line IFs in QBASIC.

See also
   * ElseIf
   * Do...Loop
   * #if
   * Select Case



-------------------------------------------------------------- KeyPgIif ----
IIf

Conditional function that returns one of two values.

Syntax
   IIf ( condition, expr_if_true, expr_if_false )

Parameters
   condition
      The condition to test.
      A non-zero value evaluates as true, while a value of zero evaluates 
      as false.
   expr_if_true
      An expression to evaluate and return if condition is true.
      It must return:
         * a numeric value, which can be an integer, floating point number 
           or a pointer, including Boolean,
         * or a string value,
         * or an UDT value.
   expr_if_false
      An expression to evaluate and return if condition is false.
      It must be same type as expr_if_true (either numeric, either string 
      or UDT).

Return Value
   if condition is non-zero, expr_if_true, otherwise expr_if_false

Description
   IIf returns a different numeric or string or UDT value (not a reference) 
   depending of the result of a conditional expression evaluated at 
   run-time.
   Its typical use is in the middle of an expression; it avoids splitting 
   it to put a conditional in the middle.

   IIf only evaluates the expression that it needs to return.  This saves 
   time, and can also be useful to prevent evaluating expressions that 
   might be invalid depending on the condition.

   When IIf treats expressions of mixed numeric types (conditional 
   expression evaluated at run-time):
      * if at least one expression is of floating-point type, the result 
        type is the floating-point type (the bigger in case of two 
        floating-point types),
      * if the two expressions are of integer types, the result type is 
        the bigger type of both (see Coercion and Conversion for the 
        precise ranking of integer types).

   Note: If the condition evaluation can be done at compile time (if the 
   comparison expression is a constant), the usage rules are a bit more 
   flexible and IIf can for example return a reference or even return a 
   function call (but not a sub call).

Example
   Dim As Integer a, b, x, y, z
   a = (x + y + IIf(b > 0, 4, 7)) \ z

is equivalent to:
   Dim As Integer a, b, x, y, z, temp
   If b > 0 Then temp = 4 Else temp = 7
   a = (x + y + temp) \ z

   Dim As Integer I
   I = -10
   Print I, IIf(I>0, "positive", IIf(I=0, "null", "negative"))
   I = 0
   Print I, IIf(I>0, "positive", IIf(I=0, "null", "negative"))
   I = 10
   Print I, IIf(I>0, "positive", IIf(I=0, "null", "negative"))
   Sleep

   Type UDT1
     Dim As Integer I1
   End Type

   Type UDT2 Extends UDT1
     Dim As Integer I2
   End Type

   Dim As UDT1 u1, u10 = (1)
   Dim As UDT2 u2, u20 = (2, 3)

   u1 = IIf(0, u10, u20)
   Print u1.I1
   u1 = IIf(1, u10, u20)
   Print u1.I1

   u2 = IIf(0 , u10, u20)
   Print u2.I1; u2.I2
   'u2 = Iif(1, u10, u20) ''Invalid assignment/conversion
   Sleep

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Iif.

Differences from QB
   * New to FreeBASIC

See also
   * If...Then



-------------------------------------------------- KeyPgImageConvertRow ----
ImageConvertRow

Converts a row of image data into another color depth

Syntax
   Declare Sub ImageConvertRow ( ByVal src As Any  Ptr, ByVal src_bpp As 
   Long, ByVal dst As Any  Ptr, ByVal dst_bpp As Long, ByVal width As Long, 
   ByVal isrgb As Long = 1 )

Usage
   ImageConvertRow( src, src_bpp, dst, dst_bpp, width [, isrgb ] )

Parameters
   src
      The address of the start of the source row.  The source can either be 
      a full-color image with a bit depth of 24 or 32 bits per pixel, or a 
      paletted image with a bit depth of 1-8 bits per pixel.  Converting a 
      paletted image will only work properly if you are in a screen mode 
      that is using the correct palette for the image when you do the 
      conversion.
   src_bpp
      The number of bits per pixel in the source row.  1-8, 24 and 32.
   dst
      The address of the start of the destination row.  The image can be a 
      full-color image of 16 or 32 bits per pixel.  If the source is a 
      paletted image, the destination can also be a paletted image of 1 to 
      8 bits per pixel.
   dst_bpp
      The number of bits per pixel in the destination row.  Valid values 
      for this are 1-8, 16 and 32.
   width
      The length of the row in pixels.
   isrgb
      A value of zero indicates that the Red and Blue channels are the 
      other way round in the source image.  Use this switch if you want the 
      Red and Blue channels to be swapped in the conversion.

Description
   Copies the row of an image from one memory location to another, 
   converting the color information in each pixel to match the destination 
   image.

Example
   #include "fbgfx.bi"
   #if __FB_LANG__ = "fb"
   Using FB
   #endif

   Const As Long w = 64, h = 64
   Dim As IMAGE Ptr img8, img32
   Dim As Integer x, y

   '' create a 32-bit image, size w*h:
   ScreenRes 1, 1, 32, , GFX_NULL
   img32 = ImageCreate(w, h)

   If img32 = 0 Then Print "Imagecreate failed on img32!": Sleep: End

   '' create an 8-bit image, size w*h:
   ScreenRes 1, 1, 8, , GFX_NULL
   img8 = ImageCreate(w, h)

   If img8 = 0 Then Print "Imagecreate failed on img8!": Sleep: End

   '' fill 8-bit image with a pattern
   For y = 0 To h - 1
      For x = 0 To w - 1
         PSet img8, (x, y), 56 + (x + y) Mod 24
      Next x
   Next y

   '' open a graphics window in 8-bit mode, and PUT the image into it:
   ScreenRes 320, 200, 8
   WindowTitle "8-bit color mode"
   Put (10, 10), img8

   Sleep

   '' copy the image data into a 32-bit image
   Dim As Byte Ptr p8, p32
   Dim As Long pitch8, pitch32

   #ifndef ImageInfo '' older versions of FB don't have the ImageInfo feature
   #define GETPITCH(img_) IIf(img_->Type=PUT_HEADER_NEW,img_->pitch,img_->old.width*img_->old.bpp)
   #define GETP(img_) CPtr(Byte Ptr,img_)+IIf(img_->Type=PUT_HEADER_NEW,SizeOf(PUT_HEADER),SizeOf(_OLD_HEADER))
   pitch8 = GETPITCH(img8): p8 = GETP(img8)
   pitch32 = GETPITCH(img32): p32 = GETP(img32)
   #else
   ImageInfo( img8,  , , , pitch8,  p8  )
   ImageInfo( img32, , , , pitch32, p32 )
   #endif

   For y = 0 To h - 1
      ImageConvertRow(@p8 [ y * pitch8 ],  8, _
                  @p32[ y * pitch32], 32, _
                  w)
   Next y

   '' open a graphics window in 32-bit mode and PUT the image into it:
   ScreenRes 320, 200, 32
   WindowTitle "32-bit color mode"
   Put (10, 10), img32

   Sleep

   '' free the images from memory:
   ImageDestroy img8
   ImageDestroy img32

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __ImageConvertRow.

Differences from QB
   * New to FreeBASIC

See also
   * ScreenRes
   * Get (Graphics)
   * Put (Graphics)
   * ImageCreate
   * ImageDestroy
   * ImageInfo



------------------------------------------------------ KeyPgImagecreate ----
ImageCreate

Allocates and initializes storage for an image

Syntax
   Declare Function ImageCreate ( ByVal width As Long, ByVal height As Long
   , ByVal color As ULong = transparent_color ) As Any Ptr
   Declare Function ImageCreate ( ByVal width As Long, ByVal height As Long
   , ByVal color As ULong = transparent_color, ByVal depth As Long ) As Any 
   Ptr

Usage
   result = ImageCreate( width, height [, [ color ][, depth ]] )

Parameters
   width
      The desired width, in number of pixels.
   height
      The desired height, in number of pixels.
   color
      The pixel value to fill the area of the image.
   depth
      The desired color depth, in bits per pixel.

Return Value
   If the image could not be created, NULL (0) is returned, otherwise, the 
   address of the image is returned. ImageCreate must be called after 
   graphic mode initialization, else it returns 0.

   Consequently, in case of Shared variable declaration, ImageCreate cannot 
   be used as integrated initializer, even inside an Udt (in member field 
   or constructor), because the initialization value (of shared variable) 
   is set at the start of the program before any user code is run. The 
   image allocation call must be in a separated executable instruction, and 
   after the graphic mode initialization.

Description
   Both procedures allocate memory for an image of the specified width and 
   height. If not successful, NULL (0) is returned. Otherwise, an image of 
   that size is created and initialized by filling the entire area of 
   pixels with the value color. If not specified, color assumes the value 
   of the transparent color for the current graphics screen, which can be 
   found by calling ScreenControl. In any case, the address of the image is 
   returned, which is then controlled by the user, and must be destroyed 
   using ImageDestroy.

   The first procedure creates an image with a color depth matching that of 
   the current graphics screen, which can be found by calling ScreenControl
   . The second procedure creates an image with a color depth of depth, in 
   bits per pixel. For both procedures, the resulting image can be used in 
   drawing procedures while in any screen mode -- and across mode changes 
   -- as long as the color depth of the image matches that of the graphics 
   screen.

   ImageCreate is the recommended way to allocate memory for new images. 
   The memory layout -- size, structure, etc. -- while documented, may 
   change from version to version, making manual calculation of the sizes 
   involved error-prone. However, ImageInfo can be used to retrieve, among 
   other things, the size, in bytes, of an existing image, allowing memory 
   to be manually allocated for a copy of an image, or to be read from or 
   written to a file or device.

   Get (Graphics) can be used to initialize an image using pre-allocated 
   memory.

Example
   '' Create a graphics screen.
   ScreenRes 320, 200, 32

   '' Create a 64x64 pixel image with a darkish green background.
   Dim image As Any Ptr = ImageCreate( 64, 64, RGB(0, 128, 0) )

   If image = 0 Then
      Print "Failed to create image."
      Sleep
      End -1
   End If

   '' Draw a semi-transparent, red circle in the center of the image.
   Circle image, (32, 32), 28, RGBA(255, 0, 0, 128),,, 1.0, f

   '' Draw the image onto the screen using various blitting methods.
   Put (120, 60), image, PSet
   Put (140, 80), image, Alpha

   '' Destroy the image.
   ImageDestroy image

   Sleep

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Imagecreate.

Differences from QB
   * New to FreeBASIC

See also
   * ImageDestroy
   * ImageInfo
   * Get (Graphics)
   * Internal pixel formats



----------------------------------------------------- KeyPgImageDestroy ----
ImageDestroy

Destroys and deallocates storage for an image

Syntax
   Declare Sub ImageDestroy ( ByVal image As Any Ptr )

Usage
   ImageDestroy( image )

Parameters
   image
      The address of the image to destroy.

Description
   Destroys the image pointed to by image, which must be an address 
   returned from a call to ImageCreate.

   Calling ImageDestroy on a null pointer induces no action.

Example
   See ImageCreate for an example on using ImageDestroy.

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Imagedestroy.

Differences from QB
   * New to FreeBASIC

See also
   * ImageCreate



-------------------------------------------------------- KeyPgImageInfo ----
ImageInfo

Retrieves information about an image

Syntax
   Declare Function ImageInfo ( ByVal image As Const Any Ptr, ByRef width As
   Long = 0, ByRef height As Long = 0, ByRef bypp As Long = 0, ByRef pitch 
   As Long = 0, ByRef pixdata As Any Ptr = 0, ByRef size As Long = 0 ) As 
   Long
   Declare Function ImageInfo ( ByVal image As Const Any Ptr, ByRef width As
   LongInt, ByRef height As LongInt, ByRef bypp As LongInt = 0, ByRef pitch 
   As LongInt = 0, ByRef pixdata As Any Ptr = 0, ByRef size As LongInt = 0 
   ) As Long

Usage
   in the LONG (or INTEGER<32>) version of the function:
      result = ImageInfo( image [, [ width ] [, [ height ] [, [ bypp ] [, [ 
      pitch ] [ , [ pixdata ] [, size ]]]]]] )
   in the LONGINT (or INTEGER<64>) version of the function:
      result = ImageInfo( image , width , height [, [ bypp ] [, [ pitch ] [ 
      , [ pixdata ] [, size ]]]] )

Parameters
   image
      The address of the image.
   width
      Stores the width of the image, in pixels.
   height
      Stores the height of the image, in pixels.
   bypp
      Stores the bytes per pixel of the image - i.e. the size of a single 
      pixel, in bytes.
   pitch
      Stores the pitch of the image - i.e. the size of each scanline (row), 
      in bytes.  Note that this may be more than just width * bypp, because 
      the scanlines may be padded to allow them to be aligned better in 
      memory.
   pixdata
      Stores the address of the start of the first scanline of the image.
   size
      Stores the size of the image in memory, in bytes.

Return Value
   If image doesn't point to a valid image, one (1) is returned. Otherwise, 
   width, height, bypp, pitch, pixdata and size are assigned appropriate 
   values, and zero (0) is returned.

Description
   ImageInfo provides various information about an image, such as its 
   dimensions and color depth, but also provides you with the information 
   you need to directly access all the pixel data in the pixel buffer.

   It can also provide the size of the image in memory, which is useful for 
   allocating memory to copy the existing image, or to write the image to a 
   file.

   ImageInfo is an alternative way to access the main characteristics of an 
   image, rather than directly accessing the internal FB.IMAGE structure 
   (defined in fbgfx.bi) through a typed pointer to member data.

   The error code returned by ImageInfo can be checked using Err in the 
   next line. The function version of  ImageInfo returns directly the error 
   code as a 32 bit Long.

Example
   '' pixelptr(): use imageinfo() to find the pointer to a pixel in the image
   '' returns null on error or x,y out of bounds
   Function pixelptr(ByVal img As Any Ptr, ByVal x As Integer, ByVal y As Integer) As Any Ptr

      Dim As Long w, h, bypp, pitch
      Dim As Any Ptr pixdata
      Dim As Long result
      
      result = ImageInfo(img, w, h, bypp, pitch, pixdata)
      
      If result = 0 Then '' seems like a valid image
         If x < 0 Or x >= w Then Return 0
         If y < 0 Or y >= h Then Return 0
         Return pixdata + y * pitch + x * bypp
      Else
         Return 0
      End If
      
   End Function

   '' usage example:

   '' 320*200 graphics screen, 8 bits per pixel
   ScreenRes 320, 200, 8

   Dim As Any Ptr ip '' image pointer

   Dim As Byte Ptr pp '' pixel pointer (use byte for 8 bits per pixel)

   ip = ImageCreate(32, 32) '' create an image (32*32, 8 bits per pixel)

   If ip <> 0 Then

      '' draw a pattern on the image
      For y As Integer = 0 To 31

         For x As Integer = y - 5 To y + 5 Step 5

            '' find the pointer to pixel at x,y position
            '' note: this is inefficient to do for every pixel!
            pp = pixelptr(ip, x, y)

            '' if success, plot a value at the pixel
            If (pp <> 0) Then *pp = 15

         Next x

      Next y

      '' put the image and draw a border around it
      Put (10, 10), ip, PSet
      Line (9, 9)-Step(33, 33), 4, b

      '' destroy the image to reclaim memory
      ImageDestroy ip

   Else
      Print "Error creating image!"
   End If

   Sleep
      

   '' Create 32-bit graphics screen and image.
   ScreenRes 320, 200, 32
   Dim image As Any Ptr = ImageCreate( 64, 64 )

   Dim pitch As Long
   Dim pixels As Any Ptr

   '' Get enough information to iterate through the pixel data.
   If 0 <> ImageInfo( image, ,,, pitch, pixels ) Then
      Print "unable to retrieve image information."
      Sleep
      End
   End If

   '' Draw a pattern on the image by directly manipulating pixel memory.
   For y As Integer = 0 To 63
      Dim row As ULong Ptr = pixels + y * pitch
      
      For x As Integer = 0 To 63
         row[x] = RGB(x * 4, y * 4, (x Xor y) * 4)
      Next x
   Next y

   '' Draw the image onto the screen.
   Put (10, 10), image

   ImageDestroy( image )

   Sleep
      

Version
   * Before fbc 1.08.0:
         Syntax:
            Declare Function ImageInfo ( ByVal image As Any Ptr, ByRef 
            width As Integer = 0, ByRef height As Integer = 0, ByRef bypp As
            Integer = 0, ByRef pitch As Integer = 0, ByRef pixdata As Any 
            Ptr = 0, ByRef size As Integer = 0 ) As Long
         Usage:
            result = ImageInfo( image [, [ width ] [, [ height ] [, [ bypp 
            ] [, [ pitch ] [, [ pixdata ] [, size ]]]]]] )

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Imageinfo.

Differences from QB
   * New to FreeBASIC

See also
   * ImageCreate
   * ImageDestroy
   * ImageConvertRow
   * Get (Graphics)
   * Put (Graphics)
   * Internal pixel formats



------------------------------------------------------------ KeyPgOpImp ----
Operator Imp (Implication)

Returns the bitwise-and (implication) of two numeric values

Syntax
   Declare Operator Imp ( ByRef lhs As T1, ByRef rhs As T2 ) As Ret

Usage
   result = lhs Imp rhs

Parameters
   lhs
      The left-hand side expression.
   T1
      Any numeric or boolean type.
   rhs
      The right-hand side expression.
   T2
      Any numeric or boolean type.
   Ret
      A numeric or boolean type (varies with T1 and T2).

Return Value
   Returns the bitwise-implication of the two operands.

Description
   This operator returns the bitwise-implication of its operands, a logical 
   operation that results in a value with bits set depending on the bits of 
   the operands (for conversion of a boolean to an integer, false or true 
   boolean value becomes 0 or -1 integer value).

   The truth table below demonstrates all combinations of a 
   boolean-implication operation:

      +-------+-------+------+
      |Lhs Bit|Rhs Bit|Result|
      |0      |0      |1     |
      |1      |0      |0     |
      |0      |1      |1     |
      |1      |1      |1     |
      +-------+-------+------+

   No short-circuiting is performed - both expressions are always 
   evaluated.

   The return type depends on the types of values passed. Byte, UByte and 
   floating-point type values are first converted to Integer. If the left 
   and right-hand side types differ only in signedness, then the return 
   type is the same as the left-hand side type (T1), otherwise, the larger 
   of the two types is returned. Only if the left and right-hand side types 
   are both Boolean, the return type is also Boolean.

   This operator can be overloaded for user-defined types.

Example
   Dim As UByte a, b, c
   a = &b00001111
   b = &b01010101
   c = a Imp b '' c = &b11110101

Dialect Differences
   * In the -lang qb dialect, this operator cannot be overloaded.

Differences from QB
   * None

See also
   * Operator Truth Tables



------------------------------------------------------- KeyPgImplements ----
Implements

Specifies an interface to be implemented by a user-defined type
   Note: Stub page. Even though this keyword is reserved already, 
   interfaces are not implemented yet.

Syntax
   Type typename Implements interface
      ...
   End Type

Description

Example

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Implements.

Differences from QB
   * New to FreeBASIC

See also
   * Type
   * Extends
   * Extends Zstring
   * Extends Wstring



----------------------------------------------------------- KeyPgImport ----
Import

External linkage attribute for public data located in DLL's

Syntax
   Extern Import symbolname[( subscripts)] [ Alias "aliasname"] [ As 
   DataType] [, ...]

Description
   Is used only (with the Extern keyword) in external modules to access 
   global variables from Win32 DLLs: the variable names will be added to 
   the dynamic library import list so that their addresses can be fixed at 
   run-time.
   This is due to the level of indirection on any such access: an implicit 
   pointer dereference.

Example

   /* mydll.c :
   	compile With
   	  gcc -Shared -Wl,--strip-all -o mydll.dll mydll.c
   */
   __declspec( dllexport ) Int MyDll_Data = 0x1234;

   /'  import.bas :
   	Compile with
   	  fbc import.bas
   '/
   #inclib "mydll"

   Extern Import MyDll_Data Alias "MyDll_Data" As Integer

   Print "&h" + Hex( MyDll_Data )

   ' Output:
   ' &h1234

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Import.

Differences from QB
   * New to FreeBASIC

See also
   * Extern



------------------------------------------------------------ KeyPgInkey ----
Inkey

Returns a string representing the first key waiting in the keyboard buffer

Syntax
   Declare Function Inkey ( ) As String

Usage
   result = Inkey[$]

Return Value
   The first character found in the keyboard buffer, or an empty string (""
   ) if none found.

Description
   Peeks into the keyboard buffer and returns a String representation of 
   the first character, if any, found. The key is then removed from the 
   buffer, and is not echoed to the screen. If the keyboard buffer is 
   empty, an empty string ("") is immediately returned without waiting for 
   keys.

   If the key is in the ASCII character set, a one-character String 
   consisting of that character is returned.
   If the key is an "extended" one (numeric pad, cursors, functions) a 
   two-character String is returned, the first of which is the extended 
   character  (See dialect differences below), and the second is the raw 
   scancode for the keyboard.

   For FB's built-in functionality of getting keyboard input, see 
   Keyboard Input (Basics).

   The Shift, Ctrl, Alt, and AltGr keys can't be read independently by this 
   function as they never enter the keyboard buffer (although, perhaps 
   obviously, Shift-A will be reported by Inkey differently than Control-A 
   et cetera; Alt-A is an extended key a la the above).

   See also Input() or GetKey, or Sleep to wait for a key press if the 
   keyboard buffer is empty.

Example
   Print "press q to quit"
   Do
      Sleep 1, 1
   Loop Until Inkey = "q"

   '' Compile with -lang fblite or qb

   #lang "fblite"

   #if __FB_LANG__ = "qb"
   #define EXTCHAR Chr$(0)
   #else
   #define EXTCHAR Chr(255)
   #endif

   Dim k As String

   Print "Press a key, or Escape to end"
   Do

      k = Inkey$

      Select Case k

         Case "A" To "Z", "a" To "z": Print "Letter: " & k
         Case "1" To "9":             Print "Number: " & k

         Case Chr$(32): Print "Space"

         Case Chr$(27): Print "Escape"

         Case Chr$(9): Print "Tab"

         Case Chr$(8): Print "Backspace"

         Case Chr$(32) To Chr$(127)
            Print "Printable character: " & k

         Case EXTCHAR & "G": Print "Up Left / Home"
         Case EXTCHAR & "H": Print "Up"
         Case EXTCHAR & "I": Print "Up Right / PgUp"

         Case EXTCHAR & "K": Print "Left"
         Case EXTCHAR & "L": Print "Center"
         Case EXTCHAR & "M": Print "Right"

         Case EXTCHAR & "O": Print "Down Left / End"
         Case EXTCHAR & "P": Print "Down"
         Case EXTCHAR & "Q": Print "Down Right / PgDn"

         Case EXTCHAR & "R": Print "Insert"
         Case EXTCHAR & "S": Print "Delete"

         Case EXTCHAR & "k": Print "Close window / Alt-F4"

         Case EXTCHAR & Chr$(59) To EXTCHAR & Chr$(68)
            Print "Function key: F" & Asc(k, 2) - 58

         Case EXTCHAR & Chr$(133) To EXTCHAR & Chr$(134)
            Print "Function key: F" & Asc(k, 2) - 122

         Case Else
            If Len(k) = 2 Then
               Print Using "Extended character: chr$(###, ###)"; Asc(k, 1); Asc(k, 2)
            ElseIf Len(k) = 1 Then
               Print Using "Character chr$(###)"; Asc(k)
            End If

      End Select

      If k = Chr$(27) Then Exit Do

      Sleep 1, 1

   Loop

Dialect Differences
   * The extended character is Chr(255) in the -lang fb and -lang fblite 
     dialects.
      * In the -lang qb dialect, the extended character depends on how the 
        keyword is written. If the QB form Inkey$ is used, the extended 
        character is Chr(0).  If it is referenced as __Inkey, the extended 
        char is Chr(255).
      * In all other dialects, the extended char is always Chr(255).
   * The string type suffix "$" is required in the -lang qb dialect.
   * The string type suffix "$" is optional in the -lang fblite dialect.
   * The string type suffix "$" is ignored in the -lang fb dialect, warn 
     only with the -w suffix compile option (or -w pedantic compile 
     option).

Differences from QB
   * None in the -lang qb dialect.
   * QBasic returned a Chr(0) as the first character for an extended key, 
     but FreeBASIC returns Chr(255) as the first character in the -lang fb 
     and -lang fblite dialects.

See also
   * Sleep
   * GetKey
   * Input()
   * MultiKey
   * Keyboard scancodes
   * Keyboard Input



-------------------------------------------------------------- KeyPgInp ----
Inp

Returns a value at a hardware port.

Syntax
   Declare Function Inp ( ByVal port As UShort ) As Long

Usage
   value = Inp(port)

Parameters
   port
      Port number to read.

Return Value
   The value at the specified port.

Description
   This function retrieves the value at 'port' and returns immediately.

Example
   '' Turn off PC speaker
   Out &h61,Inp(&h61) And &hfc

	
Platform Differences
   * In the Windows and Linux versions three port numbers (&H3C7, &H3C8, 
     &H3C9) are hooked by the graphics library when a graphics mode is in 
     use to emulate QB's VGA palette handling. This use is deprecated; use 
     Palette to retrieve and set palette colors.

   * Using true port access in the Windows version requires the program to 
     install a device driver for the present session. For that reason, 
     Windows executables using hardware port access should be run with 
     administrator permits each time the computer is restarted. Further 
     runs don't require admin rights as they just use the already installed 
     driver. The driver is only 3K in size and is embedded in the 
     executable.

See also
   * Out
   * Wait
   * Palette

   


------------------------------------------------------------ KeyPgInput ----
Input

Reads a list of values from the keyboard

Syntax
   Input [;] ["prompt" ,|; ] variable_list

Parameters
   prompt
      an optional string literal that is written to the screen as a prompt. 
      If it is followed by a semicolon (;), a question mark ("? ") will be 
      appended to the prompt.  If it is followed by a comma, nothing will 
      be appended.
   variable_list
      a list of comma-separated variables used to hold the values read from 
      the user.

Description
   Reads a list values from the keyboard up until the first carriage 
   return. Numerical values are converted from their string representation 
   into the corresponding types in the variable list. Characters are echoed 
   to the screen as they are typed.

   If there is more than one value in the input list, then the input line 
   will be split up by scanning for delimiters - commas (,) after strings, 
   or commas and whitespace after numbers.  Surrounding whitespace will be 
   trimmed from string values. If an input string has a comma in it, it 
   must be wrapped in quotes ("...") to prevent it being split up.
   For inputting to a single string without delimiting, Line Input should 
   be used instead.

   The prompt - if any - is written to the screen at the current cursor 
   location, and characters read are echoed to the screen immediately 
   following the prompt. If no prompt is specified, characters are echoed 
   at the current cursor location.

   The optional leading semicolon (;) after Input is similar to the 
   optional trailing semicolon in a Print statement: the cursor will remain 
   on the same line after all of the characters have been echoed, 
   otherwise, the cursor will move to the beginning of the next line.

   If more values are read than are listed in the variable list, extra 
   values will be ignored; if fewer values are read (i.e. the user presses 
   enter before inputting all values), the remaining variables will be 
   initialized (numeric variables to zero (0), and string variables to the 
   empty string ("")).

   Numeric values are converted using methods similar to the procedures Val 
   and ValLng, using the most appropriate function for the number format, 
   converting as many numeric characters as possible.

   Input has a limited edit capacity: it allows to use the left and right 
   cursor keys to navigate the text, and to erase or insert characters.  If 
   a better user interface is needed, a custom input routine should be 
   used.

Example

   Example #1
   Dim user_name As String, user_age As Integer

   Input "Enter your name and age, separated by a comma: ", user_name, user_age

   Print "Your name is " & user_name & ", and you are " & user_age & " years old."

   Example #2
   Dim As Double a, b
   Dim As String yn

   Do
      
      Input   "Please enter a number: ", a
      Input ; "And another: ", b
      Print , "Thank you"
      Sleep 500
      Print
      Print "The total is "; a + b
      Print
      
      Do
         Input "Would you like to enter some more numbers"; yn
         yn = LCase(yn)
      Loop Until yn = "y" Or yn = "n"
      
   Loop While LCase(yn) = "y"

Differences from QB
   * If the user inputs the wrong number of values, or if it expects a 
     number for a value and gets a string that is not a valid number, then 
     QBASIC issues the message "Redo from start", and does not continue 
     further until it receives a valid input.
   * QB does not treat space as a delimiter when inputting a number from 
     the console.

See also
   * Input #
   * Input()
   * Line Input



---------------------------------------------------- KeyPgInputfilemode ----
Input (File Mode)

Specifies text file to be opened for input mode

Syntax
   Open filename for Input [Encoding encoding_type] [Lock lock_type] as [#]
   filenum 

Parameters
   filename
      file name to open for input
   encoding_type
      indicates encoding type for the file
   lock_type
      locking to be used while the file is open
   filenum
      unused file number to associate with the open file

Description
   A file mode used with Open to open a text file for reading.

   This mode allows to read sequentially lines of text with Line Input #, 
   or to read comma separated values with Input #. 

   Text files can't be simultaneously read and written in FreeBASIC, so if 
   both functions are required on the same file, it must be opened twice.

   filename must be a string expression resulting in a legal file name in 
   the target OS, without wildcards. The file will be sought for in the 
   present directory, unless the filename contains a path . If the file 
   does not exist, an error is issued. The pointer is set at the first 
   character of the file.

   Encoding_type indicates the Unicode Encoding of the file, so characters 
   are correctly read. If omitted, "ascii" encoding is defaulted. Only 
   little endian character encodings are supported at the moment. 
      *"utf8", 
      *"utf16" 
      *"utf32" 
      *"ascii" (the default)

   Lock_type indicates the way the file is locked  for other processes, it 
   is one of:
      * Read - the file can be opened simultaneously by other processes, 
        but not for reading
      * Write - the file can be opened simultaneously by other processes, 
        but not for writing
      * Read Write - the file cannot be opened simultaneously by other 
        processes (the default)

   filenum is a valid FreeBASIC file number (in the range 1..255) not being 
   used for any other file presently open. The file number identifies the 
   file for the rest of file operations. A free file number can be found 
   using the FreeFile function.

Example
   Dim ff As UByte
   Dim randomvar As Integer
   Dim name_str As String
   Dim age As Integer

   '' collect the test data and output to file with Write #
   Input "What is your name? ", name_str
   Input "What is your age? ", age
   Randomize
   Print

   ff = FreeFile
   Open "testfile" For Output As #ff
   Write #ff, Int(Rnd*42), name_str, age
   Close #ff

   '' clear variables
   randomvar = 0
   name_str = ""
   age = 0

   '' input the variables, using Input #
   ff = FreeFile
   Open "testfile" For Input As #ff
   Input #ff, randomvar, name_str, age
   Close #ff

   Print "Random Number was: " & randomvar
   Print "Your name is: " & name_str
   Print "Your age is: " & age

   'File outputted by this sample will look something like this
   '(not including the leading comment marker):
   '23,"Your Name",19

Differences from QB

See also
   * Input (Console I/O)
   * Input #
   * Input()
   * Append
   * Open
   * Output



---------------------------------------------------------- KeyPgInputPp ----
Input #

Reads a list of values from a text file

Syntax
   Input # filenum, variable_list

Parameters
   filenum
      a file number of a file or device opened for Input
   variable_list
      a list of variables used to hold the values read

Description
   Reads from a text file through a bound file number a delimiter-separated 
   set of values and writes them in reading order into the variables in 
   variable_list. If a variable is numeric the read value is converted from 
   its string representation into the corresponding type.

   Numeric values are converted in a similar way to the procedures Val and 
   ValLng, using the most appropriate function for the number format.

   Delimiters may be commas or line breaks. Whitespace is also treated as a 
   separator after numbers. A string including a comma or a whitespace must 
   be surrounded by double quotes. 

   To read an entire line into a string, use Line Input instead.

   Write # can be used to create a file readable with Input #.

   Note:
      - Using Input # is naturally dedicated to Input Access file mode.
      - It is also allowed in Binary/Random Access file mode, but this was 
      never well tested and results may vary.

Example
   Dim a As Integer
   Dim b As String
   Dim c As Single

   Open "myfile.txt" For Output As #1
   Write #1, 1, "Hello, World", 34.5
   Close #1

   Open "myfile.txt" For Input As #1
   Input #1, a, b, c
   Close #1
   Print a, b, c

Differences from QB
   * QB has a bug in INPUT # that causes it to read past the end of the 
     line if it does not find a matching end-quote when reading a string. 
     If you are porting QB code that relies upon this bug, you may need to 
     edit your data files to remove newlines from inside quoted strings, or 
     to use a custom function to piece back together the multiline string.

See also
   * Input
   * Input()
   * Line Input #
   * Write #
   * Open
   * Input (File Mode)



--------------------------------------------------------- KeyPgInputnum ----
Input()

Reads a number of characters from console or file

Syntax
   Declare Function Input ( n As Integer ) As String
   Declare Function Input ( n As Integer, filenum As Integer ) As String

Usage
   result = Input[$]( n [, [#]filenum ] )

Parameters
   n
      Number of bytes to read.
   filenum
      File number of a bound file or device.

Return Value
   Returns a String of the characters read.

Description
   Reads a number of characters from the console, or a bound file/device 
   specified by filenum.

   The first version waits for and reads n characters from the keyboard 
   buffer. Extended keys are not read. The characters are not echoed to the 
   screen.

   The second version waits for and reads n characters from a file or 
   device. The file position is updated.

   Note: Using Input() is dedicated to Input Access file mode, but it is 
   also allowed in Binary/Random Access file mode with some restrictions on 
   the values of n (for random mode, n must be equal to the record length 
   set by the LEN clause (or implicit value) in the OPEN statement).

Example
   Print "Select a color by number" 
   Print "1. blue"
   Print "2. red"
   Print "3. green"
   Dim choice As String
   Do
      choice = Input(1)
   Loop Until choice >= "1" And choice <= "3"

Dialect Differences
   * The string type suffix "$" is required in the -lang qb dialect.
   * The string type suffix "$" is optional in the -lang fblite dialect.
   * The string type suffix "$" is ignored in the -lang fb dialect, warn 
     only with the -w suffix compile option (or -w pedantic compile 
     option).

Differences from QB
   * None in the -lang qb dialect.

See also
   * Winput()
   * GetKey
   * Inkey



----------------------------------------------------- KeyPgSfxGenerated ----
Generated Sound Commands

Commands for generated sound, PLAY strings, and sfxlib mix settings.

Syntax
   Beep [ duration, pitch ]
   Sound frequency, duration
   Sound channel, frequency, duration, volume
   Tone channel, frequency, duration
   Noise channel, duration, volume
   Noise channel, frequency, duration, volume
   Note name, octave, duration
   Note channel, name, octave, duration
   Play music
   Play channel, music
   Play music1, music2
   Play music1, music2, music3
   Tempo bpm
   bpm = Tempo()
   Channel channel
   channel = Channel()
   Octave octave
   octave = Octave()
   Voice instrument
   instrument = Voice()
   Vol level
   Volume level
   level = Volume()
   Volume channel, level
   level = Volume( channel )
   Balance position
   position = Balance()
   Pan channel, position
   position = Pan( channel )
   Wave id, waveform
   Envelope id, attack, decay, sustain, release
   Instrument id, wave_id, envelope_id
   Instrument channel, instrument_id

Description
   These commands synthesize sound directly through sfxlib.  Sound, Tone, 
   Noise, Note, and Play create voices.  Tempo, Channel, Octave, and Voice 
   set defaults used by PLAY-string and generated-sound commands.  Volume, 
   Vol, Balance, and Pan control mix levels and stereo placement.

   Sound accepts the high-impact classic form Sound frequency, duration and
   the explicit channel form Sound channel, frequency, duration, volume.
   When both arguments are integers, duration is interpreted as the PC BASIC
   timer-tick value.

   Wave defines a waveform id.  The currently supported waveform values 
   are:
      * 0 sine
      * 1 square
      * 2 triangle
      * 3 saw
      * 4 noise

   Envelope defines an ADSR envelope using seconds for attack, decay, and 
   release, and a 0.0 to 1.0 sustain level.  Instrument can define an 
   instrument from a waveform and envelope, or assign an instrument to a 
   channel.

   The channel-oriented commands use sfxlib's channel table.  Channels are 
   zero-based.

Example
   See examples/sfxlib/basics-01-generated-sound.bas, 
   examples/sfxlib/basics-02-play-strings.bas, 
   examples/sfxlib/basics-03-channels-mix.bas, 
   examples/sfxlib/basics-04-instruments.bas, and 
   examples/sfxlib/showcase.bas.

Platform Differences
   * On headless or diagnostic runs, SFXLIB_DRIVER=null can be set before 
     program startup to use the null output driver.

Differences from QB
   * New to FreeBASIC.

See also
   * Beep
   * Music
   * Sfx
   * Sound Library Reference



------------------------------------------------------------ KeyPgInstr ----
InStr

Locates the first occurrence of a substring or character within a string

Syntax
   Declare Function InStr ( ByRef str As Const String,  [ Any ] ByRef 
   substring As Const String ) As Integer
   Declare Function InStr ( ByRef str As Const WString, [ Any ] ByRef 
   substring As Const WString ) As Integer
   Declare Function InStr ( ByVal start As Integer, ByRef str As Const 
   String, [ Any ] ByRef substring As Const String ) As Integer
   Declare Function InStr ( ByVal start As Integer, ByRef str As Const 
   WString, [ Any ] ByRef substring As Const WString ) As Integer

Usage
   first = InStr( [ start, ] str, [ Any ] substring )

Parameters
   str
      The string where to search.
   substring
      The substring to find.
   start
      The position in str at which the search will begin. The first 
      character starts at position 1.

Return Value
   The position of the first occurrence of substring in str.

Description
   Locates the position of the first occurrence of a substring or character 
   within a string. In the first form of InStr (without start parameter), 
   the search begins at the first character.

   Zero (0) is returned if: either substring is not found, either str or 
   substring are empty strings, or start < 1.

   If the Any keyword is specified, InStr returns the first occurrence of 
   any character in substring.

Example
   ' It will return 4
   Print InStr("abcdefg", "de")

   ' It will return 0
   Print InStr("abcdefg", "h")

   ' It will search for any of the characters "f", "b", "c", and return 2 as "b" is encountered first
   Print InStr("abcdefg", Any "fbc")

   Dim test As String
   Dim idx As Integer

   test = "abababab"
   idx = InStr(test, "b")

   Do While idx > 0 'if not found loop will be skipped
      Print """b"" at " & idx
      idx = InStr(idx + 1, Test, "b")
   Loop

'A Unicode example:
dim text as wstring*20
text = "&#1055;&#1088;&#1080;&#1074;&#1077;&#1090;, &#1084;&#1080;&#1088;!"
print instr(text,"&#1077;&#1090;") ' displays 5

Platform Differences
   * The wide-character string version of InStr is not supported for DOS 
     target.

Differences from QB
   * QB returns start if search is a zero length string.
   * QB does not support Unicode.

See also
   * InStrRev
   * Mid (Function)



--------------------------------------------------------- KeyPgInstrrev ----
InStrRev

Locates the last occurrence of a substring or character within a string

Syntax
   Declare Function InStrRev ( ByRef str As Const String, [ Any ] ByRef 
   substring As Const String, ByVal start As Integer = -1 ) As Integer
   Declare Function InStrRev ( ByRef str As Const WString, [ Any ] ByRef 
   substring As Const WString, ByVal start As Integer = -1 ) As Integer

Usage
   last = InStrRev( str, [ Any ] substring [, start ]  )

Parameters
   str
      The string where to search.
   substring
      The substring to find.
   start
      The position in str at which the search will begin. The first 
      character starts at position 1.

Return Value
   The position of the last occurrence of substring in str.

Description
   Locates the position of the last occurrence of a substring or character 
   within a string.  If start parameter is not given or is less than zero, 
   the search begins at the last character.

   Zero (0) is returned if:
      * substring is not found, or
      * either str or substring is an empty strings, or 
      * start is zero, or 
      * start is greater than the length of str.

   If the Any keyword is specified, InStrRev returns the last occurrence of 
   any character in substring.

Example
   ' It will return 4
   Print InStrRev("abcdefg", "de")

   ' It will return 0
   Print InStrRev("abcdefg", "h")

   Dim test As String
   Dim idx As Integer

   test = "abababab"
   idx = InStrRev(test, "b")

   Do While idx > 0 'if not found loop will be skipped
      Print """b"" at " & idx
      idx = InStrRev(Test, "b", idx - 1)
   Loop

'A Unicode example:
dim text as wstring*20
text = "&#1055;&#1088;&#1080;&#1074;&#1077;&#1090;, &#1084;&#1080;&#1088;!"
print instrrev(text,"&#1077;&#1090;") ' displays 5

Platform Differences
   * The wide-character string version of InStrRev is not supported for 
     DOS target.

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Instrrev.

Differences from QB
   * New to FreeBASIC

See also
   * InStr
   * Mid (Function)



-------------------------------------------------------------- KeyPgInt ----
Int

Returns the floor of a number

Syntax
   Declare Function Int ( ByVal number As Single ) As Single
   Declare Function Int ( ByVal number As Double ) As Double
   Declare Function Int ( ByVal number As Integer ) As Integer
   Declare Function Int ( ByVal number As UInteger ) As UInteger

Usage
   result = Int( number )

Parameters
   number
      the floating-point number to round

Return Value
   Returns the floor of number, i.e. the largest integer that is less than 
   or equal to it.

Description
    Int returns the floor of number.  For example, Int(4.9) will return 4.0
   , and Int(-1.3) will return -2.0.  For integer types, the number is 
   returned unchanged.

   Note: To return the ceiling of number, i.e. the smallest integer that is 
   greater than or equal to it, one can use -Int( -number ).

   The Int unary Operator can be overloaded with user defined types.

Example
   Print Int(1.9)  '' will print  1
   Print Int(-1.9) '' will print -2 

Dialect Differences
   * In the -lang qb dialect, this operator cannot be overloaded.

Differences from QB
   * None

See also
   * Fix
   * CInt
   * Operator



---------------------------------------------------------- KeyPgInteger ----
Integer

Standard data type: 32-bit or 64-bit signed, same size as SizeOf(Any Ptr)

Syntax
   Dim variable As Integer
   Dim variable As Integer<bits>

Parameters
   bits
      A numeric constant expression indicating the size in bits of integer 
      desired.  The values allowed are 8, 16, 32 or 64.

Description
   Integer is the main data type FreeBASIC uses for integer math and 
   bitwise operations. It is the default type for number literals.

   In the first form Integer is a 32-bit or 64-bit signed whole-number data 
   type, depending on the target platform.

   If an explicit bit size is given (the second form), a data type is 
   provided that can hold values from -1LL Shl (bits-1) up to (1LL Shl (
   bits-1)) - 1. The selected data type is Byte for Integer<8>, Short for 
   Integer<16>, Long for Integer<32> and LongInt for Integer<64>.

Example
   #ifdef __FB_64BIT__
      Dim x As Integer = &H8000000000000000
      Dim y As Integer = &H7FFFFFFFFFFFFFFF
      Print "Integer Range = "; x; " to "; y
   #else
      Dim x As Integer = &H80000000
      Dim y As Integer = &H7FFFFFFF
      Print "Integer Range = "; x; " to "; y
   #endif

Dialect Differences
   * In the -lang fb and -lang fblite dialects, the Integer data type is 
     32-bit or 64-bit depending on target platform
   * In the -lang qb dialect, the Integer data type is 16-bit, regardless 
     of platform.

Differences from QB
   * The ability to select a bit size is new to FreeBASIC
   * The INTEGER type is always 16 bits wide in QB.

See also
   * Long
   * LongInt
   * UInteger
   * CInt
   * Table with variable types overview, limits and suffixes



--------------------------------------------------------------- KeyPgIs ----
Is

Clause in the Select Case statement block.

Syntax
   Case Is expression

Description
   Is specifies that a particular case inside a Select Case block will be 
   evaluated based on an expression including the greater than (>) or less 
   than (<) operator and a value. 

Example
   See example at Select Case.

See also
   * Select Case
   * Operator Is



------------------------------------------------------------- KeyPgOpIs ----
Operator Is (Run-Time Type Information)

Check if an object is compatible to a type derived from its compile-time 
type
(in the context of inheritance)

Syntax
   result = expression Is  typename

Parameters
   expression
      The expression to check, an object of a type that is directly or 
      indirectly derived from Object using Extends.
   typename
      The child type to check for. This type must be directly or indirectly 
      derived from the type of expression (the compile-time type of the 
      object).

Return Value
   Returns negative one (-1) if the expression is an object of real-type 
   typename or one of its base-types derived from the expression type, or 
   zero (0) if it's an object of an incompatible type.

Description
   The Is operator must be used in conjunction with inheritance in order to 
   check compatibility between objects and types from an inheritance 
   structure extending the built-in Object type.

   The Is operator is a binary operator that checks whether an object is 
   compatible to its derived types at run-time. Because Is relies on 
   Run-Time Type Information (RTTI), it can only be used with types that 
   are derived from the built-in Object type using Extends. The compiler 
   disallows using Is for checks that can be solved at compile-time.

   The Is operator is successful not only for the real-type (the "lowest"), 
   but also for its base-types, as long as they are still below the type of 
   expression (the compile-time type). In order to determine the real-type, 
   all possibilities from lowest to highest must be checked.

   Extending the built-in Object type allows to add an extra hidden vtable 
   pointer field at the top of the Type. The vtable is used to access 
   information for run-time type identification used by the Is operator.

   This operator cannot be overloaded.

Example
   Type Vehicle Extends Object
      As String Name
   End Type

   Type Car Extends Vehicle
   End Type

   Type Cabriolet Extends Car
   End Type

   Type Bike Extends Vehicle
   End Type

   Sub identify(ByVal p As Object Ptr)
      Print "Identifying:"

      '' Not a Vehicle object?
      If Not (*p Is Vehicle) Then
         Print , "unknown object"
         Return
      End If

      '' The cast is safe, because we know it's a Vehicle object
      Print , "name: " & CPtr(Vehicle Ptr, p)->Name

      If *p Is Car Then
         Print , "It's a car"
      End If

      If *p Is Cabriolet Then
         Print , "It's a cabriolet"
      End If

      If *p Is Bike Then
         Print , "It's a bike"
      End If
   End Sub

   Dim As Car ford
   ford.name = "Ford"
   identify(@ford)

   Dim As Cabriolet porsche
   porsche.name = "Porsche"
   identify(@porsche)

   Dim As Bike mountainbike
   mountainbike.name = "Mountain Bike"
   identify(@mountainbike)

   Dim As Vehicle v
   v.name = "some unknown vehicle"
   identify(@v)

   Dim As Object o
   identify(@o)

Differences from QB
   * New to FreeBASIC

See also
   * Extends
   * Extends Zstring
   * Extends Wstring
   * Object
   * Is (Select Case)
   * TypeOf
 


----------------------------------------------------------- KeyPgIsDate ----
IsDate

Tests if a string can be converted to a Date Serial

Syntax
   Declare Function IsDate ( ByRef stringdate As Const String ) As Long

Usage
   #include "vbcompat.bi"
   result = IsDate( stringdate )

Parameters
   stringdate
      the string to test

Return Value
   Returns non-zero (-1) if the date string can be converted to a 
   Date Serial, otherwise returns zero (0).

Description
   Date strings must be in the format set in the regional settings of the 
   OS to be considered valid dates.

   IsDate(Date) will return non-zero (-1) only if the regional settings 
   specify the same date format that QB used.

   The compiler will not recognize this function unless vbcompat.bi or 
   datetime.bi is included.

Example
   #include "vbcompat.bi"

   Dim s As String, d As Long

   Do
     Print
     Print "Enter a date: "

     Line Input s

     If s = "" Then Exit Do

     If IsDate( s ) = 0 Then
      Print "'"; s; "' is not a valid date"
     Else
      d = DateValue( s )
      Print "year  = "; Year( d )
      Print "month = "; Month( d )
      Print "day   = "; Day( d )
     End If

   Loop

Differences from QB
   * New to FreeBASIC

See also
   * Date Serials
   * DateSerial
   * TimeValue
   * DateValue



----------------------------------------------------- KeyPgIsredirected ----
IsRedirected

Checks whether stdin or stdout is redirected to a file

Syntax
   Declare Function IsRedirected ( ByVal is_input As Long = 0 ) As Long

Usage
   #include "fbio.bi"
   result = IsRedirected( is_input )

Parameters
   is_input
      A Long indicating the type of information to return.

Return Value
   Returns non-zero (-1) if stdin or stdout is redirected, otherwise 
   returns zero (0).

Description
   IsRedirected checks whether stdin or stdout is redirected to a file, 
   instead of being connected to the console/terminal as usual.

   If is_input is equal to non-zero (-1), IsRedirected checks stdin.
   If is_input is equal to zero (0), IsRedirected checks stdout.

Example
   '' A Windows based example, just for the use principle
   '' Self-sufficient example, using his own .exe file as dummy input file for stdin redirection

   #include "fbio.bi"

   '' Quotation marks wrapping for compatibility with spaces in path name
   Dim As String pathExe = """" & ExePath & """"
   Dim As String fileExe = Mid(Command(0), InStrRev(Command(0), "\") + 1)
   Dim As String redirection = " < """ & Command(0)
   If LCase(Right(Command(0), 4)) = ".exe" Then
     redirection &= """"
   Else
     redirection &= ".exe"""
   End If

   If Command() = "" Then  '' First process without stdin redirection
     '' Check stdin redirection
     Print "First process without stdin redirection: IsRedirected(-1) = "; IsRedirected(-1)
     '' Creation of asynchronous second process with stdin redirected from file.exe
     Shell("start /d " & pathExe & " /b " & fileExe & redirection & " secondprocess")
     '' Waiting for termination of asynchronous second process
     Sleep
   ElseIf Command() = "secondprocess" Then  '' Second process with stdin redirection
     '' Check stdin redirection
     Print "Second process with stdin redirection  : IsRedirected(-1) = "; IsRedirected(-1)
   End If

Differences from QB
   * New to FreeBASIC.

See also
   * Reset(Streamno)




============================================================================
    K

------------------------------------------------------------- KeyPgKill ----
Kill

Deletes a file from disk / storage media.

Syntax
   Declare Function Kill ( ByRef filename As Const String ) As Long

Usage
   result = Kill( filename )

Parameters
   filename
      The filename is the name of the disk file to delete. If the file is 
      not in the current directory, the path must also be given as 
      path/file.

Return Value
   Returns zero (0) on success, or non-zero on error.

Description
   Kill deletes a file from disk / storage media.

   The error code returned by Kill can be checked using Err in the next 
   line. The function version of  Kill returns directly the error code as a 
   32 bit Long.
 
Example
   Dim filename As String = "file.ext"
   Dim result As Long = Kill( filename )

   If result <> 0 Then Print "error trying to kill " ; filename ; " !"

Platform Differences
   On some platforms, Kill may be able to remove folders and read-only 
   files.  Whether it succeeds or fails here is not currently defined.  It 
   may be necessary to check the attributes of the file you are deleting, 
   and decide accordingly whether you want to try Killing it.

Differences from QB
   * KILL can optionally be used as function in FreeBASIC.

See also
   * Shell
   * RmDir




============================================================================
    L

----------------------------------------------------------- KeyPgLbound ----
LBound

Returns the lower bound of an array's dimension

Syntax
   Declare Function LBound ( array() As Any, ByVal dimension As Integer = 1 
   ) As Integer

Usage
   result = LBound( array [, dimension ] )

Parameters
   array
      an array of any type
   dimension
      the dimension to get lower bound of

Return Value
   Returns the lower bound of an array's dimension.
 
Description
   LBound returns the lowest value that can be used as an index into a 
   particular dimension of an array.

   Array dimensions are numbered from one (1) to n, where n is the total 
   number of dimensions. If dimension is not specified, LBound will return 
   the lower bound of the first dimension.

   If dimension is zero (0), LBound returns 1, corresponding to the lower 
   bound of the array dimensions 1..n. UBound returns n, the number of 
   dimensions, in this case. This can be used to detect the array's number 
   of dimensions.

   For any other (non-zero) dimension values outside of the valid range 1..
   n, LBound returns 0. UBound returns -1 in this case. This can be used to 
   detect whether a certain dimension exists in the array, and also works 
   when used on an empty array which does not have any valid dimensions.

   Thus, for empty dynamic arrays, we get:
      * Lbound(array) = 0 and Ubound(array) = -1 (dimension 1 does not 
        exist)
      * Lbound(array, 0) = 1 and Ubound(array, 0) = 0 (zero dimensions)
      * @array(Lbound(array)) = 0 (no data buffer allocated) - Note: No 
        longer supported since fbc 1.20.0

Example
   Dim array(-10 To 10, 5 To 15, 1 To 2) As Integer

   Print LBound(array) 'returns -10
   Print LBound(array, 2) 'returns 5
   Print LBound(array, 3) 'returns 1

See also
   * UBound
   * Static
   * Dim
   * ReDim



------------------------------------------------------------ KeyPgLcase ----
LCase

Returns a lower case copy of a string

Syntax
   Declare Function LCase ( ByRef str As Const String, ByVal mode As Long = 
   0 ) As String
   Declare Function LCase ( ByRef str As Const WString, ByVal mode As Long 
   = 0 ) As WString

Usage
   result = LCase[$]( str [ , mode ] )

Parameters
   str
      String to convert to lowercase.
   mode
      The conversion mode: 0 = current locale, 1 = ASCII only

Return Value
   Lowercase copy of str.

Description
   Returns a copy of str with all of the letters converted to lower case.

   If str is empty, the null string ("") is returned.

Example
   Print LCase("AbCdEfG")

Output:

   abcdefg

Platform Differences
   * The wide-character string version of LCase is not supported for DOS 
     target.

Dialect Differences
   * The string type suffix "$" is required in the -lang qb dialect.
   * The string type suffix "$" is optional in the -lang fblite dialect.
   * The string type suffix "$" is ignored in the -lang fb dialect, warn 
     only with the -w suffix compile option (or -w pedantic compile 
     option).

Differences from QB
   * QB does not support Unicode.

See also
   * UCase



------------------------------------------------------------- KeyPgLeft ----
Left

Returns the leftmost substring of a string

Syntax
   Declare Function Left ( ByRef str As Const String, ByVal n As Integer ) 
   As String
   Declare Function Left ( ByRef str As Const WString, ByVal n As Integer ) 
   As WString

Usage
   result = Left[$]( str, n )

Parameters
   str
      The source string.
   n
      The number of characters to return from the source string.

Return Value
   Returns the leftmost substring from str.

Description
   Returns the leftmost n characters starting from the left (beginning) of 
   str. If str is empty, then the null string ("") is returned. If n <= 0 
   then the null string ("") is returned. If n > len(str) then the entire 
   source string is returned.

Example
   Dim text As String = "hello world"
   Print Left(text, 5)

   will produce the output:

   hello

An Unicode example:

dim text as wstring*20
text = "&#1055;&#1088;&#1080;&#1074;&#1077;&#1090;, &#1084;&#1080;&#1088;!"
print left(text, 6) 'displays "&#1055;&#1088;&#1080;&#1074;&#1077;&#1090;"

Platform Differences
   * DOS does not support the wide-character string version of Left.

Dialect Differences
   * The string type suffix "$" is required in the -lang qb dialect.
   * The string type suffix "$" is optional in the -lang fblite dialect.
   * The string type suffix "$" is ignored in the -lang fb dialect, warn 
     only with the -w suffix compile option (or -w pedantic compile 
     option).

Differences from QB
   * QB does not support Unicode.

See also
   * Right
   * Mid (Function)



-------------------------------------------------------------- KeyPgLen ----
Len

Returns the length of an expression or data type

Syntax
   Declare Function Len ( ByRef expression As String ) As Integer
   Declare Function Len ( ByRef expression As ZString ) As Integer
   Declare Function Len ( ByRef expression As WString ) As Integer

   Declare Operator Len ( ByRef expression As datatype ) As datatype

   Declare Function Len ( datatype ) As Integer	

Usage
   result = Len( expression )
      or
   result = Len( DataType )

Parameters
   expression
      An expression of any type.
   datatype
      A DataType.

Return Value
   Returns the size of an expression or DataType (including the data fields 
   of a UDT) in bytes.

Description
   Len returns the length of an expression or the size of a DataType, in 
   bytes.

   In the first form, if expression is of type String, WString or ZString, 
   the length of the string in characters will be returned. If the 
   expression is of a user defined type, an Operator Len compatible with 
   that data type is called.  Otherwise, the size of the expression's data 
   type in bytes is returned.

   In the second form, if expression is ZString or WString, the size in 
   bytes of an ASCII or Unicode character is returned, respectively. If 
   datatype is String, the size of the string descriptor type is returned.

   If there is both a user defined type and a variable visible with the 
   same name in the current scope, the user defined type takes precedence 
   over the variable.  To ensure that the Len takes the variable instead of 
   the user defined type, wrap the argument to Len with parentheses to 
   force it to be seen as an expression.  For example Len((variable)).

   Note: When used with array names, Len returns the length of the array 
   datatype, but not the total number of its elements.
   For clarity, it is recommended that you avoid this potential confusion, 
   and use Len on the array datatype doing Len(Typeof(array)), rather than 
   the array name only doing Len(array).

   The Len unary Operator can be overloaded with user defined types.

Example
   Print Len("hello world") 'returns "11"
   Print Len(Integer) ' returns 4

   Type xyz
      a As Integer
      b As Integer
   End Type

   Print Len(xyz) ' returns 8
      

Version
   * Before fbc 1.08.0:
         Len was not returning the size of the data fields of a UDT.
         When a variable from a given namespace was accessed with the 
         namespace's name prefix, the argument to Len had to be wrapped 
         with parentheses to force it to be seen as an expression. For 
         example Len((namespace_name.variable)).

Dialect Differences
   * Len only allows expressions in the -lang qb dialect. 
   * Can be used with built-in types and user-defined types in the -lang fb
     and -lang fblite dialects.

Differences from QB
   * Can be used with built-in types and user-defined types in the -lang fb
     and -lang fblite dialects.
   * None in the -lang qb dialect.

See also
   * SizeOf



-------------------------------------------------------------- KeyPgLet ----
Let

Indicates the assignment operator.

Syntax
   Let variable = value
or
   Let( variable1 [, variable2 [, ... ]] ) = udt
or
   Operator typename.Let ( [ ByRef | ByVal ] rhs As datatype )
      statements
   end operator

Description
   Command intended to help the programmer to distinguish an assignment 
   statement (e.g. Let a = 1) from an equality test (e.g. If a = 1 then ...
   ).  As the compiler does not require it, it is usually omitted.

   Let can be used as a left-hand side operator to assign the members of a 
   user defined type to multiple variables. See Operator Let() (Assignment)

   Let is used with operator overloading to refer the assignment operator. 
   See Operator Let (Assignment)

Example
   '' Compile with -lang fblite or qb

   #lang "fblite"

   ' these two lines have the same effect:
   Let x = 100
   x = 100

Dialect Differences
   * The use of Let to indicate an assignment statement (Let variable = 
     expr) is not allowed in the -lang fb dialect.
   * The UDT to multi-variable Let assignment is only available in the 
     -lang fb dialect.
   * Overloading of operators is not available in the -lang qb and 
     -lang fblite dialects.

Differences from QB
   * None in the -lang fb dialect.
   * The Let operator is new to FreeBASIC.
   * The UDT to multi-variable Let assignment is new to FreeBASIC.

See also
   * Operator =[>] (Assignment)
   * Operator Let (Assignment)
   * Operator Let() (Assignment)
   * Operator



-------------------------------------------------------------- KeyPgLib ----
Lib

Specifies the library where a sub or function can be found as part of a 
declaration

Syntax
   Declare { Sub | Function } proc_name Lib "libname" [ Alias "symbol_name" 
   ] ( arguments list ) As return_type

   Extern "mangling" lib "libname"
      declarative statements
   end Extern

   Type T
      As Integer dummy
      Declare Constructor Lib "libname" [ Alias "symbol_name" ] ( arguments 
      list )
   end Type

Description
   In Sub or Function declarations, and also in class method declarations 
   (including constructors and destructors), Lib indicates the library 
   containing the function. Libraries specified in this way are linked in 
   as if #Inclib "Libname" or -l libname had been used.

   Lib can also be used with Extern ... End Extern Blocks to specifiy a Lib 
   for all declarations inside.

Example
   '' mydll.bas
   '' compile with:
   ''   fbc -dll mydll.bas

   Public Function GetValue() As Integer Export
     Function = &h1234
   End Function

   Declare Function GetValue Lib "mydll" () As Integer

   Print "GetValue = &h"; Hex(GetValue())

   ' Expected Output :
   ' GetValue = &h1234

Differences from QB
   * New to FreeBASIC

See also
   * Declare
   * #inclib



----------------------------------------------------- KeyPgLinegraphics ----
Line (Graphics)

Draws a line

Syntax
   Line [target,] [[STEP]|(x1, y1)]-[STEP] (x2, y2) [, [color][, [B|BF][, 
   style]]]
   or
   Line - (x2, y2) [, [color][, [B|BF][, style]]]

Parameters
   target
      specifies buffer to draw on
   STEP
      indicates that the starting coordinates are relative
   (x1, y1)
      starting coordinates of the line
   STEP
      indicates that ending coordinates are relative
   (x2, y2)
      ending coordinates of the line
   color
      the color attribute.
   B|BF
      specifies box or box filled mode
   style
      line style

Description
   Graphics statement that draws a straight line or a box between two 
   points. The action will take place on the current work page set via 
   ScreenSet, or onto the buffer Get/Put buffer if specified.

   Line coordinates are affected by custom coordinates system set via Window
   and View (Graphics) statements, and respect clipping rectangle set by 
   View (Graphics). If a pair of coordinates is preceded by the STEP 
   keyword, the coordinates are assumed to be relative to the last graphics 
   cursor position. If the B flag is specified, a rectangle will be drawn 
   instead of a line, with (x1,y1)-(x2,y2) as the coordinates of the 
   opposite rectangle corners. If BF is specified, a filled rectangle will 
   be drawn.

   Color denotes the color attribute, which is mode specific (see Color and 
   Screen (Graphics) for details). If omitted, the current foreground color 
   as set by the Color statement is used.

   Style, if specified, allows styled line drawing; its value is 
   interpreted as a 16-bit bitmask, and Line will use it to skip pixel 
   drawing. Starting at (x1,y1), the most significant bit of the style mask 
   is checked: if 1, the pixel is drawn, if 0, it's skipped. This repeats 
   for all the line pixels with the other bits, with the mask being reused 
   when the 16 bits are all checked.

   When Line is used as Line - (x2, y2), a line is drawn from the current 
   cursor position to the (x2,y2) coordinates specified by Line.  
   Alternatively, Point can be used to get the current cursor position.

   Note: Either chained use or boxes drawn with Line can induce pixels 
   overdrawn at some locations. Thus, the resultant (blended) color of 
   these overdrawn pixels is affected if a transparent color (in 
   conjunction with the GFX_ALPHA_PRIMITIVES option flag) is used.

Example
   '' draws a diagonal red line with a white box, and waits for 3 seconds
   Screen 13
   Line (20, 20)-(300, 180), 4
   Line (140, 80)-(180, 120), 15, b
   Line - ( 200, 200 ), 15
   Sleep 3000

   ' Draws 2 lines with 2 different line styles in 2 different colors
   ScreenRes 320, 240

   Line (10, 100)-(309, 140),  4, B, &b1010101010101010 ' red box with dashed border

   Line (20, 115)-(299, 115),  9,  , &b1111000011111111 ' blue dashed line
   Line (20, 125)-(299, 125), 10,  , &b0000000011110000 ' green dashed line

   Sleep

Differences from QB
   * target is new to FreeBASIC

See also
   * Circle
   * Window
   * View (Graphics)



-------------------------------------------------------- KeyPgLineinput ----
Line Input

Reads one line of input from the keyboard

Syntax
   Line Input [;] [promptstring {;|,} ] stringvariable1
      or
   Line Input [;] promptstring {;|,} stringvariable2 , maxlength

Parameters
   promptstring
      prompt to display before waiting for input. If it is followed by a 
      semicolon (;), a question mark ("? ") will be appended to the prompt. 
      If it is followed by a comma, nothing will be appended.
   stringvariable1
      variable-length or fixed_length (and known) string, to receive the 
      line of text
   stringvariable2
      dereferenced {z|w}string pointer or {z|w}string variable passed by 
      reference (string buffer size unknown for both), to receive the line 
      of text
   maxlength
      maximum number of characters allowed to be written to the string 
      buffer, including the NULL terminator

Description
   Reads a line of text from the keyboard and stores it in a string 
   variable.

   The promptstring - if any - is written to the screen at the current 
   cursor location, and characters read are echoed to the screen 
   immediately following the prompt. If no prompt is specified, characters 
   are echoed at the current cursor location.

   The optional leading semicolon (;) after Line Input is similar to the 
   optional trailing semicolon in a Print statement: the cursor will remain 
   on the same line after all of the characters have been echoed, 
   otherwise, the cursor will move to the beginning of the next line.

   Line Input has a limited edit capacity: it allows to use the left and 
   right cursor keys to navigate the text, and to erase or insert 
   characters. If a better user interface is needed, a custom input routine 
   should be used.

   Two syntaxes are available:
      * The first syntax is only allowed when the string buffer size 
        (provided by stringvariable1) is either variable or fixed (and 
        known). For this first syntax, the promptstring parameter is 
        optional.
      * The second syntax with maxlength parameter is only allowed when 
        the string buffer size (provided by stringvariable2) is unknown. 
        This happens for dereferenced ZString/WString pointers, or ZString/
        WString variables passed by reference. This can used to truncate 
        the text line to be read, or avoid overflowing beyond allocated 
        data of the provided string buffer. For this second syntax, the 
        promptstring parameter is mandatory even if it is empty (use "").

Example
   Dim s As String
   Line Input "Enter a line"; s
   Print "Full line that you entered:"
   Print "'"; s; "'"
   Print

   Const maxlength = 11  '' max 10 characters plus 1 null terminal character
   Dim pz As ZString Ptr = CAllocate(maxlength, SizeOf(ZString))
   Line Input "Enter a line"; *pz, maxlength
   Print "First " & maxlength - 1 & " characters that you entered:"
   Print "'"; *pz; "'"
   Deallocate(pz)

Version
   * Before fbc 1.10.0, the second syntax (with maxlength parameter) was 
     not supported.

Differences from QB
   * QBASIC only allowed literal strings for the prompt text.  FreeBASIC 
     allows any variable or constant string expression.

See also
   * Line Input #
   * Input



------------------------------------------------------ KeyPgLineinputPp ----
Line Input #

Reads one line of text from a file

Syntax
   Line Input #file number, string_variable_1
      or
   Line Input #file number, string_variable_2 , max_length

Parameters
   file number
      file number of an file opened for Input
   string_variable_1
      variable-length or fixed_length (and known) string, to receive the 
      line of text
   string_variable_2
      dereferenced {z|w}string pointer or {z|w}string variable passed by 
      reference (string buffer size unknown for both), to receive the line 
      of text
   max_length
      maximum number of characters allowed to be written to the string 
      buffer, including the NULL terminator

Description
   Reads a line from an open text file (opened for Input through a bound 
   file number) and stores it in a string variable.  

   A line of text ends at, but does not include the end of line characters. 
   An end of line character may be the LF character (Chr(10)) or the CRLF 
   character pair (Chr(13,10)).

   Two syntaxes are available:
      * The first syntax is only allowed when the string buffer size 
        (provided by string_variable_1) is either variable or fixed (and 
        known).
      * The second syntax with max_length parameter is only allowed when 
        the string buffer size (provided by string_variable_2) is unknown. 
        This happens for dereferenced ZString/WString pointers, or ZString/
        WString variables passed by reference. This can used to truncate 
        the text line to be read, or avoid overflowing beyond allocated 
        data of the provided string buffer.

   Note:
      - Using Line Input # is naturally dedicated to Input Access file 
      mode.
      - It is also allowed in Binary/Random Access file mode, but this was 
      never well tested and results may vary.

Example
   Open "myfile.txt" For Output As #1
   Print #1, "Hello, World"
   Close #1

   Dim s As String
   Open "myfile.txt" For Input As #1
   Line Input #1, s
   Close #1
   Print "'" & s & "'"

   Const maxlength = 6  '' max 5 characters plus 1 null terminal character
   Dim pz As ZString Ptr = CAllocate(maxlength, SizeOf(ZString))
   Open "myfile.txt" For Input As #1
   Line Input #1, *pz, maxlength
   Close #1
   Print "'" & *pz & "'"
   Deallocate(pz)

Version
   * Before fbc 1.10.0, the second syntax (with max_length parameter) was 
     not supported.

Differences from QB
   * None

See also
   * Line Input
   * Input #
   * Open
   * Input (File Mode)



----------------------------------------------------------- KeyPgLoByte ----
LoByte

Gets the lowest byte of the operand.

Syntax
   #define LoByte( expr ) (Cast(UInteger, expr) And &h000000FF)

Usage
   result = LoByte( expr )

Parameters
   expr
      A numeric expression, converted to an UInteger value.

Return Value
   Returns the value of the low byte of expr.

Description
   This macro converts the numeric expression expr to an UInteger value, 
   then expands to an UInteger representing the value of its 
   least-significant (low) byte.

Example
   Dim N As UInteger

   'Note there are 16 bits
   N = &b1010101110000001
   Print "N is                                       "; N
   Print "The binary representation of N is          "; Bin(N)
   Print "The most significant byte (MSB) of N is    "; HiByte(N)
   Print "The least significant byte (LSB) of N is   "; LoByte(N)
   Print "The binary representation of the MSB is    "; Bin(HiByte(N))
   Print "The binary representation of the LSB is    "; Bin(LoByte(N))
   Sleep

The output would look like:

   N Is                                       43905
   The Binary representation of N Is          1010101110000001
   The most significant Byte (MSB) of N Is    171
   The least significant Byte (LSB) of N Is   129
   The Binary representation of the MSB Is    10101011
   The Binary representation of the LSB Is    10000001

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __LOBYTE.

Differences from QB
   * New to FreeBASIC

See also
   * HiByte
   * LoWord
   * HiWord



-------------------------------------------------------------- KeyPgLoc ----
LOC

Returns the file position where the last file read/write was performed

Syntax
   Declare Function LOC ( ByVal filenum As Long ) As LongInt

Usage
   result = LOC( filenum )

Parameters
   filenum
      The file number of an open file.

Return Value
   The file position where the last read/write was performed.

Description
   Returns the position where the last file read/write was performed.

   The position is indicated in records:
      In files opened FOR RANDOM the record length specified when file was 
      opened is used
      In  text files (FOR INPUT|OUTPUT|APPEND, a record length of 128 bytes 
      is supposed.
      In files opened for BINARY a 1 byte record length is used.

   In FreeBASIC the file position is 1 based, the first record of a file is 
   record 1 (LOC=1 after reading or writing the first record, LOC=0 for the 
   start position in the file).

   When used with a serial device, LOC returns the number of bytes waiting 
   to be read from the serial device's input buffer.

Example
   Dim b As String

   If Open Com ("com1:9600,n,8,1,cs,rs,ds,bin" For Binary As #1) <> 0 Then
     Print "unable to open serial port"
     End
   End If

   Print "Sending command: AT"

   Print #1, "AT" + Chr(13, 10);

   Sleep 500,1

   Print "Response:"

   While( LOC(1) > 0 )
     b = Input(LOC(1), 1)
     Print b;
   Wend

   Close #1

Differences from QB
   * None

See also
   * LOF
   * EOF
   * Seek (Function)
   * Open



------------------------------------------------------------ KeyPgLocal ----
Local

Error handling statement to set the current error handler

Syntax
   On Local Error Goto label

Description
   The Local clause in an On Error construction allows to define an error 
   handler in the same Sub or Function the On Local Error is in.

    Remark: Presently, the Local clause (authorized only inside 
   Sub/Function) is ignored by the compiler, and the error handler should 
   be in the scope of the same procedure the On [Local] Error is in.

Example
   '' compile with -lang fblite or qb

   #lang "fblite"

   Declare Sub foo

   foo
   Print "ok"
   Sleep

   Sub foo
     Dim errno As Integer
     On Local Error Goto fail
     Open "xzxwz.zwz" For Input As #1
     On Local Error Goto 0
     Exit Sub
   fail:                  ' here starts the error handler
     errno = Err
     Print "Error "; errno      ' just print the error number
     Sleep
   End Sub

Differences from QB
   * The LOCAL clause comes from PDS 7.1. QB 4.5 does not allow local 
     error handling.

See also
   * On Error
   * Labels



----------------------------------------------------------- KeyPgLocate ----
Locate

Sets the current cursor position

Syntax
   Declare Function Locate( row As Long = 0, column As Long = 0, state As 
   Long = -1, start As Long = 0, stop As Long = 0 ) As Long

Usage
   Locate [row], [column], [state]

   result = Locate( [row], [column], [state] )
   new_column = LoByte( result )
   new_row = HiByte( result )
   new_state = HiWord( result )

Parameters
   row
      the 1-based vertical character position in the console.
   column
      the 1-based horizontal character position in the console.
   state
      the state of the cursor in console-mode only: 0 is off, 1 is on; text 
      cursor is never visible in graphics mode.
   start
      Ignored. Allowed for -lang qb dialect compatibility only.
   stop
      Ignored. Allowed for -lang qb dialect compatibility only.

Return Value
   Returns a 32 bit Long containing the current cursor position and state. 
   The Low Byte Of The Low Word contains the column, the 
   High Byte Of The Low Word contains the row, and the High Word contains 
   the cursor state.

   If any of the row, column or state parameters were just set by the call 
   to Locate, then the return value will reflect these new values, not the 
   previous ones. If any of the parameters were omitted in the call to 
   Locate, then the return value will reflect the current values, which are 
   the same as before the call to Locate.

   Locate will attempt to position the cursor at the specified row and 
   column. If the position is beyond the screen extents, cursor will not 
   reposition. And next Print to the screen will continue at last valid 
   cursor position.  When printing to the last line of the screen, and the 
   Print statement has a new line character, the screen will scroll and 
   reposition the cursor automatically to the last line, column 1.

Description
   Sets the text cursor in both graphics and console modes.

Example
   Locate 10
   Print "Current line:"; CsrLin

   '' Text cursor + mouse tracking
   Dim As Long x = 0, y = 0, dx, dy

   Cls
   Locate , , 1

   While Inkey <> Chr(27)
      GetMouse dx, dy
      If( dx <> x Or dy <> y ) Then
         Locate y+1, x+1: Print " ";
         x = dx
         y = dy
         Locate 1, 1: Print x, y, ""
         Locate y+1, x+1: Print "X";
      End If
   Wend

Differences from QB
   * The start and stop arguments have no effect in FreeBASIC.
   * QB will raise an error if row or column are beyond the screen 
     extents.

See also
   * CsrLin
   * Pos
   * Print
   * ?



------------------------------------------------------------- KeyPgLock ----
Lock

Restricts read/write access to a file or portion of a file

Syntax
   Lock #filenum, record
   Lock #filenum, start To end

Parameters
   filenum
      The file number used to Open the file.
   record
      The record (Random files) to lock.
   start
      The first byte position (Binary files) to lock from.
   end
      The last byte position (Binary files) to lock to.

Description
   Lock temporarily restricts access by other threads or programs to a 
   file, or portion of a file, usually to allow safe writing to it.

   After modifying the data, an Unlock with the same parameters as the Lock 
   should be issued.

   Note: This command does not always work, neither as documented nor as 
   expected. It appears to be broken at the moment.

Example
   '' e.g. locking a file, reading 100 bytes, and unlocking it. 
   '' To run, make sure there exists a file called 'file.ext' 
   '' in the current directory that is at least 100 bytes.

   Dim array(1 To 100) As Integer
   Dim f As Integer, i As Integer
   f = FreeFile
   Open "file.ext" For Binary As #f
   Lock #f, 1 To 100
   For i = 1 To 100
      Get #f, i, array(i)
   Next
   Unlock #f, 1 To 100
   Close #f

Differences from QB
   * Currently, FB cannot implicitly lock the entire file
   * In Random mode, FB cannot lock a range of records

See also
   * Open
   * Unlock
   * ScreenLock



-------------------------------------------------------------- KeyPgLof ----
LOF

Returns the length of an open disk file

Syntax
   Declare Function LOF ( ByVal filenum As Long ) As LongInt

Usage
   result = LOF( filenum )

Parameters
   filenum
      The file number of an open disk file.

Return Value
   The length in bytes of an open disk file.

Description
   Returns the length, in bytes, of a file opened previously with Open 
   using the given filenum.

   With Open Com it returns the length of the data pending to be read in 
   the receive buffer.

Example
   Dim f As Long
   f = FreeFile
   Open "file.ext" For Binary As #f
   Print LOF(f)
   Close #f

Differences from QB
   * None

See also
   * LOC
   * EOF
   * Open



-------------------------------------------------------------- KeyPgLog ----
Log

Returns the natural logarithm of a given number

Syntax
   Declare Function Log cdecl ( ByVal number As Double ) As Double

Usage
   result = Log( number )

Parameters
   number
      The number to calculate the natural log.

Return Value
   Returns the logarithm with the base e (also know as the natural 
   logarithm) of number.

Description
   There can be some confusion with this notation given that in mathematics 
   the natural logarithm function is usually denoted LN, while the 
   logarithm of base 10 is often denoted as LOG. FreeBASIC, like most 
   computer programming languages, uses LOG to denote the natural 
   logarithm. The required number argument can be any valid numeric 
   expression greater than zero. If number is zero, FreeBASIC returns a 
   special value representing "-infinity", printing like "-Inf". If number 
   is less than zero, Log returns a special value representing "not 
   defined", printing like "NaN" or "IND", exact text is platform 
   dependent. If number is an uninitialized variable, -infinity is 
   returned.

   Log can be overloaded as operator to accept user-defined types.

Example
   'Find the logarithm of any base
   Function LogBaseX (ByVal Number As Double, ByVal BaseX As Double) As Double
      LogBaseX = Log( Number ) / Log( BaseX )
      'For reference:   1/log(10)=0.43429448
   End Function

   Print "The log base 10 of 20 is:"; LogBaseX ( 20 , 10 )
   Print "The log base 2 of 16 is:"; LogBaseX ( 16 , 2 )

   Sleep

The output would look like:

   The Log Base 10 of 20 Is: 1.301029995663981
   The Log Base 2 of 16 Is: 4

Differences from QB
   * None

See also
   * Exp



------------------------------------------------------------- KeyPgLong ----
Long

Standard data type: 32-bit signed integer

Syntax
   Dim variable As Long

Description
   32-bit signed whole-number data type. Can hold values from -2147483648 
   to 2147483647. Corresponds to a signed DWORD.

Example
     Dim x As Long = &H80000000
     Dim y As Long = &H7FFFFFFF
     Print "Long Range = "; x; " to "; y

   Output:
   Long Range = -2147483648 To  2147483647

See also
   * Integer
   * LongInt
   * ULong
   * Table with variable types overview, limits and suffixes



---------------------------------------------------------- KeyPgLongint ----
LongInt

Standard data type: 64 bit signed

Syntax
   Dim variable As LongInt

Description
   A 64-bit signed whole-number data type. Can hold values from -9 223 372 
   036 854 775 808 to 9 223 372 036 854 775 807. Corresponds to a signed 
   QWORD.

Example
     Dim x As LongInt = &H8000000000000000
     Dim y As LongInt = &H7FFFFFFFFFFFFFFF
     Print "LongInt Range = "; x; " to "; y

   Output:
   LongInt Range = -9223372036854775808 To  9223372036854775807

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Longint.

Differences from QB
   * New to FreeBASIC

See also
   * ULongInt
   * CLngInt
   * Table with variable types overview, limits and suffixes



------------------------------------------------------------- KeyPgLoop ----
Loop

Control flow statement for looping.

Syntax
   Do
      [ statement block ]
   Loop [ { Until | While } condition ]

Example
   See example at Do...Loop.

See also
   * Do...Loop

   


----------------------------------------------------------- KeyPgLoWord ----
LoWord

Gets the lowest 16bit word of the operand.

Syntax
   #define LoWord( expr ) (Cast(UInteger, expr) And &h0000FFFF)

Usage
   result = LoWord( expr )

Parameters
   expr
      A numeric expression, converted to an UInteger value.

Return Value
   Returns the value of the low word of expr.

Description
   This macro converts the numeric expression expr to an UInteger value, 
   then expands to an UInteger representing the value of its 
   least-significant (low) 16bit word.

Example
   Dim N As UInteger

   'Note there are 32 bits
   N = &b10000000000000011111111111111111

   Print "N is                                       "; N
   Print "The binary representation of N is          "; Bin(N)
   Print "The most significant word (MSW) of N is    "; HiWord(N)
   Print "The least significant word (LSW) of N is   "; LoWord(N)
   Print "The binary representation of the MSW is    "; Bin(HiWord(N))
   Print "The binary representation of the LSW is    "; Bin(LoWord(N))

   Sleep

The output would look like:

   N Is                                       2147614719
   The Binary representation of N Is          10000000000000011111111111111111
   The most significant word (MSW) of N Is    32769
   The least significant word (LSW) of N Is   65535
   The Binary representation of the MSW Is    1000000000000001
   The Binary representation of the LSW Is    1111111111111111

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __LOWORD.

Differences from QB
   * New to FreeBASIC

See also
   * LoByte
   * HiByte
   * HiWord



------------------------------------------------------------- KeyPgLpos ----
LPos

Returns the number of characters sent to the printer port in the last LPrint
statement.

Syntax
   Declare Function LPos ( ByVal printer As Long ) As Long

Usage
   result = LPOS(printer)

Parameters
   printer
      Either 0, 1, 2 or 3.  Represents the printer port (LPT#)

Return Value
   Returns the number of characters sent.

Description
   Used to determine, from the last LPrint, how many characters were sent 
   to the printer port.

Example
   ' compile with -lang fblite or qb

   #lang "fblite"

   Dim test As String = "LPrint Example test"

   Print "Sending '" + test + "' to LPT1 (default)"
   LPrint test
   Print "LPT1 last recieved " + Str(LPos(1)) + " characters"
   Print "String sent was " + Str(Len(test)) + " characters long"

   Sleep

Differences from QB
   * None

See also
   * LPrint



----------------------------------------------------------- KeyPgLprint ----
LPrint

Writes text to the default printer.

Syntax
   LPrint  [ Using formatstring,] [expressionlist] [(, | ;)] ...

Parameters
   formatstring
      String specifying the output format.
   expressionlist
      List of variables to output according to the specified format.

Description
   Prints expressionlist to the printer attached to the parallel port LPT1, 
   or if it does not exist, to the default printer.  To print to a printer 
   different from the default one, use Open Lpt.

   The Using clause formats expressionlist according to formatstring.  
   Except an UDT, any data type can be passed to LPrint expressionlist, 
   expressions do not need to be first converted to strings.

   Using a comma (,) as separator or in the end of the expressionlist will 
   place the cursor in the next column (every 14 characters), using a 
   semi-colon (;) won't move the cursor. If neither of them are used in the 
   end of the expressionlist, then a new-line will be printed.

   Some printers will not print at all until a Chr(12) (End of Page) 
   character is printed.

   Internally, FreeBASIC uses the special file number -1 for printing using 
   LPrint.  This file number may be safely closed using Close -1.  The next 
   use of LPrint will automatically reopen it as needed.

Example
   '' Compile with -lang fblite or qb

   #lang "fblite"

   '' new-line
   LPrint "Hello World!"

   '' no new-line
   LPrint "Hello"; "World"; "!";

   LPrint

   '' column separator
   LPrint "Hello!", "World!"

   '' end of page
   LPrint Chr$(12)

Differences from QB
   * None

Dialect Differences
   * LPrint is not supported in the -lang fb dialect. In this dialect the 
     printer must be properly opened with Open Lpt and Print # must be used 
     to print.

See also
   * Open Lpt
   * Print
   * ?
   * Print #
   * ? #
   * Write



------------------------------------------------------------- KeyPgLset ----
LSet

Left-justifies a string

Syntax
   Declare Sub LSet ( ByRef dst As String, ByRef src As Const String )
   Declare Sub LSet ( ByVal dst As WString Ptr, ByVal src As Const WString 
   Ptr )

Usage
   LSet dst, src
   LSet dst_udt, src_udt

Parameters
   dst
      String String to receive the data.
   src
      Source String to get the data.
   dst_udt
      User defined Type to receive the data.	
   src_udt
      User defined Type to copy the data from.

Description
   LSet left justifies text into the string buffer dst, filling the left 
   part of the string with src and the right part with spaces. The string 
   buffer size is not modified.
   If text is too long for the string buffer size, LSet truncates 
   characters from the right.

   For compatibility with QBasic, LSet can also copy a user defined type 
   variable into another one. The copy is made byte for byte, without any 
   care for fields or alignment. It's up to the programmer to take care for 
   the  validity of the result.

Example
   Dim buffer As String
   buffer = Space(10)
   LSet buffer, "91.5"
   Print "-[" & buffer & "]-"

	Output:

   -[91.5      ]-

   Type mytype1
      x As Integer
      y As Integer
   End Type

   Type mytype2
      z As Integer
   End Type

   Dim a As mytype1 , b As mytype2
   b.z = 1234

   LSet a, b
   Print a.x

Differences from QB
   *In QB, the syntax was LSet dst = src. That syntax is also supported by 
     FB.

See also
   * RSet
   * Space
   * Put (File I/O)
   * MKD
   * MKI
   * MKL
   * MKS



------------------------------------------------------------ KeyPgLtrim ----
LTrim

Removes surrounding substrings or characters on the left side of a string

Syntax
   Declare Function LTrim ( ByRef str As Const String, [ Any ] ByRef 
   trimset As Const String = " " ) As String
   Declare Function LTrim ( ByRef str As Const WString, [ Any ] ByRef 
   trimset As Const WString = WStr(" ") ) As WString

Usage
   result = LTrim[$]( str [, [ Any ] trimset ] )

Parameters
   str
      The source string.
   trimset
      The substring to trim.

Return Value
   Returns the trimmed string.

Description
   This procedure trims surrounding characters from the left (beginning) of 
   a source string:
      * Substrings matching trimset will be trimmed if specified, 
        otherwise spaces (ASCII code 32) are trimmed.
      * If the Any keyword is used, any character matching a character in 
        trimset will be trimmed.
   All comparisons are case-sensitive.

Example
   Dim s1 As String = "  101 Things to do."
   Print "'" + LTrim(s1) + "'"
   Print "'" + LTrim(s1, " 01") + "'"
   Print "'" + LTrim(s1, Any " 01") + "'"

   Dim s2 As String = "BaaBaaBAA Test Pattern"
   Print "'" + LTrim(s2, "Baa") + "'"
   Print "'" + LTrim(s2, Any "BaA") + "'"

   will produce the output:

   '101 Things to do.'
   '  101 Things to do.'
   'Things to do.'
   'BAA Test Pattern'
   ' Test Pattern'

Platform Differences
   * DOS version/target of FreeBASIC does not support the wide-character 
     version of LTrim.

Dialect Differences
   * The string type suffix "$" is required in the -lang qb dialect.
   * The string type suffix "$" is optional in the -lang fblite dialect.
   * The string type suffix "$" is ignored in the -lang fb dialect, warn 
     only with the -w suffix compile option (or -w pedantic compile 
     option).

Differences from QB
   * QB does not support specifying a trimset string or the ANY clause.

See also
   * RTrim
   * Trim




============================================================================
    M

------------------------------------------------------------- KeyPgMidi ----
Midi

Controls MIDI output through sfxlib.

Syntax
   result = Midi Open( device )
   result = Midi Close()
   result = Midi Play( filename )
   result = Midi Stop()
   result = Midi Pause()
   result = Midi Resume()
   result = Midi Send( status, data1, data2 )

Description
   Midi opens a MIDI output device, plays MIDI files where supported, and 
   sends raw three-byte MIDI messages through Midi Send.

   MIDI support depends on the target and the active sfxlib backend.  
   Programs should be prepared for a MIDI device or MIDI file playback to 
   be unavailable.

Example
   See examples/sfxlib/midi-open.bas, examples/sfxlib/midi-send.bas, 
   examples/sfxlib/midi-play.bas, and examples/sfxlib/showcase.bas.

Differences from QB
   * New to FreeBASIC.

See also
   * Device
   * Music



----------------------------------------------------- KeyPgMidstatement ----
Mid (Statement)

Overwrites a substring of a string with another

Syntax
   Declare Sub Mid ( ByRef text As String, ByVal start As Integer, ByVal 
   length As Integer, ByRef expression As Const String )
   Declare Sub Mid ( ByVal text As WString Ptr, ByVal start As Integer, 
   ByVal length As Integer, ByVal expression As Const WString Ptr )

Usage
   Mid( text, start ) = expression
      Or
   Mid( text, start, length ) = expression

Parameters
   text
      The string to work with.
   start
      The start position in text of the substring to overwrite. The first 
      character starts at position 1.
   length
      The number of characters to overwrite.

Description
   Copies a maximum of length characters of expression into text, starting 
   at start.

   If length is not specified, all of expression is copied. The size of the 
   string text is unchanged; if expression is too big, as much of it is 
   copied up to the end of text.

   Mid can also be used as a function to return part of another string.  
   See Mid (Function).

Example
   Dim text As String

   text = "abc 123"
   Print text 'displays "abc 123"

   ' replace part of text with another string
   Mid(text, 5, 3) = "456" 
   Print text 'displays "abc 456"

Differences from QB
   * None

See also
   * Mid (Function)



------------------------------------------------------ KeyPgMidfunction ----
Mid (Function)

Returns a substring of a string

Syntax
   Declare Function Mid ( ByRef str as Const String, ByVal start as integer 
   ) as String
   Declare Function Mid ( ByVal str as Const WString Ptr, ByVal start as 
   integer ) as WString
   Declare Function Mid ( ByRef str as Const String, ByVal start as 
   integer, ByVal n as integer ) as String
   Declare Function Mid ( ByVal str as Const WString Ptr, ByVal start as 
   integer, ByVal n as integer ) as WString

Usage
   result = Mid[$]( str, start [, n ] )

Parameters
   str
      The source string.
   start
      The start position in str of the substring. The first character 
      starts at position 1.
   n
      The substring length, in characters.

Description
   Returns a substring starting from start in str. If str is empty then the 
   null string ("") is returned. If start <= 0 or start > len(str) then the 
   null string ("") is returned.

   In the first form of Mid, all of the remaining characters are returned. 
   In the second form, if n < 0 or n > len(str) - start then all of the 
   remaining characters are returned.

Example
   Print Mid("abcdefg", 3, 2)
   Print Mid("abcdefg", 3)
   Print Mid("abcdefg", 2, 1)

   will produce the output:
   cd
   cdefg
   b

A Unicode example:
   Wiki: code rendered this way to allow display of the Unicode characters.

dim text as wstring * 20
   text = "&#1055;&#1088;&#1080;&#1074;&#1077;&#1090;, 
   &#1084;&#1080;&#1088;!"
   print mid(text, 6, 4) ' displays "&#1090;, &#1084;"

Platform Differences
   * DOS does not support the wide-character string versions of Mid.

Dialect Differences
   * The string type suffix "$" is required in the -lang qb dialect.
   * The string type suffix "$" is optional in the -lang fblite dialect.
   * The string type suffix "$" is ignored in the -lang fb dialect, warn 
     only with the -w suffix compile option (or -w pedantic compile 
     option).

Differences from QB
   * QB does not support Unicode.

See also
   * InStr
   * Mid (Statement)
   * Left
   * Right
   * Asc



----------------------------------------------------------- KeyPgMinute ----
Minute

Gets the minute of the hour from a Date Serial 

Syntax
   Declare Function Minute ( ByVal date_serial As Double ) As Long

Usage
   #include "vbcompat.bi"
   result = Minute( date_serial )

Parameters
   date_serial
      the date serial

Return Value
   Returns the minute from a  variable containing a date in  Date Serial  
   format.

Description
 
   The compiler will not recognize this function unless vbcompat.bi is 
   included.

Example
   #include "vbcompat.bi"

   Dim ds As Double = DateSerial(2005, 11, 28) + TimeSerial(7, 30, 50)

   Print Format(ds, "yyyy/mm/dd hh:mm:ss "); Minute(ds)

Differences from QB
   * Did not exist in QB. This function appeared in PDS and VBDOS

See also
   * Date Serials



-------------------------------------------------------------- KeyPgMkd ----
MKD

Does a binary copy from a Double variable to a String, setting its length 
to 8 bytes

Syntax
   Declare Function MKD ( ByVal number As Double ) As String

Usage
   result = MKD[$]( number )

Parameters
   number
      A Double variable to binary copy to a String.

Return Value
   Returns a String with a binary copy of the Double.

Description
   Does a binary copy from a Double variable to a String, setting its 
   length to 8 bytes. The resulting string can be read back to a Double by 
   CVD.

   This function is useful to write numeric values to buffers without using 
   a Type definition.

Example
   Dim n As Double, e As String
   n = 1.2345
   e = MKD(n)
   Print n, CVD(e)

Dialect Differences
   * The string type suffix "$" is required in the -lang qb dialect.
   * The string type suffix "$" is optional in the -lang fblite dialect.
   * The string type suffix "$" is ignored in the -lang fb dialect, warn 
     only with the -w suffix compile option (or -w pedantic compile 
     option).

Differences from QB
   * None

See also
   * MKI
   * MKL
   * MKS
   * CVD
   * CVI
   * CVL
   * CVS



------------------------------------------------------------ KeyPgMkdir ----
MkDir

Makes a folder/directory on the local file system

Syntax
   Declare Function MkDir ( ByRef folder As Const String ) As Long

Usage
   result = MkDir( folder )

Parameters
   folder
      The new default folder/directory to be created, or a path to the 
      sub-folder/sub-directory to be created.

Return Value
   Returns zero (0) on success, and negative one (-1) on failure.

Description
   Creates a folder/directoy on the local file system.

   If folder is not a simple folder/directory name, but a path to a 
   sub-folder/sub-directory, the parent folder(s)/directory(s) specified in 
   the path must already exist.
   (only one folder/directory can be created for each request)

Example
   Dim pathname As String = "foo\bar\baz"
   Dim result As Long = MkDir( pathname )

   If 0 <> result Then Print "error: unable to create folder " & pathname & " in the current path."

Platform Differences
   * Linux requires the filename case matches the real name of the file. 
     Windows and DOS  are case insensitive. 
   * Path separators in Linux are forward slashes / . Windows uses 
     backward slashes \ but it allows for forward slashes .  DOS uses 
     backward  \ slashes. 

Differences from QB
   * None

See also
   * Shell
   * CurDir
   * ChDir
   * RmDir



-------------------------------------------------------------- KeyPgMki ----
MKI

Does a binary copy from an integer variable to a String of the same length 
as the size of the input variable

Syntax
   Declare Function MKI ( ByVal number As Integer ) As String
   Declare Function MKI<bits> ( ByVal number As Integer<bits> ) As String

Usage
   result = MKI[$]( number )
   result = MKI[$]<bits>( number )

Parameters
   number
      A Integer or Integer<bits> variable to binary copy to a String.

Return Value
   Returns a String containing a binary copy of number.

Description
   Does a binary copy from an Integer or Integer<bits> variable to a String,
   setting its length to the number of bytes in the type. The resulting 
   string can be read back to an integer type using CVI or CVI<bits>.

   This function is useful to write numeric values to buffers without using 
   a Type definition.

   MKI supports an optional <bits> parameter before the argument.  If bits 
   is 16, MKShort will be called instead; if bits is 32, MKL will be 
   called; if bits is 64, MKLongInt will be called.  The length of the 
   return value and the required number argument type will depend on which 
   function is called.  See each function's page for more information.

Example
   Dim a As Integer, b As String
   a=4534
   b=MKI(a)
   Print a, CVI(b)

Dialect Differences
   * In the -lang qb dialect, MKI returns a 2-byte-string, since a QB 
     integer is only 16 bits.
   * In the -lang qb dialect, <bits> parameter is not supported.
   * The string type suffix "$" is required in the -lang qb dialect.
   * The string type suffix "$" is optional in the -lang fblite dialect.
   * The string type suffix "$" is ignored in the -lang fb dialect, warn 
     only with the -w suffix compile option (or -w pedantic compile 
     option).

See also
   * CVI
   * MKShort
   * MKL
   * MKLongInt
   * Integer



-------------------------------------------------------------- KeyPgMkl ----
MKL

Does a binary copy from a Long variable to a String, setting its length to 
4 bytes

Syntax
   Declare Function MKL ( ByVal number As Long ) As String

Usage
   result = MKL( number )

Parameters
   number
      A Long variable to binary copy to a String.

Return Value
   Returns a String with a binary copy of the Long.

Description
   Does a binary copy from a Long variable to a String, setting its length 
   to 4 bytes. The resulting string can be read back to a Long by CVL.

   This function is useful to write numeric values to buffers without using 
   a Type definition.

Example
   Dim a As Long, b As String
   a = 4534
   b = MKL(a)
   Print a, CVL(b)
   Sleep

Dialect Differences
   * The string type suffix "$" is required in the -lang qb dialect.
   * The string type suffix "$" is optional in the -lang fblite dialect.
   * The string type suffix "$" is ignored in the -lang fb dialect, warn 
     only with the -w suffix compile option (or -w pedantic compile 
     option).

Differences from QB
   * None

See also
   * MKD
   * MKI
   * MKS
   * CVD
   * CVI
   * CVL
   * CVS



-------------------------------------------------------- KeyPgMklongint ----
MKLongInt

Does a binary copy from a LongInt variable to a String, setting its length 
to 8 bytes

Syntax
   Declare Function MKLongInt ( ByVal number As LongInt ) As String

Usage
   result = MKLongInt[$]( number )

Parameters
   number
      A LongInt variable to binary copy to a String.

Return Value
   Returns a String with a binary copy of the LongInt.

Description
   Does a binary copy  from a LongInt variable to a string, setting its 
   length to 8 bytes. The resulting string can be read back to a longint by 
   CVLongInt

   This function is useful to write numeric values to buffers without using 
   a Type definition.

Example
   Dim a As LongInt, b As String
   a = 4534
   b = MKLongInt(a)
   Print a, CVLongInt(b)
   Sleep

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Mklongint.
   * The string type suffix "$" is optional in the -lang fblite dialect.
   * The string type suffix "$" is ignored in the -lang fb dialect, warn 
     only with the -w suffix compile option (or -w pedantic compile 
     option).

Differences from QB
   * New to FreeBASIC

See also
   * CVLongInt



-------------------------------------------------------------- KeyPgMks ----
MKS

Does a binary copy from a Single variable to a String, setting its length 
to 4 bytes

Syntax
   Declare Function MKS ( ByVal number As Single ) As String

Usage
   result = MKS[$]( number )

Parameters
   number
      A Single variable to binary copy to a String.

Return Value
   Returns a String with a binary copy of the Single.

Description
   Does a binary copy  from a Single variable to a String, setting its 
   length to 4 bytes. The resulting string can be read back to a Single by 
   CVS.

   This function is useful to write numeric values to buffers without using 
   a Type definition.

Example
   Dim n As Single, e As String
   n = 1.2345
   e = MKS(n)
   Print n, CVS(e)

Dialect Differences
   * The string type suffix "$" is required in the -lang qb dialect.
   * The string type suffix "$" is optional in the -lang fblite dialect.
   * The string type suffix "$" is ignored in the -lang fb dialect, warn 
     only with the -w suffix compile option (or -w pedantic compile 
     option).

Differences from QB
   *None

See also
   * MKI
   * MKL
   * MKD
   * CVD
   * CVI
   * CVL
   * CVS



---------------------------------------------------------- KeyPgMkshort ----
MKShort

Does a binary copy from a Short variable to a String, setting its length to 
2 bytes

Syntax
   Declare Function MKShort ( ByVal number As Short ) As String

Usage
   result = MKShort[$](number)

Parameters
   number
      A Short variable to binary copy to a String.

Return Value
   Returns a String with a binary copy of the Short.

Description
   Does a binary copy  from a SHORT variable to a string, setting its 
   length to 2 bytes. The resulting string can be read back to a Short by 
   CVShort

   This function is useful to write numeric values to buffers without using 
   a Type definition.

Example
   Dim a As Short, b As String
   a = 4534
   b = MKShort(a)
   Print a, CVShort(b)
   Sleep

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Mkshort.
   * The string type suffix "$" is optional in the -lang fblite dialect.
   * The string type suffix "$" is ignored in the -lang fb dialect, warn 
     only with the -w suffix compile option (or -w pedantic compile 
     option).

Differences from QB
   * In QBasic this function is called MKI.

See also
   * CVShort



-------------------------------------------------------- KeyPgOpModulus ----
Operator Mod (Modulus)

Finds the remainder from a division operation

Syntax
   Declare Operator Mod ( ByRef lhs As Integer, ByRef rhs As Integer ) As 
   Integer

Usage
   result = lhs Mod rhs

Parameters
   lhs
      The left-hand side dividend expression.
   rhs
      The right-hand side divisor expression.

Return Value
   Returns the remainder of a division operation.

Description
   Operator Mod (Modulus) divides two Integer expressions and returns the 
   remainder. Float numeric values are converted to Integer by rounding up 
   or down.

   Neither of the operands are modified in any way.

   This operator can be overloaded for user-defined types.

Example
   Print 47 Mod 7
   Print 5.6 Mod 2.1
   Print 5.1 Mod 2.8

Output:

   5
   0
   2

This is because: 
   * 47 divided by 7 gives a remainder of 5
   * 5.6 is rounded to 6 while 2.1 is rounded to 2. This makes the problem 
     6 MOD 2 which means 6 divided by 2 which gives a remainder of 0
   * 5.1 is rounded to 5 while 2.8 is rounded to 3. This makes the problem 
     5 MOD 3 which means 5 divided by 3 which gives a remainder of 2

Dialect Differences
   * In the -lang qb dialect, this operator cannot be overloaded.

Differences from QB
   * None

See also
   * Mathematical Functions



------------------------------------------------------------ KeyPgMonth ----
Month

Gets the month of the year from a Date Serial

Syntax
   Declare Function Month ( ByVal date_serial As Double ) As Long

Usage
   #include "vbcompat.bi"
   result = Month( date_serial )

Parameters
   date_serial
      the date

Return Value
   Returns the month number from a variable containing a date in  
   Date Serial  format.

   The month values are in the range 1-12 being 1 for January and 12 for 
   December.

Description

   The compiler will not recognize this function unless vbcompat.bi is 
   included.

Example
   #include "vbcompat.bi"

   Dim a As Double = DateSerial(2005,11,28) + TimeSerial(7,30,50)

   Print Format(a, "yyyy/mm/dd hh:mm:ss "); Month(a)

Differences from QB
   * Did not exist in QB. This function appeared in PDS and VBDOS

See also
   * Date Serials



-------------------------------------------------------- KeyPgMonthname ----
MonthName

Gets the name of a month from its integral representation

Syntax
   Declare Function MonthName ( ByVal month As Long, ByVal abbreviate As 
   Long = 0 ) As String

Usage
   #include "vbcompat.bi"
   result = MonthName( month_number [, abreviate ] )

Parameters
   month
      the number of the month of the year - 1:January through 12:December
   abbreviate
      flag to indicate that name should be abbreviated

Return Value
   Returns the local operating system language month name from month value 
   1 to 12.

Description
   If abbreviate is true, the month name abbreviation  is returned. If 
   omitted or false, the whole name is returned.
    
   The compiler will not recognize this function unless vbcompat.bi or 
   datetime.bi is included.

Example
   #include "vbcompat.bi"

   Dim ds As Double = DateSerial(2005, 11, 28) + TimeSerial(7, 30, 50)

   Print Format(ds, "yyyy/mm/dd hh:mm:ss "); MonthName(Month(ds))

Differences from QB
   * Did not exist in QB. This function appeared in Visual Basic.

See also
   * Date Serials



------------------------------------------------------------ KeyPgMusic ----
Music

Loads and controls the current music file through sfxlib.

Syntax
   result = Music Load( filename )
   result = Music Play()
   result = Music Play( filename )
   result = Music Loop()
   result = Music Loop( filename )
   Music Pause
   Music Resume
   Music Stop
   status = Music Status()
   position = Music Position()

Description
   Music is the one-current-track file playback interface.  Music Load
   loads a file as the current music and replaces any previous music.
   Music Play and Music Loop start the current music when called without a
   filename, or load and start the supplied filename directly.

   Music Pause, Music Resume, and Music Stop control the current music.
   Music Status returns 0 for stopped, 1 for playing, and 2 for paused.  
   Music Position returns the current playback position in frames.

Example
   See examples/sfxlib/music-load.bas, examples/sfxlib/music-play.bas, 
   examples/sfxlib/music-loop.bas, and examples/sfxlib/showcase.bas.

Differences from QB
   * New to FreeBASIC.

See also
   * Sfx



--------------------------------------------------------- KeyPgMultikey ----
MultiKey

Detects the status of keys by keyboard scancode.

Syntax
   Declare Function MultiKey ( ByVal scancode As Long ) As Long

Usage
   result = MultiKey(scancode)

Parameters
   scancode
      The scan code of the key to check.

Return Value
   Returns -1 if the key for the specified scan code is pressed, otherwise 
   returns 0.

Description
   MultiKey is a function which will detect the status of any key, 
   determined by scancode, at any time. It will return -1 if the key is 
   pressed, otherwise it will return 0.

   The keyboard input buffer is not disabled while you use MultiKey; that 
   is, pressed keys will be stored and subsequently returned by your next 
   call to Inkey or GetKey or Input. This means you have to empty the 
   keyboard input buffer manually when you finish using MultiKey, using 
   something like the following method:
   While Inkey <> "": Wend  '' loop until the keyboard input buffer is empty
         

   For FB's built-in functionality of getting keyboard input, see 
   Keyboard Input (Basics).

   Keeping Inkey to work while you use MultiKey allows more flexibility and 
   can be useful to detect Chr(255)+"k" combo returned on window close 
   button click, if a windowed graphics mode has been set via the 
   Screen (Graphics) statement. For a list of accepted scancodes, see 
   DOS keyboard scancodes; these are guaranteed to be valid for all 
   FreeBASIC supported platforms.
   MultiKey should always work in graphics mode, as long as the screen is 
   Unlocked. Support in the console depends on the platform the program is 
   run on though, and cannot be guaranteed.

Example
   #include "fbgfx.bi"
   #if __FB_LANG__ = "fb"
   Using FB '' Scan code constants are stored in the FB namespace in lang FB
   #endif

   Dim As Integer x, y

   ScreenRes 640, 480

   Color 2, 15

   x = 320: y = 240
   Do
      ' Check arrow keys and update the (x, y) position accordingly
      If MultiKey(SC_LEFT ) And x >   0 Then x = x - 1
      If MultiKey(SC_RIGHT) And x < 639 Then x = x + 1
      If MultiKey(SC_UP   ) And y >   0 Then y = y - 1
      If MultiKey(SC_DOWN ) And y < 479 Then y = y + 1
      
      ' Lock the page while we work on it
      ScreenLock
         ' Clear the screen and draw a circle at the position (x, y)
         Cls
         Circle(x, y), 30, , , , ,F
      ScreenUnlock
      
      Sleep 15, 1
      
      ' Run loop until user presses Escape
   Loop Until MultiKey(SC_ESCAPE)

   ' Clear Inkey buffer
   While Inkey <> "": Wend

   Print "Press CTRL and H to exit..."

   Do
      Sleep 25
      
      '' Stay in loop until user holds down CTRL and H at the same time
      If MultiKey(SC_CONTROL) And MultiKey(SC_H) Then Exit Do
   Loop
      

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Multikey.

Differences from QB
   * New to FreeBASIC

See also
   * Keyboard scancodes
   * GetMouse
   * GetJoystick
   * Screen (Graphics)
   * Inkey
   * Event
   * ScreenEvent
   * Keyboard Input



------------------------------------------------------ KeyPgMutexCreate ----
MutexCreate

Creates a mutex used for synchronizing the execution of threads

Syntax
   Declare Function MutexCreate ( ) As Any Ptr

Usage
   result = MutexCreate

Return Value
   The Any Ptr handle of the mutex created, or the null pointer (0) on 
   failure.

Description
   Mutexes, short for "Mutually Exclusive", are a way of synchronizing 
   shared data within threads.  If there is a global variable used by 
   multiple threads (or a local static variable used by a single thread 
   called multiple times), it should be "locked" during its use with a 
   mutex.  This halts all threads using MutexLock with that mutex 
   (including the implicit main thread executing main program), until it is 
   unlocked with MutexUnlock.

   Mutexcreate creates a mutex, returning a handle which is to be referred 
   to when locking, unlocking, or destroying the mutex.  Mutexes created 
   with Mutexcreate should be destroyed when no longer needed or before the 
   end of the program with MutexDestroy.

   A  mutex is a lock that guarantees three things:
   1. Atomicity - Locking a mutex is an atomic operation, meaning that the 
   operating system (or threads library) assures you that if you locked a 
   mutex, no other thread succeeded in locking this mutex at the same time.
   2. Singularity - If a thread managed to lock a mutex, it is assured that 
   no other thread will be able to lock the thread until the original 
   thread releases the lock.
   3. Non-Busy Wait - If a thread attempts to lock a thread that was locked 
   by a second thread, the first thread will be suspended (and will not 
   consume any CPU resources) until the lock is freed by the second thread. 
   At this time, the first thread will wake up and continue execution, 
   having the mutex locked by it. 

Example
   See also the ThreadCreate examples.

   'Visual example of mutual exclusion between 2 threads by using Mutex:
   'the "user-defined thread" computes the points coordinates on a circle,
   'and the "main thread" plots the points.
   '
   'Principle of mutual exclusion
   '          Thread#A                XOR                  Thread#B
   '.....                                         .....
   'MutexLock(mut)                                MutexLock(mut)
   '  Do_something#A_with_exclusion                 Do_something#B_with_exclusion
   'MutexUnlock(mut)                              MutexUnlock(mut)
   '.....                                         .....
   '
   'Behavior:
   '- The first point must be pre-calculated.
   '- Nothing prevents that a same calculated point could be plotted several times
   '(depends on execution times of the loops between main thread and user thread).
   '- Nothing prevents that a calculated point could be not plotted
   '(same remark on the loop times).
   '
   'If you comment out the lines containing "MutexLock" and "MutexUnlock"
   '(inside "user-defined thread" or/and "main thread"),
   'there will be no longer mutual exclusion between computation of coordinates and plotting of points,
   'and many points will not be plotted on circle (due to non coherent coordinates).

   '-----------------------------------------------------------------------------------------------------

   Type ThreadUDT                                   'Generic user thread UDT
      Dim handle As Any Ptr                        'Any Ptr handle to user thread
      Dim sync As Any Ptr                          'Any Ptr handle to mutex
      Dim quit As Byte                             'Boolean to end user thread
      Declare Static Sub Thread (ByVal As Any Ptr) 'Generic user thread procedure
      Dim procedure As Sub (ByVal As Any Ptr)      'Procedure(Any Ptr) to be executed by user thread
      Dim p As Any Ptr                             'Any Ptr to pass to procedure executed by user thread
      Const False As Byte = 0                      'Constante "false"
      Const True As Byte = Not False               'Constante "true"
   End Type

   Static Sub ThreadUDT.Thread (ByVal param As Any Ptr) 'Generic user thread procedure
      Dim tp As ThreadUDT Ptr = param                  'Casting to generic user thread UDT
      Do
         Static As Integer I
         MutexLock(tp->sync)                          'Mutex (Lock) for user thread
         tp->procedure(tp->p)                         'Procedure(Any Ptr) to be executed by user thread
         I += 1
         Locate 30, 38
         Print I;
         MutexUnlock(tp->sync)                        'Mutex (Unlock) for user thread
         Sleep 5, 1
      Loop Until tp->quit = tp->True                   'Test for ending user thread
   End Sub

   '-----------------------------------------------------------------------------------------------------

   Type Point2D
      Dim x As Integer
      Dim y As Integer
   End Type

   Const x0 As Integer = 640 / 2
   Const y0 As Integer = 480 / 2
   Const r0 As Integer = 200
   Const pi As Single = 4 * Atn(1)

   Sub PointOnCircle (ByVal p As Any Ptr)
      Dim pp As Point2D Ptr = p
      Dim teta As Single = 2 * pi * Rnd
      pp->x = x0 + r0 * Cos(teta)
      Sleep 5, 1                         'To increase possibility of uncorrelated data occurrence
      pp->y = y0 + r0 * Sin(teta)
   End Sub

   Screen 12
   Locate 30, 2
   Print "<any_key> : exit";
   Locate 30, 27
   Print "calculated:";
   Locate 30, 54
   Print "plotted:";

   Dim Pptr As Point2D Ptr = New Point2D
   PointOnCircle(Pptr)                   ' Computation for a first point valid on the circle

   Dim Tptr As ThreadUDT Ptr = New ThreadUDT
   Tptr->sync = MutexCreate
   Tptr->procedure = @PointOnCircle
   Tptr->p = Pptr
   Tptr->handle = ThreadCreate(@ThreadUDT.Thread, Tptr)

   Do
      Static As Integer I
      Sleep 5, 1
      MutexLock(Tptr->sync)   'Mutex (Lock) for main thread
      PSet (Pptr->x, Pptr->y) 'Plotting one point
      I += 1
      Locate 30, 62
      Print I;
      MutexUnlock(Tptr->sync) 'Mutex (Unlock) for main thread
   Loop Until Inkey <> ""
    
   Tptr->quit = Tptr->True
   ThreadWait(Tptr->handle)
   MutexDestroy(Tptr->sync)
   Delete Tptr
   Delete Pptr

   Sleep

   See also the similar CondCreate example

Dialect Differences
   * Threading is not allowed in the -lang qb dialect.

Platform Differences
   * The DOS version of FreeBASIC does not allow for threads, as the OS 
     does not support them.
   * In Linux the threads are always started in the order they are 
     created, this can't be assumed in Win32. It's an OS, not a FreeBASIC 
     issue. 

Differences from QB
   * New to FreeBASIC

See also
   * MutexDestroy
   * MutexLock
   * MutexUnlock
   * ThreadCreate
   * ThreadWait



----------------------------------------------------- KeyPgMutexDestroy ----
MutexDestroy

Destroys a mutex

Syntax
   Declare Sub MutexDestroy ( ByVal id As Any Ptr )

Usage
   MutexDestroy( id )

Parameters
   id
      The Any Ptr handle of the mutex to be destroyed.

Description
   Mutexdestroy discards a mutex created by MutexCreate.  This call should 
   be executed after any threads using the mutex are no longer in use.

   See MutexCreate for more general information on mutexes.

Example
   See the examples in MutexCreate and also ThreadCreate.

Dialect Differences
   * Threading is not allowed in the -lang qb dialect.

Platform Differences
   * The DOS version of FreeBASIC does not allow for threads, as the OS 
     does not support them.
   * In Linux the threads are always started in the order they are 
     created, this can't be assumed in Win32. It's an OS, not a FreeBASIC 
     issue. 

Differences from QB
   * New to FreeBASIC

See also
   * MutexCreate
   * MutexLock
   * MutexUnlock
   * ThreadCreate
   * ThreadWait



-------------------------------------------------------- KeyPgMutexLock ----
MutexLock

Acquires a mutex

Syntax
   Declare Sub MutexLock ( ByVal id As Any Ptr )

Usage
   MutexLock( id )

Parameters
   id
      The Any Ptr handle of the mutex to be locked.

Description
   Mutexlock halts any other threads using a mutex "handle", generated by 
   MutexCreate, until the handle is unlocked with MutexUnlock.
   Such a halted thread has its execution suspended and does not consume 
   any CPU time until the mutex is unlocked.

   See MutexCreate for more general information on mutexes.

Example
   See also the examples in MutexCreate and also ThreadCreate.

   'Example of mutual exclusion for synchronization between 2 threads
   'by using 2 Mutexes only (by self lock and mutual unlock):
   'The Producer works one time, then the Consumer works one time.
   '
   'Principle of synchronisation by mutual exclusion
   '(initial condition: mut#A and mut#B locked)
   '
   '          Thread#A              XORs              Thread#B
   'Do_something#A_with_exclusion          MutexLock(mut#A)
   'MutexUnlock(mut#A)                       Do_something#B_with_exclusion
   '.....                                  MutexUnlock(mut#B)
   'MutexLock(mut#B)                       .....

   '----------------------------------------------------------------------

   Dim Shared produced As Any Ptr
   Dim Shared consumed As Any Ptr
   Dim consumer_id As Any Ptr
   Dim producer_id As Any Ptr

   Sub consumer ( ByVal param As Any Ptr )
      For i As Integer = 0 To 9
         MutexLock produced
         Print , ",consumer gets:" ; i
         MutexUnlock consumed
         Sleep 5, 1
      Next i
   End Sub

   Sub producer ( ByVal param As Any Ptr )
      For i As Integer = 0 To 9
         Print "Producer puts:" ; i;
         MutexUnlock produced
         MutexLock consumed
      Sleep 5, 1
   Next i
   End Sub

   produced = MutexCreate
   consumed = MutexCreate
   If ( produced = 0 ) Or ( consumed = 0 ) Then
      Print "Error creating mutexes! Exiting..."
      Sleep
      End
   End If

   MutexLock produced
   MutexLock consumed

   consumer_id = ThreadCreate ( @ consumer )
   producer_id = ThreadCreate ( @ producer )
   If ( producer_id = 0 ) Or ( consumer_id = 0 ) Then
      Print "Error creating threads! Exiting..."
      Sleep
      End
   End If

   ThreadWait consumer_id
   ThreadWait producer_id

   MutexDestroy consumed
   MutexDestroy produced

   Sleep

   ' 'Threadcreate' launches one time the user-defined Sub in a separate execution thread
   '    (which runs simultaneously with the rest of the main code).
   ' If you want obtain a periodically display from the thread,
   '    you must put (into the thread) a [Do...Loop] block with a 'Sleep x, 1' to adjust the display period
   '    and a flag to exit the loop (and terminate the thread).
   '
   ' Warning:
   ' - Each thread has not its own memory of cursor position, so for that and other reasons, it is mandatory
   '      to apply an exclusion between displaying from the main code (main thread) and displaying from the user thread,
   '      by using a 'Mutex' ([Mutexlock...Mutexunlock] block).
   '   At beginning of each display block both into main thread and user thread,
   '      the initial cursor position must also be re-initialized.
   ' - The input keywords (like keyboard, mouse) cannot be safely run when the screen is locked,
   '      therefore a such keyword must be outside of any [Screenlock...Screenunlock] block (outside this block in its own thread,
   '      and protected of block of another thread by a 'Mutex').
   '
   ' See below a rustic program, but showing all these constraints:

   Dim Shared As Any Ptr sync   '' pointer to Mutex
   Dim Shared As Byte quit = 0  '' flag to end user thread
   Dim As Any Ptr handle        '' pointer to thread handle

   Sub ProcedureThread (ByVal param As Any Ptr)  '' param not used in thread body
      Do
         MutexLock(sync)       '' Mutex for exclusion of displaying
            ScreenLock        '' keyword after Mutexlock
               Locate 1, 70  '' re-initialize cursor position
               Print Date
               Locate , 71
               Print Time;
            ScreenUnlock      '' keyword before Mutexunlock
         MutexUnlock(sync)     '' end exclusion
         Sleep 100, 1          '' ajust display period
      Loop Until quit <> 0      '' test for exit thread
   End Sub

   Screen 12
   Locate 1, 62
   Print "Date:"
   Locate , 62
   Print "Time:";
   Locate 15, 20
   Print "Mouse (position):"
   Locate , 20
   Print "Mouse (buttons) :";
   Locate 30, 2
   Print "<any_key> or <click on window close button>: exit";

   sync = MutexCreate                          '' create Mutex (before Threadcreate)
   handle = ThreadCreate(@ProcedureThread, 0)  '' launch thread

   Dim As String s
   Do
      MutexLock(sync)                     '' Mutex for exclusion of displaying
         Dim As Long x, y, b
         GetMouse x, y , , b             '' keyword outside [Screenlock...Screenunlock] and protected by Mutex
         ScreenLock                      '' keyword after Mutexlock
            Locate 15, 37               '' re-initialize cursor position
            Print Using "######"; x; y
            Locate , 43
            Print Using "##"; b;
         ScreenUnlock                    '' Keyword before Mutexunlock
         s = Inkey                       '' keyword outside [Screenlock...Screenunlock] and protected by Mutex
      MutexUnlock(sync)                   '' end exclusion
      Sleep 10, 1                         '' ajust display period
   Loop Until s <> ""
    
   quit = Not quit     '' order thread end
   ThreadWait(handle)  '' wait for thread end
   MutexDestroy(sync)  '' free Mutex

Dialect Differences
   * Threading is not allowed in the -lang qb dialect.

Platform Differences
   * The DOS version of FreeBASIC does not allow for threads, as the OS 
     does not support them.
   * In Linux the threads are always started in the order they are 
     created, this can't be assumed in Win32. It's an OS, not a FreeBASIC 
     issue. 

Differences from QB
   * New to FreeBASIC

See also
   * MutexCreate
   * MutexDestroy
   * MutexUnlock
   * ThreadCreate
   * ThreadWait



------------------------------------------------------ KeyPgMutexUnlock ----
MutexUnlock

Releases a mutex lock

Syntax
   Declare Sub MutexUnlock ( ByVal id As Any Ptr )

Usage
   MutexUnlock( id )

Parameters
   id
      The Any Ptr handle of the mutex to be unlocked.

Description
   Mutexunlock releases a mutex "handle" created by MutexCreate, and locked 
   with MutexLock.  This allows other threads sharing the mutex to continue 
   execution.

   See MutexCreate for more general information on mutexes.

Example
   See the examples in MutexCreate and also ThreadCreate.

Dialect Differences
   * Threading is not allowed in the -lang qb dialect.

Platform Differences
   * The DOS version of FreeBASIC does not allow for threads, as the OS 
     does not support them.
   * In Linux the threads are always started in the order they are 
     created, this can't be assumed in Win32. It's an OS, not a FreeBASIC 
     issue. 

Differences from QB
   * New to FreeBASIC

See also
   * MutexCreate
   * MutexDestroy
   * MutexLock
   * ThreadCreate
   * ThreadWait




============================================================================
    N

------------------------------------------------------------ KeyPgNaked ----
Naked

Write functions without prolog/epilog code

Syntax
   {Sub | Function} identifier Naked [calling_convention] ( param_list ) [[ 
   ByRef ] As data_type]
      asm_statements
   End {Sub | Function}

Parameters
   identifier - name of the procedure.
   calling_convention - calling convention of the procedure - can be cdecl, 
   pascal, or stdcall
   asm_statements - the code in the procedure body.  The code for handling 
   parameters and returning values must all be done manually.  Note that 
   the methods for doing these can change, depending on the 
   calling convention.
   param_list - parameters to be passed to the procedure.
   data_type - the data type of the function.

Description
   Naked allows the programmer to write procedures without the compiler 
   generating any prolog/epilog code.
   This is useful when writing small, fast functions in Asm without any 
   unnecessary overhead (so, no register preservation for such Asm blocks).

Example
   '' Naked cdecl function (for fbc 32-bit)
   Function subtract_c Naked cdecl _   '' parameters pushed onto call stack in reverse order of declaration
      ( _
         ByVal a As Long, _
         ByVal b As Long _        '' parameter pushed onto stack in first
      ) As Long
      
      Asm
         mov eax, dword Ptr [esp+4]  '' eax = a
         Sub eax, dword Ptr [esp+8]  '' eax -= b
         ret                         '' return result in eax
      End Asm
      
   End Function

   Print subtract_c( 5, 1 ) '' 5 - 1

   ''---------------------------------------------------------------------------------------------------------------------

   '' Naked stdcall function (for fbc 32-bit)
   Function subtract_s Naked stdcall _ '' parameters pushed onto call stack in reverse order of declaration
                      _          '' called procedure responsible for removing parameters from stack
                      _          ''   (appending constant to RET instruction specifying number of bytes to release)
      ( _
         ByVal a As Long, _
         ByVal b As Long _        '' parameter pushed onto stack in first
      ) As Long
      
      Asm
         mov eax, dword Ptr [esp+4]  '' eax = a
         Sub eax, dword Ptr [esp+8]  '' eax -= b
         ret 8                       '' return result in eax and 8 bytes (2 integers) to release
      End Asm
      
   End Function

   Print subtract_s( 5, 1 ) '' 5 - 1 

   ''---------------------------------------------------------------------------------------------------------------------

   '' Naked pascal function (for fbc 32-bit)
   Function subtract_p Naked pascal _  '' parameters pushed onto call stack in same order as declaration
                      _          '' called procedure responsible for removing parameters from stack
                      _          ''   (appending constant to RET instruction specifying number of bytes to release)
      ( _
         ByVal a As Long, _       '' parameter pushed onto stack in first
         ByVal b As Long _
      ) As Long
      
      Asm
         mov eax, dword Ptr [esp+8]  '' eax = a
         Sub eax, dword Ptr [esp+4]  '' eax -= b
         ret 8                       '' return result in eax and 8 bytes (2 longs) to release
      End Asm
      
   End Function

   Print subtract_p( 5, 1 ) '' 5 - 1

   '' Naked cdecl function (for fbc 32-bit)
   '' plus ecx register preserved in asm block by creating user stack
   Function subtract_cp Naked cdecl _      '' parameters pushed onto call stack in reverse order of declaration
      ( _
         ByVal a As Long, _
         ByVal b As Long _            '' parameter pushed onto stack in first
      ) As Long
      
      Asm
         push ebp                        '' push ebp onto stack   => esp -= 4
         mov ebp, esp                    '' ebp = esp
                                 ''    => create user stack 4 bytes above call stack
         push ecx                        '' push ecx onto user stack   => esp -= 4
         mov eax, dword Ptr [(ebp+4)+4]  '' eax = a   (supplementary offset of +4 bytes only due to 'push ebp')
         mov ecx, dword Ptr [(ebp+8)+4]  '' ecx = b   (supplementary offset of +4 bytes only due to 'push ebp')
         Sub eax, ecx                    '' eax -= ecx
         pop ecx                         '' pop ecx from user stack   => esp += 4
         mov esp, ebp                    '' esp = ebp
         pop ebp                         '' pop ebp from stack   => esp += 4
                                 ''    => discard user stack
         ret                             '' return result in eax
      End Asm
      
   End Function

   Print subtract_cp( 5, 1 ) '' 5 - 1

Platform Differences
   * The default calling convention depends on the target platform, thus 
     it is best to specify the expected calling convention explicitly when 
     using Naked.

Differences from QB
   * New to FreeBASIC

See also
   * Asm
   * Calling Conventions
   * Function
   * Sub
   * cdecl
   * pascal
   * stdcall



------------------------------------------------------------- KeyPgName ----
Name

Renames a file on disk

Syntax
   Declare Function Name( ByRef oldname As Const String, ByRef newname As 
   Const String ) As Long

Usage
   result = Name( oldname, newname )

Parameters
   oldname
      Name of an existing file.
   newname
      New name of the file.

Return Value
   Returns zero (0) on success and non-zero on failure.

Description
   Renames a file or folder originally called oldname to newname.

   The function is not guaranteed to succeed if a file/folder exists with 
   the same name.  It may  succeed, overwriting the original, or it may 
   fail.  For greater control, FileExists could be used to test for an 
   existing file, and Kill could be used to delete an existing file 
   beforehand.

Example
   Dim OldName As String
   Dim NewName As String
   Dim result As Long 

   OldName = "dsc001.jpg"
   NewName = "landscape.jpg"

   result = Name( OldName, NewName )
   If 0 <> result Then 
      Print "error renaming " & oldname & " to " & newname & "."
   End If

Differences from QB
   * In QB, NAME required AS rather than a comma between the old and new 
     names.  This is because NAME was a language keyword rather than a 
     function.

See also
   * Kill
   * FileExists



-------------------------------------------------------- KeyPgNamespace ----
Namespace

Declares a namespace block.

Syntax
   Namespace identifier [ Alias "aliasname" ]
      statements
   End Namespace

Parameters
   identifier
      The name of the namespace (including nested names specifier).
   aliasname
      An alternate external name for the namespace.

Description
   Namespaces allow to group entities like objects (predefined data-types 
   and UDTs including Union and Enum) and procedures (including their 
   declarations) under a name. This way the global scope can be divided in 
   "sub-scopes", each one with its own name. 

   Whether or not explicitly declared a namespace in a source file, the 
   compiler adds a default namespace. This unnamed namespace, called the 
   global namespace, is present in every file.
   Any identifier in the global namespace is available for use in a named 
   namespace (even global symbols with the same name as keywords may be 
   declared inside a namespace). 

   Namespaces implicitly have public access and this is not modifiable.
   A variable declared inside a namespace is always implicitly static and 
   visible throughout the entire program even if the declaration modifier 
   Shared is not specified (static and shared are optional, but this may 
   improve code readability).

   Namespaces do not have any effect on the visibility of a define.
   It is possible to define a namespace in two or more declarations.

   Namespaces are commonly used in libraries where you don't want all the 
   symbols from that library to crowd the user's space (called the global 
   namespace). 
   For example, if you used the "Forms" library, it might define the Point 
   type for describing an X and Y coordinate, and you might also define it 
   for another purpose. This can be resolved by creating the namespace 
   Forms for the library, and then referring to its Point type as 
   Forms.Point, and yours as just Point. 

   To access from outside a defined symbol in a namespace, add the 
   namespace identifier followed by a dot as a prefix of the symbol, or 
   bring the namespace symbols into the current scope by means of the 
   Using (Namespaces) statement.
   To access duplicated symbols defined as global outside the namespace, 
   add one or preferably two dot(s) as prefix: .SomeSymbol or preferably ..
   SomeSymbol (or only ..SomeSymbol if inside a With..End With block).

   Note: The parser allows to define anonymous Namespaces (without 
   identifier term), but this is the only similarity with the actual C++ 
   capability: The FB compiler automatically generates multiple separate 
   anonymous Namespaces instead of one only per module in such a case.
   The FB anonymous Namespaces are almost unusable because all their 
   declarations are inaccessible, even from the body of the module that 
   contains them. Apart from encapsulating module constructors/destructors 
   also inside, nothing else can be done with them.

Example
   Namespace Forms
      Type Point '' A 2D point
         As Integer x
         As Integer y
      End Type
      '' Since we are inside of the namespace, Point resolves to Forms.Point.
      Sub AdjustPoint( ByRef pt As Point, ByVal newx As Integer, ByVal newy As Integer )
         pt.x = newx
         pt.y = newy
      End Sub
   End Namespace

   Type Point '' A 3D point
      As Integer x
      As Integer y
      As Integer z
   End Type

   Sub AdjustPoint( ByRef pt As Point, ByVal newx As Integer, ByVal newy As Integer, ByVal newz As Integer )
      pt.x = newx
      pt.y = newy
      pt.z = newz
   End Sub

   Dim pt1 As Point
   AdjustPoint( pt1, 1, 1, 1 )
   Dim pt2 As Forms.Point
   Forms.AdjustPoint( pt2, 1, 1 )

   Namespaces are GCC C++ compatible, the following code aims to test that.
   (cpp)
   // mylib.cpp
   // To compile:
   //	g++ -c mylib.cpp -o mylib.o
   //	ar rcs libmylib.a mylib.o

   #include <string.h>
   #include <ctype.h>

   Namespace mylib
   {
   	Int test() 
   	{
   		Return 123;
   	}
   }

   '' test.bas

   Extern "c++" Lib "mylib"
      Namespace mylib Alias "mylib"
         Declare Function test() As Integer
      End Namespace
   End Extern

   Print mylib.test()

Dialect Differences
   * Namespaces are not supported in the -lang qb dialect.

Differences from QB
   * New to FreeBASIC

See also
   * Using (Namespaces)



------------------------------------------------------------ KeyPgOpNew ----
Operator New Expression

Operator to dynamically allocate memory and construct data of a specified 
type.

Usage
   result = New datatype
      or
   result = New datatype ( initializers, ... )
      or
   result = New datatype[ count ]

Parameters
   datatype
      Name of the data type to create.
   initializers
      Initial value(s) for the variable.
   count
      Exact number of elements to allocate.

Return Value
   A pointer of type datatype to the newly allocated data, or null pointer 
   if the memory allocation failed.

Description
   The New Expression operator dynamically allocates memory and constructs 
   a specified data type.

   For simple types, like integers, an initial value can be given. For 
   types without constructors, initial values can be specified for each 
   field (either with default initializer at data-field declaration, or 
   with initializer list as in New datatype (initializers, ..) if all type 
   data-fields are numeric primitives only and without any default 
   initializers). For types with at least one constructor, the initialize 
   list (if any) must match an existing constructor. If no initializers are 
   given, the default values for those types will be set.

   New[] Expression operator is the (one-dimensional) array-version of the 
   New Expression operator and allocates enough memory for the specified 
   number of objects. The default constructor for the type will be used to 
   set the initial values for each item.

   Objects created with New Expression operator must be freed with 
   Delete Statement operator. Object array created with New[] Expression 
   operator must be freed with Delete[] Statement operator, the 
   array-version of Delete Statement operator. You cannot mix and match the 
   different versions of the operators.

   Specifying an initial value of Any, as in New datatype (Any) will 
   allocate memory for the type, but not initialize the data.  This is only 
   valid on data types that do not have constructors (otherwise for data 
   types with constructors, syntax of simple memory allocation with pointer 
   conversion, like Cptr(datatype Ptr, Allocate(Sizeof(datatype))), can be 
   substituted to the invalid use of New...Any).

   Specifying an initial value of Any, as in New datatype[count] {Any} will 
   allocate memory for the array, but not initialize the data.  This is 
   only valid on data types that do not have constructors (otherwise for 
   data types with constructors, syntax of simple memory allocation with 
   pointer conversion, like Cptr(datatype Ptr, Allocate(count * 
   Sizeof(datatype))), can be substituted to the invalid use of New...Any).

   The total memory, in bytes, to be allocated with New datatype[count] 
   expression is calculated as sizeof(datatype) * count, plus 
   sizeof(uinteger) if there is an implicit or explicit Destructor.  The 
   total memory requested in bytes to be allocated must not overflow the 
   value that can be held by a UInteger.  The extra uinteger, if allocated, 
   stores the number of elements as part of the allocation, so that 
   Delete Statement can determine the count of destructors to call.

   If the memory allocation fails, a null pointer is returned and no 
   constructors are called.

   The dynamic memory allocation process part provided by the New 
   Expression operator can be overloaded for user-defined types as a member 
   operator New Overload. The following process part for data construction 
   can never be modified.

   Note: Using pointer = New datatype[count] may be unsafe if pointer was 
   declared with a type different from datatype (for sub-type polymorphism 
   purpose for example), because the pointer arithmetic fails to access the 
   elements if the pointer type size is different from the size of datatype 
   (when using Operator [] (Pointer Index) or adding an offset (element 
   number) to the pointer, or even when Delete[] Statement itself (the 
   array-version of Delete Statement) must destroy the elements).

Example
   Type Rational
      As Integer numerator, denominator
   End Type

   ' Create and initialize a "rational" and store its address.
   Dim p As Rational Ptr = New Rational(3, 4)

   ' Test if null return pointer
   If (p = 0) Then
      Print "Error: unable to allocate memory"
   Else
      Print p->numerator & "/" & p->denominator
      ' Destroy the rational and give its memory back to the system.
      Delete p
   End If

   Sleep

   ' Allocate memory for 100 integers and store the address of the first one.
   Dim p As Integer Ptr = New Integer[100]

   ' Test if null return pointer
   If (p = 0) Then
      Print "Error: unable to allocate memory"
   Else
      ' Assign some values to the integers in the array.
      For i As Integer = 0 To 99
         p[i] = i
      Next
      ' Free the entire integer array.
      Delete[] p
   End If

   Print "Done."
   Sleep

   '' Example of nested New [] to get a 2-dimentional object array (4*3)

   Type UDT
      Dim As Integer N
      Declare Constructor ()
      Declare Destructor ()
   End Type

   Constructor UDT ()
      Print "Constructor",
   End Constructor

   Destructor UDT ()
      Print "Destructor",
   End Destructor

   Dim As UDT Ptr Ptr p = New UDT Ptr [4]  '' New [] allocation for the first dimension:
                                 ''   no internal allocation of extra uinteger because
                                 ''   allocation of array of pointers (to UDT objects with destructor)
   For I As Integer = 0 To 3
      p[I] = New UDT [5]                  '' New [] allocations for the last dimension:
                                 ''   internal allocation of an extra uinteger for each New [],
                                 ''   because allocation of an array of UDT objects with destructor
      Print
   Next I

   For I As Integer = 0 To 3
      For J As Integer = 0 To 4
         p[I][J].N = I * 10 + J  '' assignment of each object array element
      Next J
   Next I

   Print
   For I As Integer = 0 To 3
      For J As Integer = 0 To 4
         Print p[I][J].N,        '' display of each object array element
      Next J
      Print
   Next I
   Print

   For I As Integer = 0 To 3
      Delete [] p[I]  '' Delete [] deallocations for the last dimension
      Print
   Next I
   Delete [] p         '' Delete [] deallocation for the first dimension)
   Print

   Sleep

      Output example:

   Constructor   Constructor   Constructor   Constructor   Constructor
   Constructor   Constructor   Constructor   Constructor   Constructor
   Constructor   Constructor   Constructor   Constructor   Constructor
   Constructor   Constructor   Constructor   Constructor   Constructor

    0             1             2             3             4
    10            11            12            13            14
    20            21            22            23            24
    30            31            32            33            34

   Destructor    Destructor    Destructor    Destructor    Destructor
   Destructor    Destructor    Destructor    Destructor    Destructor
   Destructor    Destructor    Destructor    Destructor    Destructor
   Destructor    Destructor    Destructor    Destructor    Destructor

Dialect Differences
   * Only available in the -lang fb dialect.

Differences from QB
   * New to FreeBASIC

See also
   * Delete Statement
   * Placement New
   * New Overload



--------------------------------------------------- KeyPgOpPlacementNew ----
Operator Placement New

Operator to construct an object at a specified memory address.

Syntax
   result = New(address) datatype
      or
   result = New(address) datatype ( initializers, ... )
      or
   result = New(address) datatype[ count ]

Parameters
   address 
      the location in memory to construct. the parenthesis are not 
      optional.
   initializers
      Initial value(s) for the variable.
   datatype
      name of the data type to construct.
   count
      Number of elements to construct.

Return Value
   A pointer of type datatype to the newly constructed data.

Description
   The Placement New operator constructs a specified data type at the 
   specified memory location. 

   For simple types, like integers, an initial value can be given. For 
   types without Constructors, initial values can be specified for each 
   field (either with default initializer at data-field declaration, or 
   with initializer list as in New datatype (initializers, ..) if all type 
   data-fields are numeric primitives only and without any default 
   initializers). For types with at least one constructor, the initialize 
   list (if any) must match an existing constructor. If no initializers are 
   given, the default values for those types will be set.

   Memory is not allocated when using the Placement New operator. Instead, 
   the memory at the specified address is used (the provided memory size 
   must be large enough to contain all the placement).
   It is incorrect to call Delete Statement on the address. The proper way 
   is to only call the destructor if one exists (implicitly or explicitly), 
   with syntax as for a member method by using member access operator.
   See examples below for proper Placement New operator usage.

   Placement New[] operator is the (one-dimensional) array-version of the 
   Placement New operator and constructs the specified number of objects 
   from the specified memory location. The default constructor for the type 
   will be used to set the initial values for each item.

   Specifying an initial value of Any, as in New(address)datatype (Any) or 
   New(address)datatype[count] {Any} will not initialize the data.  This is 
   only valid on data types that do not have constructors (otherwise for 
   data types with constructors, syntax of simple pointer conversion, like 
   Cptr(datatype Ptr, address), can be substituted to the invalid use of 
   New...Any).

   Because it does not provide any dynamic memory allocation process, the 
   Placement New operator (unlike the New Expression operator) does not 
   allow any overloading by a member operator for user-defined types.

   Note: Using pointer = New(address)datatype[count] may be unsafe if 
   pointer was declared with a type different from datatype (for sub-type 
   polymorphism purpose for example), because the pointer arithmetic fails 
   to access the elements if the pointer type size is different from the 
   size of datatype (when using Operator [] (Pointer Index) or adding an 
   offset (element number) to the pointer).

Example
   '' "placement new" example

   Type Rational
      As Integer    numerator, denominator
      Declare Constructor ( ByVal n As Integer, ByVal d As Integer )
      As String ratio = "/"
   End Type

   Constructor Rational ( ByVal n As Integer, ByVal d As Integer )
      This.numerator = n
      This.denominator = d
   End Constructor

   Scope
      
      '' allocate some memory to construct as a Rational
      Dim As Any Ptr ap = CAllocate(Len(Rational))
      
      '' make the placement new call
      Dim As Rational Ptr r = New (ap) Rational( 3, 4 )
      
      '' you can see, the addresses are the same, just having different types in the compiler
      Print ap, r
      
      '' confirm all is okay
      Print r->numerator & r->ratio & r->denominator
      
      '' delete must not be used with placement new
      '' destroying must be done explicitly if a destructor exists (implicitly or explicitly)
      ''   (in this example, the var-string member induces an implicit destructor)
      r->Destructor( )
      
      '' we explicitly allocated, so we explicitly deallocate
      Deallocate( ap )
      
   End Scope

Dialect Differences
   * Only available in the -lang fb dialect.

Differences from QB
   * New to FreeBASIC

See also
   * Destructor
   * New Expression



------------------------------------------------------------- KeyPgNext ----
Next

Control flow statement to mark the end of a For...Next loop.

Syntax
   Next [ identifier_list ]

Description
   Indicates the end of a statement block associated with a matching For 
   statement. 

   When Next is used on its own without an identifier_list, it closes the 
   most recent For statement block.

   identifier_list is optional and may be one or more variable names 
   separated by commas.  This form of the Next statement is retained for 
   compatibility with QB.  identifier_list, if given, must match the 
   identifiers used in the associated For statements in reverse order, from 
   inner to outer.

Example
   For i As Integer = 1 To 10
      For j As Integer = 1 To 2
         ' ...
      Next
   Next

   For i As Integer = 1 To 10
      For j As Integer = 1 To 2
         ' ...
      Next j
   Next i

   For i As Integer = 1 To 10
   For j As Integer = 1 To 2
      ' ...
   Next j,i

Differences from QB
   * ByRef arguments cannot be used as counters.

See also
   * For...Next



------------------------------------------------------- KeyPgResumenext ----
Resume Next

Error handling statement to resume execution after a jump to an error 
handler

Syntax
   Resume Next

Description
   Resume Next is used in the traditional QB error handling mechanism 
   within an error handler (called by On Error) to return execution to the 
   line after the one that caused the error.  Usually this is used to avoid 
   executing the same line and causing the error again.

   Resume Next resets the Err value to 0

Example
   '' Compile with -lang fblite or qb

   #lang "fblite"

   Dim As Single i, j

   On Error Goto ErrHandler

   i = 0
   j = 5
   j = 1 / i ' this line causes a divide-by-zero error; execution jumps to ErrHandler label

   Print "ending..."

   End ' end the program so that execution does not fall through to the error handler again

   ErrHandler:

   Resume Next ' execution jumps to 'Print "ending..."' line, but j is now in an undefined state

Dialect Differences
   *  RESUME NEXT is not supported in the -lang fb dialect. Statements can 
     be used in its function form to return an error code
   If Open( "text" For Input As #1 ) <> 0 Then
     Print "Unable to open file"
   End If

 

Differences from QB
   * Must compile with -ex or -exx option

See also
   * Err
   * Resume
   * Error Handling



----------------------------------------------------- KeyPgSfxGenerated ----
Generated Sound Commands

Commands for generated sound, PLAY strings, and sfxlib mix settings.

Syntax
   Beep [ duration, pitch ]
   Sound frequency, duration
   Sound channel, frequency, duration, volume
   Tone channel, frequency, duration
   Noise channel, duration, volume
   Noise channel, frequency, duration, volume
   Note name, octave, duration
   Note channel, name, octave, duration
   Play music
   Play channel, music
   Play music1, music2
   Play music1, music2, music3
   Tempo bpm
   bpm = Tempo()
   Channel channel
   channel = Channel()
   Octave octave
   octave = Octave()
   Voice instrument
   instrument = Voice()
   Vol level
   Volume level
   level = Volume()
   Volume channel, level
   level = Volume( channel )
   Balance position
   position = Balance()
   Pan channel, position
   position = Pan( channel )
   Wave id, waveform
   Envelope id, attack, decay, sustain, release
   Instrument id, wave_id, envelope_id
   Instrument channel, instrument_id

Description
   These commands synthesize sound directly through sfxlib.  Sound, Tone, 
   Noise, Note, and Play create voices.  Tempo, Channel, Octave, and Voice 
   set defaults used by PLAY-string and generated-sound commands.  Volume, 
   Vol, Balance, and Pan control mix levels and stereo placement.

   Sound accepts the high-impact classic form Sound frequency, duration and
   the explicit channel form Sound channel, frequency, duration, volume.
   When both arguments are integers, duration is interpreted as the PC BASIC
   timer-tick value.

   Wave defines a waveform id.  The currently supported waveform values 
   are:
      * 0 sine
      * 1 square
      * 2 triangle
      * 3 saw
      * 4 noise

   Envelope defines an ADSR envelope using seconds for attack, decay, and 
   release, and a 0.0 to 1.0 sustain level.  Instrument can define an 
   instrument from a waveform and envelope, or assign an instrument to a 
   channel.

   The channel-oriented commands use sfxlib's channel table.  Channels are 
   zero-based.

Example
   See examples/sfxlib/basics-01-generated-sound.bas, 
   examples/sfxlib/basics-02-play-strings.bas, 
   examples/sfxlib/basics-03-channels-mix.bas, 
   examples/sfxlib/basics-04-instruments.bas, and 
   examples/sfxlib/showcase.bas.

Platform Differences
   * On headless or diagnostic runs, SFXLIB_DRIVER=null can be set before 
     program startup to use the null output driver.

Differences from QB
   * New to FreeBASIC.

See also
   * Beep
   * Music
   * Sfx
   * Sound Library Reference



----------------------------------------------------- KeyPgSfxGenerated ----
Generated Sound Commands

Commands for generated sound, PLAY strings, and sfxlib mix settings.

Syntax
   Beep [ duration, pitch ]
   Sound frequency, duration
   Sound channel, frequency, duration, volume
   Tone channel, frequency, duration
   Noise channel, duration, volume
   Noise channel, frequency, duration, volume
   Note name, octave, duration
   Note channel, name, octave, duration
   Play music
   Play channel, music
   Play music1, music2
   Play music1, music2, music3
   Tempo bpm
   bpm = Tempo()
   Channel channel
   channel = Channel()
   Octave octave
   octave = Octave()
   Voice instrument
   instrument = Voice()
   Vol level
   Volume level
   level = Volume()
   Volume channel, level
   level = Volume( channel )
   Balance position
   position = Balance()
   Pan channel, position
   position = Pan( channel )
   Wave id, waveform
   Envelope id, attack, decay, sustain, release
   Instrument id, wave_id, envelope_id
   Instrument channel, instrument_id

Description
   These commands synthesize sound directly through sfxlib.  Sound, Tone, 
   Noise, Note, and Play create voices.  Tempo, Channel, Octave, and Voice 
   set defaults used by PLAY-string and generated-sound commands.  Volume, 
   Vol, Balance, and Pan control mix levels and stereo placement.

   Sound accepts the high-impact classic form Sound frequency, duration and
   the explicit channel form Sound channel, frequency, duration, volume.
   When both arguments are integers, duration is interpreted as the PC BASIC
   timer-tick value.

   Wave defines a waveform id.  The currently supported waveform values 
   are:
      * 0 sine
      * 1 square
      * 2 triangle
      * 3 saw
      * 4 noise

   Envelope defines an ADSR envelope using seconds for attack, decay, and 
   release, and a 0.0 to 1.0 sustain level.  Instrument can define an 
   instrument from a waveform and envelope, or assign an instrument to a 
   channel.

   The channel-oriented commands use sfxlib's channel table.  Channels are 
   zero-based.

Example
   See examples/sfxlib/basics-01-generated-sound.bas, 
   examples/sfxlib/basics-02-play-strings.bas, 
   examples/sfxlib/basics-03-channels-mix.bas, 
   examples/sfxlib/basics-04-instruments.bas, and 
   examples/sfxlib/showcase.bas.

Platform Differences
   * On headless or diagnostic runs, SFXLIB_DRIVER=null can be set before 
     program startup to use the null output driver.

Differences from QB
   * New to FreeBASIC.

See also
   * Beep
   * Music
   * Sfx
   * Sound Library Reference



------------------------------------------------------------ KeyPgOpNot ----
Operator Not (Complement)

Returns the bitwise-not (complement) of a numeric value

Syntax
   Declare Operator Not ( ByRef rhs As Byte ) As Integer
   Declare Operator Not ( ByRef rhs As UByte ) As Integer
   Declare Operator Not ( ByRef rhs As Single ) As Integer
   Declare Operator Not ( ByRef rhs As Double ) As Integer

   Declare Operator Not ( ByRef rhs As T ) As T

Usage
   result = Not rhs

Parameters
   rhs
      The right-hand side expression.
   T
      Any numeric or boolean type.

Return Value
   Returns the bitwise-complement of its operand.

Description
   This operator returns the bitwise-complement of its operand, a logical 
   operation that results in a value with bits set depending on the bits of 
   the operand.
   (for a boolean type, 'Not false' returns 'true' and 'Not true' returns 
   'false')

   The truth table below demonstrates all combinations of a 
   boolean-complement operation:

      +-------+------+
      |Rhs Bit|Result|
      |0      |1     |
      |1      |0     |
      +-------+------+

   This operator can be overloaded for user-defined types.

Example
   ' Using the NOT operator on a numeric value

   Dim numeric_value As Byte
   numeric_value = 15 '00001111

   'Result = -16 =     11110000
   Print Not numeric_value

   ' Using the NOT operator on conditional expressions
   Dim As UByte numeric_value1, numeric_value2
   numeric_value1 = 15
   numeric_value2 = 25

   If Not numeric_value1 = 10 Then Print "Numeric_Value1 is not equal to 10"
   If Not numeric_value2 = 25 Then Print "Numeric_Value2 is not equal to 25"

   ' This will output "Numeric_Value1 is not equal to 10" because
   ' the first IF statement is false.
   ' It will not output the result of the second IF statement because the
   ' condition is true. 

Dialect Differences
   * In the -lang qb dialect, this operator cannot be overloaded.

Differences from QB
   * None

See also
   * Operator Truth Tables



-------------------------------------------------------------- KeyPgNow ----
Now

Gets the current system time as a Date Serial 

Syntax
   Declare Function Now ( ) As Double

Usage
   #include "vbcompat.bi"
   result = Now

Return Value
   Returns a date serial containing the system's date and time at execution 
   time.

Description
   As the time is the decimal part of a date serial, if the value of Now is 
   saved to an integer, the time in it will be reset to 00:00:00

   The compiler will not recognize this function unless vbcompat.bi is 
   included.

Example
   #include "vbcompat.bi"

   Dim a As Double = Now()

   Print Format(a, "yyyy/mm/dd hh:mm:ss") 

Differences from QB
   * Did not exist in QB. This function appeared in PDS and VBDOS

See also
   * Date Serials




============================================================================
    O

----------------------------------------------------------- KeyPgObject ----
Object

Built-in type providing run-time type information

Syntax
   Type Object
      As fb_BaseVT Ptr vtable_ptr
      Declare Constructor()
   End Type

Usage
   Type typename Extends Object
   End Type

   Dim variable As Object

Description
   Object is a built-in type which provides Run-Time Type Information 
   (RTTI) for all types derived from it using Extends, allowing them to be 
   used with Operator Is, and to support Virtual and Abstract methods.

   Extending the built-in Object type allows to add an extra hidden vtable 
   pointer field at the top of the Type. The vtable is used to dispatch 
   Virtual  and Abstract methods and to access information for run-time 
   type identification used by Operator Is.

Example
   See the Operator Is page, the Virtual and Abstract pages.

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Object.

Differences from QB
   * New to FreeBASIC

See also
   * Extends
   * Extends Zstring
   * Extends Wstring
   * Operator Is
   * Virtual
   * Abstract



-------------------------------------------------------------- KeyPgOct ----
Oct

Converts a number to octal representation

Syntax
   Declare Function Oct ( ByVal number As UByte ) As String
   Declare Function Oct ( ByVal number As UShort ) As String
   Declare Function Oct ( ByVal number As ULong ) As String
   Declare Function Oct ( ByVal number As ULongInt ) As String
   Declare Function Oct ( ByVal number As Const Any Ptr ) As String

   Declare Function Oct ( ByVal number As UByte, ByVal digits As Long ) As 
   String
   Declare Function Oct ( ByVal number As UShort, ByVal digits As Long ) As 
   String
   Declare Function Oct ( ByVal number As ULong, ByVal digits As Long ) As 
   String
   Declare Function Oct ( ByVal number As ULongInt, ByVal digits As Long ) 
   As String
   Declare Function Oct ( ByVal number As Const Any Ptr, ByVal digits As 
   Long ) As String

Usage
   result = Oct[$]( number [, digits ] )

Parameters
   number
      A number or expression evaluating to a number.  A floating-point 
      number will be converted to a LongInt.
   digits
      Desired number of digits in the returned string.

Return Value
   A string containing the unsigned octal representation of number.

Description
   Returns the unsigned octal string representation of number. Octal digits 
   range from 0 to 7.

   If you specify digits > 0, the result string will be exactly that 
   length.  It will be truncated or padded with zeros on the left, if 
   necessary.

   The length of the returned string will not be longer than the maximum 
   number of digits required for the type of number (3 characters for Byte, 
   6 for Short, 11 for Long, and 22 for LongInt)

   If you want to do the opposite, i.e. convert an octal string back into a 
   number, the easiest way to do it is to prepend the string with "&O", and 
   convert it to an integer type, using a function like CInt, similarly to 
   a normal numeric string.  E.g. CInt("&O77")

Example
   Print Oct(54321)
   Print Oct(54321, 4)
   Print Oct(54321, 8)

   will produce the output:

   152061
   2061
   00152061

Dialect Differences
   * The string type suffix "$" is required in the -lang qb dialect.
   * The string type suffix "$" is optional in the -lang fblite dialect.
   * The string type suffix "$" is ignored in the -lang fb dialect, warn 
     only with the -w suffix compile option (or -w pedantic compile 
     option).

Differences from QB
   * In QBASIC, there was no way to specify the number of digits returned.
   * The size of the string returned was limited to 32 bits, or 11 octal 
     digits.

See also
   * Bin
   * Hex
   * ValInt
   * ValLng



----------------------------------------------------- KeyPgSfxGenerated ----
Generated Sound Commands

Commands for generated sound, PLAY strings, and sfxlib mix settings.

Syntax
   Beep [ duration, pitch ]
   Sound frequency, duration
   Sound channel, frequency, duration, volume
   Tone channel, frequency, duration
   Noise channel, duration, volume
   Noise channel, frequency, duration, volume
   Note name, octave, duration
   Note channel, name, octave, duration
   Play music
   Play channel, music
   Play music1, music2
   Play music1, music2, music3
   Tempo bpm
   bpm = Tempo()
   Channel channel
   channel = Channel()
   Octave octave
   octave = Octave()
   Voice instrument
   instrument = Voice()
   Vol level
   Volume level
   level = Volume()
   Volume channel, level
   level = Volume( channel )
   Balance position
   position = Balance()
   Pan channel, position
   position = Pan( channel )
   Wave id, waveform
   Envelope id, attack, decay, sustain, release
   Instrument id, wave_id, envelope_id
   Instrument channel, instrument_id

Description
   These commands synthesize sound directly through sfxlib.  Sound, Tone, 
   Noise, Note, and Play create voices.  Tempo, Channel, Octave, and Voice 
   set defaults used by PLAY-string and generated-sound commands.  Volume, 
   Vol, Balance, and Pan control mix levels and stereo placement.

   Sound accepts the high-impact classic form Sound frequency, duration and
   the explicit channel form Sound channel, frequency, duration, volume.
   When both arguments are integers, duration is interpreted as the PC BASIC
   timer-tick value.

   Wave defines a waveform id.  The currently supported waveform values 
   are:
      * 0 sine
      * 1 square
      * 2 triangle
      * 3 saw
      * 4 noise

   Envelope defines an ADSR envelope using seconds for attack, decay, and 
   release, and a 0.0 to 1.0 sustain level.  Instrument can define an 
   instrument from a waveform and envelope, or assign an instrument to a 
   channel.

   The channel-oriented commands use sfxlib's channel table.  Channels are 
   zero-based.

Example
   See examples/sfxlib/basics-01-generated-sound.bas, 
   examples/sfxlib/basics-02-play-strings.bas, 
   examples/sfxlib/basics-03-channels-mix.bas, 
   examples/sfxlib/basics-04-instruments.bas, and 
   examples/sfxlib/showcase.bas.

Platform Differences
   * On headless or diagnostic runs, SFXLIB_DRIVER=null can be set before 
     program startup to use the null output driver.

Differences from QB
   * New to FreeBASIC.

See also
   * Beep
   * Music
   * Sfx
   * Sound Library Reference



--------------------------------------------------------- KeyPgOffsetof ----
OffsetOf

Returns the offset of a field within a type.

Syntax
   #define OffsetOf(typename, fieldname) CInt( @Cast( typename Ptr, 0 )->
   fieldname )	

Usage
   result = OffsetOf( typename, fieldname )

Parameters
   typename
      Name of the type as defined using the Type...End Type statements.
   fieldname
      Name of the field as defined within the type (or within the base 
      types for a derived type).

Description
   For a non-derived type, OffsetOf will return the location fieldname as 
   offset in bytes from the beginning of typename.

   For a derived type, OffsetOf will return the location fieldname as 
   offset in bytes from the beginning of its highest base type.
   Note: if a member of the base type is overridden by a new member, the 
   offset of the old member cannot be accessed from the derived type.

Example
   Type MyType
     x As Single
     y As Single
     Union
      b As Byte
      i As Integer
     End Union
   End Type

   Print "OffsetOf x = "; OffsetOf(MyType, x)
   Print "OffsetOf y = "; OffsetOf(MyType, y)
   Print "OffsetOf b = "; OffsetOf(MyType, b)
   Print "OffsetOf i = "; OffsetOf(MyType, i)

Output
   OffsetOf x =  0
   OffsetOf y =  4
   OffsetOf b =  8
   OffsetOf i =  8

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Offsetof.

Differences from QB
   * New to FreeBASIC

See also
   * Type...End Type
   * SizeOf



---------------------------------------------------------- KeyPgOnerror ----
On Error

Error handling statement to set the current error handler

Syntax
   On [Local] Error Goto label

Parameters
   label
      Label to jump to when an error occurs

Description
   On Error triggers a jump to an error handler when an error occurs. Such 
   errors can be triggered by built-in statements such as Open, or when the 
   Error statement is used.

   Note: The error checking for built-in statements is only enabled if the 
   program is compiled with one of the -e, -ex or -exx options. On Error 
   remains working with Error even when none of these options are used.

   On Local Error can be used to specify a local error handler inside a 
   procedure. This allows for specialized per-procedure error handling and 
   will override the global error handler, if any.
   Without Local, the handler must be in the main part of the module.
   Remark: Presently, the Local clause is ignored by the compiler.

   On Error Goto 0 deactivates the current error handler.

Example
   '' Compile with QB (-lang qb) dialect

   '$lang: "qb"

   On Error Goto errorhandler
   Error 24 '' simulate an error
   Print "this message will not be seen"

   errorhandler:
   n = Err
   Print "Error #"; n; "!"
   End

   '' compile as: fbc onerror.bas -ex

   #lang "fblite"

   Function hFileExists( filename As String ) As Integer Static
      Dim f As Integer

      hFileExists = 0

      On Local Error Goto exitfunction

      f = FreeFile
      Open filename For Input As #f
      
      Close #f

      hFileExists = -1

   exitfunction:
      Exit Function
   End Function

      Print "File exists (0=false): "; hFileExists( Command )

      On Error Goto errhandler
      Error 1234
      Print "back from resume next"
      End 0

   errhandler:
      Print "error number: " + Str( Err ) + " at line: " + Str( Erl )
      Resume Next

Differences from QB
   * QB has no LOCAL clause and requires the label to be in the main part 
     of the module. 

See also
   * Error
   * Local
   * Err
   * Runtime Error Codes
   * Error Handling
   * Labels



---------------------------------------------------------- KeyPgOngosub ----
On...Gosub

Calls a label based on an expression

Syntax
   On expression GoSub label1[, ...]

Description
   Branches to different labels depending on the value of expression. An 
   expression value of 1 will branch to the first label, a value of 2 to 
   the second, etc.  If the value of expression is zero (0) or greater than 
   the number of items in the list, execution continues on the next 
   statement following the On...Gosub.

   This statement behaves exactly like GoSub and execution may return to 
   the statement following the On...Gosub using Return.

   It is recommended that the structured Select Case conditional statement 
   be used instead of On...Gosub.

Example
   '' Compile with -lang qb

   '$lang: "qb"

   choice = 3
   On choice GoSub labela, labelb, labelc
   Print "Good bye."
   End

   labela:
   Print "choice a"
   Return

   labelb:
   Print "choice b"
   Return

   labelc:
   Print "choice c"
   Return

Dialect Differences
   * Only available in the -lang qb and -lang fblite dialects.
   * On Gosub support is disabled by default in the -lang fblite unless 
     the Option Gosub statement is used.

Differences from QB
   * FreeBASIC does not generate a run-time error if expression is 
     negative or greater than 255.

See also
   * Select Case
   * On...Goto
   * GoSub
   * Return (From Gosub)
   * Option Gosub
   * Labels



----------------------------------------------------------- KeyPgOngoto ----
On...Goto

Jumps to a label based on an expression.

Syntax
   On expression Goto label1[, ...]

Description
   Branches to different labels depending on the value of expression. An 
   expression value of 1 will branch to the first label, a value of 2 to 
   the second, etc.  If the value of expression is zero (0) or greater than 
   the number of items in the list, execution continues on the next 
   statement following the On...Goto.

   It is recommended that the structured Select Case conditional statement 
   be used instead of On...Goto.

Example
   Dim choice As Integer

   Input "Enter a number: ", choice

   On choice Goto labela, labelb, labelc

   labela:
   Print "choice a"
   End

   labelb:
   Print "choice b"
   End

   labelc:
   Print "choice c"
   End

Differences from QB
   * FreeBASIC does not generate a run-time error if expression is 
     negative or greater than 255.

See also
   * Select Case
   * On...Gosub
   * Goto
   * Labels



---------------------------------------------------------- KeyPgInclude ----
#include

Preprocessor statement to include contents of another source file

Syntax
   #include [once] "file"

Description
   #include inserts source code from another file at the point where the 
   #include directive appears.  This has the effect of compiling the source 
   code from the include file as though it were part of the source file 
   that includes it.  Once the compiler has reached the end of the include 
   file, the original source file continues to be compiled.

   This is useful to remove code from a file and separate it into more 
   files. It is useful to have a single file with declarations in a program 
   formed by several modules. You may include files within an include file, 
   although avoid including the original file into itself, this will not 
   produce valid results. Typically, include files will have an extension 
   of .bi and are mainly used for declaring subs/functions/variables of a 
   library, but any valid source code may be present in an include file.

   The Once specifier tells the compiler to include the file only once even 
   if it is included several times by the source code.

   $Include is an alternative form of include, existing only for 
   compatibility with QuickBASIC. It is recommended to use #include 
   instead.

   The compiler will automatically convert path separator characters ( '/' 
   and '\' ) as needed to properly load the file.  The filename name may be 
   an absolute or relative path.  

   For relative paths, or where no path is given at all, the include file 
   is search for in the following order:
   * Relative from the directory of the source file
   * Relative from the current working directory
   * Relative from addition directories specified with the -i command line 
     option
   * The include folder of the FreeBASIC installation (FreeBASIC\inc, 
     where FreeBASIC is the folder where the fbc executable is located)

Example
   ' header.bi file
   Type FooType
      Bar As Byte
      Barbeque As Byte 
   End Type

   ' main.bas file
   #include "header.bi"

   Dim Foo As FooType

   Foo.Bar = 1
   Foo.Barbeque = 2

Differences from QB
   * New to FreeBASIC

See also
   * #define
   * #inclib
   * Compiler Option: -i
   * Compiler Option: -include



------------------------------------------------------------- KeyPgOpen ----
Open

Opens a disk file for reading or writing using file operations

Syntax
   Open filename For Input [encoding_type] [lock_type] As [#]filenumber
   Open filename For Output [encoding_type] [lock_type] As [#]filenumber
   Open filename For Append [encoding_type] [lock_type] As [#]filenumber

   Open filename For Binary [access_type] [lock_type] As [#]filenumber
   Open filename For Random [access_type] [lock_type] As [#]filenumber [Len 
   = record_length]

Usage
   result = Open( filename[,] For {Input|Output|Append}[,] As filenumber )
      or
   result = Open( filename[,] For Binary[,] Access {Read|Write}[,] As 
   filenumber )
      or
   result = Open( filename[,] For Random[,] Access {Read|Write}[,] As 
   filenumber [[,] Len =  record_length] )
      or
   Open filename For {Input|Output|Append} As filenumber
      or
   Open filename For Binary Access {Read|Write} As filenumber
      or
   Open filename For Random Access {Read|Write} As filenumber [Len =  
   record_length]

Parameters
   filename
      A string value of the name of the disk file to open. Relative file 
      paths are relative to the current directory (see CurDir).
   encoding_type
      The encoding to be used when reading or writing text, can be one of:
         * Encoding "ascii" (ASCII encoding is used, default)
         * Encoding "utf8" (8-bit Unicode encoding is used)
         * Encoding "utf16" (16-bit Unicode encoding is used)
         * Encoding "utf32" (32-bit Unicode encoding  is used)
   access_type
      The type of access requested by the calling process.
         * Access [Read] [Write] (both read and write access can be used, 
           which is the default)
   lock_type
      Imposes restrictions on disk file access from other processes 
      (threads or programs), can be either:
         * Shared (the file can be freely accessed by other processes)
         * Lock [Read] [Write] (both read and write access can be denied 
           to other processes)
   filenumber
      An available file number to bind to the disk file, which can be found 
      with FreeFile.
   record_length
      The size, in bytes, of each record read from or written to the disk 
      file. The default is 128.

Return Value
   In the first usage, Open() returns a 32 bit Long value: zero (0) on 
   success and a non-zero error code otherwise.

Description
   Opens a disk file for reading and/or writing. The file number file_num 
   is bound to the file on disk, for use in subsequent file operations, 
   such as Input # and Lock. The next available file number can be 
   retrieved with FreeFile.

   The Input, Output and Append file modes open disk files for sequential 
   text I/O, useful for reading or writing plain text files:
      * When the Input mode is specified, only reading file operations can 
        be used, like Line Input # and Get #. If the disk file does not 
        exist a runtime error will be thrown.
      * The Append mode specifies that only writing operations can be 
        used, like Print # and Put #.  Writing operations will take place 
        at the end of the disk file if it exists, preserving the existing 
        data.
      * The Output mode is like the Append mode, except that if the file 
        exists then its contents are deleted and its length reset to zero 
        before writing.

   The Input, Output and Append file modes also allow selection of a 
   character encoding to be used when reading from or writing text to the 
   disk file. ASCII or a Unicode encoding may be specified (see the 
   description of the encoding_type parameter above).

   The Binary and Random file modes open disk files for random-access 
   reading or writing of arbitrary sized binary data:
      * The Binary file mode allows reading and writing of simple data 
        type values, like Byte or LongInt, using binary read or write 
        operations, like Get #. LOC and Seek are among the procedures used 
        for reading and writing to arbitrary locations in the disk file.
      * The Random file mode is similar to Binary, except that file I/O 
        operations always use a constant data size when reading or writing.

   By default, the Binary and Random file modes allow both reading and 
   writing operations on the opened disk file, but this can be changed by 
   specifying an access type (see the description for the access_type 
   parameter above). When opening an existing file in Binary or Random file 
   mode, and with the only Write access type specified, all data in the 
   file are previously deleted at opening, before any other operation.

   For any file mode, access to the opened disk file can be restricted or 
   granted to other threads or programs by specifying a lock type (see the 
   description for the lock_type parameter above). If no lock type is 
   specified, other threads of the current program can freely open the disk 
   file (Shared), while other programs cannot (Lock Read Write). Lock and 
   Unlock can be used to temporarily restrict access to parts of a file.

   The error code returned by Open  can be checked using Err in the next 
   line. The function version of  Open returns directly the error code as a 
   32 bit Long.

Example
   ' Create a string and fill it.
   Dim buffer As String, f As Integer
   buffer = "Hello World within a file."

   ' Find the first free file number.
   f = FreeFile

   ' Open the file "file.ext" for binary usage, using the file number "f".
   Open "file.ext" For Binary As #f
   If Err>0 Then Print "Error opening the file":End

   ' Place our string inside the file, using number "f".
   Put #f, , buffer

   ' Close all open files.  
   Close

   ' End the program. (Check the file "file.ext" upon running to see the output.)
   End

   'OPEN A COM PORT
   Open Com "COM1:9600,N,8,1" As #1
   If Err>0 Then Print "The port could not be opened."

   'COM1, 9600 BAUD, NO PARITY BIT, EIGHT DATA BITS, ONE STOP BIT

   'function version of OPEN
   If Open("file.ext" For Binary Access Read As #1) = 0 Then

      Print "Successfully opened file"

      '' ...

      Close #1

   Else

      Print "Error opening file"

   End If

Platform Differences
   * Linux requires the filename case matches the real name of the file. 
     Windows and DOS are case insensitive.
   * Path separators in Linux are forward slashes /. Windows uses backward 
     slashes \ but it allows for forward slashes /.  DOS uses backward 
     slashes \.
   * On Windows, a file number used in a dynamic link library is not the 
     same as an identical file number used in the main program.  File 
     numbers can not be passed or returned and then used between a DLL and 
     an executable.
   * If you try to open a directory on Linux, the Open command will 
     succeed.

Differences from QB
   * Using MS-DOS device names to open streams or hardware devices ("LPT:"
     , "SCR:", etc.) is supported only in the -lang qb dialect; for other 
     modes FreeBASIC's new composite keywords must be used: see Open Com,  
     Open Cons,  Open Err,  Open Pipe,  Open Lpt,  Open Scrn, Open Tcp, and 
     Open Tcp Server.
   * Open can be called as a function that returns an error code.

Dialect Differences
   * The -lang qb dialect supports the old GW-BASIC-style syntax OPEN 
     mode_string, #filenumber, filename [length] with mode_string being "I" 
     for input, "O" for output, "A" for append, "R" for random, "B" for 
     binary. 

See also
   * Err (and a list of error codes)
   * Close
   * FreeFile
   * Open Cons, Open Err, Open Pipe, Open Lpt, Open Com, Open Scrn, 
     Open Tcp, Open Tcp Server



---------------------------------------------------------- KeyPgOpenCom ----
Open Com

Opens a serial port for input and output, using it as if it were file 
operations.

Syntax
   Declare Function Open Com ( byref options As String, As filenumber As 
   Long ) As Long

Usage
   result = Open Com( options[,] As[#] filenumber )

Parameters
   options
      A String containing options used in controlling the port.
   filenumber
      The file number to bind to the port.

Return Value
   Open Com() returns a 32 bit Long: a zero (0) on success and a non-zero 
   error code otherwise.

Description
   This command opens a serial port of the PC, allowing to send and receive 
   data by using the normal file commands as Print  #, Input #, Get #, ...

   The main parameter is a String that describes, at the very least, which 
   communications port to open. It has the format:

      "Comn: [ baudrate ][ , [ parity ][ , [ data_bits ][ , [ stop_bits ][ 
      , [ extended_options ]]]]]"

   where,
   n
      Com port to open. "1", "2", "3", "4", etc.  Some platforms will 
      support more serial ports depending on how the operating system is 
      configured.  Where n is not given, "COM:" will map to "COM1:", except 
      on Linux where "COM:" maps to "/dev/modem"
   baudrate
      "300" (default), "1200", ..., etc.
   parity
      "N" (none), "E" (even, default), "O" (odd), "S" (space), "M" (mark), 
      "PE" (QB-quirk: checked, even parity)
   data_bits
      "5", "6", "7" (default) or "8".
   stop_bits
      "1", "1.5" or "2". (default value depends on baud rate and data bits, 
      see table below)

            +-----------------------------------+---------------------------+
            |Condition                          |Default number of stop bits|
            |baud rate <= 110 and data bits = 5 |1.5                        |
            |baud rate <= 110 and data bits >= 6|2                          |
            |baud rate > 110                    |1                          |
            +-----------------------------------+---------------------------+

   extended_options
      Miscellaneous options. (See table below)

            +------+-------------------------------------------------------------------------------+
            |Option|Action                                                                         |
            |'CSn' |Set the CTS duration (in ms) (n>=0), 0 = turn off, default = 1000              |
            |'DSn' |Set the DSR duration (in ms) (n>=0), 0 = turn off, default = 1000              |
            |'CDn' |Set the Carrier Detect duration (in ms) (n>=0), 0 = turn off                   |
            |'OPn' |Set the 'Open Timeout' (in ms) (n>=0), 0 = turn off                            |
            |'TBn' |Set the 'Transmit Buffer' size (n>=0), 0 = default, depends on platform        |
            |'RBn' |Set the 'Receive Buffer' size (n>=0), 0 = default, depends on platform         |
            |'RS'  |Suppress RTS detection                                                         |
            |'LF'  |Communicate in ASCII mode (add LF to every CR) - Win32 doesn't support this one|
            |'ASC' |same as 'LF'                                                                   |
            |'BIN' |The opposite of LF and it'll always work                                       |
            |'PE'  |Enable 'Parity' check                                                          |
            |'DT'  |Keep DTR enabled after CLOSE                                                   |
            |'FE'  |Discard invalid character on error                                             |
            |'ME'  |Ignore all errors                                                              |
            |'IRn' |IRQ number for COM (only supported (?) on DOS)                                 |
            +------+-------------------------------------------------------------------------------+

   All items except for the COM port are optional. The order of baudrate, 
   parity, data_bits, stop_bits is fixed. Any skipped fixed item ( baudrate
   , etc...) must be empty.

   The error code returned by Open Com can be checked using Err in the next 
   line. The function version of  Open Com returns directly the error code 
   as a 32 bit Long.

Example
   Open Com "COM1:9600,N,,2" As 1

   Opens COM1 with 9600 baud, no parity, 7 data bits and 2 stop bits.

   Open Com "COM1:115200" As 1

   Opens COM1 with 115200 baud, "even" parity, 7 data bits and 1 stop bits. 
   

Platform Differences
   * On the Windows platform 
      "COM:" maps to "COM1:"
      baud rate must be an unsigned 32-bit integer, and is passed on 
      directly to the operating system.
   * On the Linux platform
      "COM:" maps to "/dev/modem"
      "COM1:" maps to "/dev/ttyS0"
      "COM2:" maps to "/dev/ttyS1", etc 
      "/dev/xyz:" maps to "/dev/xyz", etc
      baud rate must be one of 50, 150, 300, 600, 1200, 1800, 2400, 4800, 
      9600, 19200, 38400, 57600, 115200, 230400, 460800, 500000, 576000, 
      921600, 1000000, 1152000
      in fbc >= 1.09.0, baud rate can also be one of 1500000, 2000000, 
      2500000, 3000000, 3500000, 4000000
      the baud rates supported depend on the system where the fbc compiler 
      itself was compiled and built
   * The DOS serial driver is experimental and can access COM ports 1 to 4 
     
      It uses the following base io and IRQ's as default: 
      COM1 - &h3f8 - IRQ4 
      COM2 - &h2f8 - IRQ3 
      COM3 - &h3e8 - IRQ4 
      COM4 - &h2e8 - IRQ3 
      An alternate IRQ can be specified using the the "IRn" protocol option 
      where n is 3 through 7 (first PIC). Since fbc 1.10.0, n can also be 8 
      through 15 (second PIC).
      Currently not supported: IRQ's on the slave PIC, alternate base I/O 
      addresses, Timeouts and most errors as detected in QB, hardware flow 
      control, FIFO's.
      "COM:" maps to "COM1:"
      baud rate must be between 50 and 115200
Dialect Differences
   * In the -lang qb dialect the old syntax OPEN "COMx:... is supported. 

Differences from QB
   * In QB the syntax was OPEN  "COMx:[baudrate] [,parity, [data_bits, 
     [stop_bits, [extended_options]]]]"  FOR INPUT|OUTPUT|RANDOM AS [#] n
   * In QB, only "COM1:" and "COM2:" are supported.  In FreeBASIC, any 
     correctly configured serial port may be used.

See also
   * Open



--------------------------------------------------------- KeyPgOpenCons ----
Open Cons

Opens the console's standard input (stdin) or output (stdout) streams, 
using it as if it were file operations.

Syntax
   Open Cons As [#]filenumber
   Open Cons For Input As [#]filenumber
   Open Cons For Output As [#]filenumber

Usage
   result = Open Cons( [For {Input|Output}[,]] As filenumber )
      (or using the QB-like syntax,)
   Open Cons [For {Input|Output}] As filenumber

Parameters
   filenumber
      An available file number to bind to the stdin or stdout stream, which 
      can be found with FreeFile.

Return Value
   In the first usage, Open Cons() returns a 32 bit Long: a zero (0) on 
   success and a non-zero error code otherwise.

Description
   Open Cons opens the console's stdin or stdout streams for reading or 
   writing. A file number is bound to the stream, which is used in 
   subsequent file operations, such as Input #. An available file number 
   can be retrieved with FreeFile.

   The Input file mode opens the stdin stream for reading file operations, 
   such as Line Input #, while the Output file mode opens the stdout stream 
   for writing file operations, such as Print #. The Output file mode is 
   the default if not specified.

   The stdin and stdout streams are the ones used when the calling process' 
   input or output is redirected (piped) by OS commands, or when it is 
   opened with Open Pipe.

   To open both the stdin and stdout streams for file operations, a process 
   must use multiple file numbers.

   The normal screen commands, such as Color and Locate, do not work in 
   this mode, because they do not accept a file number.
   The Tab keyword, regardless of the given column number, is always 
   interpreted as a simple comma (,) (next output will take place at the 
   next 14 column boundary).

   The error code returned by Open Cons can be checked using Err in the 
   next line. The function version of  Open Cons returns directly the error 
   code as a 32 bit Long.

   Warning: Presently, Open Cons does not work as described above. Without 
   any file mode specifier, a runtime error 1 (illegal function call) 
   occurs. With the Input file mode specifier, the only input mode is well 
   supported. But with the Output file mode specifier, input and output 
   modes are simultaneously supported.

Runtime errors:
   Open Cons throws one of the following runtime errors:

   (1) Illegal function call
      * filenumber was not free at the time. use FreeFile to ensure that 
        filenumber is free.

Example
   Dim a As String

   Open Cons For Input As #1
   Open Cons For Output As #2

   Print #2,"Please write something and press ENTER"
   Line Input #1,a
   Print #2, "You wrote : ";a

   Close
   Sleep

Differences from QB
   * In QB the syntax was OPEN "CON:" FOR INPUT|OUTPUT AS [#] filenumber

See also
   * Open
   * Open Scrn
   * Open Err
   * FreeFile



---------------------------------------------------------- KeyPgOpenErr ----
Open Err

Opens both the standard input (stdin) and standard error (stderr) streams, 
using it as if it were file operations.

Syntax
   Open Err [for mode] As [#]filenumber As Long

Usage
   Open Err [for mode] as [#]filenumber
      or
   result = Open Err( [for mode[,]] as [#]filenumber )

Parameters
   mode
      Ignored.
   filenumber
      An unused file number.

Return Value
   A 32 bit Long: a zero is returned if Open Err() completed successfully, 
   otherwise a non-zero value is returned to indicate failure.

Description
   This command opens stdin to read from and stderr to write to the console 
   allowing read and write operations with normal file commands.

   stderr is an output stream different from stdout allowing error messages 
   to be redirected separately from the main console output.

   The normal console commands, such as Color and Locate, do not work in 
   this mode, because they do not accept a file number.
   The Tab keyword, regardless of the given column number, is always 
   interpreted as a simple comma (,) (next output will take place at the 
   next 14 column boundary).

   The [For Input|Output] mode is allowed for compatibility, but is 
   ignored.

   The error code returned by Open Err can be checked using Err in the next 
   line. The function version of  Open Err returns directly the error code 
   as a 32 bit Long.

Runtime errors:
   Open Err throws one of the following runtime errors:

   (1) Illegal function call
      * Filenumber was not free at the time. use FreeFile to ensure that 
        filenumber is free.

Example
   Dim a As String
   Open Err For Input  As #1
   Print #1,"Please write something and press ENTER"
   Line Input #1, a 
   Print #1, "You wrote"; a
   Close
   Sleep

Differences from QB
   * New to FreeBASIC

See also
   * Open



---------------------------------------------------------- KeyPgOpenLpt ----
Open Lpt

Open a printer device, using it as if it were file operations.

Syntax
   Open Lpt ["[LPT[x]:][Printer_Name][,TITLE=Doc_Title][,EMU=TTY]"] [For 
   Input|Output] As #filenumber

Usage
   Open Lpt "LPT..." As [#]filenumber
      or
   result = Open Lpt( "LPT..."[,] As [#]filenumber )

Parameters
   x
      Specifies a port number.  If omitted, output is sent to the system 
      print spooler.
   Printer_Name
      Name of printer to open.  This parameter is ignored on DOS.
   TITLE=Doc_Title
      Title of the print job as seen by the printer spooler.  This 
      parameter is ignored on DOS.
   EMU=TTY
      Emulation of TTY output on a windows GDI printer, using driver text 
      imaging.  This parameter is ignored on DOS and Linux.
   For Input|Output
      clause is allowed for compatibility, but it is ignored.
   filenumber
      An unused file number to assign to the device.

Return Value
   A 32 bit Long: 0 is returned if Open Lpt() completed successfully, 
   otherwise a non-zero value is returned to indicate failure.

Description
   Open Lpt opens a connection to a printer device.  The connection is 
   treated like a file, so data may be written to the printer using Print 
   and Put # commands.  

   Any printer attached to the system may be opened with Open Lpt

   Open Lpt "LPT:" ... will try to open the default printer on Windows and 
   Linux, and "LPT1:" on DOS.

   LPrint will automatically try to open the default printer on Windows and 
   Linux, and "LPT1:" on DOS.

   The error code returned by Open Lpt can be checked using Err in the next 
   line. The function version of  Open Lpt returns directly the error code 
   as a 32 bit Long.

Platform specific notes:

   Windows
      The argument EMU=TTY assumes printable ASCII or Unicode text, and 
      applies printer driver text imaging to the input.  EMU=TTY also 
      allows the usage of CR, LF, BS, TAB, FF, etc., for virtual print-head 
      movement...even when the printer is a GDI printer and therefore 
      doesn't itself understand these special characters.  If ",EMU=TTY" is 
      omitted, the data must be sent in the printer's language (ESC/P, 
      HPGL, PostScript, etc...).  Other useful emulation modes aren't 
      supported yet.

   Linux
      A printer spooler available through lp must be installed to access 
      printers by name or a default printer.  Spooler access was tested 
      only with CUPS, but other spoolers may work that are invoked through 
      lp.  Port are zero-based on Linux. "LPT1:" corresponds with 
      "/dev/lp0".

      The data must be sent in the printer's language (ESC/P, HPGL, 
      PostScript, etc...). Emulation modes aren't supported yet.

   DOS
      FreeBASIC does not support print spoolers on DOS.  Printers must be 
      accessible through "LPTx:".

      The data must be sent in the printer's language (ESC/P, HPGL, 
      PostScript, etc...).  Emulation modes aren't supported yet.

Example
   ' Send some text to the Windows printer on LPT1:, using driver text imaging.
   Open Lpt "LPT1:EMU=TTY" For Output  As #1
   Print #1, "Testing!" 
   Close

   ' Sends contents of text file test.txt to Windows printer named "ReceiptPrinter"
   Dim RptInput As String
   Dim PrintFileNum As Long, RptFileFileNum As Long

   RptFileFileNum = FreeFile
   Open "test.txt" For Input As #RptFileFileNum

   PrintFileNum = FreeFile
   Open Lpt "LPT:ReceiptPrinter,TITLE=ReceiptWinTitle,EMU=TTY" As _
      #PrintFilenum

   While (EOF(RptFileFileNum) = 0)
         Line Input #RptFileFileNum, RptInput
         Print #PrintFileNum, RptInput
   Wend

   Close #PrintFileNum  ' Interestingly, does not require CHR(12).  But if pagination is desired, CHR(12) is the way.

   Close #RptFileFileNum

   Print "Press any key to end program..."
   GetKey

   End

   'This simple program will print a PostScript file to a PostScript compatible printer.
   Dim As Long FFI, PPO
   Dim As String temp

   FFI = FreeFile()
   Open "sample.ps" For Input Access Read As #FFI
   PPO = FreeFile()
   Open Lpt "LPT1:" For Output As #PPO
   While (EOF(FFI) = 0)
   Line Input #FFI, temp
   Print #PPO, temp
   Wend

   Close #FFI
   Close #PPO

   Print "Printing Completed!"

Dialect Differences
   * In the -lang qb dialect the old syntax is supported OPEN "LPT:..." . 
     This syntax used in the other dialects will open a regular file.

See also
   * Open
   * LPrint



--------------------------------------------------------- KeyPgOpenPipe ----
Open Pipe

Opens an external process' standard input (stdin) or output (stdout) 
stream, using it as if it were file operations.

Syntax
   Open Pipe shell_command For Input As [#]filenumber
   Open Pipe shell_command For Output As [#]filenumber
   Open Pipe shell_command For Binary access_type [#]filenumber

Usage
   result = Open Pipe( command[,] For {Input|Output}[,] As filenumber )
      or,
   result = Open Pipe( command[,] For Binary[,] access_type[,] As 
   filenumber )
      (or in the QB-like syntax,)
   Open Pipe filename For {Input|Output} As filenumber
      (or,)
   Open Pipe filename For Binary access_type As filenumber

Parameters
   shell_command
      The external process to execute in the operating system command 
      shell. Relative file paths are relative to the current directory (see 
      CurDir).  When opening a pipe for a process that requires double 
      quotes in either its executable path, or its arguments, the entire 
      pipe string should be nested inside of double quotes.
   access_type
      The type of read or write access requested by the calling process.
         * Access {Read|Write} (either the stdin or stdout stream of the 
           external process can be opened)
   filenumber
      An available file number to bind to the external process' stdin or 
      stdout stream.

Return Value
   In the first usage, Open Pipe() returns a 32 bit Long: a zero (0) on 
   success and a non-zero error code otherwise.

Description
   Open Pipe executes another process in the command shell and opens either 
   its stdin or stdout streams for reading or writing. A file number is 
   bound to the stream, which is used in subsequent file operations, such 
   as Input #. An available filenumber can be retrieved with FreeFile. If 
   the external process does not exist, a runtime error is thrown.

   The Input and Output file modes open the external process' stdin and 
   stdout streams, respectively, for sequential text I/O, useful for 
   reading or writing plain text. Characters, words or whole lines can then 
   be read or written using text-mode file operations, such as Line Input # 
   and Print #.

   The Binary file mode opens the external process' stdin or stdout streams 
   - depending on the access type specified (see description of the 
   access_type parameter above) - for random-access reading or writing of 
   arbitrarily sized and interpreted raw data. Simple data type values, 
   like Byte and LongInt, and whole chunks of memory can be read from or 
   written to the streams with binary-mode file operations like Get # and 
   Put #.
   Bidirectional pipes are not supported by FB and must be implemented 
   using the OS' API functions.

   The error code returned by Open Pipe can be checked using Err in the 
   next line. The function version of  Open Pipe returns directly the error 
   code as a 32 bit Long.

Runtime errors:
   Open Pipe throws one of the following runtime errors:

   (1) Illegal function call
      * filenumber was not free at the time. use FreeFile to ensure that 
        filenumber is free.

Example
   '' This example uses Open Pipe to run a shell command and retrieve its output. 
   #ifdef __FB_UNIX__
   Const TEST_COMMAND = "ls *"
   #else
   Const TEST_COMMAND = "dir *.*"
   #endif

   Open Pipe TEST_COMMAND For Input As #1

   Dim As String ln
   Do Until EOF(1)
      Line Input #1, ln
      Print ln
   Loop

   Close #1

Platform Differences
   * The Binary file mode is not supported on all platforms; Open Pipe 
     will throw an error if it is unable to open the external process' 
     stdin or stdout streams in binary mode.

Differences from QB
   * New to FreeBASIC

See also
   * Shell
   * Open
   * Open Cons
   * Open Err
   * FreeFile



--------------------------------------------------------- KeyPgOpenScrn ----
Open Scrn

Opens the screen directly for input and output, using it as if it were file 
operations.

Syntax
   Open Scrn [for mode] As [#]filenumber As Long

Usage
   Open Scrn [for mode] as [#]filenumber
      or
   result = Open Scrn( [for mode[,]] as [#]filenumber )

Parameters
   mode
      Either Input or Output.  If omitted, Output is assumed.
   filenumber
      An unused file number.

Return Value
   A 32 bit Long: a zero (0) is returned if Open Scrn() completed 
   successfully, otherwise a non-zero value is returned to indicate 
   failure.

Description
   This command opens the screen (in text or graphics screen mode) for both 
   input and output as a file, allowing to read/write from/to it with 
   normal file commands.

   This command may use direct access to the screen for speed in some 
   implementations, so  it should not be used when the input / output is 
   required to be redirected or piped with OS commands.    

   The normal screen commands, such as Color and Locate, do not work in 
   this mode, because they do not accept a file number.

   The [For Input|Output] clause is allowed for compatibility, but is 
   ignored.

   filenumber is an unused file number.

   An unused file number can be found using FreeFile.

   The error code returned by Open Scrn can be checked using Err in the 
   next line. The function version of  Open Scrn returns directly the error 
   code as a 32 bit Long.

Runtime errors:
   Open Scrn throws one of the following runtime errors:

   (1) Illegal function call
      * filenumber was not free at the time. use FreeFile to ensure that 
        filenumber is free.	

Example
   Dim a As String
   Open Scrn For Input  As #1
   Print #1,"Please write something and press ENTER"
   Line Input #1,a
   Print #1, "You wrote";a
   Close
   Sleep

Differences from QB
   * QB used OPEN "SCRN:" ...

See also
   * Open
   * Open Cons



---------------------------------------------------------- KeyPgOpenTcp ----
Open Tcp

Opens a TCP client connection and binds it to a file number.

Syntax
   Declare Function Open Tcp ( options As String, As [#]filenumber As Long 
   ) As Long

Usage
   result = Open Tcp( options[,] As [#]filenumber )
   Open Tcp options As [#]filenumber

Parameters
   options
      A comma-separated string describing the connection.
   filenumber
      The file number to bind to the connected socket.

Return Value
   Returns zero (0) on success, or a non-zero error code on failure.

Description
   Open Tcp connects to a TCP server and exposes the socket through 
   FreeBASIC's normal file I/O statements.  Once opened, the file number 
   can be used with Print #, Line Input #, Input(), Get #, and Put #.

   The options string accepts:
      * host=name-or-address, required for client connections
      * port=number, required
      * timeout=milliseconds, optional socket timeout

   Unknown options are ignored so that future TCP options can be added 
   without breaking existing programs.

   For sockets, EOF means that no byte is currently available to read.  Use 
   Eoc to test whether the peer has closed the connection.

Example
   See examples/network/opentcp/http-get.bas.

Platform Differences
   * TCP support is not available on all targets.  Programs that need to 
     be portable should use target defines such as FB_DOS, FB_JS, and 
     FB_XBOX where appropriate.

Differences from QB
   * New to FreeBASIC.

See also
   * Open Tcp Server
   * Tcp Accept
   * Eoc
   * Open



---------------------------------------------------- KeyPgOpenTcpServer ----
Open Tcp Server

Opens a listening TCP server socket and binds it to a file number.

Syntax
   Declare Function Open Tcp Server ( options As String, As [#]filenumber As
   Long ) As Long

Usage
   result = Open Tcp Server( options[,] As [#]filenumber )
   Open Tcp Server options As [#]filenumber

Parameters
   options
      A comma-separated string describing the listening socket.
   filenumber
      The file number to bind to the server socket.

Return Value
   Returns zero (0) on success, or a non-zero error code on failure.

Description
   Open Tcp Server creates a listening TCP socket.  The server file number 
   is passed to Tcp Accept to accept incoming connections.  The accepted 
   client receives its own file number and can then be read from or written 
   to using normal file I/O statements.

   The options string accepts:
      * host=name-or-address, optional bind address
      * port=number, required
      * backlog=count, optional listen backlog, default 16
      * timeout=milliseconds, optional socket timeout

   Server file numbers are not used for data transfer.  Use Tcp Accept and 
   then read or write the returned client file number.

Example
   See examples/network/opentcp/http-server.bas and 
   examples/network/opentcp/two-connections-selftest.bas.

Platform Differences
   * TCP support is not available on all targets.  Programs that need to 
     be portable should use target defines such as FB_DOS, FB_JS, and 
     FB_XBOX where appropriate.

Differences from QB
   * New to FreeBASIC.

See also
   * Open Tcp
   * Tcp Accept
   * Close



--------------------------------------------------------- KeyPgOperator ----
Operator

Declares or defines an overloaded operator.

Syntax
   { Type | Class | Union } typename
      Declare Operator Cast () [ ByRef ] As datatype
      Declare Operator @ () [ ByRef ] As datatype Ptr
      Declare Operator assignment_op ( [ ByRef | ByVal ] rhs As datatype )
      Declare Operator [] ( index As datatype ) [ ByRef ] As datatype
      Declare Operator New ( size As UInteger ) As Any Ptr
      Declare Operator New[] ( size As UInteger ) As Any Ptr
      Declare Operator Delete ( buf  As Any Ptr )
      Declare Operator Delete[] ( buf  As Any Ptr )
   End { Type | Class | Union }

   { Type | Class | Union } typename
      Declare Operator For ()
      Declare Operator For ( [ ByRef | ByVal ] stp As typename )
      Declare Operator Step ()
      Declare Operator Step ( [ ByRef | ByVal ] stp As typename )
      Declare Operator Next ( [ ByRef | ByVal ] cond As typename ) As 
      Integer
      Declare Operator Next ( [ ByRef | ByVal ] cond As typename, [ ByRef | 
      ByVal ] stp As typename ) As Integer
   End { Type | Class | Union }

   Declare Operator unary_op ( [ ByRef | ByVal ] rhs As datatype ) As 
   datatype
   Declare Operator binary_op ( [ ByRef | ByVal ] lhs As datatype, [ ByRef 
   | ByVal ] rhs As datatype ) As datatype

   Operator typename.Cast () [ ByRef ] As datatype [ Export ]
   Operator typename.@ () [ ByRef ] As datatype Ptr [ Export ]
   Operator typename.assignment_op ( [ ByRef | ByVal ] rhs As datatype ) [ 
   Export ]
   Operator typename.[] ( index As datatype ) [ ByRef ] As datatype [ Export
   ]
   Operator unary_op ( [ ByRef | ByVal ] rhs As datatype ) As datatype [ 
   Export ]
   Operator binary_op ( [ ByRef | ByVal ] lhs As datatype, [ ByRef | ByVal 
   ] rhs As datatype ) As datatype [ Export ]
   Operator typename.New ( size as uinteger ) As Any Ptr [ Export ]
   Operator typename.New[] ( size As UInteger ) As Any Ptr [ Export ]
   Operator typename.Delete ( buf  As Any Ptr ) [ Export ]
   Operator typename.Delete[] ( buf  As Any Ptr ) [ Export ]

Parameters
   typename 
      Name of the Type, Class, Union, or Enum.
   assignment_op 
      let += -= *= &= /= \= mod= shl= shr= and= or= xor= imp= eqv= ^=
   unary_op
      - not * -> abs sgn fix frac int exp log sin asin cos acos tan atn len 
      sqr
   binary_op
      + - * & / \ mod shl shr and or xor imp eqv ^ = <> < > <= >=

Description
   The built in operators like =, +, and cast have predefined behaviors 
   when used in expressions.  These operators can be overloaded to do 
   something other than predefined operations when at least one of the 
   arguments to the operator is a Type, Class, Enum, or Union data type.

   Operators are just functions.  The operator '+' has functionality like 
   Function Plus( A as DataType, B as DataType ) as DataType.  See 
   Operator Overloading for more information.  Operators can be overloaded 
   to accept different data types as parameters.  The Cast Operator is the 
   only operator (or function) that can be declared multiple times when 
   only the return type differs, but not the same as the Type, Class, or 
   Union it is declared in (for not explicit usage, the compiler may decide 
   which cast overload to call based on how the object is used).

   Non-static operator members are declared inside the Type, Class, or Union
   .  Global operators are declared outside.  All operator definitions 
   (procedure bodies) must appear outside.

   Let, Cast, and other assignment operators must be declared inside the 
   Type, Class, or Union.  As all non-static member procedures, they have 
   passed a hidden This parameter.

   Unary operators must be declared outside the Type, Class, or Union and 
   have a return data type explicitly declared.  Unary operators can be 
   overloaded to return any valid data type, except for 
   Operator -> (Pointer To Member Access) which must return a Type, Class, 
   or Union data type.

   Binary operators must be declared outside the Type, Class, or Union and 
   have a return data type explicitly declared.  Binary operators can be 
   overloaded with valid data types, including for relational operators, 
   which can also return any valid data type.

   Let refers to the assignment operator, as in LET a=b. The Let keyword is 
   omitted in common practice, and is not allowed in the -lang fb dialect.  
   However, Let() can be used to assign the fields of a UDT to multiple 
   variables.

   See For, Step, and Next for more information on overloading the For..Next
   statement for use with user defined types.

   Although declared inside the Type, Class, or Union, the member operators 
   New, New[], Delete, and Delete[] are always static, even if not 
   explicitly declared (Static keyword is unnecessary but allowed).

Example
   '' operator1.bas

   Type Vector2D
     As Single x, y

     '' Return a string containing the vector data.
     Declare Operator Cast() As String

     '' Multiply the vector by a scalar.
     Declare Operator *= ( ByVal rhs As Single )
   End Type

   '' Allow two vectors to be able to be added together.
   Declare Operator + ( ByRef lhs As Vector2D, ByRef rhs As Vector2D ) As Vector2D

   '' Return the modulus (single) of the vector using the overloaded operator abs().
   Declare Operator Abs (  ByRef rhs As Vector2D ) As Single

   Operator Vector2D.cast () As String
     Return "(" + Str(x) + ", " + Str(y) + ")"
   End Operator

   Operator Vector2D.*= ( ByVal rhs As Single )
     This.x *= rhs
     This.y *= rhs
   End Operator

   Operator + ( ByRef lhs As Vector2D, ByRef rhs As Vector2D ) As Vector2D
     Return Type<Vector2D>( lhs.x + rhs.x, lhs.y + rhs.y )
   End Operator

   Operator Abs ( ByRef rhs As Vector2D ) As Single
     Return Sqr( rhs.x * rhs.x + rhs.y * rhs.y )
   End Operator

   Dim a As Vector2D = Type<Vector2D>( 1.2, 3.4 )
   Dim b As Vector2D = Type<Vector2D>( 8.9, 6.7 )
   Dim c As Vector2D = Type<Vector2D>( 4.3, 5.6 )

   Print "a = "; a, "abs(a) ="; Abs( a )
   Print "b = "; b, "abs(b) ="; Abs( b )
   Print "a + b = "; a + b, "abs(a+b) ="; Abs( a + b )
   Print "c = "; c, "abs(c) ="; Abs( c )
   Print "'c *= 3'"
   c *= 3
   Print "c = "; c, "abs(c) ="; Abs( c )

   Small use case of the operator "[]": simplest smart pointers for byte 
   buffers.
   '' operator3.bas

   '' A smart pointer is an object which behaves like a pointer but does more than a pointer:
   '' - This object is flexible as a pointer and has the advantage of being an object,
   ''   like constructor and destructor called automatically.
   '' - Therefore, the destructor of the smart pointer will be automatically called
   ''   when this object goes out of scope, and it will delete the user pointer.

   '' Example of simplest smart pointers for byte buffers:
   '' - Constructor and destructor allow to allocate, deallocate, and resize the byte buffer.
   '' - Pointer index operator allows to access buffer elements.
   '' - Copy-constructor and let-operator are just declared in private section,
   ''   in order to disallow copy construction and any assignment.

   Type smartByteBuffer
     Public:
      Declare Constructor (ByVal size As UInteger = 0)
      Declare Operator [] (ByVal index As UInteger) ByRef As Byte
      Declare Destructor ()
     Private:
      Declare Constructor (ByRef rhs As smartByteBuffer)
      Declare Operator Let (ByRef rhs As smartByteBuffer)
      Dim As Byte Ptr psbb
   End Type

   Constructor smartByteBuffer (ByVal size As UInteger = 0)
     This.destructor()
     If size > 0 Then
      This.psbb = New Byte[size]
      Print "Byte buffer allocated"
     End If
   End Constructor

   Operator smartByteBuffer.[] (ByVal index As UInteger) ByRef As Byte
     Return This.psbb[index]
   End Operator

   Destructor smartByteBuffer ()
     If This.psbb > 0 Then
      Delete[] This.psbb
      This.psbb = 0
      Print "Byte buffer deallocated"
     End If
   End Destructor

   Scope
     Dim As smartByteBuffer sbb = smartByteBuffer(256)
     For I As Integer = 0 To 255
      sbb[I] = I - 128
     Next I
     Print
     For I As Integer = 0 To 255
      Print Using "#####"; sbb[I];
     Next I
     Print
   End Scope

Dialect Differences
   * Only available in the -lang fb dialect.

See also
   * Class
   * Union
   * Type
   * Coercion and Conversion



----------------------------------------------------------- KeyPgOption ----
Option()

Specifies additional attributes and/or characteristics of symbols.

Syntax
   Option( "literal-text" )

Parameters
   literal-text
      The literal text specifying the option. See description.

Description
   Option() allows the programmer to specify additional attributes or 
   characteristics.  Enclosing the string into quotes and parentheses is 
   required in the syntax.  Unrecognized options are ignored.

   Option can also be used as a statement to specify other compile time 
   options.  See Compiler Switches.

   Individual options are explained below.

SSE
   Option("SSE") indicates that a floating point value (Single or Double) 
   returned from a function is stored in the xmm0 register.  Option("Sse") 
   is ignored unless the source is compiled with the -fpu SSE command line 
   option.  This option may be used immediately after the return type in a 
   function declaration or function definition.  This option is an 
   optimization only and not required to compile programs using the -fpu SSE
   command line option.

   Declare Function ValueInXmm0 () As Double Option("sse")

FPU
   Option("FPU") indicates that a floating point value (Single or Double) 
   returned from a function is stored in the st(0) register.  This option 
   may be used immediately after the return type in a function declaration 
   or function definition.

   Declare Function ValueInStZero () As Double Option("fpu")

Differences from QB
   * New to FreeBASIC

See also
   * Compiler Option: -fpu
   * Compiler Switches



------------------------------------------------------- KeyPgOptionbase ----
Option Base

Specifies a default lower bound for array declarations

Syntax
   Option Base base_subscript

Parameters
   base_subscript
      an numeric literal value

Description
   Option Base is a statement that sets the default lower bound for any 
   following array declarations. This default remains in effect for the 
   rest of the module in which Option Base is used, and can be overridden 
   by declaring arrays with an explicit lower bound, or with another Option 
   Base statement.

   Note: initially, the default base is 0.

Example
   '' Compile with the "-lang qb" or "-lang fblite" compiler switches

   #lang "fblite"

   Dim foo(10) As Integer      ' declares an array with indices 0-10

   Option Base 5

   Dim bar(15) As Integer      ' declares an array with indices 5-15
   Dim baz(0 To 4) As Integer  ' declares an array with indices 0-4

Dialect Differences
   * Only available in the -lang fblite and -lang qb dialects.
   * In -lang fb, Option Base is not allowed, and the default lower bound 
     is always 0.

Differences from QB
   * QBASIC only supported values of 0 or 1 for base_subscript.
   * In QBASIC the word Base was a reserved keyword, and couldn't be used 
     as a variable name.
   * Arrays must always be explicitly created in FreeBASIC.  QBASIC would 
     implicitly create an array from base_subscript to 10 if one was used 
     in code without being predefined.

See also
   * Dim
   * ReDim
   * LBound



------------------------------------------------------ KeyPgOptionbyval ----
Option ByVal

Specifies parameters are to be passed by value by default in procedure 
declarations

Syntax
   Option ByVal

Description
   Option ByVal is a statement that sets the default passing convention for 
   procedure parameters to by value, as if declared with ByVal. This 
   default remains in effect for the rest of the module in which Option 
   ByVal is used, and can be overridden by specifying ByRef in parameter 
   lists.

Example
   '' compile with the "-lang fblite" compiler switch

   #lang "fblite"

   Sub TestDefaultByref( a As Integer )
     '' change the value
     a = a * 2
   End Sub

   Option ByVal

   Sub TestDefaultByval( a As Integer )
     a = a * 2
   End Sub

   Dim a As Integer = 1

   Print "a = "; a
   TestDefaultByref( a )
   Print "After TestDefaultByref : a = "; a
   Print

   Print "a = "; a
   TestDefaultByval( a )
   Print "After TestDefaultByval : a = "; a
   Print

Dialect Differences
   * Only available in the -lang fblite and -lang qb dialects.

Differences from QB
   * New to FreeBASIC

See also
   * __FB_OPTION_BYVAL__



---------------------------------------------------- KeyPgOptiondynamic ----
Option Dynamic

Specifies variable-length array declarations

Syntax
   Option Dynamic

Description
   Option Dynamic is a statement that specifies that any following array 
   declarations are variable-length, whether they are declared with 
   constant subscript ranges or not. This remains in effect for the rest of 
   the module in which Option Dynamic is used, and can be overridden with 
   Option Static.  It is equivalent to the '$Dynamic metacommand.

Example
   '' Compile with "-lang fblite" compiler switch

   #lang "fblite"

   Dim foo(99) As Integer      ' declares a fixed-length array

   Option Dynamic

   Dim bar(99) As Integer      ' declares a variable-length array
   ' ...
   ReDim bar(199)              ' resize the array

Dialect Differences
   * Only available in the -lang fblite and -lang qb dialects.

Differences from QB
   * New to FreeBASIC

See also
   * __FB_OPTION_DYNAMIC__
   * '$Dynamic
   * '$Static
   * Option Static
   * Dim
   * ReDim



----------------------------------------------------- KeyPgOptionescape ----
Option Escape

Specifies that string literals should be processed for C-like escape 
sequences by default

Syntax
   Option Escape

Description
   Option Escape is a statement that causes string literals to be processed 
   for C-like escape sequences by default. Normally, escape sequences have 
   no effect in string literals unless the string is prefixed with the  
   ! Operator (Escaped String Literal). This default remains in effect for 
   the rest of the module in which Option Escape is used, and can be 
   overridden by prefixing string literals with the 
   $ Operator (Non-Escaped String Literal).

   See Literals in the Programmer's Guide to learn more about escape 
   sequences.

Example
   '' Compile with the "-lang fblite" compiler switch

   #lang "fblite"

   Option Escape

   Print "Warning \a\t The path is:\r\n c:\\Freebasic\\Examples"
   Print $"This string doesn't have expanded escape sequences: \r\n\t"

   #include "crt.bi"

   Dim As Integer a = 2, b = 3
   printf("%d * %d = %d\r\n", a, b, a * b)

Dialect Differences
   * Only available in the -lang fblite and -lang qb dialects.

Differences from QB
   * New to FreeBASIC

See also
   * __FB_OPTION_ESCAPE__
   * Operator ! (Escaped String Literal)
   * Operator $ (Non-Escaped String Literal)
   * Literals



--------------------------------------------------- KeyPgOptionexplicit ----
Option Explicit

Forces variables, objects and arrays to be declared before they are used

Syntax
   Option Explicit

Description
   Option Explicit is a statement that forces any following variable, 
   object or array usage to be preceded by a declaration, with, for 
   example, Dim or Static. This rule remains in effect for the rest of the 
   module in which Option Explicit is used, and cannot be overridden.

Example
   '' Compile with the "-lang qb" or "-lang fblite" compiler switches

   #lang "fblite"

   Option Explicit

   Dim a As Integer            ' 'a' must be declared..
   a = 1                       ' ..or this statement will fail to compile.

   Dialect Differences
   * Only available in the -lang fblite and -lang qb dialects.

Differences from QB
   *New to FreeBASIC

See also
   * __FB_OPTION_EXPLICIT__



------------------------------------------------------ KeyPgOptiongosub ----
Option Gosub

Enables support for GoSub and On Gosub.

Syntax
   Option Gosub

Description
   Option Gosub enables support for GoSub and Return (from gosub).

   Because Return could mean return-from-gosub or return-from-procedure, 
   Option Gosub and Option Nogosub can be used to enable and disable GoSub 
   support.  When GoSub support is disabled, Return is then recognized as 
   return-from-procedure.

Example
   '' Compile with the "-lang fblite" compiler switch

   #lang "fblite"

   '' turn on gosub support
   Option GoSub

   GoSub there
   backagain:
      Print "backagain"
      End

   there:
      Print "there"
      Return

Dialect Differences
   * Only available in the -lang fblite and -lang qb dialects.

Differences from QB
   * New to FreeBASIC

See also
   * __FB_OPTION_GOSUB__
   * Option Nogosub
   * GoSub
   * Return (From Gosub)
   * Return (From Procedure)



---------------------------------------------------- KeyPgOptionnogosub ----
Option Nogosub

Disables support for GoSub and On Gosub.

Syntax
   Option Nogosub

Description
   Option Nogosub disables support for GoSub and Return (from gosub).

   Because Return could mean return-from-gosub or return-from-procedure, 
   Option Gosub and Option Nogosub can be used to enable and disable GoSub 
   support.  When GoSub support is disabled, Return is then recognized as 
   return-from-procedure.

Example
   '' Compile with the "-lang qb" compiler switch

   '$lang: "qb"

   '' turn off gosub support
   Option nogosub

   Function foo() As Integer
      Return 1234
   End Function

   Print foo

Dialect Differences
   * Only available in the -lang fblite and -lang qb dialects.

Differences from QB
   * New to FreeBASIC

See also
   * __FB_OPTION_GOSUB__
   * Option Gosub
   * GoSub
   * Return (From Procedure)
   * Return (From Gosub)



-------------------------------------------------- KeyPgOptionnokeyword ----
Option NoKeyword

"Undefines" a reserved keyword

Syntax
   Option NoKeyword keyword

Parameters
   keyword
      the keyword to undefine

Description
   Option NoKeyword is a statement that undefines a FreeBASIC reserved 
   keyword, meaning it can be used as an identifier for a variable, object, 
   procedure or any other symbol. The keyword is undefined for the rest of 
   the module in which Option NoKeyword is used.

Example
   '' Compile with the "-lang fblite" compiler switch

   #lang "fblite"

   Option NoKeyword Int        ' remove the keyword 'int' from the internal
                        ' symbol table

   Dim Int As Integer          ' declare a variable with the name 'int'

Dialect Differences
   * Only available in the -lang fblite and -lang qb dialects.

Differences from QB
   * New to FreeBASIC

See also
   * #undef



---------------------------------------------------- KeyPgOptionprivate ----
Option Private

Specifies internal linkage by default for procedure declarations

Syntax
   Option Private

Description
   Option Private is a statement that gives any following procedure 
   declarations internal linkage by default, as if declared with Private. 
   This default remains in effect for the rest of the module in which 
   Option Private is used, and can be overridden by declaring procedures 
   with Public.

Example
   '' Compile with the "-lang fblite" compiler switch

   #lang "fblite"

   Sub ProcWithExternalLinkage()
      ' ...
   End Sub

   Option Private

   Sub ProcWithInternalLinkage()
      ' ...
   End Sub

   Public Sub AnotherProcWithExternalLinkage()
      ' ...
   End Sub

Dialect Differences
   * Only available in the -lang fblite and -lang qb dialects.

Differences from QB
   * New to FreeBASIC

See also
   * __FB_OPTION_PRIVATE__
   * Private
   * Public



----------------------------------------------------- KeyPgOptionstatic ----
Option Static

Reverts to default array declaration behavior

Syntax
   Option Static

Description
   Option Static is a statement that overrides the behavior of 
   Option Dynamic, that is, arrays declared with constant subscript ranges 
   are fixed-length. This remains in effect for the rest of the module in 
   which Option Static is used, and can be overridden with Option Dynamic.  
   It is equivalent to the '$Static metacommand.

Example
   '' Compile with the "-lang fblite" compiler switch

   #lang "fblite"

   Option Dynamic

   Dim foo(100) As Integer         ' declares a variable-length array

   Option Static

   Dim bar(100) As Integer         ' declares a fixed-length array

Dialect Differences 
   * Only available in the -lang fblite and -lang qb dialects.

Differences from QB
   * New to FreeBASIC

See also
   * '$Dynamic
   * '$Static
   * Dim
   * Erase
   * ReDim
   * Option Dynamic
   * Static



------------------------------------------------------------- KeyPgOpOr ----
Operator Or (Inclusive Disjunction)

Returns the bitwise-or (inclusive disjunction) of two numeric values

Syntax
   Declare Operator Or ( ByRef lhs As T1, ByRef rhs As T2 ) As Ret

Usage
   result = lhs Or rhs

Parameters
   lhs
      The left-hand side expression.
   T1
      Any numeric or boolean type.
   rhs
      The right-hand side expression.
   T2
      Any numeric or boolean type.
   Ret
      A numeric or boolean type (varies with T1 and T2).

Return Value
   Returns the bitwise-disjunction of the two operands.

Description
   This operator returns the bitwise-disjunction of its operands, a logical 
   operation that results in a value with bits set depending on the bits of 
   the operands (for conversion of a boolean to an integer, false or true 
   boolean value becomes 0 or -1 integer value).

   The truth table below demonstrates all combinations of a 
   boolean-disjunction operation:

      +-------+-------+------+
      |Lhs Bit|Rhs Bit|Result|
      |0      |0      |0     |
      |1      |0      |1     |
      |0      |1      |1     |
      |1      |1      |1     |
      +-------+-------+------+

   No short-circuiting is performed - both expressions are always 
   evaluated.

   The return type depends on the types of values passed. Byte, UByte and 
   floating-point type values are first converted to Integer. If the left 
   and right-hand side types differ only in signedness, then the return 
   type is the same as the left-hand side type (T1), otherwise, the larger 
   of the two types is returned. Only if the left and right-hand side types 
   are both Boolean, the return type is also Boolean.

   This operator can be overloaded for user-defined types.

Example
   ' Using the OR operator on two numeric values
   Dim As UByte numeric_value1, numeric_value2
   numeric_value1 = 15 '00001111
   numeric_value2 = 30 '00011110

   'Result =  31  =     00011111       
   Print numeric_value1 Or numeric_value2
   Sleep

   ' Using the OR operator on two conditional expressions
   Dim As UByte numeric_value
   numeric_value = 10

   If numeric_value = 5 Or numeric_value = 10 Then Print "Numeric_Value equals 5 or 10"
   Sleep

   ' This will output "Numeric_Value equals 5 or 10" because
   ' while the first condition of the first IF statement is false, the second is true

Dialect Differences
   * In the -lang qb dialect, this operator cannot be overloaded.

Differences from QB
   * None

See also
   * OrElse
   * Operator Truth Tables



------------------------------------------------------------ KeyPgOrGfx ----
Or (Graphics Put)

Parameter to the Put graphics statement which uses a bit-wise Or as the 
blitting method

Syntax
   Put [ target, ] [ STEP ] ( x,y ), source [ ,( x1,y1 )-( x2,y2 ) ], Or

Parameters
   Or
      Required.

Description
   The Or method combines each source pixel with the corresponding 
   destination pixel, using the bit-wise Or function.  The result of this 
   is output as the destination pixel.
   This method works in all graphics modes.  There is no mask color, 
   although color values of 0 (RGBA(0, 0, 0, 0) in full-color modes) will 
   have no effect, because of the behavior of Or.

   In full-color modes, each component (red, green, blue and alpha) is kept 
   in a discrete set of bits, so the operation can be made to only affect 
   some of the channels, by making sure the all the values of the other 
   channels are set to 0.

Example
   ''open a graphics window
   ScreenRes 320, 200, 16

   ''create 3 sprites containing red, green and blue circles
   Const As Long r = 32
   Dim As Any Ptr cr, cg, cb
   cr = ImageCreate(r * 2 + 1, r * 2 + 1, RGBA(0, 0, 0, 0))
   cg = ImageCreate(r * 2 + 1, r * 2 + 1, RGBA(0, 0, 0, 0))
   cb = ImageCreate(r * 2 + 1, r * 2 + 1, RGBA(0, 0, 0, 0))
   Circle cr, (r, r), r, RGB(255, 0, 0), , , 1, f
   Circle cg, (r, r), r, RGB(0, 255, 0), , , 1, f
   Circle cb, (r, r), r, RGB(0, 0, 255), , , 1, f

   ''put the sprite at three different multipier
   ''levels, overlapping each other in the middle
   Put (146 - r, 108 - r), cr, Or
   Put (174 - r, 108 - r), cg, Or
   Put (160 - r,  84 - r), cb, Or

   ''free the memory used by the sprites
   ImageDestroy cr
   ImageDestroy cg
   ImageDestroy cb

   ''pause the program before closing
   Sleep

Differences from QB
   * None

See also
   * Or
   * Put (Graphics)



--------------------------------------------------------- KeyPgOpOrElse ----
Operator Orelse (Short Circuit Inclusive Disjunction)

Returns the short circuit-or (Inclusive Disjunction) of two numeric values

Syntax
   Declare Operator OrElse ( ByRef lhs As T1, ByRef rhs As T2 ) As Ret

Usage
   result = lhs OrElse rhs

Parameters
   lhs
      The left-hand side expression.
   T1
      Any numeric or boolean type.
   rhs
      The right-hand side expression.
   T2
      Any numeric or boolean type.
   Ret
      A numeric or boolean type (varies with T1 and T2).

Return Value
   Returns the short circuit-or (inclusive disjunction) of the two 
   operands.

Description
   This operator evaluates the left hand side expression.  If the result is 
   nonzero, then -1 (true) is immediately returned.  If the result is zero 
   then the right hand side is evaluated, and the logical result from that 
   is returned, returning -1 (true) for a nonzero value or 0 (false) for 
   zero.
   (for conversion of a boolean to an integer, false or true boolean value 
   becomes 0 or -1 integer value)

   The truth table below demonstrates all combinations of a short 
   circuit-or operation, the '-' denotes that the operand is not evaluated.

      +---------+---------------+------+
      |Lhs Value|Rhs Value      |Result|
      |0        |0              |0     |
      |0        |nonzero        |-1    |
      |nonzero  |(not evaluated)|-1    |
      +---------+---------------+------+

   OrElse equivalent to:
   Iif( Lhs = 0, Rhs <> 0 , -1 )

   Short-circuiting is performed - only expressions needed to calculate the 
   result are evaluated.  The left hand side lhs is evaluated first, and 
   only if it evaluates to zero (false) is the right hand side rhs also 
   evaluated. If the left hand side evaluation lhs returns non-zero (true), 
   it is known that at that point that the overall condition is true, so 
   the right hand side rhs is not evaluated (skipped).

   The return type is almost always an Integer, of the value 0 or -1, 
   denoting false and true respectively. Except if the left and right-hand 
   side types are both Boolean, then the return type is also Boolean.

   This operator cannot be overloaded for user-defined types.

Example
   '' Using the ORELSE operator to test
   '' if a value is out of range

   Dim As Integer n
   Input "Enter a number between 1 and 10: ", n

   Function test(ByVal n As Integer) As Integer
      Print "expression evaluated"
      Return n
   End Function

   '' print value only if n is in range [1, 10]
   If test(n) < 1 OrElse test(n) > 10 Then  '' if n < 1, second expression is not evaluated
      Print "   => out of range"
   Else
      Print "   => n ="; n
   End If
   Sleep

Differences from QB
   * This operator was not available in QB.

See also
   * AndAlso
   * Or
   * Operator Truth Tables



-------------------------------------------------------------- KeyPgOut ----
Out

Outputs a value to a hardware port.

Syntax
   Declare Function Out ( ByVal port As UShort , ByVal data As UByte ) As 
   Long

Usage
   Out port,value

Parameters
   port
      Hardware port to write to.
   data
      Data value to write.

Description
   This function sends value to port and returns immediately.

Example
   'speakersound.bas 
   Sub Sound(ByVal freq As UInteger, dur As UInteger)
     Dim t As Double,f1 As Unsigned Short
      f1 = 1193181 \ freq
      Out &h61,Inp(&h61) Or 3
      Out &h43,&hb6
      Out &h42,LoByte(f1)
      Out &h42,HiByte(f1)
      t=Timer 
      While ((Timer - t) * 1000) < dur
        Sleep 0,1
      Wend
      Out &h61,Inp(&h61) And &hfc
   End Sub

   Sound(523, 60)  'C5
   Sound(587, 60)  'D5
   Sound(659, 60)  'E5
   Sound(698, 60)  'F5
   Sound(784, 60)  'G5
   Sound(880, 60)  'A5
   Sound(988, 60)  'B5
   Sound(1046, 60) 'C6 

	

Platform Differences
   * In the Windows and Linux versions three port numbers (&H3C7, &H3C8, 
     &H3C9) are hooked by the graphics library when a graphics mode is in 
     use to emulate QB's VGA palette handling. This use  is deprecated; use 
     Palette to retrieve and set palette colors.

   * Using true port access in the Windows version requires the program to 
     install a device driver for the present session. For that reason, 
     Windows executables using hardware port access should be run with 
     administrator permits each time the computer is restarted. Further 
     runs don't require admin rights as they just use the already installed 
     driver. The driver is only 3K in size and is embedded in the 
     executable.

See also
   * Inp
   * Wait
   * Palette

   


----------------------------------------------------------- KeyPgOutput ----
Output

Specifies text file to be opened for output mode

Syntax
   Open filename for Output [Encoding encoding_type] [Lock lock_type] as 
   [#]filenum 

Parameters
   filename
      file name to open for output
   encoding_type
      indicates encoding type for the file
   lock_type
      locking to be used while the file is open
   filenum
      unused file number to associate with the open file

Description
   A file mode used with Open to open a text file for writing.

   This mode is used to write text with Print #, or comma separated values 
   with Write #. 

   Text files can't be simultaneously read and written in FreeBASIC, so if 
   both functions are required on the same file, it must be opened twice.

   filename must be a string expression resulting in a legal file name in 
   the target OS, without wildcards. The file will be sought for in the 
   present directory, unless the filename contains a path . If the file 
   does not exist, it is created. The pointer is set at the first character 
   of the file.

   Encoding_type indicates the Unicode Encoding of the file, so characters 
   are correctly read. If omitted, "ascii" encoding is defaulted. Only 
   little endian character encodings are supported at the moment. 
      *"utf8"
      *"utf16"
      *"utf32" 
      *"ascii" (the default)

   Lock_type indicates the way the file is locked  for other processes, it 
   is one of:
      * Read - the file can be opened simultaneously by other processes, 
        but not for reading
      * Write - the file can be opened simultaneously by other processes, 
        but not for writing
      * Read Write - the file cannot be opened simultaneously by other 
        processes (the default)

   filenum Is a valid FreeBASIC file number (in the range 1..255) not being 
   used for any other file presently open. The file number identifies the 
   file for the rest of file operations. A free file number can be found 
   using the FreeFile function.

Example
   Dim ff As UByte
   Dim randomvar As Integer
   Dim name_str As String
   Dim age_ubyte As UByte

   ff = FreeFile
   Input "What is your name? ",name_str
   Input "What is your age? ",age_ubyte
   Open "testfile" For Output As #ff
   Write #ff, Int(Rnd(0)*42),name_str,age_ubyte
   Close #ff
   randomvar=0
   name_str=""
   age_ubyte=0

   Open "testfile" For Input As #ff
   Input #ff, randomvar,name_str,age_ubyte
   Close #ff

   Print "Random Number was: ", randomvar
   Print "Your name is: " + name_str
   Print "Your age is: " + Str(age_ubyte)

   'File outputted by this sample will look like this,
   'minus the comment of course:
   '23,"Your Name",19 

Differences from QB

See also
   * Append
   * Input (File Mode)
   * Open



--------------------------------------------------------- KeyPgOverload ----
Overload

Specifies that a procedure name can be overloaded

Syntax
   Declare [Static] Sub procedure_name [cdecl|stdcall|pascal] Overload [
   Alias "external_name"] [([parameter_list])] [Constructor [priority]] [
   Static] [Export]

   Declare [Static] Function procedure_name [cdecl|stdcall|pascal] Overload 
   [Alias "external_name"] [([parameter_list])] [ ByRef ] As return_type [
   Static] [Export]

   [Public|Private] Sub procedure_name [cdecl|stdcall|pascal] Overload [
   Alias "external_name"] [([parameter_list])] [Constructor [priority]] [
   Static] [Export]
      ..procedure body..
   End Sub

   [Public|Private] Function procedure_name [cdecl|stdcall|pascal] Overload 
   [Alias "external_name"] [([parameter_list])] [ ByRef ] As return_type  [
   Static] [Export]
      ..procedure body..
   End Function

Description
   In procedure declarations, Overload allows procedure names to be 
   overloaded, that is, other procedures (regardless of whether to be subs 
   or functions) can then be declared with the same name if their parameter 
   lists are unique. Two parameter lists are unique if they contain a 
   different number of parameters, or have parameters of different types. 
   Note that this means that two or more procedures cannot be declared with 
   the same name if they differ in return type alone.
   A variadic procedure name can never be overloaded.

   Once a procedure name has been declared overloaded, further declarations 
   using the name need not specify Overload, but it is allowed.

   Overload is not necessary in member procedure declarations, as they are 
   always implicitly overloaded.

   When calling an overloaded procedure name, a match score is calculated 
   comparing the call argument types with the parameter types for each 
   candidate procedure (major resolution on datatypes themselves, minor 
   resolution on datatype sizes).
   The highest matching score wins. If this highest score is too low, or if 
   several overloaded procedures have the same highest score, the compiler 
   then generates an error at compile time (no matching procedure, or 
   ambiguous call).

Example
   Declare Function SUM Overload (A As Integer,B As Integer) As Integer
   Declare Function SUM Overload (A As Single,B As Single) As Single
   Function SUM  (A As Integer,B As Integer) As Integer
      Function=A+B
   End Function   
   Function SUM  (A As Single,B As Single) As Single
      Function=A+B
   End Function   
   Dim As Integer A,B
   Dim As Single A1,B1
   A=2
   B=3
   A1=2.
   b1=3.
   Print SUM(A,B)
   Print SUM (A1,B1)
   Sleep

Differences from QB
   * New to FreeBASIC

See also
   * Declare
   * Sub, Function



--------------------------------------------------------- KeyPgOverride ----
Override

Method attribute; specifies that a method must override a virtual

Syntax
   Type typename Extends basename
      ...
      Declare Sub|Function|Operator|Property|Destructor ... ( [
      parameterlist] ) [[ ByRef ] As datatype] Override
      ...
   End Type

Description
   In method declarations, Override can be used to indicate that this 
   method is expected to override a Virtual or Abstract method from the 
   base class. Then the compiler will show an error if the method does not 
   override anything (only a non-static method can override a virtual or 
   abstract method).

   Use of Override is not mandatory to override a virtual or abstract 
   method, it is highly recommended, as it will help prevent inadvertent 
   errors (name/signature not matching).

   Override can only be specified on the method declaration in the UDT 
   block, but not on the method body, because it is just a compile-time 
   check in the context of the inheritance hierarchy, and does not affect 
   the method in any way.

   Override is only recognized as a keyword at the end of member procedure 
   declarations. It can still be used as identifier elsewhere.

Example
   Type A Extends Object
      Declare Virtual Sub f1( )
      Declare Virtual Function f2( ) As Integer
   End Type

   Type B Extends A
      Declare Sub f1( ) Override
      Declare Function f2( ) As Integer Override
   End Type

   Sub A.f1( )
   End Sub

   Function A.f2( ) As Integer
      Function = 0
   End Function

   Sub B.f1( )
   End Sub

   Function B.f2( ) As Integer
      Function = 0
   End Function

Differences from QB
   * New to FreeBASIC

See also
   * Virtual, Abstract




============================================================================
    P

------------------------------------------------------------ KeyPgPaint ----
Paint

Fills an area delimited by a border of a specified color

Syntax
   Paint [target,] [STEP] (x, y)[, [paint][, [border_color]]]

Parameters
   target
      specifies buffer to draw on.  
   STEP
      indicates that coordinates are relative
   (x, y)
      coordinates of the pixel on which to start the flood fill (paint)
   paint
      the color attribute or fill pattern
      a numeric value indicates a color, while a string indicates a fill 
      pattern
   border_color
      boundary color for the fill

Description
   Graphics command to fill an area delimited by a border of specified 
   color. Also known as 'flood-fill' or 'paint bucket'.

   Paint can operate on the current work page as set by the ScreenSet 
   statement or on the target Get/Put buffer, if specified.

   Filling starts at specified (x,y) coordinates; if STEP is specified, 
   these are relative to the last graphics cursor position. Coordinates are 
   also affected by custom coordinates system set up by Window and/or 
   View (Graphics) statements; clipping set by View also applies.

   If the paint argument is a number, it is assumed a color in the same 
   format used by the Color statement, and the region is flood-filled using 
   that color. If paint is a String, the region will be filled using a 
   pattern; the pattern is always 8*8 pixels, and the passed string must 
   hold pixels data in a format dependent on the current color depth. The 
   string holds pattern pixels row by row, and its size should be as 
   follows:

   For color depths 1, 2, 4 and 8:
   size = 8 * 8 = 64
   For color depths 15 and 16:
   size = (8 * 8) * 2 = 128
   For color depths 24 and 32:
   size = (8 * 8) * 4 = 256

   If the passed string is smaller, missing pixels will be 0. If the paint 
   argument is omitted, normal filling is performed using the current 
   foreground color set by Color. Flood-filling continues until pixels of 
   the specified border color are found; if border_color is omitted, the 
   current background color is assumed.

   Warning: If the border is drawn with a transparent color (in conjunction 
   with the GFX_ALPHA_PRIMITIVES option flag) and some pixels are overdrawn 
   on it, the resultant (blended) color of these overdrawn pixels can cause 
   a leak point through which the fill color escapes outside the border. So 
   drawing a border with a transparent color is not recommended.

Example
   ' draws a white circle painted blue inside
   Screen 13
   Circle (160, 100), 30, 15
   Paint (160, 100), 1, 15
   Sleep

   ' draws a circle and fills it with a checkered pattern

   '' choose the bit depth for the Screen
   '' try setting this to other values: 8, 16 or 32

   Const bit_depth = 8

   '' function for returning a pixel color, represented as a string
   '' returns a the string in the appropriate format for the current bit depth
   Function paint_pixel( ByVal c As ULong, ByVal bit_depth_ As Integer ) As String
      
      If bit_depth_ <= 8 Then '' 8-bit:
         Function =  Chr( CUByte(c) )
         
      ElseIf bit_depth_ <= 16 Then '' 16-bit:
         Function = MKShort( c Shr 3 And &h1f Or _
                        c Shr 5 And &h7e0 Or _
                        c Shr 8 And &hf800 )
         
      ElseIf bit_depth_ <= 32 Then '' 32-bit:
         Function = MKL(c)
         
      End If
      
   End Function

   '' open a graphics window at the chosen bit depth
   ScreenRes 320, 200, bit_depth

   '' declare variables for holding colors
   Dim As ULong c, c1, c2, cb

   '' declare string variable for holding the pattern used in Paint
   Dim As String paint_pattern = ""

   '' set colors
   If bit_depth <= 8 Then
      c1 = 7  ''pattern color 1
      c2 = 8  ''pattern color 2
      cb = 15 ''border color
   Else
      c1 = RGB(192, 192, 192) '' pattern color 1
      c2 = RGB(128, 128, 128) '' pattern color 2
      cb = RGB(255, 255, 255) '' border color
   End If

   '' make the pattern to be used in Paint
   For y As UInteger = 0 To 7
      For x As UInteger = 0 To 7
         
         '' choose the color of the pixel (c)
         If (x \ 4 + y \ 4) Mod 2 > 0 Then
            c = c1
         Else
            c = c2
         End If
         
         '' add the pixel to the pattern
         paint_pattern = paint_pattern + paint_pixel(c, bit_depth)
         
         '' the following line can be used if you want to draw the 
         '' pattern tile in the top left hand corner of the screen:
         
         ' pset (x, y), c
         
      Next x
   Next y

   '' draw a circle with the border color
   Circle (160, 100), 50, cb, , , 1.0

   '' paint the circle region with paint_pattern, stopping at the border color
   Paint (160, 100), paint_pattern, cb

   '' pause before ending the program
   Sleep

Differences from QB
   * target is new to FreeBASIC
   * In QB, the fill pattern was always 8-bits wide, and the height was 
     the length of the string (up to 64). In FreeBASIC, the fill pattern is 
     8 pixels wide, independent of the color depth, and the height is 
     always 8
   * The background color parameter supported by QB is not supported by 
     the FreeBASIC version

See also
   * Screen (Graphics)



---------------------------------------------------------- KeyPgPalette ----
Palette

Customizes colors in modes with paletted colors

Syntax
   Palette [Get] [index, color]
   Palette [Get] [index, r, g, b]
   Palette [Get] Using arrayname(idx)

Parameters
   Get
      indicates getting palette information rather than setting palette 
      information
   index
      palette index
   color
      color attribute
   r
      red color component
   g
      green color component
   b
      blue color component
   Using
      indicates using array of color values
   arrayname(idx)
      array and index to get/set color attributes

Description
   The Palette statement is used to retrieve or customize the current 
   palette for graphics modes with a color depth of up to 8bpp; using 
   Palette while in a mode with a higher color depth will have no effect. 
   Calling Palette with no argument restores the default palette for 
   current graphics mode, as set by the Screen (Graphics) statement.
   The GfxLib sets a default palette when a Screen mode is initialized.

   First form
      If you specify index and color, these are dependent on the current 
      mode:
         +-----------+-----------+-----------+
         |Screen mode|index range|color range|
         |1          |0-3        |0-15       |
         |2          |0-1        |0-15       |
         |7,8        |0-15       |0-15       |
         |9          |0-15       |0-63       |
         |11         |0-1        |see below  |
         |12         |0-15       |see below  |
         |13 to 21   |0-255      | see below |
         +-----------+-----------+-----------+

      In screen modes 1, 2, 7, 8 and 9 you can assign to each color index 
      one of the colors in the available range. In other screen modes, the 
      color must be specified in the form &hBBGGRR, where BB, GG and RR are 
      the blue, green and red components ranging &h0-&h3F in hexadecimal (0
      -63 in decimal). If you don't like hexadecimal form, you can use the 
      following formula to compute the integer value to pass to this 
      parameter:
      color = red Or (green Shl 8) Or (blue Shl 16)
      Where red, green and blue must range 0-63. Please note that color 
      values accepted by Palette are not the in the same form as returned 
      by the RGB macro (the red and blue fields are inverted, and the range 
      is different); this is for backward compatibility with QB.

   Second form
      In the second form, you specify the red, green and blue components 
      for a palette entry directly, by calling Palette with 4 parameters. 
      In this case r, g and b must be in the range 0-255.

   Third form
      Calling Palette Using allows to set a list of color values all at 
      once; you should pass an array holding enough elements as the color 
      indices available for your current graphics mode color depth (2 for 
      1bpp, 4 for 2bpp, 16 for 4bpp or 256 for 8bpp). The array elements 
      must be integer color values in the form described above. The colors 
      stored into arrayname starting with given idx index are then assigned 
      to each palette index, starting with index 0.

   Form 1 and 3 are for backward compatibility with QB; form 2 is meant to 
   ease palette handling. Any change to the palette is immediately visible 
   on screen.

   If the Get option is specified, Palette retrieves instead of setting 
   color values for the current palette. The parameters have the same 
   meaning as specified for the form being used, but in this case color, r, 
   g and b must be variables passed by reference that will hold the color 
   RGB values on function exit.

Example
   ' Setting a single color, form 1.
   Screen 15
   Locate 1,1: Color 15
   Print "Press any key to change my color!"
   Sleep
   ' Now change color 15 hues to bright red
   Palette 15, &h00003F
   Sleep

   ' Getting a single color, form 2.
   Dim As ULong r, g, b
   Screen 13
   Palette Get 32, r, g, b
   Print "Color 32 hues:"
   Print Using "Red:### Green:### Blue:###"; r; g; b
   Sleep

   ' Getting whole palette, form 3.
   Dim pal(0 To 255) As ULong
   Screen 13
   Palette Get Using pal
   For i As Integer = 0 To 15
      Print Using "Color ## = &"; i; Hex(pal(i), 6)
   Next i
   Sleep

Differences from QB
   * QBasic did not support PALETTE GET to retrieve a palette.
   * QBasic did not allow passing individual red/green/blue values.

See also
   * Screen (Graphics)
   * Color
   * Using
   * Internal Pixel Formats
   * Default Palettes



----------------------------------------------------- KeyPgSfxGenerated ----
Generated Sound Commands

Commands for generated sound, PLAY strings, and sfxlib mix settings.

Syntax
   Beep [ duration, pitch ]
   Sound frequency, duration
   Sound channel, frequency, duration, volume
   Tone channel, frequency, duration
   Noise channel, duration, volume
   Noise channel, frequency, duration, volume
   Note name, octave, duration
   Note channel, name, octave, duration
   Play music
   Play channel, music
   Play music1, music2
   Play music1, music2, music3
   Tempo bpm
   bpm = Tempo()
   Channel channel
   channel = Channel()
   Octave octave
   octave = Octave()
   Voice instrument
   instrument = Voice()
   Vol level
   Volume level
   level = Volume()
   Volume channel, level
   level = Volume( channel )
   Balance position
   position = Balance()
   Pan channel, position
   position = Pan( channel )
   Wave id, waveform
   Envelope id, attack, decay, sustain, release
   Instrument id, wave_id, envelope_id
   Instrument channel, instrument_id

Description
   These commands synthesize sound directly through sfxlib.  Sound, Tone, 
   Noise, Note, and Play create voices.  Tempo, Channel, Octave, and Voice 
   set defaults used by PLAY-string and generated-sound commands.  Volume, 
   Vol, Balance, and Pan control mix levels and stereo placement.

   Sound accepts the high-impact classic form Sound frequency, duration and
   the explicit channel form Sound channel, frequency, duration, volume.
   When both arguments are integers, duration is interpreted as the PC BASIC
   timer-tick value.

   Wave defines a waveform id.  The currently supported waveform values 
   are:
      * 0 sine
      * 1 square
      * 2 triangle
      * 3 saw
      * 4 noise

   Envelope defines an ADSR envelope using seconds for attack, decay, and 
   release, and a 0.0 to 1.0 sustain level.  Instrument can define an 
   instrument from a waveform and envelope, or assign an instrument to a 
   channel.

   The channel-oriented commands use sfxlib's channel table.  Channels are 
   zero-based.

Example
   See examples/sfxlib/basics-01-generated-sound.bas, 
   examples/sfxlib/basics-02-play-strings.bas, 
   examples/sfxlib/basics-03-channels-mix.bas, 
   examples/sfxlib/basics-04-instruments.bas, and 
   examples/sfxlib/showcase.bas.

Platform Differences
   * On headless or diagnostic runs, SFXLIB_DRIVER=null can be set before 
     program startup to use the null output driver.

Differences from QB
   * New to FreeBASIC.

See also
   * Beep
   * Music
   * Sfx
   * Sound Library Reference



----------------------------------------------------------- KeyPgPascal ----
pascal

Specifies a Pascal-style calling convention in a procedure declaration

Syntax
   Sub name pascal [Overload] [Alias "alias"] ( parameters )
   Function name pascal [Overload] [Alias "alias"] ( parameters ) [ ByRef ] 
   As return_type

Description
   In procedure declarations, pascal specifies that a procedure will use 
   the pascal calling convention. In the Pascal calling convention, any 
   parameters are to be passed (pushed onto the stack) in the same order in 
   which they are listed, that is, from left to right. The procedures need 
   not preserve the EAX, ECX or EDX registers, and must clean up the stack 
   (pop any parameters) before it returns.

   pascal is not allowed to be used with variadic procedure declarations 
   (those with the last parameter listed as "...").

   pascal is the default calling convention for procedures in Microsoft 
   QuickBASIC, and is the standard convention used in the Windows 3.1 API.

   If a procedure definition has a declaration (with calling convention 
   explicit or by default) and the definition does not explicitly specify a 
   calling convention, then the calling convention is implied by the 
   declaration.

Example
   Declare Function MyFunc pascal Alias "MyFunc" (MyParm As Integer) As Integer

Differences from QB
   * New to FreeBASIC

See also
   * cdecl, stdcall
   * Declare
   * Sub, Function



------------------------------------------------------------ KeyPgPcopy ----
PCopy

Copies one graphical or text page onto another

Syntax
   Declare Function PCopy ( ByVal source As Long = -1, ByVal destination As 
   Long = -1 ) As Long

Usage
   PCopy [ source ] [, destination ]

Parameters
   source
      page to copy from
   destination
      page to copy to

Return Value
   Returns zero (0) if successful, or a non-zero error code to indicate a 
   failure.

Description
   Copies one graphical or text video page to another. Useful for drawing 
   all graphics on one invisible page and copying it to the active visible 
   page - creating smooth graphics and animation. Known as 'double 
   buffering' or 'page flipping'.

   source and destination refer to page numbers. The 'source' page is 
   copied over the 'destination' page when pcopy is called.

   If the source argument is omitted, the current working page is assumed.  
   If the destination page is omitted, the current visible page is assumed.

   PCopy is inactive if the destination page is locked.

   The error code returned by PCopy can be checked using Err in the next 
   line. The function version of  PCopy returns directly the error code as 
   a 32 bit Long.

Example

   'Sets up the screen to be 320x200 in 8-bit color with 2 video pages.
   ScreenRes 320, 200, 8, 2

   'Sets the working page to 1 and the displayed page to 0
   ScreenSet 1, 0

   'Draws a circle moving across the top of the screen
   For x As Integer = 50 To 269
      Cls                    'Clears the screen so we can start fresh
      Circle (x, 50), 50, 14 'Draws a yellow circle with a 50 pixel radius on page 1
      PCopy 1, 0             'Copies our image from page 1 to page 0
      Sleep 25               'Waits for 25 milliseconds.
   Next x

   'Wait for a keypress before the screen closes
   Sleep

   '' Compile with -lang fblite or qb

   #lang "fblite"

   '' Console mode example:

   '' Set the working page number to 0, and the visible page number to 1
   #if __FB_LANG__ = "QB"
   Screen ,, 0, 1
   #else
   Screen , 0, 1
   #endif

   Dim As Integer i, frames, fps
   Dim As Double t

   t = Timer

   Do
      '' Fill working page with a certain color and character
      Cls
      Locate 1, 1
      Color (i And 15), 0
      Print String$(80 * 25, Hex$(i, 1));
      i += 1

      '' Show frames per second
      Color 15, 0
      Locate 1, 1
      Print "fps: " & fps,
      If Int(t) <> Int(Timer) Then
         t = Timer
         fps = frames
         frames = 0
      End If
      frames += 1

      '' Copy working page to visible page
      PCopy

      '' Sleep 50ms per frame to free up cpu time
      Sleep 50, 1

      '' Run loop until the user presses a key
   Loop Until Len(Inkey$)

Platform Differences
   * Maximum number of text pages in Windows is 4.
   * Maximum number of text pages in DOS is 8.
   * Maximum number of text pages in all other targets is 1.
   * Maximum number of graphics pages depends on what was specified when 
     the Screen (Graphics) or ScreenRes statement was called.

Differences from QB
   * None

See also
   * ScreenCopy
   * Flip
   * Screen (Graphics)



------------------------------------------------------------- KeyPgPeek ----
Peek

Gets the value of an arbitrary type at an address in memory

Syntax
   Declare Function Peek ( ByVal address As Any Ptr ) ByRef As UByte
   Declare Function Peek ( datatype, ByVal address As Any Ptr ) ByRef As 
   datatype

Usage
   Peek( [ datatype, ] address )

Parameters
   address
      The address in memory to get the value from.
   datatype
      The type of value to get. If omitted, UByte is assumed.

Description
   This procedure returns a reference to the value in memory given by a 
   memory address, and is equivalent to:
      *cast(ubyte ptr, address)
         or
      *cast(datatype ptr, address)
   thus this keyword can also be used to assign a value to a memory 
   location, similarly to Poke.

   Note: When using Peek, the -exx compiler option does not add code for 
   null-pointer checking (no nullity test on the value of address).

Example
   Dim i As Integer, p As Integer Ptr
   p = @i

   Poke Integer, p, 420
   Print Peek(Integer, p)

   will produce the output:

   420

Differences from QB
   * Peek did not support the datatype parameter in QB, and could only 
     return individual bytes.
   * Peek returns a reference in FB, so can be used to set the memory 
     contents of the address, like with Operator * (Value Of).
   * DEF SEG isn't needed anymore because the address space is 32-bit flat 
     in FreeBASIC.

See also
   * Poke
   * Operator * (Value Of)


----------------------------------------------------- KeyPgSfxGenerated ----
Generated Sound Commands

Commands for generated sound, PLAY strings, and sfxlib mix settings.

Syntax
   Beep [ duration, pitch ]
   Sound frequency, duration
   Sound channel, frequency, duration, volume
   Tone channel, frequency, duration
   Noise channel, duration, volume
   Noise channel, frequency, duration, volume
   Note name, octave, duration
   Note channel, name, octave, duration
   Play music
   Play channel, music
   Play music1, music2
   Play music1, music2, music3
   Tempo bpm
   bpm = Tempo()
   Channel channel
   channel = Channel()
   Octave octave
   octave = Octave()
   Voice instrument
   instrument = Voice()
   Vol level
   Volume level
   level = Volume()
   Volume channel, level
   level = Volume( channel )
   Balance position
   position = Balance()
   Pan channel, position
   position = Pan( channel )
   Wave id, waveform
   Envelope id, attack, decay, sustain, release
   Instrument id, wave_id, envelope_id
   Instrument channel, instrument_id

Description
   These commands synthesize sound directly through sfxlib.  Sound, Tone, 
   Noise, Note, and Play create voices.  Tempo, Channel, Octave, and Voice 
   set defaults used by PLAY-string and generated-sound commands.  Volume, 
   Vol, Balance, and Pan control mix levels and stereo placement.

   Sound accepts the high-impact classic form Sound frequency, duration and
   the explicit channel form Sound channel, frequency, duration, volume.
   When both arguments are integers, duration is interpreted as the PC BASIC
   timer-tick value.

   Wave defines a waveform id.  The currently supported waveform values 
   are:
      * 0 sine
      * 1 square
      * 2 triangle
      * 3 saw
      * 4 noise

   Envelope defines an ADSR envelope using seconds for attack, decay, and 
   release, and a 0.0 to 1.0 sustain level.  Instrument can define an 
   instrument from a waveform and envelope, or assign an instrument to a 
   channel.

   The channel-oriented commands use sfxlib's channel table.  Channels are 
   zero-based.

Example
   See examples/sfxlib/basics-01-generated-sound.bas, 
   examples/sfxlib/basics-02-play-strings.bas, 
   examples/sfxlib/basics-03-channels-mix.bas, 
   examples/sfxlib/basics-04-instruments.bas, and 
   examples/sfxlib/showcase.bas.

Platform Differences
   * On headless or diagnostic runs, SFXLIB_DRIVER=null can be set before 
     program startup to use the null output driver.

Differences from QB
   * New to FreeBASIC.

See also
   * Beep
   * Music
   * Sfx
   * Sound Library Reference



------------------------------------------------------------- KeyPgPmap ----
PMap

Maps coordinates between view and physical mapping.

Syntax
   Declare Function PMap ( ByVal coord As Single, ByVal func As Long ) As 
   Single

Usage
   result = PMap( coord, func )

Parameters
   coord
      An expression indicating the coordinate to be mapped.
   func
      The mapping function number to be applied to given coordinate.

Return Value
   The mapped coordinate value.

Description
   This function converts a coordinate between view (as defined by the 
   Window statement) and physical (as set by the View (Graphics) statement) 
   mappings. Depending on the value of func, expr is used to compute a 
   different mapping to be returned by PMap:

         +-----------+---------------------------------------------------------------------------------+
         |func value:|return value:                                                                    |
         |0          |Treats expr as x view coordinate and returns corresponding x physical coordinate.|
         |1          |Treats expr as y view coordinate and returns corresponding y physical coordinate.|
         |2          |Treats expr as x physical coordinate and returns corresponding x view coordinate.|
         |3          |Treats expr as y physical coordinate and returns corresponding y view coordinate.|
         +-----------+---------------------------------------------------------------------------------+

Example
   ScreenRes 640, 480
   Window Screen (0, 0)-(100, 100)
   Print "Logical x=50, Physical x="; PMap(50, 0)   '' 320
   Print "Logical y=50, Physical y="; PMap(50, 1)   '' 240
   Print "Physical x=160, Logical x="; PMap(160, 2) '' 25
   Print "Physical y=60, Logical y="; PMap(60, 3)   '' 12.5
   Sleep

Differences from QB
   * None

See also
   * Window
   * View (Graphics)



------------------------------------------------------------ KeyPgPoint ----
Point

Returns the color attribute of a specified pixel coordinate

Syntax
   result = Point( coord_x, coord_y [,buffer] )
   or
   result = Point( function_index )

Usage
   coord_x
      x coordinate of the pixel
   coord_y
      y coordinate of the pixel
   buffer
      the image buffer to read from
   function_index
      the type of screen coordinate to return: one of the values 0, 1, 2, 3

Return Value
   The return datatype is a ULong.

   If the x, y coordinates of a pixel are provided Point returns the color 
   attribute at the specified coordinates, as an 8-bit palette index in 8 
   bpp indexed modes, a 24-bit RGB value in 16 bpp modes (upper 8 bits 
   unused, limited precision of R,G,B), and a 32-bit RGB or RGBA value in 
   32 bpp modes (upper 8 bits unused or holding Alpha). Note that it does 
   NOT return a 16-bit value (5 bits R + 6 bits G + 5 bits B).

   If the argument is a function index, Point returns one of the graphics 
   cursor coordinates set by the last graphics command.

      +--------+------------------------------------------------------------------------------------------------------------------------------+
      |Argument| Value Returned                                                                                                               |
      | 0      |The current physical x coordinate.                                                                                            |
      |1       |The current physical y coordinate.                                                                                            |
      | 2      |The current view x coordinate. This returns the same value as the POINT(0) function if the WINDOW statement has not been used.|
      |3       |The current view y coordinate. This returns the same value as the POINT(1) function if the WINDOW statement has not been used.|
      +--------+------------------------------------------------------------------------------------------------------------------------------+

Description
   GfxLib Function with two different uses.
   If supplied with two coordinates it reads the color of the pixel at the 
   coordinate coord_x, coord_y of the screen, or of the buffer, if 
   supplied.
   The value return is a color index in a 256 or less color 
   Screen (Graphics), and an RGB value in true color modes. If the 
   coordinates are off-screen or off-buffer, -1 is returned

   If supplied with a single value it returns the one of the coordinates of 
   the graphics cursor as set by the last graphics command executed. If the 
   last command was executed in a buffer, the values returned will be 
   coordinates in the buffer. Arguments out of the range 0-3 will return 0.

   The function Point does not work in text modes.

   Speed note: while Point provides valid results, it is quite slow to call 
   repeatedly due to the overhead of additional calculations and checks. 
   Much better performance can be achieved by using direct memory access 
   using the results obtained from ImageInfo and ScreenInfo/ScreenPtr.

Example
   ' Set an appropriate screen mode - 320 x 240 x 8bpp indexed color
   ScreenRes 320, 240, 8

   ' Draw a line using color 12 (light red)
   Line (20,20)-(100,100), 12

   ' Print the color of a point on the line
   Print Point(20,20)

   ' Sleep before the program closes
   Sleep
      

   Output:

   12
   		

Version
   Before fbc 1.08.0, the return datatype was an Integer.

Differences from QB
   * buffer is new to FreeBASIC
   * In 16 bpp and 32 bpp modes, a 32-bit value is returned instead of an 
     8-bit palette index

See also
   * PSet - write pixels
   * PMap
   * Color
   * View (Graphics)
   * Window
   * Internal pixel formats



------------------------------------------------------- KeyPgPointCoord ----
PointCoord

Queries Draw's pen position in graphics mode

Syntax
   Declare Function PointCoord( ByVal func As Long ) As Single

Usage
   result = PointCoord( func )

Description
   The PointCoord function can be used to query x and y position of the Draw
   pen in graphics mode. The result value depends on the passed func value:

      +-----------+---------------------------------------------------------+
      |func value:|return value:                                            |
      |0          |x physical coordinate, same as PMap( PointCoord( 2 ), 0 )|
      |1          |y physical coordinate, same as PMap( PointCoord( 3 ), 1 )|
      |2          |x view coordinate                                        |
      |3          |y view coordinate                                        |
      +-----------+---------------------------------------------------------+

Example
   Screen 12

   Print "--- Default window coordinate mapping ---"
   Print "DRAW pen position, at the default (0,0):"
   Print "Physical:", PointCoord( 0 ), PointCoord( 1 )
   Print "View:", PointCoord( 2 ), PointCoord( 3 )

   Draw "BM 50,50"
   Print "DRAW pen position, after being moved to (50,50):"
   Print "Physical:", PointCoord( 0 ), PointCoord( 1 )
   Print "View:", PointCoord( 2 ), PointCoord( 3 )

   Print "--- Changing window coordinate mapping ---"
   Window Screen (-100, -100) - (100, 100)

   Draw "BM 0,0"
   Print "DRAW pen position, after being moved to (0,0):"
   Print "Physical:", PointCoord( 0 ), PointCoord( 1 )
   Print "View:", PointCoord( 2 ), PointCoord( 3 )

   Draw "BM 50,50"
   Print "DRAW pen position, after being moved to (50,50):"
   Print "Physical:", PointCoord( 0 ), PointCoord( 1 )
   Print "View:", PointCoord( 2 ), PointCoord( 3 )

   Sleep

Differences from QB
   * New to FreeBASIC

See also
   * PMap
   * Window



-------------------------------------------------------------- KeyPgPtr ----
(Pointer | Ptr)

A variable declaration type modifier

Syntax
   ... As DataType {Pointer | Ptr}

Description
   Declares a pointer variable.
   The variable type can be a predefined type or a user-defined type.

   Operator @ (Address Of) operator or VarPtr are used to take the address 
   of a variable. The Operator * (Value Of) operator is used to dereference 
   the pointer, that is, access the actual value stored in the memory 
   location the pointer is pointing at.

Example
   ' Create the pointer.
   Dim p As Integer Ptr

   ' Create an integer value that we will point to using pointer "p"
   Dim num As Integer = 98845

   ' Point p towards the memory address that variable "num" occupies.
   p = @num

   ' Print the value stored in memory pointed to by pointer "p"
   Print "Pointer 'p' ="; *p
   Print 

   ' Print the actual location in memory that pointer "p" points at.
   Print "Pointer 'p' points to memory location:"
   Print p

   Dim p As ZString Pointer
   Dim text As String
   text = "Hello World!"
   p = StrPtr(text) + 6
   Print text
   Print *p

   '' Output:
   '' Hello World!
   '' World!

   Type mytype
      a As Integer = 12345
   End Type

   Dim As mytype mt

   Dim As mytype Ptr pmt
   pmt = @mt

   Print (*pmt).a  '' or Print pmt->a

   '' Output:
   '' 12345

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Pointer or __Ptr.

Differences from QB
   * New to FreeBASIC

See also
   * Allocate



------------------------------------------------------------- KeyPgPoke ----
Poke

Assigns a value to a location in memory.

Syntax
   Declare Sub Poke ( ByVal address As Any Ptr, ByRef value As UByte )
   Declare Sub Poke ( datatype, ByVal address As Any Ptr, ByRef value As 
   datatype )

Usage
   Poke [ datatype, ] address, value

Parameters
   datatype
      The type of data at the specified address. If omitted, UByte is 
      assumed.
   address
      The location in memory to assign to.
   value
      The value to assign.

Description
   Poke assigns a value to a location in memory. It is equivalent to
      *cast(ubyte ptr, address) = value
         or
      *cast(datatype ptr, address) = value

   When datatype is a user-defined type, Poke assigns value using the 
   type's Operator Let.

   Note: When using Poke, the -exx compiler option does not add code for 
   null-pointer checking (no nullity test on the value of address).

Example
   Dim i As Integer, p As Integer Ptr
   p = @i

   Poke Integer, p, 420
   Print Peek(Integer, p)

   Will produce the output:

   420

Differences from QB
   * Only the byte form were supported in QB.
   * DEF SEG isn't needed anymore because the address space is 32-bit flat 
     in FreeBASIC.

See also
   * Peek



-------------------------------------------------------------- KeyPgPos ----
Pos

Returns the horizontal (left to right) position of the text cursor

Syntax
   Declare Function Pos ( ) As Long
   Declare Function Pos ( ByVal dummy As Long ) As Long

Usage
   result = Pos[ ( dummy ) ]

Parameters
   dummy
      An unused parameter retained for backward compatibility with QBASIC.

Return Value
   Returns the horizontal position of the text cursor.

Description
   Returns the horizontal (left to right) position of the text cursor. The 
   leftmost column is number 1.

Example
   Dim As Long p

   '' print starting column position
   p = Pos()
   Print "position: "; p

   '' print a string, without a new-line
   Print "ABCDEF";

   '' print new column position:
   p = Pos()
   Print: Print "position: "; p
   Print

   ''position changes after each Print:
   Print "Column numbers: "
   Print Pos(), Pos(), Pos(), Pos(), Pos()

Differences from QB
   * The dummy parameter was not optional in QBASIC.

See also
   * CsrLin
   * Tab
   * Locate



--------------------------------------------------------- KeyPgPreserve ----
Preserve

Used with ReDim to preserve contents will resizing an array

Syntax
   ReDim Preserve array(...) [As datatype]

Description
   Used with ReDim so that when an array is resized, data is not reset but 
   is preserved. This means when the array is enlarged that only new data 
   is reset, while the old data remains the same (but not necessarily at 
   the same absolute addresses in memory).

   NOTE: ReDim Preserve may not work as expected in all cases:
      Preserve's current behavior is to keep the original data contiguous 
      in memory, and only expand or truncate the size of the memory (if 
      resizing is not possible, the whole original data block is first 
      shifted to another memory location).
      Its behavior (with a single dimension) is well-defined only when the 
      upper bound is changed.  If the lower bound is changed, the current 
      result is that the data is in effect shifted to start at the new 
      lower bound.
      If there are multiple dimensions, only the upper bound of only the 
      first dimension may be changed safely.  If the first dimension is 
      reduced, the existing mappable data may be lost.  If lower-order 
      dimensions are resized at all, the effects can be hard to predict 
      (because multidimensional arrays are stored in row-major order : 
      values differing only in the last index are contiguous).

Example
   ReDim array(1 To 3) As Integer
   Dim i As Integer

   array(1) = 10
   array(2) = 5
   array(3) = 8

   ReDim Preserve array(1 To 10)

   For i = 1 To 10
      Print "array("; i; ") = "; array(i)
   Next

Differences from QB
   * Preserve wasn't supported until PDS 7.1

See also
   * Dim
   * LBound
   * ReDim
   * UBound



----------------------------------------------------------- KeyPgPreset ----
PReset

Plots a single pixel

Syntax
   PReset [target ,] [STEP] (x, y) [,color]

Parameters
   target
      specifies buffer to draw on.  
   STEP
      indicates that coordinates are relative
   (x, y)
      coordinates of the pixel.
   color
      the color attribute.

Description
   target specifies buffer to draw on.  target may be an image created with 
   ImageCreate or Get (Graphics).  If omitted, target defaults to the 
   screen's current work page.

   (x, y) are the coordinates of the pixel.  STEP if present, indicates 
   that (x, y) coordinates are relative to the graphics cursor position.  
   If omitted, (x, y) are relative to the upper left-hand corner of target. 
   The x and y coordinates are affected by the last call to the 
   View (Graphics) and Window statements, and respect the current clipping 
   region as set by the View (Graphics) statement.

   color specifies the color attribute.  If omitted, color defaults to the 
   current background color.  See Color.  color is graphics mode specific, 
   see Color and Screen (Graphics) for details.

Example
   Screen 13

   'Set background color to 15
   Color , 15

   'Draw a pixel with the background color at 10, 10
   PReset (10,10)

   'Draw a pixel with the background color at Last x cord +10, Last y cord +10
   PReset Step (10,10)
   Sleep

Differences from QB
   * target is new to FreeBASIC

See also
   * PSet



------------------------------------------------------------ KeyPgPrint ----
(Print | ?)

Writes text to the screen

Syntax
   (Print | ?) [ expressionlist ] [ , | ; ]

Parameters
   expressionlist
      list of items to print

Description
   Print outputs a list of values to the screen. Numeric values are 
   converted to their string representation, with left padding for the 
   sign. Objects of user-defined types must overload Operator Cast () As 
   String.

   Consecutive values in the expression list are separated either by a 
   comma (,) or semicolon (;). A comma indicates printing should take place 
   at the next 14 column boundary, while a semicolon indicates values are 
   printed with no space between them.  This has a similar effect to 
   concatenating expressions using + or &.

   Print also supports the special expressions, Spc() and Tab().  These can 
   be used to space out expressions, or to align the printing to a specific 
   column.

   A new-line character is printed after the values in the expression list 
   unless the expression list is followed by a comma or semicolon.  A Print 
   without any expressions or separators following it will just print a 
   new-line.

   NOTE: Print resets the Err value after each expression is printed.

   NOTE: In graphics mode, Draw String provides a flexible alternative to 
   Print: it prints a string to the screen with pixel positioning, 
   transparent background, and can use a user-supplied font.

Example
   '' print "Hello World!", and a new-line
   Print "Hello World!"

   '' print several strings on one line, then print a new-line
   Print "Hello";
   Print "World"; "!";
   Print

   '' column separator
   Print "Hello!", "World!"

   '' printing variables/expressions
   Dim As Double pi = Atn(1) * 4
   Dim As String s = "FreeBASIC"

   Print "3 * 4 ="; 3 * 4

   Print "Pi is approximately"; pi
   Print s; " is great!"

Dialect Differences
   * In the -lang qb dialect, an extra space is printed after any integer 
     number.

Differences from QB
   * None, when using QBASIC's variable types in -lang qb, except that no 
     extra space is displayed after any floating-point number.
   * Unsigned numbers are printed without a space before them.
   * QB did not support casting for UDTs, so didn't allow them to be Print
     ed.

See also
   * Spc
   * Tab
   * Print #
   * ? #
   * Print Using
   * ? Using
   * Write
   * Draw String
   * Input



---------------------------------------------------------- KeyPgPrintPp ----
(Print | ?) #

Writes a list of values to a file or device

Syntax
   (Print | ?) # filenum, [ expressionlist ] [ , | ; ]

Parameters
   filenum
      The file number of a file or device opened for Output or Append.
   expressionlist
      List of values to write.

Description
   Print # outputs a list of values to a text file or device. Numeric 
   values are converted to their string representation, with left padding 
   for the sign. Objects of user-defined types must overload Operator Cast 
   () As String.

   Consecutive values in the expression list are separated either by a 
   comma (,) or semicolon (;). A comma indicates printing should take place 
   at the next 14 column boundary, while a semicolon indicates values are 
   printed with no space between them.

   A new-line character is printed after the values in the expression list 
   unless the expression list is followed by a comma or semicolon.

   Note that the comma (,) immediately following the file number is still 
   necessary, even the expression list is empty.  In this case a new-line 
   is printed, just as with a normal expression list that doesn't have a 
   comma or semicolon at the end.

   Note:
      - Using Print # is naturally dedicated to Output/Append Access file 
      mode.
      - It is also allowed in Binary/Random Access file mode, but this was 
      never well tested and results may vary.

Example
   Open "bleh.dat"  For Output As #1
      
      Print #1, "abc def"
      Print #1, 1234, 5678.901, "xyz zzz"
      
      Close #1

Dialect Differences
   * In the -lang qb dialect, an extra space is printed after numbers.

Differences from QB
   * None, when using QBASIC's variable types in -lang qb.
   * Unsigned numbers are printed without a space before them.
   * QB did not support casting for UDTs, so didn't allow them to be Print
     ed.

See also
   * Print Using
   * ? Using
   * Print
   * ?
   * Write #
   * Open



------------------------------------------------------- KeyPgPrintusing ----
(Print | ?) Using

Outputs formatted text to the screen or output device.

Syntax
   (Print | ?) [# filenum ,] [ printexpressionlist {,|;} ] Using 
   formatstring ; [ expressionlist [ ; ] ]

Parameters
   filenum
      The file number of a file or device opened for Output or Append.  
      (Alternatively LPrint may be used where appropriate, instead of 
      Print #)
   printexpressionlist
      Optional preceding list of items to print, separated by commas (,) or 
      semi-colons (;) (see Print for more details).
   formatstring
      Format string to use.
   expressionlist
      List of items to format, separated by semi-colons (;).

Description
   Print to screen various expressions using a format determined by the 
   formatstring parameter. Internally, Print Using uses a buffer size of 
   2048 bytes: while it is highly unlikely that this buffer would be 
   filled, it should be noted that output would be truncated should this 
   limit be reached.

   If no expression list is given, the format string will be printed up to 
   the first special marker.  Note that the semi-colon after formatstring 
   is still necessary, even if no expression list is given.

   The format string dictates how the expressions are to be formatted when 
   output to the screen, indicated by the use of special marker characters. 
   There are markers for formatting both string and numeric output:

   String formatting

         +------+------------------------------------------------------------------------------------------------------------------------------------+
         |Marker|Formatting                                                                                                                          |
         |!     |prints the first character of a string                                                                                              |
         |\   \ |prints two or more characters of a string - as many as are occupied by the backslashes ('\') and any enclosed space characters (' ')|
         |&     |prints the entire string                                                                                                            |
         +------+------------------------------------------------------------------------------------------------------------------------------------+

   If an exact amount of characters is specified (with "!" or "\ \"), the 
   string will be truncated or padded with spaces on the right as needed to 
   output that many characters.

   Numeric formatting

         +------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
         |Marker|Formatting                                                                                                                                                            |
         |#     |placeholder for either an integer digit, or a decimal digit if a decimal point precedes it                                                                            |
         |,     |placed after integer digit indicates groups of 3 digits should be separated by commas in fixed-point notation                                                         |
         |.     |placed near # indicates place for the decimal point                                                                                                                   |
         |^^^   |uses exponential notation (E+/-#) when placed after the digit characters                                                                                              |
         |^^^^  |uses exponential notation (E+/-##) when placed after the digit characters                                                                                             |
         |^^^^^ |uses exponential notation (E+/-###) when placed after the digit characters                                                                                            |
         |+     |placed before/after the format string, controls whether the sign of a number is prepended/appended, and causes an explicit '+' sign to be printed for positive numbers|
         |-     |placed after the format string, causes the sign of the number to be appended rather than prepended, appending a space/negative sign for positive/negative numbers     |
         |$$    |placed at the start of integer digits, causes a dollar sign to be prepended to the number (after the sign if one is prepended)                                        |
         |**    |placed at the start of integer digits, causes any padding on the left to be changed from spaces to asterisks                                                          |
         |**$   |placed at the start of integer digits, pads on the left with asterisks, and prepends a dollar sign after the asterisks                                                |
         |&     |prints a number intelligently, using the exact number of digits required (new to version 0.21.0b)                                                                     |
         +------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------+

   All of the special marker characters can be escaped by preceding them 
   with the underscore character "_", allowing them to be printed directly. 
   For example, "_!" is printed as "!", and "__" is printed as "_".

   If a numerical value cannot fit in the number of digits indicated by the 
   format string, the formatting is adapted to fit the number, possibly 
   switching to scientific notation, and the number is printed preceded by 
   the percent "%" character. E.g., the number 1234 with a formatstring of 
   "##.##" would be printed as "%1234.00".

   All other characters within the format string are printed as they 
   appear.

   A new-line character is printed after the values in the expression list 
   unless the expression list is followed by a semicolon (;).

Example

   Print Using "The value is #.## seconds"; 1.019
   Print Using "The ASCII code for the pound sign (_#) is ###"; Asc("#")
   Print Using "The last day in the year is & \ \"; 31; "December"
   Print
   For exponent As Integer = 1 To 5
      Print Using "10 ^ # = ######"; exponent; 10 ^ exponent
   Next exponent

   will produce the output:

   The value Is 1.02 seconds
   The ASCII code For the pound sign (#) Is  35
   The last Day in the Year Is 31 Dec

   10 ^ 1 =     10
   10 ^ 2 =    100
   10 ^ 3 =   1000
   10 ^ 4 =  10000
   10 ^ 5 = 100000

Differences from QB
   * QB didn't allow "&" to be used for printing numbers.

See also
   * Print
   * ?
   * Print #
   * ? #
   * Format
   * Using
   * Palette Using

			

---------------------------------------------------------- KeyPgPrivate ----
Private

Specifies a procedure having internal linkage

Syntax
   Private Sub procedure_name [cdecl|stdcall|pascal] [Overload] [Alias 
   "external_name"] [([parameter_list])] [Constructor [priority]] [Static] 
   [Export]
      ..procedure body..
   End Sub

   Private Function procedure_name [cdecl|stdcall|pascal] [Overload] [Alias 
   "external_name"] [([parameter_list])] [ ByRef ] As return_type  [Static] 
   [Export]
      ..procedure body..
   End Function

Description
   In procedure definitions (forbidden at declaration line level), Private 
   specifies that a procedure has internal linkage, meaning its name is not 
   visible to external modules.
   Therefore among the compiled modules, two procedures with the same 
   identifier, but defined inside different modules, may exist if both are 
   Private.

   The compiler removes the Private procedures that are not called, but 
   this does not currently work for Private procedures that are only called 
   by other Private procedures that are not called themselves, because the 
   first one appears as being called.

   The Option Private statement allows procedures to be defined with 
   internal linkage by default.

Example
   'e.g.

   Private Sub i_am_private
   End Sub

   Sub i_am_public
   End Sub

Differences from QB
   * New to FreeBASIC

See also
   * Private: (Access Control)
   * Public
   * Option Private
   * Sub
   * Function



------------------------------------------------------- KeyPgVisPrivate ----
Private: (Access Control)

Specifies private member access control in a Type or Class

Syntax
   Type typename
      Private:
         member declarations
   End Type

Parameters
   typename
      name of the Type or Class
   member declarations
      declarations for fields, functions, or enumerations

Description
   Private: indicates that member declarations following it have private 
   access.
   Private members are accessible only from inside a member procedure of 
   their Type or Class. Seen from inside such a member procedure, it is as 
   if the protected member is in fact public, and that regardless of the 
   object on which the access operator is applied.

   member declarations following Private: are private until a different 
   access control specifier is given, like Public: or Protected:.

   Members in a Type declaration are Public: by default if no member access 
   control specifier is given.

Example
   Type testing
     number As Integer
     Private:
      nome As String
     Declare Sub setNome( ByRef newnome As String )
   End Type

   Sub testing.setnome( ByRef newnome As String )
     '' This is OK. We're inside a member function for the type
     this.nome = newnome
   End Sub

   Dim As testing myVariable

   '' This is OK, number is public
   myVariable.number = 69

   '' this would generate a compile error 
   '' - nome is private and we're trying to access it outside any of this TYPE's member functions 
   '' myVariable.nome = "FreeBASIC"

Dialect Differences
   * Available only in the -lang fb dialect.

Differences from QB
   * New to FreeBASIC

See also
   * Private
   * Public: (Access Control)
   * Protected: (Access Control)
   * Type



-------------------------------------------------------- KeyPgOpProcptr ----
Operator Procptr (Procedure Pointer And Vtable Index)

Returns the address of any procedure, and the index in the vtable for a 
virtual/abstract member procedure.

Syntax
   Declare Operator ProcPtr ( ByRef identifier As proctype [, Any|
   user_proctype ] ) As internal_proctype Ptr
   Declare Operator ProcPtr ( ByRef identifier As proctype, virtual [ Any|
   user_proctype ] ) As Integer

Usage
   result = ProcPtr ( identifier [, [virtual] [any|user_proctype] ] )

Parameters
   identifier
      A procedure identifier.
   user_proctype
      Any user type of procedure (sub/function, static/member, 
      normal/virtual).
      (internal_proctype has a supplementary first parameter byref as 
      udt_name only for the member procedures of UDT udt_name)

Return Value
   Returns the address of any procedure (first syntax), or the index in the 
   vtable for a virtual/abstract member procedure (second syntax with 
   additional qualifier virtual).
   (any, ie any procedure signature, does not induce any particular 
   selection (compared to its non-use), but just allows for writing ProcPtr 
   always with 2 arguments)

Description
   First syntax:
      - This operator returns the address of a Sub or Function 
      static/member procedure or member operator.
      - The type of the return value corresponds to the internal signature 
      of the procedure (user signature, plus a supplementary first 
      parameter byref as udt_name for a member procedure) .
   Second syntax (with qualifier virtual):
      - This operator returns the zero based index in the vtable for a 
      virtual/abstract member procedure or member operator.
      - In case of overridden member procedure (polymorphism), the vtable 
      index allows access, from the vtable of the used instance, to the 
      address of the most derived override member procedure.

   When using the user_proctype argument, ProcPtr syntax allows of getting 
   procedure pointer or vtable index for based on parameter types 
   (including sub/function type and return type if any).
   This makes it possible to explicitly specify the right procedure to 
   resolve procedure overloads, or make a check for parameter types 
   (including sub/function type and return type if any) on non-overloaded 
   procedures.

   Operator @ (Address Of), when used with procedures, behaves the same as 
   the first ProcPtr syntax without second argument.

   Note:
      - If the procedure member is abstract, then  ProcPtr ( identifier [, 
      any|user_proctype ] )  returns a null procedure pointer of the member 
      procedure call signature (internal_proctype).
      - If there is no vtable entry (or no vtable at all) then  ProcPtr ( 
      identifier , virtual [any|user_proctype] )  returns the special value 
      of -1.

Example
   ' This example uses ProcPtr to demonstrate function pointers
   Declare Function Subtract( x As Integer, y As Integer) As Integer
   Declare Function Add( x As Integer, y As Integer) As Integer
   Dim myFunction As Function( x As Integer, y As Integer) As Integer

   ' myFunction will now be assigned to Add
   myFunction = ProcPtr( Add )
   Print myFunction(2, 3)

   ' myFunction will now be assigned to Subtract.  Notice the different output.
   myFunction = ProcPtr( Subtract )
   Print myFunction(2, 3)

   Function Add( x As Integer, y As Integer) As Integer
      Return x + y
   End Function

   Function Subtract( x As Integer, y As Integer) As Integer
      Return x - y
   End Function

   Sub s Overload()
   End Sub

   Sub s( ByVal i As Integer )
   End Sub

   '----- since fbc 1.09.0, ProcPtr supports a second parameter (optional):
   Var s1 = ProcPtr( s, Sub() )
   Var s2 = ProcPtr( s, Sub( ByVal i As Integer ) )

   '----- before fbc 1.09.0, it was only possible with:
   'Dim s1 As Sub()
   's1 = ProcPtr( s )
   'Dim s2 As Sub( Byval i As Integer)
   's2 = ProcPtr( s )

   ' Since fbc 1.10.0, ProcPtr supports the member procedures/operators with various syntaxes

   Type UDT Extends Object
      Dim As String s1
      Dim As String s2
      Declare Virtual Sub test()
      Declare Virtual Operator Cast() As String
   End Type

   Sub UDT.test()
      Print This.s1
   End Sub

   Operator UDT.Cast() As String
      Return This.s2
   End Operator

   Var testPtr1 = ProcPtr(UDT.test)
   Var testPtr2 = ProcPtr(UDT.test, Any)
   Var testPtr3 = ProcPtr(UDT.test, Sub())

   Dim As Function(ByRef As UDT) As String castPtr1 = ProcPtr(UDT.cast)
   Dim As Function(ByRef As UDT) As String castPtr2 = ProcPtr(UDT.cast, Any)
   Dim As Function(ByRef As UDT) As String castPtr3 =  ProcPtr(UDT.cast, Function() As String)

   Var testIndex1 = ProcPtr(UDT.test, Virtual)
   Var testIndex2 = ProcPtr(UDT.test, Virtual Any)
   Var testIndex3 = ProcPtr(UDT.test, Virtual Sub())

   Dim As Integer castIndex1 = ProcPtr(UDT.cast, Virtual)
   Dim As Integer castIndex2 = ProcPtr(UDT.cast, Virtual Any)
   Dim As Integer castIndex3 = ProcPtr(UDT.cast, Virtual Function() As String)

   Print testPtr1  '' absolue address value of UDT.test pointer
   Print testPtr2  '' absolue address value of UDT.test pointer
   Print testPtr3  '' absolue address value of UDT.test pointer
   Print

   Print castPtr1  '' absolue address value of UDT.Cast pointer
   Print castPtr2  '' absolue address value of UDT.Cast pointer
   Print castPtr3  '' absolue address value of UDT.Cast pointer
   Print

   Print testIndex1  '' vtable index of UDT.test
   Print testIndex2  '' vtable index of UDT.test
   Print testIndex3  '' vtable index of UDT.test
   Print

   Print castIndex1  '' vtable index of UDT.Cast
   Print castIndex2  '' vtable index of UDT.Cast
   Print castIndex3  '' vtable index of UDT.Cast
   Print

   Dim As UDT u
   u.s1 = "Virtual Sub test()"
   u.s2 = "Virtual Operator Cast() As String"

   testPtr1(u)  '' execute u.test() through its procedure pointer
   testPtr2(u)  '' execute u.test() through its procedure pointer
   testPtr3(u)  '' execute u.test() through its procedure pointer
   Print

   Print castPtr1(u)  '' execute Cast(UDT, u) through its procedure pointer
   Print castPtr2(u)  '' execute Cast(UDT, u) through its procedure pointer
   Print castPtr3(u)  '' execute Cast(UDT, u) through its procedure pointer
   Print

   CPtr(Sub(ByRef As UDT), CPtr(Any Ptr Ptr Ptr, @u)[0][testIndex1])(u)  '' execute u.test() through its vtable index
   CPtr(Sub(ByRef As UDT), CPtr(Any Ptr Ptr Ptr, @u)[0][testIndex2])(u)  '' execute u.test() through its vtable index
   CPtr(Sub(ByRef As UDT), CPtr(Any Ptr Ptr Ptr, @u)[0][testIndex3])(u)  '' execute u.test() through its vtable index
   Print

   Print CPtr(Function(ByRef As UDT) As String, CPtr(Any Ptr Ptr Ptr, @u)[0][castIndex1])(u)  '' execute Cast(UDT, u) through its vtable index
   Print CPtr(Function(ByRef As UDT) As String, CPtr(Any Ptr Ptr Ptr, @u)[0][castIndex2])(u)  '' execute Cast(UDT, u) through its vtable index
   Print CPtr(Function(ByRef As UDT) As String, CPtr(Any Ptr Ptr Ptr, @u)[0][castIndex3])(u)  '' execute Cast(UDT, u) through its vtable index
   Print

   Sleep

   ' Since fbc 1.10.0, ProcPtr also allows to access the vtable index of a virtual/abstract member procedure/operator

   Type Parent Extends Object
      Declare Abstract Sub VirtualTest()
      Declare Virtual Operator Cast() As String
      Declare Sub NormalTest()
   End Type

   Operator Parent.Cast() As String
      Return "Parent.Cast() As String"
   End Operator

   Sub Parent.NormalTest()
      Print "Parent.NormalTest()"
   End Sub

   Type Child Extends Parent
      Declare Virtual Sub VirtualTest()          '' or Declare Sub test()
      Declare Virtual Operator Cast() As String  '' or Declare Operator Cast() As String
      Declare Sub NormalTest()
   End Type

   Sub Child.VirtualTest()
      Print "Child.VirtualTest"
   End Sub

   Operator Child.Cast() As String
      Return "Child.Cast() As String"
   End Operator

   Sub Child.NormalTest()
      Print "Child.NormalTest()"
   End Sub

   Dim As Parent Ptr p = New Child

   (*p).VirtualTest()      '' or p->VirtualTest()
   Print Cast(Parent, *p)  '' or Print *p
   (*p).NormalTest()       '' or p->NormalTest()
   Print

   #define RuntimeProcPtr(instance, procedure, signature...) _   '' pointer to procedure
      __FB_IIF__(ProcPtr(procedure, Virtual signature) >= 0, _  '' (the most derived override if exists)
               CPtr(TypeOf(ProcPtr(procedure, signature)), _
                  CPtr(Any Ptr Ptr Ptr, @(instance)) _
                  [0][ProcPtr(procedure, Virtual signature)]), _
               ProcPtr(procedure, signature))

   '' Here, providing the procedure signature to the macro is useless
   '' (because there are no procedure overloads to solve in this case)
   RuntimeProcPtr(*p, Parent.VirtualTest)(*p)  '' execute (*p).VirtualTest() through its vtable index
   Print RuntimeProcPtr(*p, Parent.Cast)(*p)   '' execute Cast(Parent, *p) through its vtable index
   RuntimeProcPtr(*p, Parent.NormalTest)(*p)   '' execute (*p).NormalTest() through its compile address
   Print

   Delete p
   Sleep

Version
   * Before fbc 1.10.0, the member procedures/operators were not 
     supported.
   * Before fbc 1.09.0, the second argument (the optional) was not 
     supported.

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Procptr (but does not support qualifier virtual).

Differences from QB
   * New to FreeBASIC

See also
   * Sub
   * VarPtr
   * StrPtr
   * Any
   * Virtual
   * Pointers



--------------------------------------------------------- KeyPgProperty ----
Property

Declares or defines a property in a type or class

Syntax
   { Type | Class } typename
      Declare Property fieldname () [ ByRef ] As datatype
      Declare Property fieldname ( [ ByRef | ByVal ] new_value As datatype 
      )
      Declare Property fieldname ( [ ByRef | ByVal ] index As datatype ) [ 
      ByRef ] As datatype
      Declare Property fieldname ( [ ByRef | ByVal ] index As datatype, [ 
      ByRef | ByVal ] new_value As datatype )
   End { Type | Class }

   Property typename.fieldname () [ ByRef ] As datatype [ Export ]
      statements
   End Property

   Property typename.fieldname ( [ ByRef | ByVal ] new_value As datatype ) 
   [ Export ]
      statements
   End Property

   Property typename.fieldname (  [ ByRef | ByVal ] index As datatype ) [ 
   ByRef ] As datatype [ Export ]
      statements
   End Property

   Property typename.fieldname (  [ ByRef | ByVal ] index As datatype, [ 
   ByRef | ByVal ] new_value As datatype ) [ Export ]
      statements
   End Property

Parameters
   typename 
      name of the Type or Class
   fieldname 
      name of the property
   new_value 
      the value passed to property to be assigned
   index 
      the property index value

Description
   Property fields are used to get and set values of a Type or Class in the 
   same way as other data fields except instead of a simple assignment to a 
   field or a value retrieved from field, a procedure is executed.

   typename is the name of the type for which the Property method is 
   declared and defined.  Name resolution for typename follows the same 
   rules as procedures when used in a Namespace.

   A Property may optionally have one index parameter.  When indexed, 
   properties are accessed as fieldname(Index) [ = value ].
   A Property without index parameter must always be used without empty 
   parentheses after fieldname.
   A get-Property can also return a reference by specifying ByRef As 
   return_type.

   A hidden This parameter having the same type as typename is passed to 
   the property procedure.  This is used to access the fields of the Type 
   or Class.

   Note: A standard Property (get & set) does not work with combination 
   operators (as "+="). But a result byref get-Property (as more generally 
   any result byref function) works with combination operators.

   Note: When a get-Property is defined with one index parameter, the 
   fieldname= syntax can not be used to return a value. For such a get-
   Property, the property= syntax (in addition to the Return syntax) is 
   only the one allowed.

Example
   Type Vector2D
     As Single x, y
     Declare Operator Cast() As String
     Declare Property Length() As Single
     Declare Property Length( ByVal new_length As Single )
   End Type

   Operator Vector2D.cast () As String
     Return "(" + Str(x) + ", " + Str(y) + ")"
   End Operator

   Property Vector2D.Length() As Single
     Length = Sqr( x * x + y * y )
   End Property

   Property Vector2D.Length( ByVal new_length As Single )
     Dim m As Single = Length
     If m <> 0 Then
      '' new vector = old / length * new_length
      x *= new_length / m
      y *= new_length / m
     End If
   End Property

   Dim a As Vector2D = ( 3, 4 )

   Print "a = "; a
   Print "a.length = "; a.length
   Print

   a.length = 10

   Print "a = "; a
   Print "a.length = "; a.length

Output:

   a = (3, 4)
   a.length =  5

   a = (6, 8)
   a.length =  10

Property Indexing:
     '' True/False
   Namespace BOOL
     Const False = 0
     Const True = Not False
   End Namespace

   Type BitNum
     Num As UInteger
     
      '' Get/Set Properties each with an Index.
     Declare Property NumBit( ByVal Index As Integer ) As Integer
     Declare Property NumBit( ByVal Index As Integer, ByVal Value As Byte )
   End Type

     '' Get a bit by it's index.
   Property BitNum.NumBit( ByVal Index As Integer ) As Integer
     Return Bit( This.Num, Index )
   End Property

     '' Set a bit by it's index.
   Property BitNum.NumBit( ByVal Index As Integer, ByVal Value As Byte )

      '' Make sure index is in Integer range.
     If Index >= ( SizeOf(This.Num) * 8 ) Then
      Print "Out of uInteger Range!"
      Exit Property
     Else
      If Index < 0 Then Exit Property
     End If
     
     If Value = BOOL.FALSE Then
      This.Num = BitReset( This.Num, Index )
     End If
     
     If Value = BOOL.TRUE Then
      This.Num = BitSet( This.Num, Index )
     End If
     
   End Property

   Dim As BitNum Foo

   Print "Testing property indexing with data types:"
   Print "FOO Number's Value: " & Foo.Num

     '' Set the bit in the number as true.
   Foo.NumBit(31) = BOOL.TRUE
   Print "Set the 31st bit of FOO"

     '' Print to see if our bit has been changed.
   Print "FOO Number's Value: " & Foo.Num
   Print "FOO 31st Bit Set? " & Foo.NumBit(31)
   Sleep
   Print ""

Output:

   Testing Property indexing With Data types:
   FOO Number's Value: 0
   Set the 31st Bit of FOO
   FOO Number's Value: 2147483648
   FOO 31st Bit Set? -1

See also
   * Class
   * Type



----------------------------------------------------- KeyPgVisProtected ----
Protected: (Access Control)

Specifies protected member access control in a Type or Class

Syntax
   Type typename
      Protected:
         member declarations
   End Type

Parameters
   typename
      name of the Type or Class
   member declarations
      declarations for fields, functions, or enumerations

Description
   Protected: indicates that member declarations following it have 
   protected access.
   Protected members are accessible only from inside a member procedure of 
   their Type or Class, and classes which are derived from this Type or 
   Class. Seen from inside such a member procedure, it is as if the 
   protected member is in fact public, and that regardless of the object on 
   which the access operator is applied.

   member declarations following Protected: are protected until a different 
   access control specifier is given, like Private: or Public:.

   Members in a Type declaration are Public: by default if no member access 
   control specifier is given.

Example
   Type animal
     Dim As String animalName
     Protected:
      Dim As Integer serialNumber
   End Type

   Type dog Extends animal
     Dim As String masterName
     Declare Sub setSerialNumber ( ByVal number As Integer )
   End Type

   Sub dog.setSerialNumber ( ByVal number As Integer )
     '' This is OK. We're inside a member function of the derived type
     This.serialNumber = number
   End Sub

   Dim As dog d

   '' This is OK, animalName is public
   d.animalName = "Buddy"

   '' this would generate a compile error: 
   '' - serialNumber is protected and we're trying to access it outside its type and the derived type
   '' d.serialNumber = 123456789

   ' Example to illustrate the access control 'Protected' with a token provided by an admin right for an user right:
   '    - The 'admin_right' type extends the 'user_right' type.
   '    - Create directly an 'user_right' object is forbidden.
   '         ('default user_right.constructor' access and 'copy user_right.constructor' access are 'Protected')
   '    - The 'user_right' type has only the access right to get the token.
   '         ('user_right.token' get-property access is 'Public' and 'user_right.token' set-property access is 'protected')
   '    - The 'admin_right' type has the access rights to set and to get the token.
   '         ('admin_right.token' get-property access and 'admin_right.token' set-property access are 'Public')
   '
   ' An 'admin_right' object is created, and then a reference of type 'user_right' to this object is defined.
   '    (create directly an 'user_right' object is forbidden)

   Type user_right
     Public:
      Declare Property token () As String          '' 'Public' to authorize user_right token get
     Protected:
      Declare Constructor ()                       '' 'Protected' to forbid user_right object default-construction
      Declare Constructor (ByRef u As user_right)  '' 'Protected' to forbid user_right object copy-construction
      Declare Property token (ByRef s As String)   '' 'Protected' to forbid user_right token set
     Private:
      Dim As String user_right_token               '' 'Private' to forbid access from outside user_right
   End Type

   Constructor user_right ()  '' Default-constructor
   End Constructor

   Constructor user_right (ByRef u As user_right)  '' Protected copy-constructor
     This.user_right_token = u.user_right_token
   End Constructor

   Property user_right.token () As String  '' Public property user_right token get
     Return This.user_right_token
   End Property

   Property user_right.token (ByRef s As String)  '' Protected property user_right token set
     This.user_right_token = s
   End Property

   Type admin_right Extends user_right
     Public:
      Declare Property token () As String         '' 'Public' to authorize admin_right token get
      Declare Property token (ByRef s As String)  '' 'Public' to authorize admin_right token set
   End Type

   Property admin_right.token () As String  '' Public property admin_right token get
     Return Base.token                      '' 'Base.' to access to the base type property shadowed by this property name
   End Property

   Property admin_right.token (ByRef s As String)  '' Public property admin_right token set
     Base.token = s                                '' 'Base.' to access to the base type property shadowed by this property name
   End Property

   Dim As admin_right ar       '' Create an admin_right type object 'ar'
   ar.token = "fxm123456789"   '' admin_right set the token for user_right
   Print "'" & ar.token & "'"  '' admin_right get the user_right token
   Print

   Dim ByRef As user_right ur = ar  '' Create a user_right type reference 'ur' to the 'ar' instance of admin_right type
   Print "'" & ur.token & "'"       '' user_right get its token
   'ur.token = "fxm0"               '' Error: Illegal member access, USER_RIGHT.TOKEN.property.set (user_right cannot set its token)

   'Dim As user_right ur1       '' Error: The default constructor has no public access
   'Dim As user_right ur2 = ar  '' Error: Constructor has no public access

   Sleep

Dialect Differences
   * Available only in the -lang fb dialect.

Differences from QB
   * New to FreeBASIC

See also
   * Class
   * Private: (Access Control)
   * Public: (Access Control)
   * Type



------------------------------------------------------------- KeyPgPset ----
Pset (Statement)

Plots a single pixel

Syntax
   PSet [target ,] [STEP] (x, y) [,color]

Parameters
   target
      specifies buffer to draw on.  
   STEP
      indicates that coordinates are relative
   (x, y)
      coordinates of the pixel.
   color
      the color attribute.

Description
   target specifies buffer to draw on.  target may be an image created with 
   ImageCreate or Get (Graphics).  If omitted, target defaults to the 
   screen's current work page.

   (x, y) are the coordinates of the pixel.  STEP if present, indicates 
   that (x, y) coordinates are relative to the graphics cursor position.  
   If omitted, (x, y) are relative to the upper left-hand corner of target. 
   The x and y coordinates are affected by the last call to the 
   View (Graphics) and Window statements, and respect the current clipping 
   region as set by the View (Graphics) statement.

   color specifies the color attribute, as an 8-bit palette index in 8 bpp 
   indexed modes, a 24-bit RGB value in 16 bpp modes (upper 8 bits of the 
   integer unused, limited precision of R,G,B), and a 32-bit RGB or RGBA 
   value in 32 bpp modes (upper 8 bits unused or holding Alpha). Note that 
   it does NOT accept a 16-bit value (5 bits R + 6 bits G + 5 bits B).  If 
   omitted, color defaults to the current foreground color.

   Speed note: while PSet provides valid results, it is quite slow to call 
   repeatedly due to the overhead of additional calculations and checks. 
   Much better performance can be achieved by using direct memory access 
   using the results obtained from ImageInfo and ScreenInfo/ScreenPtr.

Example
   ' Set an appropriate screen mode - 320 x 240 x 8bpp indexed color
   ScreenRes 320, 240, 8

   ' Plot a pixel at the coordinates 100, 100, Color 15. (white)
   PSet (100, 100), 15
   ' Confirm the operation.
   Locate 1: Print "Pixel plotted at 100, 100"
   ' Wait for a keypress.
   Sleep
    
   ' Plot another pixel at the coordinates 150, 150, Color 4. (red) 
   PSet (150, 150), 4
   ' Confirm the operation.
   Locate 1: Print "Pixel plotted at 150, 150"
   ' Wait for a keypress.
   Sleep
    
   ' Plot a third pixel relative to the second, Color 15. (white)
   ' This pixel is given the coordinates 60, 60. It will be placed
   ' at 60, 60 plus the previous coordinates (150, 150), thus plotting at 210, 210.
   PSet Step (60, 60), 15
   ' Confirm the operation.
   Locate 1: Print "Pixel plotted at 150 + 60, 150 + 60"
   ' Wait for a keypress
   Sleep

   ' Explicit end of program
   End

Differences from QB
   * target is new to FreeBASIC
   * In 16 bpp and 32 bpp modes, a 32-bit value is required instead of an 
     8-bit palette index

See also
   * Point - read out pixels
   * PReset
   * View (Graphics)
   * Window
   * Internal pixel formats



---------------------------------------------------------- KeyPgPsetGfx ----
Pset (Graphics Put)

Parameter to the Put graphics statement which selects PSet as the blitting 
method

Syntax
   Put [ target, ] [ STEP ] ( x,y ), source [ ,( x1,y1 )-( x2,y2 ) ], PSet

Parameters
   PSet
      Required.

Description
   The PSet method copies the source pixel values onto the destination 
   pixels.

   This is the simplest Put method. The pixels in the destination buffer 
   are directly overwritten with the pixels in the source buffer.  No 
   additional operations are done, and there are no color values that are 
   treated as transparent.  It has the same effect as PSetting each pixel 
   individually.

Example
   '' set up a screen: 320 * 200, 16 bits per pixel
   ScreenRes 320, 200, 16
   Line (0, 0)-(319, 199), RGB(0, 128, 255), bf

   '' set up an image with the mask color as the background.
   Dim img As Any Ptr = ImageCreate( 33, 33, RGB(255, 0, 255) )
   Circle img, (16, 16), 15, RGB(255, 255, 0),     ,     , 1, f
   Circle img, (10, 10), 3,  RGB(  0,   0, 0),     ,     , 2, f
   Circle img, (23, 10), 3,  RGB(  0,   0, 0),     ,     , 2, f
   Circle img, (16, 18), 10, RGB(  0,   0, 0), 3.14, 6.28

   Dim As Integer x = 160 - 16, y = 100 - 16

   '' Put the image with PSET
   Put (x, y), img, PSet

   '' free the image memory
   ImageDestroy img

   '' wait for a keypress
   Sleep

Differences from QB
   * None

See also
   * PSet
   * Put (Graphics)



-------------------------------------------------------------- KeyPgPtr ----
(Pointer | Ptr)

A variable declaration type modifier

Syntax
   ... As DataType {Pointer | Ptr}

Description
   Declares a pointer variable.
   The variable type can be a predefined type or a user-defined type.

   Operator @ (Address Of) operator or VarPtr are used to take the address 
   of a variable. The Operator * (Value Of) operator is used to dereference 
   the pointer, that is, access the actual value stored in the memory 
   location the pointer is pointing at.

Example
   ' Create the pointer.
   Dim p As Integer Ptr

   ' Create an integer value that we will point to using pointer "p"
   Dim num As Integer = 98845

   ' Point p towards the memory address that variable "num" occupies.
   p = @num

   ' Print the value stored in memory pointed to by pointer "p"
   Print "Pointer 'p' ="; *p
   Print 

   ' Print the actual location in memory that pointer "p" points at.
   Print "Pointer 'p' points to memory location:"
   Print p

   Dim p As ZString Pointer
   Dim text As String
   text = "Hello World!"
   p = StrPtr(text) + 6
   Print text
   Print *p

   '' Output:
   '' Hello World!
   '' World!

   Type mytype
      a As Integer = 12345
   End Type

   Dim As mytype mt

   Dim As mytype Ptr pmt
   pmt = @mt

   Print (*pmt).a  '' or Print pmt->a

   '' Output:
   '' 12345

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Pointer or __Ptr.

Differences from QB
   * New to FreeBASIC

See also
   * Allocate



----------------------------------------------------------- KeyPgPublic ----
Public

Specifies a procedure having external linkage.

Syntax
   Public Sub procedure_name [cdecl|stdcall|pascal] [Overload] [Alias 
   "external_name"] [([parameter_list])] [Constructor [priority]] [Static] 
   [Export]
      ..procedure body..
   End Sub

   Public Function procedure_name [cdecl|stdcall|pascal] [Overload] [Alias 
   "external_name"] [([parameter_list])] [ ByRef ] As return_type  [Static] 
   [Export]
      ..procedure body..
   End Function

Description
   In procedure definitions (forbidden at declaration line level), Public 
   specifies that a procedure has external linkage, meaning its name is 
   visible to external modules. If Public or Private is not specified, a 
   procedure is defined as if Public was specified.

Example
   Private Sub i_am_private
   End Sub

   Public Sub i_am_public
   End Sub

Differences from QB
   * New to FreeBASIC

See also
   * Public: (Access Control)
   * Private
   * Option Private
   * Sub
   * Function



-------------------------------------------------------- KeyPgVisPublic ----
Public: (Access Control)

Specifies public member access control in a Type or Class

Syntax
   Type typename
      Public:
         member declarations
   End Type

Parameters
   typename
      name of the Type or Class
   member declarations
      declarations for fields, functions, or enumerations

Description
   Public: indicates that member declarations following it have public 
   access.
   Public members are accessible with any usage of the Type or Class.

   member declarations following Public: are public until a different 
   access control specifier is given, like Private: or Protected:

   Members in a Type declaration are Public: by default if no member access 
   control specifier is given.

Example
   Type testing
     Private:
      nome As String
     Public:
      number As Integer
     Declare Sub setNome( ByRef newnome As String )
   End Type

   Sub testing.setnome( ByRef newnome As String )
     this.nome = newnome 
   End Sub

   Dim As testing myVariable

   '' We can access these members anywhere since
   '' they're public
   myVariable.number = 69 ''
   myVariable.setNome( "FreeBASIC" )

Dialect Differences
   * Available only in the -lang fb dialect.

Differences from QB
   * New to FreeBASIC

See also
   * Class
   * Private: (Access Control)
   * Protected: (Access Control)
   * Public
   * Type



------------------------------------------------------ KeyPgPutgraphics ----
Put (Graphics)

Copies an image on to another image or screen

Syntax
   Put [target, ] [ [STEP](x, y), source [, (x1, y1)-[STEP](x2, y2) ] [, 
   method [, ( alphaval|value|blender [, param]) ] ]

Parameters
   target
      is the address of the buffer where the image is to be drawn. If it's 
      omitted, the image gets blitted to screen. See below.
   [STEP](x, y)
      specify offsets from the upper-left corner of the destination buffer, 
      or screen, that the image gets drawn to.  STEP indicates that (x, y) 
      offsets are relative to the current graphics cursor position.
   source
      is the address of the buffer of the image to be drawn. See below.
   (x1, y1)-[STEP](x2, y2)
      specify a rectangular area in the source buffer to draw. If omitted, 
      the entire buffer is drawn. STEP indicates that x2 and y2 are 
      relative to x1 and y1, respectively.
   method
      specifies the method used to draw the image to the destination 
      buffer, and can be any one of the following (the default method is 
      XOR):

      Background-independent methods
         PSet : Source pixel values are copied without modification.
         PRESET : Source pixel values are 1's-complement negated before 
         being copied.
         Trans : Source pixel values are copied without modification. Does 
         not draw source pixels of mask color. See below.
      Background-dependent methods
         And (Graphics Put) : Destination pixels are bitwise Anded with 
         source pixels. See below.
         Or : Destination pixels are bitwise Ored with source pixels. See 
         below.
         Xor : Destination pixels are bitwise Xored with source pixels. See 
         below.
         Alpha : Source is blended with a transparency factor specified 
         either in the value parameter, or in the image's individual 
         pixels.  See below.
         Add: Source is multiplied by a value and added with saturation to 
         the destination. See below.
         Custom : Uses a user-defined function to perform blending the 
         source with the destination. See below.

   value
      is a 0..255 value specifying the transparency value for an ADD or 
      ALPHA method blit.
   blender 
      specifies the address of a user-defined function to be called in a 
      CUSTOM method blit. See below.
   param 
      specifies a parameter to pass to the custom blender.

Description
   The Put statement can be used to draw an image onto another image or 
   screen. The x and y coordinates are affected by the last call to the View
   and Window statements, and plotted image respects the current clipping 
   region set by last call to the View statement. The source image can 
   overflow the destination buffer or screen (then the copied image is 
   clipped accordingly).

   Valid Image Buffers
      The source and target image buffers must be valid image buffers. 
      Valid image buffers are created using the Get or ImageCreate 
      statements. Valid image buffers can be specified in a Put statement 
      using an array name with optional index (but never with empty 
      parentheses), or a pointer with optional index.

   Drawing methods
      Depending on the method used, the existing pixel values in the 
      destination buffer are used to calculate the pixel values that are 
      actually drawn. The PSET, PRESET and TRANS methods do not use the 
      destination buffer for calculating final pixel values, while the AND, 
      OR, XOR, ALPHA and ADD methods do. Images that are drawn with these 
      latter methods will look differently depending on the content of the 
      destination buffer.

   Different pixel formats
      The pixel format of an image buffer must be compatible with the 
      current graphics mode color depth; that is, if you acquire an image 
      using Get and you later change screen mode via the Screen (Graphics) 
      statement, the image data may not be valid in the new graphics mode, 
      and you may not be able to draw it on the screen. You should note 
      however that you will always be able to draw image buffers onto other 
      image buffers via Put as long as these buffers were created with the 
      same depth.

      The AND, OR and XOR methods produce different results depending on 
      the current color depth, as pixels are stored in different formats; 
      see Internal pixel formats for details.

   Mask Color
      The TRANS, ALPHA and ADD methods do not draw pixels in the source 
      image that use the mask color. The mask color depends on target 
      (being it an image buffer or the screen) depth: in depths up to 8 bpp 
      (paletted modes) it is equal to color index 0, while in hi/truecolor 
      depths (16 and 32 bpp) it is equal to magenta, which is RGB(255, 0, 
      255). Note that in 32 bpp modes the alpha value of a color does not 
      affect the identification of the transparent color; only the lower 24 
      bits are used to identify it. See Internal pixel formats for details. 
      

   Alpha drawing
      The ALPHA method can be used in two modes. If the value parameter is 
      specified, this is used to specify the level of transparency for the 
      whole image to be drawn; a value of 0 will draw a completely 
      transparent image, whereas a value of 255 will draw a completely 
      solid one. This mode works only when drawing onto hi/truecolor 
      targets (16 and 32 bpp).
      If the value parameter is omitted, the ALPHA method will take the 
      alpha level value on a per-pixel basis, allowing to draw images with 
      an alpha channel (certain parts of the image can be made more or less 
      transparent than others). This mode works only with 32 bpp image 
      buffers, as this is the only color depth that allows for an embedded 
      alpha value in each pixel.

   Dealing with the alpha channel
      Normally Put only allows to draw image buffers onto targets with the 
      same depth, but there is an exception. When drawing an 8 bpp image 
      buffer onto a 32 bpp target and the ALPHA method is used, the 8 bpp 
      source image is drawn into the alpha channel of the 32 bpp target. 
      This allows to easily set the whole alpha channel of an image without 
      having to deal with low level access of its pixel data.

   Custom Blend Function
      The CUSTOM method uses a user-defined function to calculate the final 
      pixel values to be drawn to the destination buffer. This function 
      will be called once for every pixel of the source image, and will 
      receive the source and destination pixel values, and a data pointer 
      passed by the Put function. The pixel value returned will be the 
      value used to draw to the destination buffer. The function has the 
      form:

      Declare Function identifier ( ByVal source_pixel As ULong, ByVal 
      destination_pixel As ULong, ByVal parameter As Any Ptr ) As ULong
         identifier is the name of the function. Can be anything.
         source_pixel is the current pixel value of the source image.
         destination_pixel is the current pixel value of the destination 
         image.
         parameter is the parameter that is passed by the Put command.  It 
         should be a data Pointer.  If omitted, its value will be zero.

Example
   The following program gives a simple example of how to Put an image to 
   the screen, including setting up an image buffer, and freeing its memory 
   after.
   '' set up the screen and fill the background with a color
   ScreenRes 320, 200, 32
   Paint (0, 0), RGB(64, 128, 255)

   '' set up an image and draw something in it
   Dim img As Any Ptr = ImageCreate( 32, 32, RGB(255, 0, 255) )
   Circle img, (16, 16), 15, RGB(255, 255, 0),     ,     , 1, f
   Circle img, (10, 10), 3,  RGB(  0,   0, 0),     ,     , 2, f
   Circle img, (23, 10), 3,  RGB(  0,   0, 0),     ,     , 2, f
   Circle img, (16, 18), 10, RGB(  0,   0, 0), 3.14, 6.28

   '' PUT the image in the center of the screen
   Put (160 - 16, 100 - 16), img, Trans

   '' free the image memory
   ImageDestroy img

   '' wait for a keypress
   Sleep

   The following example shows how to allocate memory for an image, draw 
   that image using various methods, including a custom blender, and free 
   the memory for the image:
   Declare Function checkered_blend( ByVal src As ULong, ByVal dest As ULong, ByVal param As Any Ptr ) As ULong

      Screen 14, 32                                   '' set 320*240*32 gfx mode
      
      Dim As Any Ptr sprite
      Dim As Integer counter = 0
      
      sprite = ImageCreate( 32, 32 )                  '' allocate memory for 32x32 sprite
      
      Line sprite, ( 0, 0 )-( 31, 31 ), RGBA(255, 0, 0, 64), bf  '' draw a sprite ...
      Line sprite, ( 4, 4 )-( 27, 27 ), RGBA(255, 0, 0, 192), bf
      Line sprite, ( 0, 0 )-( 31, 31 ), RGB(0, 255, 0), b
      Line sprite, ( 8, 8 )-( 23, 23 ), RGBA(255, 0, 255, 64), bf
      Line sprite, ( 1, 1 )-( 30, 30 ), RGBA(0, 0, 255, 192)
      Line sprite, ( 30, 1 )-( 1, 30 ), RGBA(0, 0, 255, 192)
      
      Cls
      Dim As Integer i : For i = 0 To 63              '' draw the background
        Line( i,0 )-( i,240 ), RGB( i * 4, i * 4, i * 4 )
      Next i
      
      '' demonstrate all drawing methods ...
      Put( 8,14 ), sprite, PSet
      Put Step( 16,20 ), sprite, PReset
      Put Step( -16,20 ), sprite, And
      Put Step( 16,20 ), sprite, Or
      Put Step( -16,20 ), sprite, Xor
      Put Step( 16,20 ), sprite, Trans
      Put Step( -16,20 ), sprite, Alpha, 96
      Put Step( 16,20 ), sprite, Alpha
      Put Step( -16,20 ), sprite, Add, 192
      Put Step( 16,20 ), sprite, Custom, @checkered_blend, @counter
      
      '' print a description near each demo
      Draw String (100, 26), "<- pset"
      Draw String Step (0, 20), "<- preset"
      Draw String Step (0, 20), "<- and"
      Draw String Step (0, 20), "<- or"
      Draw String Step (0, 20), "<- xor"
      Draw String Step (0, 20), "<- trans"
      Draw String Step (0, 20), "<- alpha (uniform)"
      Draw String Step (0, 20), "<- alpha (per pixel)"
      Draw String Step (0, 20), "<- add"
      Draw String Step (0, 20), "<- custom"
      
      ImageDestroy( sprite )                          '' free allocated memory for sprite
      Sleep : End 0

   '' custom blender function: chequered put
   Function checkered_blend( ByVal src As ULong, ByVal dest As ULong, ByVal param As Any Ptr ) As ULong
      Dim As Integer Ptr counter
      Dim As ULong pixel
      
      counter = Cast(Integer Ptr, param)
      pixel = IIf(((*counter And 4) Shr 2) Xor ((*counter And 128) Shr 7), src, dest)
      *counter += 1
      Return pixel
   End Function

Differences from QB
   * target is new to FreeBASIC
   * The TRANS, ALPHA, ADD and CUSTOM methods are new to FreeBASIC
   * FB uses a different image format internally, which is unsupported by 
     QB
   * QB throws a run-time error instead of clipping out-of-bounds images
   * In QB, only arrays can be specified as source images

See also
   * Custom (Graphics Put)
   * Put (File I/O)
   * Get (Graphics)
   * ImageCreate
   * Alpha
   * Internal pixel formats



-------------------------------------------------------- KeyPgPutfileio ----
Put (File I/O)

Writes data from a buffer to a file

Syntax
   Put #filenum As Long, [position As LongInt], data As Any [, amount As 
   UInteger]
   Put #filenum As Long, [position As LongInt], data As String
   Put #filenum As Long, [position As LongInt], data() As Any

Usage
   Put #filenum, position, data [, amount]
   varres = Put (#filenum, position, data [, amount])

Parameters
   filenum
      The value passed to Open when the file was opened.
   position
      Is the position where Put must start in the file. If the file was 
      opened For Random, the position is in records, else it is given in 
      bytes. If omitted, writing starts at the present file pointer 
      position.  The position is 1-based: i.e. the first record or byte of 
      a file is at position 1.
      If position is omitted or zero (0), file writing will start from the 
      current file position.
   data
      Is the buffer where data is written from. It can be a numeric 
      variable, a string, an array or a user-defined type (including 
      referenced by This). The operation will try to transfer to disk the 
      complete variable, unless amount is given. For a user-defined type 
      instance, the data impacted is only the non-static data members.
      When putting arrays, data should be followed by an empty pair of 
      brackets: '()'.  Put will write all of the data in the array.  amount 
      is not allowed.
      When putting Strings, the number of bytes written is the same as the 
      number of bytes in the string data.  amount is not allowed.
      Note: If you want to write values from a buffer, you should NOT pass 
      a pointer to the buffer; instead you should pass the first variable 
      in the buffer (this can be done by dereferencing the pointer with 
      Operator * (Value Of)). If you pass a pointer directly, then Put will 
      put the memory from the pointer variable, not the memory it points 
      to.
   amount
      Makes Put write to file amount consecutive variables to the file - 
      i.e. it writes ( amount * SizeOf(data) ) bytes of data, starting at 
      data's location in memory, into the file.  If amount is omitted it 
      defaults to 1, meaning that Put just writes a single variable.

Return Value
   Put() returns a 32 bit Long: 0 on success; nonzero on error. "disk full" 
   is considered as an error, and results in return code 3. An "exact" 
   amount of data written before is not available, and wouldn't be really 
   useful anyway. 

Description
   Writes binary data from a buffer variable to a file opened in Binary or 
   Random mode.

   Put can be used as a function, and will return 0 on success or an error 
   code on failure.	

   For files opened in Random mode, the size in bytes of the data to write 
   must match the specified record size.

   Note:
      - If a real [w/z]string variable is passed to Put, the amount 
      parameter should be forbidden as it is when passing a string. Do not 
      use. Otherwise, it is dangerously used to multiply the string length 
      to be written to the file, but possibly by overflowing outside the 
      provided [w/z]string buffer.
      - If a dereferenced [w/z]string pointer is passed to Put, the amount 
      parameter is not taken into account as it is when passing a 
      dereferenced numeric pointer. Do not use. But instead of respecting 
      the amount parameter, the pointed buffer is written to the file up to 
      the zero element (terminal element which is excluded).
      - For finer granularity, any [w/z]string variable can be safely 
      passed to Put as numeric buffer by providing the first numeric 
      element (an indexed [w/z]string variable, or a dereferenced 
      [w/z]string pointer then indexed) and the number of numeric elements 
      to be processed.

   Note:
      - Using Put # is naturally dedicated to Binary/Random Access file 
      mode.
      - It is also allowed in Ouput/Append Access file mode, but this was 
      never well tested and results may vary.

Example
   ' Create variables for the file number, and the number to put
   Dim As Long f
   Dim As Long value

   ' Find the first free file number
   f = FreeFile()

   ' Open the file "file.ext" for binary usage, using the file number "f"
   Open "file.ext" For Binary As #f

     value= 10

     ' Write the bytes of the integer 'value' into the file, using file number "f"
     ' starting at the beginning of the file (position 1)
     Put #f, 1, value

   ' Close the file
   Close #f

   ' Create an integer array
   Dim buffer(1 To 10) As Integer
   For i As Integer = 1 To 10
      buffer(i) = i
   Next

   ' Find the first free file file number
   Dim f As Long
   f = FreeFile()

   ' Open the file "file.ext" for binary usage, using the file number "f"
   Open "file.ext" For Binary As #f
   ' Write the array into the file, using file number "f"
   ' starting at the beginning of the file (position 1)
   Put #f, 1, buffer()

   ' Close the file
   Close #f

   Dim As Byte Ptr lpBuffer
   Dim As Long hFile
   Dim As Integer Counter
   Dim As UInteger Size

   Size = 256

   lpBuffer = Allocate(Size)
   For Counter = 0 To Size-1
     lpBuffer[Counter] = (Counter And &HFF)
   Next

   ' Get free file file number
   hFile = FreeFile()

   ' Open the file "test.bin" in binary writing mode
   Open "test.bin" For Binary Access Write As #hFile

     ' Write 256 bytes from the memory pointed to by lpBuffer
     Put #hFile, , lpBuffer[0], Size

   ' Close the file
   Close #hFile

   ' Free the allocated memory
   Deallocate lpBuffer

   ' 'THIS' can be used as argument for writing/filling all non-static data of an UDT instance to/from a file

   Type UDT
      Dim As String * 32 s
      Dim As Double d
      Declare Sub Save(ByRef filename As String)
      Declare Sub Load(ByRef filename As String)
   End Type

   Sub UDT.Save(ByRef filename As String)
      Dim As Integer f
      f = FreeFile()
      Open filename For Binary As #f
      Put #f, , This  '' writes all non-static data of the UDT instance to the file
      Close #f
   End Sub

   Sub UDT.Load(ByRef filename As String)
      Dim As Integer f
      f = FreeFile()
      Open filename For Binary As #f
      Get #f, , This  '' fills all non-static data of the UDT instance from the file
      Close #f
   End Sub

   Dim As UDT u1
   u1.s = "PI number"
   u1.d = 3.14159
   u1.Save("file.ext")

   Dim As UDT u2
   u2.Load("file.ext")
   Print u2.s
   Print u2.d

Differences from QB
   * Put can write full arrays as in VB or, alternatively, write a 
     multiple of the data size from buffer's memory location.
   * Put can be used as a function in FB, to find the success/error code 
     returned without having to use error handling procedures.

See also
   * Put (Graphics) different usage of same keyword 
   * Get (File I/O)
   * Open
   * Close
   * Random
   * Binary
   * FreeFile




============================================================================
    R

----------------------------------------------------------- KeyPgRandom ----
Random

Specifies file or device to be opened for random access mode

Syntax
   Open filename for Random [Access access_type] [Lock lock_type] as [#]
   filenum [Len = record_length]

Parameters
   filename
      file name to open
   access_type
      indicates whether the file may be read from, written to or both
   lock_type
      locking to be used while the file is open
   filenum
      unused file number to associate with the open file
   record_length
      the size of the record used for the file

Description
   Opens a file or device for reading and/or writing binary data in the 
   given file filenum, with records of size record_length.
   If the file does not exist, a new file will be created, otherwise any 
   data existing in the file is preserved by Open.  The file pointer is 
   initialized by Open at the start of the file, at record number 1. File 
   operations move the file position in steps of record_length bytes.
   This file mode uses an user-defined Type buffer variable to read/write 
   full records in a file. The buffer variable uses to include several 
   fields.
   The data is saved in binary mode, in the same internal format FreeBASIC 
   uses, by means of Get # and Put #.

   filename must be string expression resulting in a legal file name in the 
   target OS, without wildcards. The file will be sought for in the present 
   directory, unless a path is given.

   Access_type - By default Random mode allows to both read and write the 
   file, unless an Access type is specified, it must be one of:
      * Read - the file is opened for input only
      * Write - the file is opened for output only
      * Read Write - the file is opened for input and output (the default)

   Lock_type indicates the way the file is locked for other processes 
   (users or threads), it is one of:
      * Shared - The file can be freely accessed by other processes     
      * Lock Read - The file can't be opened simultaneously for reading
      * Lock Write - The file can't be opened simultaneously for writing
      * Lock Read Write - The file cannot be opened simultaneously by 
        other processes.
      If no lock type is stated, the file will be Shared for other threads 
      of the program and Lock Read Write for other programs.
      Lock and Unlock can be used to restrict temporally access to parts of 
      a file.

   filenum is a valid FreeBASIC file number (in the range 1..255) not being 
   used for any other file presently open. This number identifies the file 
   for the rest of file operations. A free file number can be found using 
   the FreeFile function.

   record_length is the amount of bytes the file pointer will move for each 
   individual Get and Put, it must match the size of the buffer variable 
   used when Getting and Putting data. If omitted, it defaults to 128.

Example
   '' This example generates a test file and then lets you view random records
   '' that are read live from the file.

   Type Entry
      slen As Byte
      sdata As String * 10
   End Type

   Dim u As Entry
   Dim s As String

   Open "testfile" For Random As #1 Len = SizeOf(Entry)

   '' Write out 9 records with predefined data
   For i As Integer = 1 To 9
      Read s
      u = Type( Len(s), s )
      Put #1, i, u
   Next

   Data ".,-?!'@:", "abc",      "def"
   Data "ghi",      "jkl",      "mno"
   Data "pqrs",     "tuv",      "wxyz"

   '' Let the user view records by specifying their index number
   Do
      Dim i As Integer
      Input "Record number: ", i
      If i < 1 Or i > 9 Then Exit Do

      Get #1, i, u
      Print i & ": " & Left( u.sdata, u.slen )
      Print
   Loop

   Close #1

   Type ScoreEntry Field = 1
      As String * 20 Name
      As Single score
   End Type

   Dim As ScoreEntry entry

   '' Generate a fake boring highscore file
   Open "scores.dat" For Random Access Write As #1 Len = SizeOf(entry)
   For i As Integer = 1 To 10
      entry.name = "Player " & i
      entry.score = i
      Put #1, i, entry
   Next
   Close #1

   '' Read out and display the entries
   Open "scores.dat" For Random Access Read As #1 Len = SizeOf(entry)
   For i As Integer = 1 To 10
      Get #1, i, entry
      Print i & ":", entry.name, Str(entry.score), entry.score
   Next
   Close #1

Differences from QB
   * Care must be taken with dynamic or fixed length strings inside user 
     defined types (UDT), see the warning at Type.
   * The keyword Field can only be used with Type to specify the packing 
     of the UDT. 

See also
   * Open
   * Binary
   * Get #
   * Put #



-------------------------------------------------------- KeyPgRandomize ----
Randomize

Seeds the random number generator

Syntax
   Declare Sub Randomize ( ByVal seed As Double = -1.0, ByVal algorithm As 
   Long = 0 )

Usage
   Randomize [ seed ][, algorithm ]

Parameters
   seed
      A Double seed value for the random number generator, but the 
      fractional part is clipped for all algorithms except algorithm #4 
      (see below). If omitted, a value based on Timer will be used instead.
   algorithm
      An integer value to select the algorithm (see the standard header 
      "fbprng.bi" for available algorithms). If omitted, the default 
      algorithm for the current language dialect is used.

Description
   Sets the random seed that helps Rnd generate random numbers, and selects 
   the algorithm to use.
   The constants for algorithm are defined in fbprng.bi. In the -lang fb 
   dialect, these constants are part of the FB Namespace.
   Valid values for algorithm are:
      FB_RND_AUTO (0) - Default for current language dialect. This is 
      algorithm FB_RND_MTWIST (3) in the -lang fb dialect, FB_RND_QB (4) in 
      the -lang qb dialect and FB_RND_CRT (1) in the -lang fblite dialect.
      FB_RND_CRT (1) - Uses the C runtime library's rand() function. This 
      will give different results depending on the platform.
      FB_RND_FAST (2) - Uses a fast implementation. This should be stable 
      across all platforms, and provides 32-bit granularity, reasonable 
      degree of randomness.
      FB_RND_MTWIST (3) - Uses the Mersenne Twister. This should be stable 
      across all platforms, provides 32-bit granularity, and gives a high 
      degree of randomness.
      FB_RND_QB (4) - Uses a function that is designed to give the same 
      random number sequences as QBASIC. This should be stable across all 
      platforms, and provides 24-bit precision, with a low degree of 
      randomness.
      FB_RND_REAL (5) - Available on Win32 and Linux, using system features 
      (Win32 Crypto API, Linux /dev/urandom) to provide cryptographically 
      random numbers. If those system APIs are unavailable, algorithm 
      FB_RND_MTWIST (3) will be used instead.

      For any given seed, each algorithm will produce a specific, 
      deterministic sequence of numbers for that seed. If you want each 
      call to Randomize to produce a different sequence of numbers, a seed 
      that is not quite predictable should be used - for example, the value 
      returned from Timer. Omitting the seed parameter will use a value 
      based on this.

      Note: for all algorithms except algorithm #4, because the fractional 
      part of the seed is clipped, the using the Timer value directly as a 
      parameter will produce the same seed if used more than once in the 
      same second. However, it is generally not worth calling Randomize 
      twice with unpredictable seeds anyway, because the second sequence 
      will be no more random than the first, or even possibly worse by 
      inducing sequence overlapping. In most cases, the Mersenne twister 
      should provide a sufficiently random sequence of numbers, without 
      requiring reseeding between Rnd calls.

      When you call Randomize with the QB compatible algorithm, part of the 
      old seed is retained. This means that if you call Randomize several 
      times with the same seed, you will not get the same sequence each 
      time. To get a specific sequence in QB compatible mode, set the seed 
      by calling Rnd with a negative parameter.

      Note:
            Randomize is thread-safe (by using an internal mutex), but not 
            thread specific.
            Unfinished structures for other random number generators are 
            also available in the standard header "fbprng.bi".

Example
   '' Seed the RNG to the method using C's rand()
   Randomize , 1

   '' Print a sequence of random numbers
   For i As Integer = 1 To 10
      Print Rnd
   Next
      

Version
   * Before fbc 1.10.0 (for fbc 1.08.0 and fbc 1.09.0), "fbprng.bi" was 
     named "fbmath.bi".
   * Before fbc 1.08.0:
      The standard "fbmath.bi" header for available algorithms did not 
      exist.
      Randomize was not thread-safe.

Dialect Differences
   The default algorithm used depends on the current dialect in use:
      * With the -lang fb dialect, a 32 bit Mersenne Twister function with 
        a granularity of 32 bits is used.
      * With the -lang qb dialect, a function giving the same output as Rnd
        in QB is used. The granularity is 24 bits.
      * With the -lang deprecated and -lang fblite dialects, the function 
        in the C runtime available in the system is used. The function has 
        a granularity of 15 bits in Win32, and 32 bits in Linux and DOS.

Differences from QB
   * The algorithm parameter is new to FreeBASIC.
   * QBASIC only had one algorithm (replicated in FB in algorithm number 4
     , and set as the default in the -lang qb dialect).

See also
   * Rnd
   * Language dialects



------------------------------------------------------------- KeyPgRead ----
Read

Reads values stored with the Data statement.

Syntax
   Read variable_list

Description
   Reads data stored in the application with the Data command. 

   The elements of the variable_list must be of basic types, numeric, 
   strings or elements of arrays and user defined types.

   All the Data statements in the program behave as a single list, after 
   the last element of one Data statement is read, the first element of the 
   following Data statement will be read.
   The program should not attempt to Read after the last Data element.  The 
   results are (in all dialects) undefined,  and the program may crash 
   (Page Fault).

   Data constants can only be of simple types (numeric or string).  A 
   string read into a numeric variable will be evaluated by the Val 
   function.

   The "Restore label" statement makes the first Data item after label the 
   next item to be read, allowing the user to choose specific sections of 
   data to be read.

Example
   ' Create an array of 5 integers and a string to hold the data.
   Dim As Integer h(4)
   Dim As String hs
   Dim As Integer readindex

   ' Set up to loop 5 times (for 5 numbers... check the data)
   For readindex = 0 To 4

     ' Read in an integer.
     Read h(readindex)

     ' Display it.
     Print "Number" ; readindex ; " = " ; h(readindex)

   Next readindex

   ' Spacer.
   Print

   ' Read in a string.
   Read hs

   ' Print it.
   Print  "String = " + hs

   ' Await a keypress.
   Sleep

   ' Exit program.
   End

   ' Block of data.
   Data 3, 234, 4354, 23433, 87643, "Bye!"

Dialect Differences
   * None in syntax and usage of Read
   * See the Data page for more information on differences in storing the 
     data

Differences from QB
   * None in syntax and usage of Read
   * See the Data page for more information on differences in storing the 
     data

See also
   * Data
   * Restore



--------------------------------------------------------- KeyPgReadFile ----
Read (File Access)

File access specifier

Syntax
   Open filename As String For Binary Access Read As #filenum As Integer

Description
   Specifier for the Access clause in the Open statement.  Read specifies 
   that the file is accessible for input.

Example
   See example at Access

Differences from QB
   * None known.

See also
   * Access
   * Open



---------------------------------------------------- KeyPgReadWriteFile ----
Read Write (File Access)

File access specifier

Syntax
   Open filename As String For Binary Access Read Write As #filenum As 
   Integer

Description
   Specifier for the Access clause in the Open statement.  Read Write 
   specifies that the file is accessible for both input and output.

Example
   See example at Access

Differences from QB
   * None known.

See also
   * Access
   * Open



------------------------------------------------------- KeyPgReallocate ----
Reallocate

Reallocates storage for an existing reserved block of memory

Syntax
   Declare Function Reallocate cdecl ( ByVal pointer As Any Ptr, ByVal 
   count As UInteger ) As Any Ptr

Usage
      result = Reallocate( pointer, count )

Parameters
   pointer
      The address of allocated memory to be reallocated.
   count
      The number of bytes, in total, to be reallocated.

Return Value
   The address of the reallocated memory. A null (0) pointer is returned if 
   reallocation was unsuccessful, and the original memory pointed to by 
   pointer remains unchanged.

Description
   Reallocates memory previously allocated with Allocate or CAllocate. The 
   contents of the buffer are preserved, although if count is less than the 
   original size of the memory block, the buffer will be truncated. If the 
   size is increased, the added memory range is not initialized to 
   anything.

   The reallocation first attempts to resize the memory already allocated 
   without moving its starting address in order to avoid recopying the data 
   to be kept (returned pointer value unchanged). If this is not possible, 
   a new separate memory area is allocated with recopy of the data to be 
   kept before deallocating the old memory area (returned pointer value 
   modified).

   When using Reallocate, the result pointer must be saved to prevent a 
   potential memory leak, because the original pointer may no longer be 
   valid after reallocation.  The value of the new pointer should be 
   checked - if it is 0, the reallocation has failed - the original pointer 
   remains valid, and the amount of memory allocated to it has not changed.

   Reallocated memory must be freed with Deallocate when no longer needed.

   If pointer is null (0), then ReAllocate behaves identically to Allocate. 
   If pointer is valid and count is null (0), then ReAllocate behaves 
   similar to Deallocate and a null (0) pointer is returned.

   If the memory has previously been deallocated by a call to Deallocate or 
   ReAllocate, the behavior is undefined.

   When manually allocating memory for String descriptors (or Udts that 
   contain one), if count is larger than the original size of the memory 
   block, the new extra memory range must be explicitly cleared to zeroes 
   before the first string use (for example, using Clear).  Otherwise 
   accessing the string will cause undefined results (trying to write or 
   read at a random place in memory, or trying to deallocate a random 
   pointer).

   Note:
      Reallocate cannot be used inside a member procedure if pointer points 
      to the instance itself of the object, because that could cause 
      horrible crashes:
         * If pointer is modified by Reallocate (object data moved into 
           memory), the passed This reference becomes inconsistent, in the 
           same way as a dangling pointer.
         * In that case, all subsequent accesses to any non-static member 
           field from this member procedure will be erroneous, except if 
           the passed This reference would be readjusted (by means of @This 
           = new pointer value) immediately after executing Reallocate in 
           the body of this member procedure.

Example
   Dim a As Integer Ptr, b As Integer Ptr, i As Integer

   a = Allocate( 5 * SizeOf(Integer) )   ' Allocate memory for 5 integers

   If a = 0 Then Print "Error Allocating a": End

   For i = 0 To 4
     a[i] = (i + 1) * 2   ' Assign integers to the buffer
   Next i

   b = Reallocate( a, 10 * SizeOf(Integer) )   ' Reallocate memory for 5 additional integers

   If b <> 0 Then

      a = b   ' Discard the old pointer and use the new one

      For i = 5 To 9
        a[i] = (i + 1) * 2   ' Assign more integers to the buffer
      Next i

      For i = 0 To 9   ' Print the integers
        Print i, a[i]
      Next i
      Print

   Else '' Reallocate failed, memory unchanged

      Print "Error Reallocating a"

      For i = 0 To 4   ' Print the integers
        Print i, a[i]
      Next i
      Print

   End If

   Deallocate a   ' Clean up
      

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Reallocate.

Differences from QB
   * New to FreeBASIC

See also
   * Allocate
   * CAllocate
   * Deallocate



------------------------------------------------------------ KeyPgRedim ----
ReDim

Defines or resizes a variable-length array

Syntax
   Declaring a Dynamic Array:
      ReDim [ Shared ] symbolname([subscript [, ...]]) As datatype [, ...]
      ReDim [ Shared ] As datatype symbolname([subscript [, ...]]) [, ...]

   Resizing a Dynamic Array:
      ReDim [ Preserve ] symbolname([subscript [, ...]]) [, ...]
   or:
      ReDim [ Preserve ] [ ( ] expression [ ) ] ([subscript [, ...]]) [, 
      ...]

Parameters
   Shared
      Specifies shared (file-scope) access to the array throughout the 
      module.
   Preserve
      When used with an existing array, the contents of the array will be 
      preserved during the resize. Note that in some cases Preserve will 
      not preserve data at its original index, see below.
   symbolname
      A new or existing array identifier.
   expression or (expression)
      An expression referring to an existing array. This can be used to 
      resize arrays which are members of user-defined types. In some cases, 
      it is necessary to specify parentheses around the expression 
      (especially if the array expression itself contains parentheses) - 
      see the examples below.
   subscript: [ lowerbound To ] upperbound
      The lower and upper bound range for a dimension of the array. Lower 
      bound defaults to zero (0), or the default Base, if not specified.
   datatype
      The type of elements contained in the array.

Description
   ReDim can be used to define new variable-length arrays, or resize 
   existing variable-length arrays while keeping the same number of 
   dimensions. ReDim always produces variable-length arrays, so, unlike Dim
   , variable-length arrays can be defined with constant subscripts.

   When defining a new variable-length array, its elements are default 
   constructed. For simple data types like Integer or Double, the elements 
   are initialized to zero (0). For user-defined types with a default 
   constructor, that will be called.

   When used with in a user-defined type, ReDim creates variable-length 
   arrays while being able to pre-size them with constant subscripts.

   NOTES: 
      * ReDim Preserve may not work as expected in all cases:
         * Preserve's current behavior is to keep the original data 
           contiguous in memory, and only expand or truncate the size of 
           the memory (if resizing is not possible, the whole original data 
           block is first shifted to another memory location).
         * Its behavior (with a single dimension) is well-defined only 
           when the upper bound is changed.  If the lower bound is changed, 
           the current result is that the data is in effect shifted to 
           start at the new lower bound.
         * With multiple dimensions, only the upper bound of only the 
           first dimension may be safely increased.  If the first dimension 
           is reduced, the existing mappable data may be lost. If 
           lower-order dimensions are resized at all, the effects can be 
           hard to predict (because multidimensional arrays are stored in 
           row-major order : values differing only in the last index are 
           contiguous).
      * ReDim cannot be used on fixed-size arrays - i.e. arrays with 
        constant bounds made with Dim:
         * This includes the fixed-size arrays contained in UDTs 
           (user-defined Types).
         * This also includes fixed-length arrays passed as parameters in 
           a procedure: FreeBASIC cannot prevent you trying this at 
           compile-time, but generates an error at run-time.
      * ReDim cannot be used inside a member procedure if the array 
        contains as element the instance itself of the object, because that 
        could cause horrible crashes:
         * If the array data are moved into memory by ReDim, the passed 
           This reference becomes inconsistent, in the same way as a 
           dangling pointer.
         * In that case, all subsequent accesses to any non-static member 
           field from this member procedure will be erroneous, except if 
           the passed This reference would be readjusted (by means of @This 
           = @array(...)) immediately after executing ReDim in the body of 
           this member procedure.

Example
   '' Define a variable-length array with 5 elements
   ReDim array(0 To 4) As Integer

   For index As Integer = LBound(array) To UBound(array)
      array(index) = index
   Next

   '' Resize a variable-length array with 10 elements 
   '' (the lower bound should be kept the same)
   ReDim Preserve array(0 To 9)

   Print "index", "value"
   For index As Integer = LBound(array) To UBound(array)
      Print index, array(index)
   Next

   This program will produce the following output:

   index         value
    0             0
    1             1
    2             2
    3             3
    4             4
    5             0
    6             0
    7             0
    8             0
    9             0

   '' Define a variable-length array
   Dim array() As Integer

   '' ReDim array to have 3*4 elements
   ReDim array(1 To 3, 1 To 4)

   Dim As Integer n = 1, i, j

   Print "3 * 4:"
   Print
   For i = LBound(array, 1) To UBound(array, 1)
      For j = LBound(array, 2) To UBound(array, 2)
         array(i, j) = n
         Print Using "##  "; array(i, j);
         n += 1
      Next
      Print
   Next
   Print

   '' ReDim Preserve array to have 4*4 elements, preserving the contents
   '' (only the first upper bound should be changed)
   ReDim Preserve array(1 To 4, 1 To 4)

   Print "4 * 4:"
   Print
   For i = LBound(array, 1) To UBound(array, 1)
      For j = LBound(array, 2) To UBound(array, 2)
         Print Using "##  "; array(i, j);
      Next
      Print
   Next
   Print

   '' ReDim Preserve array to have 2*4 elements, preserving but trancating the contents
   '' (only the first upper bound should be changed)
   ReDim Preserve array(1 To 2, 1 To 4)

   Print "2 * 4:"
   Print
   For i = LBound(array, 1) To UBound(array, 1)
      For j = LBound(array, 2) To UBound(array, 2)
         Print Using "##  "; array(i, j);
      Next
      Print
   Next
   Print

   This program will produce the following output:

   3 * 4:

    1   2   3   4
    5   6   7   8
    9  10  11  12

   4 * 4:

    1   2   3   4
    5   6   7   8
    9  10  11  12
    0   0   0   0

   2 * 4:

    1   2   3   4
    5   6   7   8

   '' Define a variable-length array as UDT field
   Type UDT
      Dim As Integer array(Any)
   End Type

   Dim As UDT u(0 To 3)

   '' For use of Redim with a complex array expression
   '' (especially if the array expression itself contains parentheses),
   '' the array expression must be enclosed in parentheses
   '' in order to solve the parsing ambiguity:
   ''    Redim u(0).array(0 To 9)
   ''    induces error 4: Duplicated definition, u in 'Redim u(0).array(0 To 9)'
   ReDim (u(0).array)(0 To 9)

Differences from QB
   * Preserve was in Visual Basic, but not in QBASIC.
   * Multi-dimensional arrays in FreeBASIC are in row-major order, rather 
     than column-major order.

See also
   * Common
   * Dim
   * Erase
   * Extern
   * LBound
   * Preserve
   * Shared
   * Static
   * UBound
   * Var



-------------------------------------------------------------- KeyPgRem ----
Rem

Indicates comments in the source code.

Syntax
   Rem comment

   ' Comment

   /' Multi-line
      comment '/

Description
   A source code line beginning with Rem indicates that the line is a 
   comment and will not be compiled.  

   The single quote character (') may also be used to indicate a comment 
   and may appear after other keywords on a source line.

   Multi-line comments are marked with the tokens /' and '/.  All text 
   between the two markers is considered comment text and is not compiled.

Example
   /' this is a multi line 
   comment as a header of
   this example '/

   Rem This Is a Single Line comment

   ' this is a single line comment

   ? "Hello" : Rem comment following a statement

   Dim a As Integer ' comment following a statement

   ? "FreeBASIC" : ' also acceptable 

   Dim b As /' can comment in here also '/    Integer

   #if 0
      This way of commenting Out code was
      required before version 0.16
   #endif

Differences from QB
   * Rem may also appear after other keywords on a source line in 
     FreeBASIC
   * Multiline comments are new to FreeBASIC

See also
   * #if



------------------------------------------------------------ KeyPgReset ----
Reset

Closes all open files, or resets standard I/O handles.

Syntax
   Declare Sub Reset ( )
   Declare Sub Reset ( ByVal streamno As Long )

Usage
   Reset
or
   Reset( streamno )

Parameters
   streamno
      The stream number to reset, 0 for stdin or 1 for stdout.

Description
   Reset, when called with no arguments, closes all disk files.

   Reset, when called with the streamno argument, will reset the redirected 
   or piped streams associated with stdin (0), or stdout (1).

Runtime errors:
   Reset(streamno) can set one of the following runtime errors:

   (1) Illegal function call
      * streamno was neither 0 nor 1

   (3) File I/O error
      * Resetting of stdin or stdout failed

Example
   Open "test.txt" For Output As #1
   Print #1, "testing 123"
   Reset

   Dim x As String

   '' Read from STDIN from piped input
   Open Cons For Input As #1
   While EOF(1) = 0
     Input #1, x
     Print """"; x; """"
   Wend
   Close #1

   '' Reset to read from the keyboard
   Reset(0)

   Print "Enter some text:"
   Input x

   '' Read from STDIN (now from keyboard)
   Open Cons For Input As #1
   While EOF(1) = 0
     Input #1, x
     Print """"; x; """"
   Wend
   Close #1

      Note: Under Windows, to specify to the program that data entry is 
      completed (transfer EOF), you can press CTRL+Z then press ENTER.

Differences from QB
   * None for Reset().
   * The Reset(streamno) usage is new to FreeBASIC.

See also
   * Close
   * Open
   * Open Cons
   * IsRedirected



----------------------------------------------------- KeyPgSfxGenerated ----
Generated Sound Commands

Commands for generated sound, PLAY strings, and sfxlib mix settings.

Syntax
   Beep [ duration, pitch ]
   Sound frequency, duration
   Sound channel, frequency, duration, volume
   Tone channel, frequency, duration
   Noise channel, duration, volume
   Noise channel, frequency, duration, volume
   Note name, octave, duration
   Note channel, name, octave, duration
   Play music
   Play channel, music
   Play music1, music2
   Play music1, music2, music3
   Tempo bpm
   bpm = Tempo()
   Channel channel
   channel = Channel()
   Octave octave
   octave = Octave()
   Voice instrument
   instrument = Voice()
   Vol level
   Volume level
   level = Volume()
   Volume channel, level
   level = Volume( channel )
   Balance position
   position = Balance()
   Pan channel, position
   position = Pan( channel )
   Wave id, waveform
   Envelope id, attack, decay, sustain, release
   Instrument id, wave_id, envelope_id
   Instrument channel, instrument_id

Description
   These commands synthesize sound directly through sfxlib.  Sound, Tone, 
   Noise, Note, and Play create voices.  Tempo, Channel, Octave, and Voice 
   set defaults used by PLAY-string and generated-sound commands.  Volume, 
   Vol, Balance, and Pan control mix levels and stereo placement.

   Sound accepts the high-impact classic form Sound frequency, duration and
   the explicit channel form Sound channel, frequency, duration, volume.
   When both arguments are integers, duration is interpreted as the PC BASIC
   timer-tick value.

   Wave defines a waveform id.  The currently supported waveform values 
   are:
      * 0 sine
      * 1 square
      * 2 triangle
      * 3 saw
      * 4 noise

   Envelope defines an ADSR envelope using seconds for attack, decay, and 
   release, and a 0.0 to 1.0 sustain level.  Instrument can define an 
   instrument from a waveform and envelope, or assign an instrument to a 
   channel.

   The channel-oriented commands use sfxlib's channel table.  Channels are 
   zero-based.

Example
   See examples/sfxlib/basics-01-generated-sound.bas, 
   examples/sfxlib/basics-02-play-strings.bas, 
   examples/sfxlib/basics-03-channels-mix.bas, 
   examples/sfxlib/basics-04-instruments.bas, and 
   examples/sfxlib/showcase.bas.

Platform Differences
   * On headless or diagnostic runs, SFXLIB_DRIVER=null can be set before 
     program startup to use the null output driver.

Differences from QB
   * New to FreeBASIC.

See also
   * Beep
   * Music
   * Sfx
   * Sound Library Reference



---------------------------------------------------------- KeyPgRestore ----
Restore

Changes the next read location for values stored with the Data statement.

Syntax
   Restore [label]

Description
   Sets the next-data-to-read pointer to the first element of the first Data
   statement after the label.  The label must be contained in the same 
   module as the currently-executing code.  Restore alters the normal top 
   to bottom order in which Data are Read. It allows re-reading some Data 
   or using multiple sets of Data in a single module.	
   If label is omitted, the next-data-to-read pointer is set to the first 
   Data statement found in the module.

Example
   ' Create an 2 arrays of integers and a 2 strings to hold the data.
   Dim h(4) As Integer
   Dim h2(4) As Integer
   Dim hs As String
   Dim hs2 As String
   Dim read_data1 As Integer
   Dim read_data2 As Integer

   ' Set the data read to the label 'dat2:'
   Restore dat2

   ' Set up to loop 5 times (for 5 numbers... check the data)
   For read_data1 = 0 To 4

     ' Read in an integer.
     Read h(read_data1)

     ' Display it.
     Print "Bloc 1, number"; read_data1;" = "; h(read_data1)

   Next

   ' Spacer.
   Print

   ' Read in a string.
   Read hs

   ' Print it.
   Print  "Bloc 1 string = " + hs

   ' Spacers.
   Print
   Print

   ' Set the data read to the label 'dat1:'
   Restore dat1

   ' Set up to loop 5 times (for 5 numbers... check the data)
   For read_data2 = 0 To 4

     ' Read in an integer.
     Read h2(read_data2)

     ' Display it.
     Print "Bloc 2, number"; read_data2;" = "; h2(read_data2)

   Next

   ' Spacer.
   Print

   ' Read in a string.
   Read hs2

   ' Print it.
   Print  "Bloc 2 string = " + hs2

   ' Await a keypress.
   Sleep

   ' Exit program.
   End

   ' First block of data.
   dat1:
   Data 3, 234, 4354, 23433, 87643, "Bye!"

   ' Second block of data.
   dat2:
   Data 546, 7894, 4589, 64657, 34554, "Hi!"

Differences from QB
   * None

See also
   * Data
   * Read
   * Labels



----------------------------------------------------------- KeyPgResume ----
Resume

Error handling statement to resume execution after a jump to an error 
handler

Syntax
   Resume

Description
   Resume is used in the traditional QB error handling mechanism within an 
   error handler (called by On Error) to return execution to the line that 
   caused the error.  Usually this is used after the error has been handled 
   gracefully in order to try the previously erroneous operation again with 
   corrected data.

   Resume resets the Err value to 0

Example
   '' Compile with -lang fblite or qb

   #lang "fblite"

   Dim As Single i, j

   On Error Goto ErrHandler

   i = 0
   j = 1 / i ' this line causes a divide-by-zero error on the first try; execution jumps to ErrHandler label

   Print j ' after the value of i is corrected, prints 0.5

   End ' end the program so that execution does not fall through to the error handler again

   ErrHandler:

   i = 2
   Resume ' execution jumps back to 'j = 1 / i' line, which does not cause an error this time

Dialect Differences
   *  RESUME is not supported in the -lang fb dialect. Statements can be 
     used in its function form to return an error code
   If Open( "text" For Input As #1 ) <> 0 Then
     Print "Unable to open file"
   End If

 

Differences from QB
   * Does not accept line numbers or labels
   * Must compile with -ex or -exx option

See also
   * Err
   * Resume Next
   * Error Handling



------------------------------------------------------- KeyPgResumenext ----
Resume Next

Error handling statement to resume execution after a jump to an error 
handler

Syntax
   Resume Next

Description
   Resume Next is used in the traditional QB error handling mechanism 
   within an error handler (called by On Error) to return execution to the 
   line after the one that caused the error.  Usually this is used to avoid 
   executing the same line and causing the error again.

   Resume Next resets the Err value to 0

Example
   '' Compile with -lang fblite or qb

   #lang "fblite"

   Dim As Single i, j

   On Error Goto ErrHandler

   i = 0
   j = 5
   j = 1 / i ' this line causes a divide-by-zero error; execution jumps to ErrHandler label

   Print "ending..."

   End ' end the program so that execution does not fall through to the error handler again

   ErrHandler:

   Resume Next ' execution jumps to 'Print "ending..."' line, but j is now in an undefined state

Dialect Differences
   *  RESUME NEXT is not supported in the -lang fb dialect. Statements can 
     be used in its function form to return an error code
   If Open( "text" For Input As #1 ) <> 0 Then
     Print "Unable to open file"
   End If

 

Differences from QB
   * Must compile with -ex or -exx option

See also
   * Err
   * Resume
   * Error Handling



----------------------------------------------------------- KeyPgReturn ----
Return (From Procedure)

Control flow statement to return from a procedure or GoSub.

Syntax
   Return expression

Description
   Return is used to return from a procedure.

   Because Return could mean return-from-gosub or return-from-procedure, 
   Option Gosub and Option Nogosub can be used to enable and disable GoSub 
   support.  When GoSub support is disabled, Return is then recognized as 
   return-from-procedure.  When GoSub support is enabled, Return is then 
   recognized as return-from-gosub.

   Return (from procedure) is used inside a procedure to exit the procedure 
   possibly with a return value:
      * A Sub cannot specify a return return value. Return is roughly 
        equivalent to the Exit Sub idiom.
      * In a Function, Return must specify its return value.  Return 
        expression is roughly equivalent to the Function = expression : Exit
        Function idiom.
            Warning: Whatever the output branch used, the return value must 
            be always defined, otherwise an unexpected behavior may occur.

Example
   '' Return from function

   Type rational              '' simple rational number type
      numerator As Integer
      denominator As Integer
   End Type

   '' multiplies two rational types
   Function rational_multiply( r1 As rational, r2 As rational ) As rational

      Dim r As rational
      '' multiply the divisors ...
      r.numerator   = r1.numerator   * r2.numerator
      r.denominator = r1.denominator * r2.denominator

      '' ... and return the result
      Return r

   End Function

   Dim As rational r1 = ( 6, 105 )   '' define some rationals r1 and r2
   Dim As rational r2 = ( 70, 4 )
   Dim As rational r3

   r3 = rational_multiply( r1, r2 )  '' multiply and store the result in r3

   '' display the expression
   Print r1.numerator & "/" & r1.denominator; " * ";
   Print r2.numerator & "/" & r2.denominator; " = ";
   Print r3.numerator & "/" & r3.denominator

Dialect Differences
   * In the -lang fb dialect Return always means return-from-procedure.
   * In the -lang qb dialect, Return means return-from-gosub by default 
     unless changed with Option Nogosub, in which case the compiler will 
     recognize Return as return-from-procedure.
   * In the -lang fblite dialect, Return means return-from-procedure by 
     default unless changed with Option Gosub, in which case the compiler 
     will recognize Return as return-from-gosub.

Differences from QB
   * None when using the -lang qb dialect.

See also
   * Sub
   * Function
   * GoSub
   * Option Gosub
   * Option Nogosub
   * Labels
   * Return (From Gosub)



------------------------------------------------------ KeyPgReturnGosub ----
Return (From Gosub)

Control flow statement to return from a procedure or GoSub.

Syntax
   Return [ label ]

Description
   Return is used to return from a gosub GoSub.

   Because Return could mean return-from-gosub or return-from-procedure, 
   Option Gosub and Option Nogosub can be used to enable and disable GoSub 
   support.  When GoSub support is disabled, Return is then recognized as 
   return-from-procedure.  When GoSub support is enabled, Return is then 
   recognized as return-from-gosub.

   Return (from gosub) is used to return control back to the statement 
   immediately following a previous GoSub call. When used in combination 
   with GoSub, no return value can be specified.  If the optional label is 
   specified, execution continues at the specified label.  If no GoSub was 
   made, a runtime error is generated, and execution continues immediately 
   after Return.

   A GoSub should always have a matching Return statement.  However, if 
   Return (from gosub) is used where no GoSub was made, a run-time error is 
   generated.

Example
   '' GOSUB & RETURN example, compile with "-lang qb" or use "$lang" as below

   '$lang: "qb"

   Print "Let's Gosub!"
   GoSub MyGosub
   Print "Back from Gosub!"
   Sleep
   End

   MyGosub:
   Print "In Gosub!"
   Return

Dialect Differences
   * In the -lang fb dialect Return always means return-from-procedure.
   * In the -lang qb dialect, Return means return-from-gosub by default 
     unless changed with Option Nogosub, in which case the compiler will 
     recognize Return as return-from-procedure.
   * In the -lang fblite dialect, Return means return-from-procedure by 
     default unless changed with Option Gosub, in which case the compiler 
     will recognize Return as return-from-gosub.

Differences from QB
   * None when using the -lang qb dialect.

See also
   * Sub
   * Function
   * GoSub
   * Option Gosub
   * Option Nogosub
   * Labels
   * Return (From Procedure)



-------------------------------------------------------------- KeyPgRgb ----
RGB

Computes a valid color value for hi/truecolor modes

Syntax
   #define RGB(r,g,b) CULng((CUByte(r) Shl 16) Or (CUByte(g) Shl 8) Or 
   CUByte(b) Or (&hFF000000ul))

Usage
   result = RGB(red, green, blue)

Parameters
   red
      red color component value
   green
      green color component value
   blue
      blue color component value

Return Value
   The combined color.

Description
   red, green and blue are components ranging 0-255.

   The RGB function can be used to compute a valid color value for use 
   while in hi/truecolor modes. It returns an unsigned long, in the format 
   &hAARRGGBB, where RR, GG and BB equal the values passed to this 
   function, in hexadecimal format. AA is the implicit alpha value and is 
   automatically set to &hFF (opaque).
   It is possible to retrieve the red, green, blue and alpha values from a 
   color value, by using a combination of And and Shr.  The second example 
   below shows how to #define and use macros to do this.

   Note for Windows API programmers: The macro named RGB in the Windows 
   references has been renamed BGR in the FB headers for Windows to avoid 
   collisions. 

Example
   See Put (Graphics) example in addition.

   ScreenRes 640,480,32  '32 bit color
   Line(0,0)-(319,479), RGB(255,0,0) 'draws a bright red box on the left side of the window
   Line(639,0)-(320,479), RGB(0,0,255) 'draws a bright blue box on the right side of the window

   Sleep 'wait before exiting
      

   '' setting and retrieving Red, Green, Blue and Alpha values

   #define RGBA_R( c ) ( CULng( c ) Shr 16 And 255 )
   #define RGBA_G( c ) ( CULng( c ) Shr  8 And 255 )
   #define RGBA_B( c ) ( CULng( c )        And 255 )
   #define RGBA_A( c ) ( CULng( c ) Shr 24         )

   Dim As UByte r, g, b, a

   Dim As ULong col = RGB(128, 192, 64)

   Print Using "Color: _&H\      \"; Hex(col, 8)

   r = RGBA_R( col )
   g = RGBA_G( col )
   b = RGBA_B( col )
   a = RGBA_A( col )

   Print
   Print Using "Red:         _&H\\ = ###"; Hex(r, 2); r
   Print Using "Green:       _&H\\ = ###"; Hex(g, 2); g
   Print Using "Blue:        _&H\\ = ###"; Hex(b, 2); b
   Print Using "Alpha:       _&H\\ = ###"; Hex(a, 2); a
      

Version
   * Before fbc 1.08.0:
         Syntax:
            #define RGB(r,g,b) ((CULng(r) Shl 16) Or (CULng(g) Shl 8) Or 
            CULng(b) Or &hFF000000)
         RGB function returned an unsigned integer.

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Rgb.

Differences from QB
   * New to FreeBASIC

See also
   * RGBA
   * Color
   * #define

   

   


------------------------------------------------------------- KeyPgRgba ----
RGBA

Computes a valid color value including alpha (transparency) for 
hi/truecolor modes

Syntax
   #define RGBA(r,g,b,a) CULng((CUByte(r) Shl 16) Or (CUByte(g) Shl 8) Or 
   CUByte(b) Or (CUByte(a) Shl 24))

Usage
   result = RGBA(red, green, blue, alpha)

Parameters
   red
      red color component value
   green
      green color component value
   blue
      blue color component value
   alpha
      alpha component value

Return Value
   the combined color

Description
   red, green, blue and alpha are components ranging 0-255.

   The RGBA function can be used to compute a valid color value including 
   an alpha channel for use while in hi/truecolor modes. It returns an 
   unsigned long, in the format &hAARRGGBB, where RR, GG, BB, AA equal the 
   values passed to this function, in hexadecimal format.
   It is possible to retrieve the red, green, blue  and alpha values from a 
   color value, by using a combination of And and Shr.  The second example 
   below shows how to #define and use macros to do this.

Example
   'open a graphics screen (320 * 240, 32-bit)
   ScreenRes 320, 240, 32

   Dim As Any Ptr img
   Dim As Integer x, y

   'make an image that varies in transparency and color
   img = ImageCreate(64, 64)
   For x = 0 To 63
     For y = 0 To 63
      PSet img, (x, y), RGBA(x * 4, 0, y * 4, (x + y) * 2)
     Next y
   Next x
   Circle img, (31, 31), 25,      RGBA(0, 127, 192, 192), ,,, F 'semi-transparent blue circle
   Line   img, (26, 20)-(38, 44), RGBA(255, 255, 255, 0),    BF 'transparent white rectangle

   'draw a background (diagonal white lines)
   For x = -240 To 319 Step 10
     Line (x, 0)-Step(240, 240), RGB(255, 255, 255)
   Next

   Line (10,  10)-(310,  37), RGB(127, 0, 0), BF 'red box for text
   Line (10, 146)-(310, 229), RGB(0, 127, 0), BF 'green box for Putting onto

   'draw the image and some text with PSET
   Draw String(64, 20), "PSet"
   Put(48,  48), img, PSet
   Put(48, 156), img, PSet

   'draw the image and some text with ALPHA
   Draw String (220, 20), "Alpha"
   Put(208,  48), img, Alpha
   Put(208, 156), img, Alpha

   'Free the image memory
   ImageDestroy img

   'Keep the window open until the user presses a key
   Sleep
      

   '' setting and retrieving Red, Green, Blue and Alpha values

   #define RGBA_R( c ) ( CULng( c ) Shr 16 And 255 )
   #define RGBA_G( c ) ( CULng( c ) Shr  8 And 255 )
   #define RGBA_B( c ) ( CULng( c )        And 255 )
   #define RGBA_A( c ) ( CULng( c ) Shr 24         )

   Dim As UByte r, g, b, a

   Dim As ULong col = RGBA(255, 192, 64, 128)

   Print Using "Color: _&H\      \"; Hex(col, 8)

   r = RGBA_R( col )
   g = RGBA_G( col )
   b = RGBA_B( col )
   a = RGBA_A( col )

   Print
   Print Using "Red:         _&H\\ = ###"; Hex(r, 2); r
   Print Using "Green:       _&H\\ = ###"; Hex(g, 2); g
   Print Using "Blue:        _&H\\ = ###"; Hex(b, 2); b
   Print Using "Alpha:       _&H\\ = ###"; Hex(a, 2); a
      

Version
   * Before fbc 1.08.0:
         Syntax:
            #define RGBA(r,g,b,a) ((CULng(r) Shl 16) Or (CULng(g) Shl 8) Or 
            CULng(b) Or (CULng(a) Shl 24))
         RGBA function returned an unsigned integer.

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Rgba.

Differences from QB
   * New to FreeBASIC

See also
   * RGB
   * Color
   * #define



------------------------------------------------------------ KeyPgRight ----
Right

Returns the rightmost substring of a string

Syntax
   Declare Function Right ( ByRef str As Const String, ByVal n As Integer ) 
   As String
   Declare Function Right ( ByRef str As Const WString, ByVal n As Integer 
   ) As WString

Usage
   result = Right[$]( str, n )

Parameters
   str
      The source string.
   n
      The substring length, in characters.

Return Value
   Returns the rightmost substring from str.

Description
   Returns the rightmost n characters starting from the right (end) of str. 
   If str is empty, then the null string ("") is returned. If n <= 0 then 
   the null string ("") is returned. If n > len(str) then the entire source 
   string is returned.

Example
   Dim text As String = "hello world"
   Print Right(text, 5)

   will produce the output:

   world

An Unicode example:

dim text as wstring*20
text = "&#1055;&#1088;&#1080;&#1074;&#1077;&#1090;, &#1084;&#1080;&#1088;!"
print right(text, 5) 'displays " &#1084;&#1080;&#1088;!"

Platform Differences
   * DOS does not support the wide-character string version of Right.

Dialect Differences
   * The string type suffix "$" is required in the -lang qb dialect.
   * The string type suffix "$" is optional in the -lang fblite dialect.
   * The string type suffix "$" is ignored in the -lang fb dialect, warn 
     only with the -w suffix compile option (or -w pedantic compile 
     option).

Differences from QB
   * QB does not support Unicode.

See also
   * Left
   * Mid (Function)



------------------------------------------------------------ KeyPgRmdir ----
RmDir

Removes a folder/directory from the file system

Syntax
   Declare Function RmDir ( ByRef folder As Const String ) As Long

Usage
   result = RmDir( folder )

Parameters
   folder
      The folder/directory to be removed.

Return Value
   Returns zero (0) on success, and negative one (-1) on failure.

Description
   Removes a folder from the file system. The function will fail if the 
   folder is not empty.

Example
   Dim pathname As String = "foo\bar\baz"
   Dim result As Integer = RmDir( pathname )

   If 0 <> result Then Print "error: unable to remove folder " & pathname & " in the current path."

Platform Differences
   * Linux requires the folder case matches the real name of the file. 
     Windows and DOS are case insensitive. 
   * Path separators in Linux are forward slashes / . Windows uses 
     backward slashes \ but it allows for forward slashes .  DOS uses 
     backward  \ slashes. 

Differences from QB
   * None

See also
   * Shell
   * CurDir
   * ChDir
   * MkDir
   * Kill



-------------------------------------------------------------- KeyPgRnd ----
Rnd

Returns a random Double precision number in the range [0, 1)

Syntax
   Declare Function Rnd ( ByVal seed As Single = 1.0 ) As Double

Usage
   result = Rnd( seed )

Parameters
   seed
      Optional Single argument. If seed has a value of zero (0.0), the last 
      random number generated is repeate.  For any other number a new 
      random number is returned. With the QB-compatible algorithm, a 
      negative number fully reseeds the generator.  The default for no 
      argument is to return a new random number.

Return Value
   Returns the random number generated.

Description
   Returns a number of type Double in the range [0, 1) (i.e. 0 <= Rnd < 1), 
   based on a random seed (see Randomize).

   Rnd can use a variety of different algorithms - see Randomize for 
   details of the default and selectable algorithms.

   Rnd will return the same sequence of numbers every time a program is 
   run.  This sequence can be changed by reseeding the generator.

   Note:
      Rnd is thread-safe (by using an internal mutex), but not thread 
      specific. Used in the context of a multi-threaded program, only the 
      execution speed is significantly slowed down compared to a single 
      thread call context.
      Unfinished structures for other random number generators are also 
      available in the standard header "fbprng.bi".

Example
   '' Function to a random number in the range [first, last), or {first <= x < last}.
   Function rnd_range (first As Double, last As Double) As Double
      Function = Rnd * (last - first) + first
   End Function

   '' seed the random number generator, so the sequence is not the same each time
   Randomize

   '' prints a random number in the range [0, 1), or {0 <= x < 1}.
   Print Rnd

   '' prints a random number in the range [0, 10), or  {0 <= x < 10}.
   Print Rnd * 10

   '' prints a random integral number in the range  [1, 10], or {1 <= n <= 10}.
   ''     (because: 0 <= Rnd * 10 < 10)
   Print Int(Rnd * 10) + 1

   '' prints a random integral number in the range [69, 420], or {69 <= n <= 420}.
   ''     (because: 69 <= rnd_range(69, 421) < 421)
   Print Int(rnd_range(69, 421))
      

Version
   * Before fbc 1.10.0 (for fbc 1.08.0 and fbc 1.09.0), "fbprng.bi" was 
     named "fbmath.bi".
   * Before fbc 1.08.0:
         Rnd was not thread-safe (many values temporarily returned in 
         duplicate for a same thread).
         The standard "fbmath.bi" header for available algorithms did not 
         exist.

Dialect Differences
   The default algorithm used depends on the current dialect in use:
      * With the -lang fb dialect, a 32 bit Mersenne Twister function with 
        a granularity of 32 bits is used.
      * With the -lang qb dialect, a function giving the same output as 
        Rnd in QB is used. The granularity is 24 bits.
      * With the -lang deprecated and -lang fblite dialects, the function 
        in the C runtime available in the system is used. The function 
        available in Win32 has a granularity of 15 bits, and 32 bits in 
        Linux and DOS.

Differences from QB
   * None, if compiled in the -lang qb dialect.  Other dialects can also 
     use the same seeding and generating algorithms by calling Randomize 
     with the appropriate parameter.
   * For the non-QB-compatible algorithms, if the optional argument is 
     less than 0, it has the same meaning as passing an argument of 1.

See also
   * Randomize
   * Timer
   * Int



------------------------------------------------------------- KeyPgRset ----
RSet

Right justifies a string in a string buffer

Syntax
   Declare Sub RSet ( ByRef dst As String, ByRef src As Const String )
   Declare Sub RSet ( ByVal dst As WString Ptr, ByVal src As Const WString 
   Ptr )

Usage
   RSet dst, src

Parameters
   dst
      A String or WString buffer to copy the text into.
   src
      The source String or WString to be right justified.

Description
   RSet right justifies text into the string buffer dst, filling the right 
   part of the string with src and the left part with spaces.  The string 
   buffer size is not modified.

   If text is too long for the string buffer size, RSet truncates 
   characters from the right.

Example
   Dim buffer As String
   buffer = Space(10)
   RSet buffer, "91.5"
   Print "-[" & buffer & "]-"

The example above outputs:
   -[      91.5]-

Differences from QB
   * In QBasic the syntax was RSet dst = src. That syntax is also 
     supported by FB.

See also
   * LSet
   * Space
   * Put (File I/O)
   * MKD
   * MKI
   * MKL
   * MKS

   


------------------------------------------------------------ KeyPgRtrim ----
RTrim

Removes surrounding substrings or characters on the right side of a string

Syntax
   Declare Function RTrim ( ByRef str As Const String, [ Any ] ByRef 
   trimset As Const String = " " ) As String
   Declare Function RTrim ( ByRef str As Const WString, [ Any ] ByRef 
   trimset As Const WString = WStr(" ") ) As WString

Usage
   result = RTrim[$]( str [, [ Any ] trimset ] )

Parameters
   str
      The source string.
   trimset
      The substring to trim.

Return Value
   Returns the trimmed string.

Description
   This procedure trims surrounding characters from the right (end) of a 
   source string:
      * Substrings matching trimset will be trimmed if specified, 
        otherwise spaces (ASCII code 32) are trimmed.
      * If the Any keyword is used, any character matching a character in 
        trimset will be trimmed.
   All comparisons are case-sensitive.

Example
   Dim s1 As String = "Article 101  "
   Print "'" + RTrim(s1) + "'"
   Print "'" + RTrim(s1, " 01") + "'"
   Print "'" + RTrim(s1, Any " 10") + "'"

   Dim s2 As String = "Test Pattern aaBBaaBaa"
   Print "'" + RTrim(s2, "Baa") + "'"
   Print "'" + RTrim(s2, Any "Ba") + "'"

   will produce the output:


   'Article 101'
   'Article 101  '
   'Article'
   'Test Pattern aaB'
   'Test Pattern '

Platform Differences
   * DOS version/target of FreeBASIC does not support the wide-character 
     version of RTrim.

Dialect Differences
   * The string type suffix "$" is required in the -lang qb dialect.
   * The string type suffix "$" is optional in the -lang fblite dialect.
   * The string type suffix "$" is ignored in the -lang fb dialect, warn 
     only with the -w suffix compile option (or -w pedantic compile 
     option).

Differences from QB
   * QB does not support specifying a trimset string or the ANY clause.

See also
   * LTrim
   * Trim



-------------------------------------------------------------- KeyPgRun ----
Run

Transfers execution to an external program

Syntax
   Declare Function Run ( ByRef program As Const String, ByRef arguments As 
   Const String = "" ) As Long

Usage
   result = Run( program [, arguments ] )

Parameters
   program
      The file name (including file path) of the program (executable) to 
      transfer control to.
   arguments
      The command-line arguments to be passed to the program.

Return Value
   Returns negative one (-1) if the program could not be executed.

Description
   Transfers control over to an external program. When the program exits, 
   execution will return to the system.

Example
   '' Attempt to transfer control to "program.exe" in the current directory.
   Dim result As Integer = Run("program.exe")

   '' at this point, "program.exe" has failed to execute, and
   '' result will be set to -1.

Platform Differences
   * Linux requires the program case matches the real name of the file. 
     Windows and DOS  are case insensitive. The program being run may be 
     case sensitive for its command line parameters.
   * Path separators in Linux are forward slashes ("/"). Windows uses 
     backward slashes ("\") although some versions of Windows allow forward 
     slashes.  DOS uses backward slashes. 

Differences from QB
   * Run needs the full executable name, including extension (.exe) on 
     platforms that have one (Win32, DOS).
   * Returning an error code is new to FreeBASIC.

See also
   * Exec transfer temporarily, with arguments  
   * Chain transfer temporarily, without arguments
   * Command pick arguments




============================================================================
    S

------------------------------------------------------------- KeyPgSadd ----
SAdd

Returns a pointer to a string variable's data

Syntax
   Declare Function SAdd ( ByRef str As String ) As ZString Ptr
   Declare Function SAdd ( ByRef str As WString ) As WString Ptr
   Declare Function SAdd ( ByRef str As ZString ) As ZString Ptr

Usage
   result = SAdd( str )

Parameters
   str
      the string expression or variable to get the address of

Return Value
   A pointer to the data associated with str.

Description
   Returns the memory offset of the string data in the string variable.

Example
   Dim s As String

   Print SAdd(s)
   s = "hello"
   Print SAdd(s)
   s = "abcdefg, 1234567, 54321"
   Print SAdd(s)

Differences from QB
   * QB returned an integer instead of a pointer.

See also
   * StrPtr
   * VarPtr
   * ProcPtr



------------------------------------------------------------ KeyPgScope ----
Scope...End Scope

Statement to begin a new scope block

Syntax
   Scope
      [statements]
   End Scope

Description
   The Scope block allows variables to be (re)defined and used locally in a 
   program.

   When a variable is (re)defined with Dim within a scope structure, this 
   local working variable can be used from its (re)definition until the end 
   of the scope.  During this time, any variables outside the scope that 
   have the same name will be ignored, and will not be accessible by that 
   name. Any statements in the Scope block before the variable is redefined 
   will use the variable as defined outside the Scope.

   The local variables are reserved on stack at granularity level of each 
   procedure (including the main part of the program), not at granularity 
   level of each individual scope block. So a same memory space can be used 
   by local variables belonging to different scope blocks.

   To access duplicated symbols defined as global outside the scope block, 
   add one or preferably two dot(s) as prefix: .SomeSymbol or preferably ..
   SomeSymbol (or only ..SomeSymbol if inside a With..End With block).

   Scope..End Scope is not permitted when compiling with in the -lang qb 
   dialect.

Example
   Dim As Integer x = 5, y = 2
   Print "x ="; x; ", "; "y ="; y
   Scope
      Dim x As Integer = 3
      Print "x ="; x; ", "; "y ="; y
      Scope
         Dim y As Integer = 4
         Print "x ="; x; ", "; "y ="; y
      End Scope
   End Scope
   Print "x ="; x; ", "; "y ="; y

Dialect Differences
   * Explicit Scope..End Scope blocks are available only in the -lang fb 
     and -lang deprecated dialects.
   * Explicit Scope..End Scope blocks are not available in the -lang fblite
     and -lang qb dialects.

Differences from QB
   * New to FreeBASIC

See also
   * Dim
   * ReDim
   * Static
   * Var
   * Byref (Variables)



--------------------------------------------------- KeyPgScreengraphics ----
Screen (Graphics)

Initializes a graphics mode using QB-like mode numbers

Syntax
   -lang fb|fblite dialects:
      Screen mode [, [ depth ] [, [ num_pages ] [, [ flags ] [, [ 
      refresh_rate ]]]]]
      Screen , [ active_page ] [, [ visible_page ]]
   -lang qb dialect:
      Screen [ mode ] [, [ colormode ] [, [ active_page ] [, [ visible_page 
      ]]]]
 
Parameters
   mode 
      is a QB style graphics screen mode number (see below).  If mode is 0, 
      then any currently set graphics mode is closed, and all functions 
      resume their normal console-mode functionality.  See below for 
      available modes.
   depth
      is the color depth in bits per pixel.  This only has an effect for 
      modes 14 and higher.  Values of 8, 16 and 32 are allowed.  15 and 24 
      are also allowed as aliases for 16 and 32, respectively.  If omitted, 
      it defaults to 8.
   num_pages
      is the number of video pages you want, see below.  If omitted, it 
      defaults to 1.
   flags
      Are used to select several things as graphics driver priority, 
      fullscreen mode. There are constants predefined in the fbgfx.bi file 
      ready to use.  See the page ScreenRes for available flags.
   refresh_rate
      requests a refresh rate.  If it is not available in the present card 
      or the parameter is omitted, FreeBASIC chooses the rate 
      automatically.
   active_page
      Used to set the active page, where printing/drawing commands take 
      effect
   visible_page
      Used to set the visible page, which is shown to the user
   colormode
      Unused - allowed for compatibility with the QB syntax

Description
   Screen tells the compiler to link the GfxLib and initializes a QB-only, 
   QB-on-GUI or OpenGL graphics mode, depending on the flags setting.

   In QB-only modes a dumb window or fullscreen resolution is set, one or 
   more buffers in standard memory are created, console commands are 
   redirected to their graphic versions, a default palette is set and an 
   automatic screen refresh thread is started.  QB-like graphics and 
   console statements can be used.

   In QB-on-GUI modes one or more buffers in standard memory are created, 
   console commands are redirected to their graphic versions and a 
   default palette is set.  QB-like graphics and console statements can be 
   used.  It is up to the user to create a window and to refresh it with 
   the contents of the graphics buffers.

   In OpenGL modes a dumb window or fullscreen resolution is set, one or 
   more buffers in standard memory are created, and the OS's OpenGL library 
   is initialized.  From here only OpenGL commands can be used; QB-like and 
   console commands are forbidden.  This allows to initialize OpenGL in a 
   portable way; you can then also use ScreenControl to properly customize 
   the GL pixel format to be used before Screen is called or to retrieve 
   the list of supported OpenGL extensions after a mode has been set, and 
   ScreenGLProc to obtain extension function pointers.

   Any buffer that is created in standard memory uses one of three 
   supported internal pixel formats, depending on the desired color depth; 
   see Internal pixel formats for details.

   If Screen fails to set the required mode, an "Illegal function call" 
   error is issued and the screen pointer is set to 0. Thus Screen failures 
   can be detected using standard On Error processing or retrieving the 
   screen pointer with ScreenPtr.

   Before setting a fullscreen mode the program should check if that mode 
   is available in the graphics card using ScreenList.

   mode details
      Available modes list:
         QB compatibility modes:
               +-------+----------+---------+--------------+-----------+----------------------------------------+
               |Mode nr|Resolution|Emulation|Text          |char size  |colors on screen                        |
               |1      |320x200   |CGA      |40X25         |8x8        |16 background, 1 of four sets foreground|
               |2      |640x200   |CGA      |80x25         |8x8        |16 colors to 2 attributes               |
               |7      |320x200   |EGA      |40x25         |8x8        |16 colors to 16 attributes              |
               |8      |640x200   |EGA      |80x25         |8x8        |16 colors to 16 attributes              |
               |9      |640x350   |EGA      |80x25 0r 80x43|8x14 or 8x8|16 colors to 16 attributes              |
               |11     |640x480   |VGA      |80x30 or 80x60|8x16 or 8x8|256K colors to 2 attributes             |
               |12     |640x480   |VGA      |80x30 or 80x60|8x16 or 8x8|256K colors to 16 attributes            |
               |13     |320x200   |MCGA     |40X25         |8X8        |256K colors to 256 attributes           |
               +-------+----------+---------+--------------+-----------+----------------------------------------+
(the mode number '0' is dedicated to text mode)

         New FreeBASIC modes:
               +-------+----------+---------+-----------------+-----------+---------------------------------------------+
               |Mode nr|Resolution|Emulation|Text             |char size  |colors on screen                             |
               |14     |320x240   |         |40x30            |8x8        |256K colors to 256 attributes or direct color|
               | 15    |400x300   |         |50x37            |8x8        |256K colors to 256 attributes or direct color|
               | 16    |512x384   |         |64x24 or 64x48   |8x16 or 8x8|256K colors to 256 attributes or direct color|
               |17     |640x400   |         |80x25 or 80x50   |8x16 or 8x8|256K colors to 256 attributes or direct color|
               |18     |640x480   |         |80x30 or 80x60   |8x16 or 8x8|256K colors to 256 attributes or direct color|
               | 19    |800x600   |         |100x37 or 100x75 |8x16 or 8x8|256K colors to 256 attributes or direct color|
               |20     |1024x768  |         |128x48 or 128x96 |8x16 or 8x8|256K colors to 256 attributes or direct color|
               | 21    |1280x1024 |         |160x64 or 160x128|8x16 or 8x8|256K colors to 256 attributes or direct color|
               +-------+----------+---------+-----------------+-----------+---------------------------------------------+
 
   depth details
      For modes 14 and up, the depth parameter changes the color depth to 
      the specified new one; if depth is not specified, these modes run in 
      8bpp.  For modes 13 and below, depth has no effect.

   num_pages details
      You can request any number of pages for any video mode; if you omit 
      the parameter, only the visible page (number 0) will be available.  A 
      page is either the visible screen or an offscreen buffer, you can 
      show a page while working on another one; see the ScreenSet statement 
      for details.  All pages are created in standard memory, the video 
      card memory is never used for video buffering.

   flags details:
      (documented at the page ScreenRes)

   Other details
      While in windowed mode, clicking on the window close button will add 
      a keypress of (Chr(255) & "k") to the Inkey buffer.  Clicking on the 
      Maximize window button will switch to fullscreen mode if possible.  A 
      successful Screen call sets currently visible and working pages both 
      to page number 0, resets the palette to the specified mode one (see 
      Default palettes), resets the clipping region to the size of the 
      screen, disables custom coordinates mappings, moves the graphics 
      cursor to the center of the screen, moves the text cursor to the 
      top-left corner of the screen (but never visible on any graphics 
      screen), and sets foreground and background colors to bright white 
      and black respectively.

   Note on using Screen 0 (text mode only)
      The default BASIC screen mode (Screen 0) is text based.
      Screen 0 closes any graphics window, but also clears the console 
      window if it exists.
      Screen 0, , , GFX_SCREEN_EXIT (with GFX_SCREEN_EXIT=&h80000000) also 
      closes any graphics window, but does not clear the console window if 
      it exists (previous text is preserved).

Example
   ' Sets screen mode 13 (320*200, 8bpp)
   Screen 13
   Print "Screen mode 13 set"

   Sleep

   #include "fbgfx.bi"
   #if __FB_LANG__ = "fb"
   Using FB '' Screen mode flags are in the FB namespace in lang FB
   #endif

   ' Sets screen mode 18 (640*480) with 32bpp color depth and 4 pages, in windowed mode; switching disabled
   Screen 18, 32, 4, (GFX_WINDOWED Or GFX_NO_SWITCH)

   ' Check to make sure Screen was opened successfully
   If ScreenPtr = 0 Then
      Print "Error setting video mode!"
      End
   End If

   Print "Successfully set video mode"
   Sleep

Platform Differences
   * In DOS, Windowing and OpenGL related switches are not available, and 
     other issues, see GfxLib overview

Dialect Differences
   * In the -lang fb and -lang fblite dialects, the usage is:
         Screen mode [, [depth] [, [num_pages] [, [flags] [, [refresh_rate
         ]]]]]
         or:
         Screen , [active_page] [, [visible_page]]]

   * In the -lang qb dialect, the usage is:
         Screen [mode] [, [colormode] [, [active_page] [, [visible_page]]]]

Differences from QB
   * None in the -lang qb dialect.
   * In QB the syntax was Screen mode,colormode,active_page,visible_page. 
     Of those parameters FreeBASIC supports only mode and redefines the 
     rest. The use of Screen , , apage,vpage to swap screen pages is only 
     available in the -lang qb dialect.
   * ScreenSet should be used in the -lang fb and -lang fblite dialects.

See also
   * Screen (Console)
   * ScreenRes More flexible alternative to Screen
   * ScreenList Check display modes available for FB GfxLib to use
   * ScreenControl Select driver and more 
   * ScreenLock
   * ScreenUnlock
   * ScreenPtr Semi-low level access
   * ScreenSet
   * ScreenCopy
   * ScreenInfo
   * ScreenGLProc
   * Internal pixel formats



------------------------------------------------------- KeyPgScreenCons ----
Screen (Console)

Gets the character or color attribute at a given location

Syntax
   Declare Function Screen ( ByVal row As Long, ByVal column As Long, ByVal 
   colorflag As Long = 0 ) As ULong

Usage
   result = Screen( row, column [, colorflag ] )

Parameters
   row
      1-based offset from the top left corner of the console.
   column
      1-based offset from the top left corner of the console.
   colorflag
      If equal to 0, the ASCII code is returned, otherwise the color 
      attribute is returned.  If omitted, it defaults to 0.

Return Value
   The ASCII or color attribute of the character.

Description
   Screen returns the character or the color attribute found at a given 
   position of a console output. It works in console mode and in graphics 
   mode.

   The format of the color attribute depends on the current color depth:

   If the color type is a palette type with up to 4 bits per pixel (such as 
   the Win32 console), then the color attribute is an 8-bit value, where 
   the higher four bits hold the cell background color and the lower four 
   bits hold the foreground (character) color.

   If the color type is an 8-bit palette, then the color attribute is a 
   16-bit value, where the high byte holds the background color and the low 
   byte holds the foreground color.

   If the color type is full color, then the color attribute is a 32-bit 
   integer, holding a single color value.  If colorflag is equal to 1, then 
   the foreground color is returned; if colorflag is equal to 2, then the 
   background color is returned.

   The color values for the standard 16 color palette are:

         +-----+-------+-----+------------+
         |Value|Color  |Value|Color       |
         |0    |Black  |8    |Gray        |
         |1    |Blue   |9    |Bright Blue |
         |2    |Green  |10   |Bright Green|
         |3    |Cyan   |11   |Bright Cyan |
         |4    |Red    |12   |Bright Red  |
         |5    |Magenta|13   |Pink        |
         |6    |Brown  |14   |Yellow      |
         |7    |White  |15   |Bright White|
         +-----+-------+-----+------------+

Example
   Dim character_ascii_value As ULong
   Dim attribute As ULong
   Dim background As ULong
   Dim cell_color As ULong
   Dim row As Long, col As Long

   character_ascii_value = Screen( row, col )
   attribute = Screen( row, col, 1 )
   background = attribute Shr 4
   cell_color = attribute And &hf

   '' open a graphics screen with 4 bits per pixel
   '' (alternatively, omit this line to use the console)
   ScreenRes 320, 200, 4

   '' print a character
   Color 7, 1
   Print "A"

   Dim As ULong char, col, fg, bg

   '' get the ASCII value of the character we've just printed
   char = Screen(1, 1, 0)

   ''get the color attributes
   col = Screen(1, 1, 1)
   fg = col And &HF
   bg = (col Shr 4) And &HF

   Print Using "ASCII value: ### (""!"")"; char; Chr(char)
   Print Using "Foreground color: ##"; fg
   Print Using "Background color: ##"; bg
   Sleep

   '' open a graphics screen with 8 bits per pixel
   ScreenRes 320, 200, 8

   '' print a character
   Color 30, 16
   Print "Z"

   Dim As ULong char, col, fg, bg

   '' get the ASCII value of the character we've just printed
   char = Screen(1, 1, 0)

   ''get the color attributes
   col = Screen(1, 1, 1)
   fg = col And &HFF
   bg = (col Shr 8) And &HFF

   Print Using "ASCII value: ### (""!"")"; char; Chr(char)
   Print Using "Foreground color: ###"; fg
   Print Using "Background color: ###"; bg
   Sleep

   '' open a full-color graphics screen
   ScreenRes 320, 200, 32

   '' print a character
   Color RGB(255, 255, 0), RGB(0, 0, 255) 'yellow on blue
   Print "M"

   Dim As ULong char, fg, bg

   '' get the ASCII value of the character we've just printed
   char = Screen(1, 1, 0)

   ''get the color attributes
   fg = Screen(1, 1, 1)
   bg = Screen(1, 1, 2)

   Print Using "ASCII value: ### (""!"")"; char; Chr(char)
   Print Using "Foreground color: &"; Hex(fg, 8)
   Print Using "Background color: &"; Hex(bg, 8)
   Sleep

Platform Differences
   * On the Linux version, the value returned can differ from the 
     character shown on the console.  For example, unprintable control 
     codes - such as the LF character (10) that implicitly occurs after the 
     end of Printed text - may be picked up instead of the untouched 
     character in its place.

Differences from QB
   * In QB Screen triggered an error if the coordinates were out of 
     screen.

See also
   * Screen (Graphics)
   * Color



------------------------------------------------------- KeyPgScreencopy ----
ScreenCopy

Copies the contents of a graphical page into another graphical page

Syntax
   Declare Function ScreenCopy ( ByVal from_page As Long = -1, ByVal 
   to_page As Long = -1 ) As Long

Usage
   ScreenCopy [ from_page ] [, to_page ]

Parameters
   from_page
      page to copy from
   to_page
      page to copy to

Return Value
   Returns zero (0) if successful, or a non-zero error code to indicate a 
   failure.

Description
   from_page is the page to copy from. If this argument is omitted, the 
   current work page is assumed.  to_page is the page to copy to. If this 
   argument is omitted, the currently visible page is assumed.  Page 
   numbers range from 0 to num_pages - 1, where num_pages is the number of 
   pages specified when setting the graphics mode with ScreenRes or 
   Screen (Graphics).

   You can use this function to add a double buffer to your graphics. Any 
   graphics screen mode with multiple pages supports this function.

   ScreenCopy is inactive if the destination page is locked.

   There are two other functions similar to this: Flip and PCopy.  Flip is 
   designed to work in OpenGL modes, while PCopy supports console pages on 
   some platforms.  Both do the same thing as ScreenCopy in normal graphics 
   modes.

   The error code returned by ScreenCopy can be checked using Err in the 
   next line. The function version of  ScreenCopy returns directly the 
   error code as a 32 bit Long.

Example
   See also ScreenSet example.

   '' 320x200x8, with 3 pages
   Screen 13,,3

   '' image for working page #1 (visible page #0)
   ScreenSet 1, 0
   Cls
   Circle( 160, 100 ), 90, 1 ,,,, f
   Circle( 160, 100 ), 90, 15
   Print "Press 2 to copy page #2 to visible page"
   Print "Press escape to exit"

   '' image for working page #2 (visible page #0)
   ScreenSet 2, 0
   Cls
   Line( 50, 50 )-( 270, 150 ), 2, bf
   Line( 50, 50 )-( 270, 150 ), 15, b
   Print "Press 1 to copy page #1 to visible page"
   Print "Press escape to exit"

   '' page #0 is the working page (visible page #0)
   ScreenSet 0, 0
   Cls
   Print "Press 1 to copy page #1 to visible page"
   Print "Press 2 to copy page #2 to visible page"
   Print "Press escape to exit"

   Dim k As String

   Do
     k = Inkey
     Select Case k
     Case Chr(27)
      Exit Do
     Case "1"
      ScreenCopy 1, 0
     Case "2"
      ScreenCopy 2, 0
     End Select

     Sleep 25
   Loop

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Screencopy.

Differences from QB
   * New to FreeBASIC. It is a graphics-only version of PCopy - which 
     works in both text and graphics modes.

See also
   * PCopy
   * Screen (Graphics)
   * ScreenRes
   * ScreenSet



---------------------------------------------------- KeyPgScreencontrol ----
ScreenControl

Sets or gets internal graphics library settings

Syntax
   Declare Sub ScreenControl ( ByVal what As Const Long, ByRef param1 As 
   Long = &h80000000, ByRef param2 As Long = &h80000000, ByRef param3 As 
   Long = &h80000000, ByRef param4 As Long = &h80000000 )
   Declare Sub ScreenControl ( ByVal what As Const Long, ByRef param1 As 
   LongInt, ByRef param2 As LongInt = &h80000000, ByRef param3 As LongInt = 
   &h80000000, ByRef param4 As LongInt = &h80000000 )
   Declare Sub ScreenControl ( ByVal what As Const Long, ByRef param As 
   String)

Usage
   in the LONG (or INTEGER<32>) version of the sub:
      ScreenControl( what [, [ param1 ] [, [ param2 ] [, [ param3 ] [, 
      param4 ]]]] )
         or,
      ScreenControl( what , param )
   in the LONGINT (or INTEGER<64>) version of the sub:
      ScreenControl( what , param1 [, [ param2 ] [, [ param3 ] [, param4 
      ]]] )
         or,
      ScreenControl( what , param )

Parameters
   what
      specifies the function to perform
   param1
      first integer parameter, contains value to be set on entry or value 
      got on exit
   param2
      second integer parameter, contains value to be set on entry or value 
      got on exit
   param3
      third integer parameter, contains value to be set on entry or value 
      got on exit
   param4
      fourth integer parameter, contains value to be set on entry or value 
      got on exit
   param
      string parameter, contains text to be set on entry or text got on 
      exit

Description
   This function can be used to set or get internal GfxLib states. The what 
   parameter specifies which operation to perform. On operations that set 
   states, the param* parameters must contain the values to be set. On 
   operations that get states, param* will hold the values returned by 
   GfxLib when the function returns.
   The meaning of the param* parameters depend on the what parameter, whose 
   possible values are defined as constants in fbgfx.bi.  In lang fb, they 
   are set to be stored in the FB Namespace.
   Below is a list of the supported what constants - and their values as 
   defined at time of writing - along with the parameters associated with 
   them.

   Supported operations

      Note:
         (*) denotes operations that are allowed while a graphics mode has 
         not yet been set via Screen (Graphics) or ScreenRes,
         (**) denotes the operations that must be performed before the 
         graphics mode is set via Screen (Graphics) or ScreenRes,
         for all other operations, return values are zero (0) or the empty 
         string ("") and the operation has no effect if a graphics mode is 
         not available at call time.

      Get operations
   * GET_WINDOW_POS Returns the current window position, in desktop 
     coordinates.
      [OUT] param1 x
      [OUT] param2 y
   * (*) GET_WINDOW_TITLE Returns the title of the program window.
      [OUT] param title
   * GET_WINDOW_HANDLE Returns a handle to the program window.
      [OUT] param1 handle; this is a HWND in Windows, a "Window" XID in X11
      [OUT] param2 display ptr in X11
   * (*) GET_DESKTOP_SIZE Returns the desktop size, in pixels.
      [OUT] param1 width
      [OUT] param2 height
   * GET_SCREEN_SIZE Returns the current screen size in pixels.
      [OUT] param1 width
      [OUT] param2 height
   * GET_SCREEN_DEPTH Returns current graphics mode screen depth.
      [OUT] param1 bits per pixel
   * GET_SCREEN_BPP Returns current graphics mode BPP.
      [OUT] param1 bytes per pixel
   * GET_SCREEN_PITCH Returns the current graphics mode framebuffer pitch, 
     in bytes.
      [OUT] param1 pitch
   * GET_SCREEN_REFRESH Returns the current graphics mode refresh rate, in 
     hertz.
      [OUT] param1 rate
   * GET_DRIVER_NAME Returns the current graphics mode driver name.
      [OUT] param name
   * GET_TRANSPARENT_COLOR Returns the transparent color value for the 
     current graphics mode depth.
      [OUT] param1 value
   * GET_VIEWPORT Returns the current viewport as set by the 
     View (Graphics) statement, in screen coordinates.
      [OUT] param1 x1
      [OUT] param2 y1
      [OUT] param3 x2
      [OUT] param4 y2
   * GET_PEN_POS Returns the last graphical pen position, in screen 
     coordinates. This position is used in graphics functions supporting 
     relative coordinates using the Step keyword.
      [OUT] param1 x
      [OUT] param2 y
   * GET_COLOR Returns the current graphics mode color.
      [OUT] param1 foreground
      [OUT] param2 background
   * GET_ALPHA_PRIMITIVES Returns if primitives drawing support for alpha 
     channel is enabled.
      [OUT] param1 TRUE (-1) if alpha primitives is enabled, FALSE (0) 
      otherwise
   * GET_GL_EXTENSIONS Returns a string holding all supported GL 
     extensions, or the empty string if not in OpenGL mode.
      [OUT] param supported GL extensions
   * GET_HIGH_PRIORITY Returns if GFX_HIGH_PRIORITY was specified in the 
     flags passed to Screen (Graphics) or ScreenRes.
      [OUT] param1 higher priority graphics processing enabled
   * GET_SCANLINE_SIZE Returns how currently many scan lines each row of 
     fbgfx video memory should occupy on the screen
      [OUT] param1 scan line size multiplier
   * (*) GET_X86_MMX_ENABLED Returns if MMX specific blitters are enabled 
     on X86.  fbgfx will select MMX blitters if MMX is enabled and 
     available.
      [OUT] param1 TRUE (-1) if MMX is enabled, FALSE (0) otherwise
   * GET_GL_COLOR_BITS Returns the current number of bits dedicated to the 
     OpenGL color buffer
      [OUT] param1 bits
   * GET_GL_COLOR_RED_BITS Returns the current number of bits dedicated to 
     the red component of the OpenGL color buffer
      [OUT] param1 bits
   * GET_GL_COLOR_GREEN_BITS Returns the current number of bits dedicated 
     to the green component of the OpenGL color buffer
      [OUT] param1 bits
   * GET_GL_COLOR_BLUE_BITS Returns the current number of bits dedicated 
     to the blue component of the OpenGL color buffer
      [OUT] param1 bits
   * GET_GL_COLOR_ALPHA_BITS Returns the current number of bits dedicated 
     to the alpha component of the OpenGL color buffer
      [OUT] param1 bits
   * GET_GL_DEPTH_BITS Returns the current number of bits dedicated to the 
     OpenGL depth buffer
      [OUT] param1 bits
   * GET_GL_STENCIL_BITS Returns the current number of bits dedicated to 
     the OpenGL stencil buffer
      [OUT] param1 bits
   * GET_GL_ACCUM_BITS Returns the current number of bits dedicated to the 
     OpenGL accumulation buffer
      [OUT] param1 bits
   * GET_GL_ACCUM_RED_BITS Returns the current number of bits dedicated to 
     the red component of the OpenGL accumulation buffer
      [OUT] param1 bits
   * GET_GL_ACCUM_GREEN_BITS Returns the current number of bits dedicated 
     to the green component of the OpenGL accumulation buffer
      [OUT] param1 bits
   * GET_GL_ACCUM_BLUE_BITS Returns the current number of bits dedicated 
     to the blue component of the OpenGL accumulation buffer
      [OUT] param1 bits
   * GET_GL_ACCUM_ALPHA_BITS Returns the current number of bits dedicated 
     to the alpha component of the OpenGL accumulation buffer
      [OUT] param1 bits
   * GET_GL_NUM_SAMPLES Returns the current number of samples to be used 
     for OpenGL multisampling
      [OUT] param1 samples
   * GET_GL_2D_MODE Returns the current OpenGL 2D render
      [OUT] param1:
         OGL_2D_NONE No rendering
         OGL_2D_MANUAL_SYNC Manual rendering (when Flip is called)
         OGL_2D_AUTO_SYNC Automatic rendering
   * GET_GL_SCALE Returns the current zoom factor on OpenGL 2D render 
     (only allowed if OpenGL 2D render mode has yet been activated via 
     SET_GL_2D_MODE)
      [OUT] param1 zoom factor (0: no rendering)

      Set operations
   * SET_WINDOW_POS Sets the current program window position, in desktop 
     coordinates.
      [IN] param1 x
      [IN] param2 y
   * (*) SET_WINDOW_TITLE Sets the current program window title. This is 
     equivalent to calling WindowTitle( param ).
      [IN] param title
   * SET_PEN_POS Sets the current graphical pen position, in screen 
     coordinates. This position is used in graphics functions supporting 
     relative coordinates using the Step keyword.
      [IN] param1 x
      [IN] param2 y
   * (*) SET_DRIVER_NAME Sets the name of the internal graphics driver to 
     be used in subsequent calls to Screen (Graphics) or ScreenRes.
      [IN] param driver name
   * SET_ALPHA_PRIMITIVES Sets if primitives drawing should honor alpha 
     channel.
      [IN] param1 enabled
   * (*) SET_GL_COLOR_BITS Sets the number of bits dedicated to the OpenGL 
     color buffer
      [IN] param1 bits
   * (*) SET_GL_COLOR_RED_BITS Sets the number of bits dedicated to the 
     red component of the OpenGL color buffer
      [IN] param1 bits
   * (*) SET_GL_COLOR_GREEN_BITS Sets the number of bits dedicated to the 
     green component of the OpenGL color buffer
      [IN] param1 bits
   * (*) SET_GL_COLOR_BLUE_BITS Sets the number of bits dedicated to the 
     blue component of the OpenGL color buffer
      [IN] param1 bits
   * (*) SET_GL_COLOR_ALPHA_BITS Sets the number of bits dedicated to the 
     alpha component of the OpenGL color buffer
      [IN] param1 bits
   * (*) SET_GL_DEPTH_BITS Sets the number of bits dedicated to the OpenGL 
     depth buffer
      [IN] param1 bits
   * (*) SET_GL_STENCIL_BITS Sets the number of bits dedicated to the 
     OpenGL stencil buffer
      [IN] param1 bits
   * (*) SET_GL_ACCUM_BITS Sets the number of bits dedicated to the OpenGL 
     accumulation buffer
      [IN] param1 bits
   * (*) SET_GL_ACCUM_RED_BITS Sets the number of bits dedicated to the 
     red component of the OpenGL accumulation buffer
      [IN] param1 bits
   * (*) SET_GL_ACCUM_GREEN_BITS Sets the number of bits dedicated to the 
     green component of the OpenGL accumulation buffer
      [IN] param1 bits
   * (*) SET_GL_ACCUM_BLUE_BITS Sets the number of bits dedicated to the 
     blue component of the OpenGL accumulation buffer
      [IN] param1 bits
   * (*) SET_GL_ACCUM_ALPHA_BITS Sets the number of bits dedicated to the 
     alpha component of the OpenGL accumulation buffer
      [IN] param1 bits
   * (*) SET_GL_NUM_SAMPLES Sets the number of samples to be used for 
     OpenGL multisampling
      [IN] param1 samples
   * (*) SET_X86_MMX_ENABLED Sets if MMX blitters should be used on X86
      [IN] param1 enabled
   * (**) SET_GL_2D_MODE Sets OpenGL 2D render
      [IN] param1:
         OGL_2D_NONE No rendering
         OGL_2D_MANUAL_SYNC Manual rendering (when Flip is called)
         OGL_2D_AUTO_SYNC Automatic rendering
   * (**) SET_GL_SCALE Apply a zoom factor on OpenGL 2D render (only 
     allowed if OpenGL 2D render mode has yet been activated via 
     SET_GL_2D_MODE)
      [IN] param1 zoom factor (0: no rendering)

      Other operations
   * POLL_EVENTS Cause the library to poll all events, ie to check the 
     system event queue, specifically used for retrieving keyboard and 
     mouse events.  This is most useful for OpenGL code where Flip is not 
     used, as normally Flip will cause these events to be polled.

Example
   '' include fbgfx.bi for some useful definitions
   #include "fbgfx.bi"

   '' use FB namespace for easy access to types/constants
   Using FB

   Dim e As Event
   Dim As Long x0, y0, x, y
   Dim As Integer shakes = 0
   Dim As Any Ptr img

   ScreenRes 320, 200, 32
   Print "Click to shake window"

   '' find window coordinates
   ScreenControl GET_WINDOW_POS, x0, y0

   Do

      If (shakes > 0) Then
         
         '' do a shake of the window

         If (shakes > 1) Then

            '' move window to a random position near its original coordinates
            x = x0 + Int(32 * (Rnd() - 0.5))
            y = y0 + Int(32 * (Rnd() - 0.5))
            ScreenControl SET_WINDOW_POS, x, y

         Else

            '' move window back to its original coordinates
            ScreenControl SET_WINDOW_POS, x0, y0

         End If

         shakes -= 1

      End If

      If (ScreenEvent(@e)) Then
         Select Case e.type
         
         '' user pressed the mouse button
         Case EVENT_MOUSE_BUTTON_PRESS

            If (shakes = 0) Then
               '' set to do 20 shakes
               shakes = 20

               '' find current window coordinates to shake around
               ScreenControl GET_WINDOW_POS, x0, y0
            End If

         '' user closed the window or pressed a key
         Case EVENT_WINDOW_CLOSE, EVENT_KEY_PRESS
            '' exit to end of program
            Exit Do

         End Select
      End If

      '' free up CPU for other programs
      Sleep 5

   Loop
      

   '' include fbgfx.bi for some useful definitions
   #include "fbgfx.bi"

   Dim As String driver

   #ifdef __FB_WIN32__
   '' set graphics driver to GDI (Windows only), before calling ScreenRes
   ScreenControl FB.SET_DRIVER_NAME, "GDI"
   #endif

   ScreenRes 640, 480

   '' fetch graphics driver name and display it to user
   ScreenControl FB.GET_DRIVER_NAME, driver
   Print "Graphics driver name: " & driver

   '' wait for a keypress before closing the window
   Sleep
      

Version
   * Since fbc 1.20.0: GET_X86_MMX_ENABLED, SET_X86_MMX_ENABLED
   * Since fbc 1.10.0: 16 getters from GET_SCANLINE_SIZE to GET_GL_SCALE 
     added.
   * Before fbc 1.08.0:
         Syntax:
            Declare Sub ScreenControl ( ByVal what As Long, ByRef param1 As 
            Integer = 0, ByRef param2 As Integer = 0, ByRef param3 As 
            Integer = 0, ByRef param4 As Integer = 0 )
            Declare Sub ScreenControl ( ByVal what As Long, ByRef param As 
            String = "" )
         Usage:
            ScreenControl( what [, [ param1 ] [, [ param2 ] [, [ param3 ] 
            [, [ param4 ]]]]] )
               or,
            ScreenControl( what [, param ] )

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Screencontrol.

Differences from QB
   * New to FreeBASIC

See also
   * Screen (Graphics)
   * ScreenEvent
   * ScreenInfo
   * WindowTitle
   * View (Graphics)



------------------------------------------------------ KeyPgScreenevent ----
ScreenEvent

Queries for and retrieves system events.

Syntax
   Declare Function ScreenEvent ( ByVal event As Any Ptr = 0 ) As Long

Usage
   result = ScreenEvent( [ event ] )

Parameters
   event
      Specifies the buffer where the function should store the event data.

Return Value
   Returns -1 if there are pending events to be retrieved, 0 otherwise.

Description
   This function returns the latest available system event from the 
   internal GfxLib events queue. By "event" we mean any mouse or keyboard 
   activity, for example.

   The event data (if available) will be copied into the buffer pointed 
   that should be declared as an Event.
   On the Event page, see the list of event types and how to use their 
   associated fields (see also the example below).

   Querying for events
      The function returns -1 if there are pending events to be retrieved, 
      0 otherwise. If the event parameter is set to 0 (the default if 
      omitted) ScreenEvent will not be able to copy the event data and it 
      will not dequeue it from the internal events queue. Calling the 
      function this way can be useful to check if there are pending events 
      without actually fetching them.

   Note
      If you receive a KEY_PRESS, KEY_RELEASE or KEY_REPEAT event, it does 
      not clear the keyboard buffer.  If you need the buffer to be clear 
      after you receive the event, you will need to clear it manually.  See 
      Inkey.

Example
   '' include fbgfx.bi for some useful definitions
   #include "fbgfx.bi"
   #if __FB_LANG__ = "fb"
   Using fb '' constants and structures are stored in the FB namespace in lang fb
   #endif

   Dim e As Event

   ScreenRes 640, 480
   Do
      If (ScreenEvent(@e)) Then
         Select Case e.type
         Case EVENT_KEY_PRESS
            If (e.scancode = SC_ESCAPE) Then
               End
            End If
            If (e.ascii > 0) Then
               Print "'" & e.ascii & "'";
            Else
               Print "unknown key";
            End If
            Print " was pressed (scancode " & e.scancode & ")"
         Case EVENT_KEY_RELEASE
            If (e.ascii > 0) Then
               Print "'" & e.ascii & "'";
            Else
               Print "unknown key";
            End If
            Print " was released (scancode " & e.scancode & ")"
         Case EVENT_KEY_REPEAT
            If (e.ascii > 0) Then
               Print "'" & e.ascii & "'";
            Else
               Print "unknown key";
            End If
            Print " is being repeated (scancode " & e.scancode & ")"
         Case EVENT_MOUSE_MOVE
            Print "mouse moved to " & e.x & "," & e.y & " (delta " & e.dx & "," & e.dy & ")"
         Case EVENT_MOUSE_BUTTON_PRESS
            If (e.button = BUTTON_LEFT) Then
               Print "left";
            ElseIf (e.button = BUTTON_RIGHT) Then
               Print "right";
            Else
               Print "middle";
            End If
            Print " button pressed"
         Case EVENT_MOUSE_BUTTON_RELEASE
            If (e.button = BUTTON_LEFT) Then
               Print "left";
            ElseIf (e.button = BUTTON_RIGHT) Then
               Print "right";
            Else
               Print "middle";
            End If
            Print " button released"
         Case EVENT_MOUSE_DOUBLE_CLICK
            If (e.button = BUTTON_LEFT) Then
               Print "left";
            ElseIf (e.button = BUTTON_RIGHT) Then
               Print "right";
            Else
               Print "middle";
            End If
            Print " button double clicked"
         Case EVENT_MOUSE_WHEEL
            Print "mouse wheel moved to position " & e.z
         Case EVENT_MOUSE_ENTER
            Print "mouse moved into program window"
         Case EVENT_MOUSE_EXIT
            Print "mouse moved out of program window"
         Case EVENT_WINDOW_GOT_FOCUS
            Print "program window got focus"
         Case EVENT_WINDOW_LOST_FOCUS
            Print "program window lost focus"
         Case EVENT_WINDOW_CLOSE
            End
         Case EVENT_MOUSE_HWHEEL
            Print "horizontal mouse wheel moved to position " & e.w
         End Select
      End If

      Sleep 1
   Loop

Platform Differences
   * ScreenEvent does not return window related events in the DOS version, 
     but does return input events.

Dialect Differences
   * Not available in the -lang qb dialect.

Differences from QB
   * New to FreeBASIC

See also
   * Event
   * Screen (Graphics)
   * Inkey
   * MultiKey
   * GetMouse
   * Event Handling
   * Keyboard scancodes
   * Keyboard Input



----------------------------------------------------- KeyPgScreenglproc ----
ScreenGLProc

Gets the address of an OpenGL procedure

Syntax
   Declare Function ScreenGLProc ( ByRef procname As Const String ) As Any 
   Ptr

Parameters
   procname
      name of the procedure to retrieve the address of

Description
   This function can be used to get the address of any OpenGL procedure, to 
   be used to retrieve the pointers to new functions associated with OpenGL 
   extensions. If given procedure named procname cannot be found, 
   ScreenGLProc will return NULL (0).

Example
   '' include fbgfx.bi for some useful definitions
   #include "fbgfx.bi"

   Dim SwapInterval As Function(ByVal interval As Integer) As Integer
   Dim extensions As String

   '' Setup OpenGL and retrieve supported extensions
   ScreenRes 640, 480, 32,, FB.GFX_OPENGL
   ScreenControl FB.GET_GL_EXTENSIONS, extensions

   If (InStr(extensions, "WGL_EXT_swap_control") <> 0) Then
      '' extension supported, retrieve proc address
      SwapInterval = ScreenGLProc("wglSwapIntervalEXT")
      If (SwapInterval <> 0) Then
         '' Ok, we got it. Set OpenGL to wait for vertical sync on buffer swaps
         SwapInterval(1)
      End If
   End If

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Screenglproc.

Platform Differences
   * Not available for DOS target.

Differences from QB
   * New to FreeBASIC

See also
   * Screen (Graphics)
   * ScreenControl



------------------------------------------------------- KeyPgScreeninfo ----
ScreenInfo

Retrieves information about current video mode or the desktop.

Syntax
   Declare Sub ScreenInfo ( ByRef w As Long = 0, ByRef h As Long = 0, ByRef 
   depth As Long = 0, ByRef bpp As Long = 0, ByRef pitch As Long = 0, ByRef 
   rate As Long = 0, ByRef driver As String = "" )
   Declare Sub ScreenInfo ( ByRef w As LongInt, ByRef h As LongInt, ByRef 
   depth As LongInt = 0, ByRef bpp As LongInt = 0, ByRef pitch As LongInt = 
   0, ByRef rate As LongInt = 0, ByRef driver As String = "" )

Usage
   in the LONG (or INTEGER<32>) version of the sub:
      ScreenInfo [ w ] [, [ h ] [, [ depth ] [, [ bpp ] [, [ pitch ] [, [ 
      rate ] [, driver ]]]]]]
   in the LONGINT (or INTEGER<64>) version of the sub:
      ScreenInfo w , h [, [ depth ] [, [ bpp ] [, [ pitch ] [, [ rate ] [, 
      driver ]]]]]

Parameters
   w
      Width.
   h
      Height.
   depth
      Color depth in bits.
   bpp
      Bytes per pixel.
   pitch
      Bytes per scan line.
   rate
      Refresh rate.
   driver
      Driver name.

Description
   This function can be useful to get current mode informations like 
   graphics driver name, color depth, screen size and more.

   If ScreenInfo is called when no graphics mode is set, it returns the 
   information about the desktop.

   Here's a description of available fields:

      +------+-------------------------------------------------------------------------------------------+
      |w     |Width of the screen in pixels                                                              |
      |h     |Height of the screen in pixels                                                             |
      |depth |Current pixel format bits per pixel: this can be 1, 2, 4, 8, 16, or 32                     |
      |bpp   |Bytes per pixel                                                                            |
      |pitch |Size of a framebuffer row in bytes                                                         |
      |rate  |Current refresh rate, or 0 if unknown                                                      |
      |driver|Name of current graphics driver in use, like DirectX (Direct2D added on new systems) or X11|
      +------+-------------------------------------------------------------------------------------------+

Example
   Dim w As Long, h As Long
   Dim depth As Long
   Dim driver_name As String

   Screen 15, 32 
   ' Obtain info about current mode 
   ScreenInfo w, h, depth,,,,driver_name
   Print Str(w) + "x" + Str(h) + "x" + Str(depth); 
   Print " using " + driver_name + " driver" 
   Sleep 
   ' Quit graphics mode and obtain info about desktop 
   Screen 0 
   ScreenInfo w, h, depth 
   Print "Desktop running at " + Str(w) + "x" + Str(h) + "x" + Str(depth); 

Version
   * Before fbc 1.08.0:
         Syntax:
            Declare Sub ScreenInfo ( ByRef w As Integer = 0, ByRef h As 
            Integer = 0, ByRef depth As Integer = 0, ByRef bpp As Integer = 
            0, ByRef pitch As Integer = 0, ByRef rate As Integer = 0, ByRef 
            driver As String = "" )
         Usage:
            ScreenInfo [ w ] [, [ h ] [, [ depth ] [ , [ bpp ] [ , [ pitch 
            ] [ , [ rate ] [, driver ]]]]]]

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Screeninfo.

Differences from QB
   * New to FreeBASIC

See also
   * Screen (Graphics)



------------------------------------------------------- KeyPgScreenlist ----
ScreenList

Finds available fullscreen video modes

Syntax
   Declare Function ScreenList ( ByVal depth As Long = 0 ) As Long

Usage
   result = ScreenList( [ depth ] )

Parameters
   depth
      the color depth for which the list of modes is requested  (supported 
      depths are 8, 15, 16, 24 and 32)

Return Value
   returns 0, when there are no more resolutions to read.

Description
   It works like the Dir function: the first call to the function requires 
   the depth parameter to be specified, it  returns the lowest supported 
   resolution for the requested depth. Further calls to ScreenList without 
   arguments returns the next resolutions. When no more resolutions are 
   available, ScreenList returns 0.

   The result of ScreenList is encoded as a 32 bit value, with the screen 
   width as the High Word and the height as the Low Word.

   Resolutions are returned from lowest to highest supported ones. 

   It is safe to call this function before any graphics mode has been set.

Example
   Dim As Long mode
   Dim As UInteger w, h

   Print "Resolutions supported at 8 bits per pixel:"

   mode = ScreenList(8)
   While (mode <> 0)
      w = HiWord(mode)
      h = LoWord(mode)
      Print w & "x" & h
      mode = ScreenList()
   Wend

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Screenlist.

Differences from QB
   * New to FreeBASIC

See also
   * Screen (Graphics)
   * ScreenRes



------------------------------------------------------- KeyPgScreenlock ----
ScreenLock

Locks the working page's frame buffer

Syntax
   Declare Sub ScreenLock ( )

Usage
   ScreenLock

Description
   All of FreeBASIC's Graphics Library functions draw to a frame buffer and 
   an automatic routine copies the frame buffer to the actual screen memory 
   at each draw. If the user program does a lot of drawing, the automatic 
   refreshes may take a significant amount of time.

   The ScreenLock function locks the automatic refresh, so several drawing 
   operations may be done before the screen refresh is performed, thus 
   increasing the speed of execution, and preventing the user from seeing 
   partial results. 

   Frame buffer memory may be freely accessed by using pointers (see 
   ScreenPtr) ONLY while the screen is locked. Primitive graphics 
   statements (Line, PSet, Draw String, ...)  may be used at any time.

   The screen refresh remains locked until the use of ScreenUnlock 
   statement, which resumes it.  

   Calls to ScreenLock must be paired with a matching call to ScreenUnlock. 
   The graphics driver keeps track of how many times ScreenLock has been 
   called using a counter.  Only the first call to ScreenLock actually 
   performs a locking operation.  Subsequent calls to ScreenLock only 
   increment the counter.  Conversely, ScreenUnlock only decrements the 
   lock counter until it reaches zero at which time the actual unlock 
   operation will be performed.  Using Screen (Graphics) or ScreenRes will 
   release all locks and set the lock counter back to zero before changing 
   screen modes.

   It is strongly recommended that the lock on a page be held for as short 
   a time as possible. Only screen drawing should occur while the screen is 
   locked, input/output and waiting must be avoided. In Win32 and Linux the 
   screen is locked by stopping the thread that processes also the OS' 
   events. If the screen is kept locked for a long time the event queue 
   could overflow and make the system unstable. When the induced lock time 
   becomes too long, use preferably the method of double buffering (with 
   ScreenCopy).

   The automatic refresh takes place only in the visible page of the frame 
   buffer. ScreenLock has no effect when drawing to pages other than the 
   visible one. 	

Example
   '' Draws a circle on-screen at the mouse cursor
   Dim As Long mx, my
   Dim As String key

   ScreenRes 640, 480, 32

   Do

     'process
     GetMouse(mx, my)
     key = Inkey()

     'draw
     ScreenLock()
     Cls()
     Circle (mx, my), 8, RGB(255, 255, 255)
     ScreenUnlock()

     'free up CPU time
     Sleep(18, 1)
     
   Loop Until key = Chr(27) Or key = Chr(255, 107)

Platform Differences
   * In DOS, the mouse arrow does not react to mouse movements while the 
     screen is locked

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Screenlock.

Differences from QB
   * New to FreeBASIC

See also
   * Screen (Graphics) - Setting mode
   * ScreenRes - Setting mode
   * ScreenUnlock
   * ScreenPtr



-------------------------------------------------------- KeyPgScreenptr ----
ScreenPtr

Returns a pointer to the current work page's frame buffer

Syntax
   Declare Function ScreenPtr ( ) As Any Ptr

Usage
   result = ScreenPtr

Return Value
   a pointer to the current work page frame buffer memory, or NULL (0) if 
   no graphics mode is set.

Description
   ScreenPtr provides a way to directly read/write the working page's frame 
   buffer. ScreenLock should be used before any read or writes are 
   attempted. The pointer returned is valid up until any subsequent call to 
   Screen (Graphics) or ScreenRes, which invalidates it.

   ScreenPtr can also be used to test if a call to Screen (Graphics) or 
   ScreenRes was successful, indicated by a non-NULL (<> 0) return value.

   In order to access a pixel in the screen buffer, you will need to know 
   the screen's bytes per pixel and pitch (bytes per row), and also the 
   width and height to avoid going out of bounds.  This information can be 
   found out using ScreenInfo.
   Each row in the frame buffer is pitch bytes long.  The frame buffer 
   consists of height rows, stored in order of their position on the 
   screen, running from top to bottom, left to right.

   Because of the design of FreeBASIC graphics library, ScreenPtr (if 
   non-NULL) will always point to the backbuffer, and never to actual video 
   RAM.

Example
   Const SCREEN_WIDTH = 640, SCREEN_HEIGHT = 480
   Dim As Long w, h, bypp, pitch

   '' Make 8-bit screen.
   ScreenRes SCREEN_WIDTH, SCREEN_HEIGHT, 8

   '' Get screen info (w and h should match the constants above, bypp should be 1)
   ScreenInfo w, h, , bypp, pitch

   '' Get the address of the frame buffer. An Any Ptr 
   '' is used here to allow simple pointer arithmetic
   Dim buffer As Any Ptr = ScreenPtr()
   If (buffer = 0) Then
      Print "Error: graphics screen not initialized."
      Sleep
      End -1
   End If

   '' Lock the screen to allow direct frame buffer access
   ScreenLock()
      
      '' Find the address of the pixel in the centre of the screen
      '' It's an 8-bit pixel, so use a UByte Ptr.
      Dim As Integer x = w \ 2, y = h \ 2
      Dim As UByte Ptr pixel = buffer + (y * pitch) + (x * bypp)
      
      
      '' Set the center pixel color to 10 (light green).
      *pixel = 10

   '' Unlock the screen.
   ScreenUnlock()

   '' Wait for the user to press a key before closing the program
   Sleep

   Const SCREEN_WIDTH = 256, SCREEN_HEIGHT = 256
   Dim As Long w, h, bypp, pitch

   '' Make 32-bit screen.
   ScreenRes SCREEN_WIDTH, SCREEN_HEIGHT, 32

   '' Get screen info (w and h should match the constants above, bypp should be 4)
   ScreenInfo w, h, , bypp, pitch

   '' Get the address of the frame buffer. An Any Ptr 
   '' is used here to allow simple pointer arithmetic
   Dim buffer As Any Ptr = ScreenPtr()
   If (buffer = 0) Then
      Print "Error: graphics screen not initialized."
      Sleep
      End -1
   End If

   '' Lock the screen to allow direct frame buffer access
   ScreenLock()
      
      '' Set row address to the start of the buffer
      Dim As Any Ptr row = buffer
      
      '' Iterate over all the pixels in the screen:
      
      For y As Integer = 0 To h - 1
         
         '' Set pixel address to the start of the row
         '' It's a 32-bit pixel, so use a ULong Ptr
         Dim As ULong Ptr pixel = row
         
         For x As Integer = 0 To w - 1
            
            '' Set the pixel value
            *pixel = RGB(x, x Xor y, y) 
            
            '' Get the next pixel address 
            '' (ULong Ptr will increment by 4 bytes)
            pixel += 1
            
         Next x
         
         '' Go to the next row
         row += pitch
         
      Next y

   '' Unlock the screen.
   ScreenUnlock()

   '' Wait for the user to press a key before closing the program
   Sleep

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Screenptr.

Differences from QB
   * New to FreeBASIC

See also
   * Screen (Graphics)
   * ScreenRes
   * ScreenInfo
   * ScreenLock
   * ScreenUnlock



-------------------------------------------------------- KeyPgScreenres ----
ScreenRes

Initializes a graphics mode by specifying horizontal and vertical 
resolution

Syntax
   Declare Function ScreenRes ( ByVal width As Long, ByVal height As Long, 
   ByVal depth As Long = 8, ByVal num_pages As Long = 1, ByVal flags As Long
   = 0, ByVal refresh_rate As Long = 0 ) As Long
 
Usage
   ScreenRes width, height [, [depth] [, [num_pages] [, [flags] [, 
   refresh_rate ]]]]
   result = ScreenRes( width, height [, [depth] [, [num_pages] [, [flags] 
   [, refresh_rate ]]]] )

Parameters
   width, height
      The display width and height, respectively. For fullscreen mode, the 
      user should check the availability of the resolution using ScreenList
      .
   depth
      The color depth in bits per pixel. Valid color depths are: 1, 2, 4, 8
      , 16 and 32.  Values of 15 and 24 are also allowed as aliases for 16 
      and 32, respectively.  If omitted, the default is 8 bits per pixel.  
      8 bits and below will give a palette image.  The default palette will 
      be the first 2 ^ depth colors of the 256-color palette used in 
      Screen (Graphics) 13.
   num_pages
      The number of video pages to create, defaults to 1. (see 
      Screen (Graphics))
   flags
      Used to set various properties of the screen, including fullscreen 
      mode and graphics driver priority. (see the standard header 
      "fbgfx.bi" for available flags)
   refresh_rate
      The desired refresh rate of the screen, only has an effect for 
      fullscreen modes, and some systems and drivers only. Defaults to an 
      appropriate value, invalid refresh rates will be ignored.

Return Value
   Returns zero (0) if successful, or a non-zero error code to indicate a 
   failure. (throws a runtime error) (???)

Description
   ScreenRes tells the compiler to link the GfxLib and initializes a 
   QB-only, QB-on-GUI or OpenGL graphics mode, depending on the flags 
   setting.

   ScreenRes  clears the created window or the full screen. In 
   non-fullscreen modes, the resolution does not have to match any 
   resolution of the graphics card. Resolutions like 555x111 are possible, 
   GfxLib will create a window of such size. See the page GfxLib overview 
   for DOS issues.

   The font size in ScreenRes modes is set to 8x8 by default.  This can be 
   changed by setting the number of text rows/columns, using the Width 
   function.

   In QB-only modes a dumb window or fullscreen resolution is set, one or 
   more buffers in standard memory are created,  console commands are 
   redirected to their graphic versions, a default palette is set and an 
   automatic screen refresh thread is started. QB-like graphics and console 
   statements can be used.  

    In QB-on-GUI modes one or more buffers in standard memory are created,  
   console commands are redirected to their graphic versions and a 
   default palette is set. QB-like  graphics and console statements can be 
   used.  It is up to the user to create a window and to refresh it with 
   the contents of the graphics buffers.

   In OpenGL modes a dumb window or fullscreen resolution is set, one or 
   more buffers in standard memory are created, and the system's OpenGL 
   library is initialized. From here only OpenGL commands can be used to 
   write to the graphics buffer. QB-like and console commands are 
   forbidden. This mode allows to initialize OpenGL in a portable way.

   The error code returned by ScreenRes can be checked using Err in the 
   next line. The function version of  ScreenRes returns directly the error 
   code as a 32 bit Long.

flags details:

   If flags are omitted, FreeBASIC uses QB-compatible graphics in windowed 
   (except in DOS) mode.  These constants are defined in fbgfx.bi.  In the 
   -lang fb dialect, these constants are part of the FB Namespace. Their 
   values can be combined to form a mask using Operator Or. Note that most 
   of the flags are not supported in DOS.

   Available flags:

   graphic mode flags
      GFX_NULL: Starts a QB-on-GUI graphics mode.  It creates a graphics 
      buffer but not a window.  User must implement the window, the events 
      manager and refresh the screen as needed.  This mode allows to mix 
      FreeBASIC drawing functions with API-driven windows.  Alternatively, 
      it allows to process graphics (for example files) without making it 
      visible on the screen, even in a purely console application.  This 
      flag overrides all other mode flags.  See an Example of GFX_NULL in 
      Windows.
      GFX_OPENGL: Initializes OpenGL to draw in a dumb window. FreeBASIC 
      graphic functions can't be used.  The screen is not automatically 
      updated, Flip must be used.  This option provides a portable way to 
      initialize the OpenGL Library.
      If none of the above options is specified, FreeBASIC enters the 
      QB-only graphics mode: it creates a buffer and a dumb window and sets 
      a thread that automatically updates the screen and manages keyboard 
      and mouse.  The FreeBASIC drawing functions can be used.

   window mode flags
      Window mode flags are meaningless if  GFX_NULL mode is used
      GFX_WINDOWED: If windowed mode is supported, FreeBASIC opens a window 
      of the requested size in the present desktop
      GFX_FULLSCREEN: The graphics card switch mode is switched to the 
      requested mode and color depth and OS fullscreen mode is used.  If 
      the mode is not available in the present card FreeBASIC switches to 
      windowed mode.
      If GFX_FULLSCREEN is not specified, the behavior for GFX_WINDOWED is 
      assumed.
      GFX_NO_SWITCH: Prevents the user from changing to fullscreen or to 
      windowed mode by pressing Alt-Enter.
      GFX_NO_FRAME: Creates a window without a border.
      GFX_SHAPED_WINDOW: Creates transparent regions wherever RGBA(255, 0, 
      255, 0) is drawn on the screen.
      GFX_ALWAYS_ON_TOP: Creates a window that stays always on top.

   option flags
      Flags working in any mode, they activate special behaviors
      GFX_ALPHA_PRIMITIVES: Tells the graphics library to enable alpha 
      channel support for all drawing primitives. This means the alpha 
      specified in a color value (via either the RGBA macro or direct color 
      in the form &hAARRGGBB) will always be used by all primitives.
      GFX_HIGH_PRIORITY: Tells the graphics library to enable a higher 
      priority for graphics processing.  Only has an effect on gdi and 
      DirectX drivers on Win32 platform and Direct2D added on new 
      platforms.
      GFX_NO_X86_MMX: Tells the graphics library not to use MMX blitters on 
      X86 even if MMX cpu instructions are available.

   OpenGL Buffer flags
      These flags work only in OpenGL graphics mode, must be combined with 
      GFX_OPENGL
      GFX_STENCIL_BUFFER: Forces OpenGL to use Stencil buffer 
      GFX_ACCUMULATION_BUFFER: Forces OpenGL to use Accumulation buffer
      GFX_MULTISAMPLE: Requests fullscreen anti-aliasing through the 
      ARB_multisample extension

   Depending on whether the GFX_FULLSCREEN parameter is present or not, 
   Screen will try to set the specified video mode in fullscreen or 
   windowed mode, respectively.  If fullscreen mode is set and the system 
   cannot set specified mode in fullscreen, it will try in windowed mode. 
   If windowed mode is set and the system fails to open a window for 
   specified mode, it will try fullscreen.  If everything fails, Screen 
   will have no effect and execution will resume from the statement 
   following the Screen call.  You should take care of checking if a 
   graphics mode has been set or not, and behave accordingly; a way to 
   check if Screen is successful is to test the return value of the 
   ScreenPtr function; see its page for details.

   Note:
      Screen 0 closes any graphics window, but also clears the console 
      window if it exists.
      Screen 0, , , GFX_SCREEN_EXIT (with GFX_SCREEN_EXIT=&h80000000) also 
      closes any graphics window, but does not clear the console window if 
      it exists (previous text is preserved).

Graphics mode console
   Console commands (Locate, Print), input can be used both with standard 
   QB Screen modes and with the extended ones too, provided the standard 
   color depth is not modified by using the second argument of Screen. 
   Where the table says more than one text resolution is available for the 
   text mode, the required text resolution can be requested by using Width. 
   Any characters Printed will erase the background around them; it does 
   not use a transparent background.

Example
   ' Set the screen mode to 320*200, with 8 bits per pixel
   ScreenRes 320, 200, 8

   ' Draw color bands in a diagonal pattern over the whole screen
   For y As Long = 0 To 200-1
      For x As Long = 0 To 320-1
         PSet (x,y),(x + y) And 255
      Next x
   Next y

   ' Display the text "Hello World!!" over the lines we've drawn, in the top-left hand corner
   Print "Hello world!!"

   ' Keep the window open until the user presses a key
   Sleep

Version
   Since 1.20.0: GFX_NO_X86_MMX

Platform Differences
   * In DOS, Windowing and OpenGL related switches are not available, and 
     other issues, see GfxLib overview

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Screenres.

Differences from QB
   * New to FreeBASIC

See also
   * Screen (Graphics) The QB-like way to set graphics mode
   * ScreenList Check display modes available for FB GfxLib to use
   * ScreenControl Select driver and more 
   * ScreenLock
   * ScreenUnlock
   * ScreenPtr Semi-low level access
   * ScreenSet
   * ScreenCopy
   * ScreenInfo
   * ScreenGLProc
   * Internal pixel formats
   * FaqPggfxlib2



-------------------------------------------------------- KeyPgScreenset ----
ScreenSet

Sets current work and visible pages

Syntax
   Declare Sub ScreenSet ( ByVal work_page As Long = -1, ByVal visible_page 
   As Long = -1 )

Usage
   ScreenSet [ work_page ] [, visible_page ]

Parameters
   work_page
      index to working page
   visible_page
      index to visible page

Description
   ScreenSet allows to set the current working page and the current visible 
   page. Page numbers range from 0 to num_pages - 1, where num_pages is the 
   number of pages specified when setting the graphics mode with ScreenRes 
   or Screen (Graphics).  You can use this function to achieve 
   page-flipping or double-buffering.

   If you provide visible_page but omit work_page, only the visible page is 
   changed. If you provide work_page but omit visible_page, only the work 
   page is changed. If you omit both arguments, both work page and visible 
   page are reset to page 0.

   ScreenSet provides one method of writing to the screen without instantly 
   displaying changes to the user.  See also ScreenLock / ScreenUnlock for 
   an alternative method of doing this.

   Note: The current cursor position is not handled independently for each 
   video page. Therefore, when another working page is selected, the 
   starting cursor position corresponds to the last cursor position on the 
   previous working page (same behavior for the text cursor and the 
   graphics cursor).

Example
   ' Open graphics screen (320*200, 8bpp) with 2 pages
   ScreenRes 320, 200, 8, 2

   ' Work on page 1 while displaying page 0
   ScreenSet 1, 0

   Dim As Integer x = -40

   Do
      '' Clear the screen, draw a box, update x
      Cls
      Line (x, 80)-Step(39, 39), 4, BF
      x += 1: If (x > 319) Then x = -40
      
      ' Wait for vertical sync: only used to control refresh rate, can be put anywhere in the Do loop
      ScreenSync
      
      ' Copy work page to visible page
      ScreenCopy
      
   Loop While Inkey = ""

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Screenset.

Differences from QB
   * New to FreeBASIC

See also
   * Screen (Graphics)
   * ScreenRes
   * ScreenCopy
   * ScreenLock
   * ScreenUnlock



------------------------------------------------------- KeyPgScreensync ----
ScreenSync

Synchronizes display updates with hardware

Syntax
   Declare Function ScreenSync ( ) As Long

Usage
   result = ScreenSync

Return Value
   Zero if successful, or non-zero if a graphics mode was not previously 
   set.

Description
   This GfxLib statement stops the execution of the program until the 
   graphics card signals it has ended tracing a frame and is going to start 
   the new one.

   If the program uses this small interval of time between frames to redraw 
   the image, the flickering is greatly reduced. In that use, ScreenSync is 
   a reminiscence of QB where there was only that equivalent method (Wait 
   &H3DA, 8) to improve the flickering. It is an empirical method because 
   it only allows to synchronize the beginning of the drawing with the 
   fixed dead time between two frames. To be used occasionally to avoid 
   flickering when only very short time of drawing.

   Except the purpose to reduce the flickering, ScreenSync can be also used 
   simply as a method of synchronization of graphic drawing with the screen 
   frame tracing (similarly to statement Sleep).

   The error code returned by ScreenSync can be checked using Err in the 
   next line. The function version of  ScreenSync returns directly the 
   error code as a 32 bit Long.

   The use of the QB-compatible form Wait &H3DA, 8 is deprecated.

Example
   'main loop
   Do
     
     ' do user input
     ' calculate_a_frame
      
     ScreenSync
     
     ' draw_ a_ frame  
     
   Loop Until Inkey <> ""

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Screensync.

Differences from QB
   * New to FreeBASIC. 
   * QBasic used Wait &H3DA, 8 for this purpose.

See also
   * Wait



----------------------------------------------------- KeyPgScreenunlock ----
ScreenUnlock

Unlocks work page's framebuffer

Syntax
   Declare Sub ScreenUnlock ( ByVal startline As Long = -1, ByVal endline As
   Long = -1 )

Usage
   ScreenUnlock [ start_line ] [, end_line ]

Parameters
   startline
      optional argument specifying first screen line to be updated. If 
      omitted, top screen line is assumed.
   endline
      optional argument specifying last screen line to be updated. If 
      omitted, bottom screen line is assumed.

Description
   ScreenUnlock unlocks the current work page assuming it was previously 
   locked by calling ScreenLock and lets the system restart updating the 
   screen regularly. When called with start_line and end_line , only the 
   screen area between those lines is assumed to have changed, and will be 
   updated. 

   An internal counter exists that remembers the screen lock state, thus 
   ScreenUnlock has an effect only on a screen that is locked.  A screen 
   that has not been locked with ScreenLock cannot get unlocked, however 
   ScreenUnlock still will force an update of given area or full screen.   

   Calls to ScreenUnlock must be paired with matching calls to ScreenLock.  
   Only the first call to ScreenLock actually performs a locking operation. 
   Subsequent calls to ScreenLock only increment the lock counter.  
   Conversely, ScreenUnlock only decrements the lock counter until it 
   reaches zero at which time the actual unlock operation will be 
   performed.  Using Screen (Graphics) or ScreenRes will release all locks 
   and set the lock counter back to zero before changing screen modes.

   All graphic statements automatically lock the screen before the function 
   call, and unlock the screen afterwards, so you do not need to do this 
   explicitly using ScreenLock and ScreenUnlock. You only need to lock the 
   screen when you wish to access the screen (framebuffer) directly using 
   ScreenPtr  or when you wish to group several graphic statements together 
   so their effects appear simultaneously on screen, thus avoiding 
   potential screen flicker during screen updates.

   Warning (Win32, Linux) : The screen is locked by stopping the thread 
   that processes also the OS' events. This means the screen should be 
   locked only for the short time required to redraw it, and no user input 
   will be received while the screen is locked. When the induced lock time 
   becomes too long, use preferably the method of double buffering (with 
   ScreenCopy).

Example
   See ScreenPtr example.

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Screenunlock.

Differences from QB
   * New to FreeBASIC

See also
   * Screen (Graphics)
   * ScreenLock
   * ScreenPtr



----------------------------------------------------------- KeyPgSecond ----
Second

Gets the seconds from a Date Serial 

Syntax
   Declare Function Second ( ByVal date_serial As Double ) As Long

Usage
   #include "vbcompat.bi"
   result = Second( date_serial )

Parameters
   date_serial
      the date serial

Return Value
   Returns the seconds from a  variable containing a date in  Date Serial  
   format.

Description
    
   The compiler will not recognize this function unless vbcompat.bi is 
   included.

Example
   #include "vbcompat.bi"

   Dim ds As Double = DateSerial(2005, 11, 28) + TimeSerial(7, 30, 50)

   Print Format(ds, "yyyy/mm/dd hh:mm:ss "); Second(ds)

Differences from QB
   * Did not exist in QB. This function appeared in PDS and VBDOS

See also
   * Date Serials



---------------------------------------------------------- KeyPgSeekset ----
Seek (Statement)

Sets the position of the next read/write operation on a file

Syntax
   Seek [#]filenum, position

Parameters
   filenum
      file number of an opened a file
   position
      the new position for i/o operations

Description
   Sets the position at which the next read or write operation on a file 
   will occur.

   The position is given in records if the file was opened in Random access 
   mode, in bytes in any other case. The position is 1 based -- the first 
   record of a file is at position 1.

   The Seek function is used to get the position of the next read or write 
   operation.

Example
   ' e.g. if you want to skip to the 100th byte in the file for reading/writing:

   Dim f As Long

   f = FreeFile
   Open "file.ext" For Binary As #f

   Seek f, 100

   Close #f

Differences from QB
   * None

See also
   * Seek (Function)
   * Open



------------------------------------------------------- KeyPgSeekreturn ----
Seek (Function)

Gets the position of the next read/write operation for a file or device

Syntax
   Declare Function Seek ( ByVal filenum As Long ) As LongInt

Parameters
   filenum
      file number of an open file

Return Value
   The file position where the next read or write operation will take 
   place.

Description
   The position is given in records if the file was opened in Random access 
   mode, in bytes in any other case. The file position returned is 1-based, 
   so the first record of a file is 1.

   The Seek statement is used to set the position of the next read or write 
   operation.

Example
   Dim f As Long, position As LongInt

   f = FreeFile
   Open "file.ext" For Binary As #f

   position = Seek(f)

   Close #f

Differences from QB
   * None

See also
   * Seek (Statement)
   * LOC
   * Open



------------------------------------------------------- KeyPgSelectcase ----
Select Case

Conditional statement block

Syntax
   Select Case expression
   [ Case expressionlist] 
      [statements]
   [ Case Else ]
      [statements]
   End Select
or
   Select Case As Const integer_expression
   [ Case constant | enumeration ]
      [ statements ]
   [ Case Else ]
      [ statements ]
   End Select

Description
   Select Case executes specific code depending on the value of an 
   expression. The expression is evaluated once, and compared against each 
   Case, in order, until a matching expression is found. The code inside 
   the matching Case branch is executed, and the program skips down to the 
   end of the Select Case block. Case Else matches any case not already 
   matched, so if there is a Case Else, at least one Case is guaranteed to 
   be executed. If no Cases match, the whole Select Case block will be 
   skipped.

   End Select is used to close the Select Case...End Select block.

   Exit Select can be used to escape the Select Case block, preventing 
   further code in the Case block from being executed.

   Note for C users: In FreeBASIC, Select Case works like a switch block 
   where all cases have a break at the end. As there is no fall-through, 
   multiple options must be put in an expression list in a single Case.

   Besides integer types, floating point and string expressions are also 
   supported with the first syntax.  

   Syntax of an expression list:
   { expression | expression To expression | Is relational operator 
   expression }[, ...]

   * expr: evaluates expr, and compares for equality with the original 
     expression.  If they are equal, then a match has been found.  This 
     could be considered as a shorthand for "Is = expr" (see below).
   * expr1 To expr2: evaluates expr1 and checks to see if it is less than 
     or equal to the original expression.  If so, it evaluates expr2, and 
     checks to see if it is greater than or equal to the original 
     expression.  If so, then a match has been found.
   * Is relational_operator expr: evaluates expr, and compares the 
     original operation against it, using the supplied relational_operator 
     (=, >, <, <>, <=, >=).  If the comparison is true, then a match has 
     been found.

   Multiple checks can be made in each Case, by separating them by a comma 
   (,).  Once a match is found, the program finishes its checks, and goes 
   on to execute the code statements for that Case block.  No further 
   expressions are evaluated or checked.

   example of expression lists:
      +--------------------+-----------------------------+
      |Case 1              |constant                     |
      |Case 5.4 To 10.1    |range                        |
      |Case Is > 3         |bigger than-smaller than     |
      |Case 1, 3, 5, 7 to 9|match against a set of values|
      |Case x              |value of a variable          |
      +--------------------+-----------------------------+

   If As Const is used, only integer constants (all numeric constants 
   excluding the two floating-point constants: single and double) can be 
   evaluated and the expression list supports simple constants and 
   enumerations only. "To" ranges are supported, but "Is" relational 
   operators are not.

   With As Const, a jump table is created to contain the full range of 
   integer Cases handled.  This allows Select Case As Const to be faster 
   than Select Case.
   However, the size of the range of values is limited, and after 
   converting the values to the uinteger type, the largest value in the 
   range may be no higher than the smallest value + 8191 (current 
   implementation).

   Note: No statement can be placed between the Select Case statement and 
   the first Case statement.

Example

   Dim choice As Integer

   Input "Choose a number between 1 and 10: "; choice

   Select Case As Const choice
   Case 1
      Print "number is 1"
   Case 2
      Print "number is 2"
   Case 3, 4
      Print "number is 3 or 4"
   Case 5 To 10
      Print "number is in the range of 5 to 10"
   Case Else
      Print "number is outside the 1-10 range"
   End Select

   '' SELECT CASE vs. SELECT CASE AS CONST speed test

   Const N = 50000000

   Dim As Integer dummy = 0
   Dim As Double t = Timer()

   For i As Integer = 1 To N
      Select Case i
      Case 1, 3, 5, 7, 9
         dummy += 1
      Case 2, 4, 6, 8, 10
         dummy += 1
      Case 11 To 20
         dummy += 1
      Case 21 To 30
         dummy += 1
      Case 31
         dummy += 1
      Case 32
         dummy += 1
      Case 33
         dummy += 1
      Case Is >= 34
         dummy += 1
      Case Else
         Print "can't happen"
      End Select
   Next

   Print Using "SELECT CASE: ##.### seconds"; Timer() - t
   t = Timer()

   For i As Integer = 1 To N
      Select Case As Const i
      Case 1, 3, 5, 7, 9
         dummy += 1
      Case 2, 4, 6, 8, 10
         dummy += 1
      Case 11 To 20
         dummy += 1
      Case 21 To 30
         dummy += 1
      Case 31
         dummy += 1
      Case 32
         dummy += 1
      Case 33
         dummy += 1
      Case Else
         If( i >= 34 ) Then
            dummy += 1
         Else
            Print "can't happen"
         End If
      End Select
   Next

   Print Using "SELECT CASE AS CONST: ##.### seconds"; Timer() - t
   Sleep

Differences from QB
   * Select Case As Const did not exist in QB.
   * in an "expr1 TO expr2" case, QB would always evaluate both 
     expressions, even if expr1 was higher than the original expression.
   * In the -lang qb and -lang fblite dialects, variables declared inside 
     a Select..End Select block have a function-wide scope as in QB.
   * In the -lang fb and -lang deprecated dialects, variables declared 
     inside a Select..End Select block are visible only inside the block, 
     and can't be accessed outside it. To access duplicated symbols defined 
     as global outside this block, add one or preferably two dot(s) as 
     prefix: .SomeSymbol or preferably ..SomeSymbol (or only ..SomeSymbol 
     if inside a With..End With block).

See also
   * If...Then



---------------------------------------------------------- KeyPgSetdate ----
SetDate

Sets the current system date

Syntax
   Declare Function SetDate ( ByRef newdate As Const String ) As Long

Usage
   result = SetDate( newdate )

Parameters
   newdate
      the new date to set

Return Value
   Returns zero on success or non-zero on failure on all ports except DOS.

Description
   To set the date you just format newdate and send to SetDate in a valid 
   format following one of the following: "mm-dd-yy", "mm-dd-yyyy", 
   "mm/dd/yy", or "mm/dd/yyyy" (mm is the month, dd is the day, yy or yyyy 
   is the year). Two-digit year numbers are based on the year 1900.

   The error code returned by SetDate can be checked using Err in the next 
   line. The function version of  SetDate returns directly the error code 
   as a 32 bit Long.

Example
   Dim m As String, d As String, y As String
   m = "03" 'march
   d = "13" 'the 13th
   y = "1994" 'good ol' days
   SetDate m + "/" + d + "/" + y

Platform Differences
   * On Windows the privilege SE_SYSTEMTIME_NAME is required, which 
     typically means that the calling process has to be run with 
     administrator privileges.
   * On Linux the capability CAP_SYS_TIME is required, which typically 
     means that the calling process has to run as root/superuser.

Differences from QB
   * The DATE statement was used in QB and the syntax was "DATE = string"

See also
   * Date
   * SetTime



------------------------------------------------------- KeyPgSetenviron ----
SetEnviron

Sets a system environment variable

Syntax
   Declare Function SetEnviron ( ByRef varexpression As String ) As Long

Usage
   result = SetEnviron( varexpression )

Parameters
   varexpression
      Name and setting of an environment variable in the following (or 
      equivalent) form: varname=varstring.
      (varname being the name of the environment variable, and varstring 
      being its text value to set)

Return Value
   Return zero (0) if successful, non-zero otherwise.

Description
   Modifies system environment variables.  There are several variables 
   available for editing other than the default ones on your system.  An 
   example of this would be fbgfx, where you can choose the form of 
   graphics driver the FreeBASIC graphics library will use.

Example
   'e.g. to set the system variable "path" to "c:":

   Shell "set path" 'shows the value of path
   SetEnviron "path=c:"
   Shell "set path" 'shows the new value of path

     '' WINDOWS ONLY EXAMPLE! - We just set the graphics method to use
     '' GDI rather than DirectX (or Direct2D added on new systems).
     '' You may note a difference in FPS.
   SetEnviron("fbgfx=GDI")

     '' Desktop width/height
   Dim As Long ScrW, ScrH, BPP
   ScreenInfo ScrW, ScrH, BPP

     '' Create a screen at the half width/height of your monitor.
     '' Normally this would be slow, but GDI is fairly fast for this kind
     '' of thing.
   ScreenRes ScrW/2, ScrH/2, BPP

     '' Start our timer/
   Dim As Double T = Timer

     '' Lock our page
   ScreenLock
   Do
     
      '' Print time since last frame
     Locate 1, 1
     Print "FPS: " & 1 / ( Timer - T )
     T = Timer
     
      '' Flip our screen
     ScreenUnlock
     ScreenLock
      '' Commit a graphical change to our screen.
     Cls
     
   Loop Until Len(Inkey)

     '' unlock our page.
   ScreenUnlock

Platform Differences
   * In Linux, varexpression  must be permanent (a literal, a variable 
     declared in the main code or a static variable declared in a 
     procedure), because Linux does not memorize the string but only a 
     pointer to its data characters.

Differences from QB
   * In QB, SetEnviron was called Environ.

See also
   * Environ
   * Shell



--------------------------------------------------------- KeyPgSetmouse ----
SetMouse

Sets the position and visibility of the mouse cursor

Syntax
   Declare Function SetMouse ( ByVal x As Long = -1, ByVal y As Long = -1, 
   ByVal visibility As Long = -1, ByVal clip As Long = -1 ) As Long

Usage
   result = SetMouse([ x ] [, [ y ] [, [ visibility ] [, [ clip ]]]])

Parameters
   (For each parameter, -1 is a special value indicating "no changes.")
   x
      optional - set x coordinate
   y
      optional - set y coordinate
   visibility
      optional - set visibility: 1 indicates visible, 0 indicates hidden
   clip
      optional - set clipping: 1 indicates mouse is clipped to graphics 
      window, 0 indicates no clipping

Return Value
   Zero (0) on success, non-zero to indicate failure.

Description
   SetMouse will set the (x, y) coordinates of the mouse pointer, as well 
   as setting its visibility.  The mouse position is set using the x and y 
   parameters.  The mouse will be visible if visibility is set to 1, and 
   invisible if visibility is set to 0.  SetMouse is intended for graphics 
   modes initiated using the Screen (Graphics) statement only.

   The error code returned by SetMouse can be checked using Err in the next 
   line. The function version of  SetMouse returns directly the error code 
   as a 32 bit Long.

Example
   Dim As Long x, y, buttons

   ' create a screen 640*480
   ScreenRes 640, 480
   Print "Click the mouse button to center the mouse"

   Do
      ' get mouse x, y and button state (wait until mouse is onscreen)
      Do: Sleep 1: Loop While GetMouse( x, y , , buttons) <> 0

      If buttons And 1 Then
         ' on left mouse click, center mouse
         SetMouse 320, 240
      End If

      ' run loop until a key is pressed or the window is closed
   Loop While Inkey = ""

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Setmouse.

Differences from QB
   * New to FreeBASIC

See also
   * GetMouse
   * Screen (Graphics)
   * MultiKey
   * GetKey



---------------------------------------------------------- KeyPgSettime ----
SetTime

Sets the current system time

Syntax
   Declare Function SetTime ( ByRef newtime As Const String ) As Long

Usage
   result = SetTime( newtime )

Parameters
   newtime
      the new time to set

Return Value
   Returns zero on success or non-zero on failure on all ports except DOS.

Description
   To set the time, format the date and send to Settime in one of the 
   following formats: "hh:mm:ss", "hh:mm", or "hh" (hh is the hour, mm is 
   the minute, and ss is the second).

   The error code returned by SetTime can be checked using Err in the next 
   line. The function version of  SetTime returns directly the error code 
   as a 32 bit Long.

Example
   SetTime "1:20:30"

Platform Differences
   * On Windows the privilege SE_SYSTEMTIME_NAME is required, which 
     typically means that the calling process has to be run with 
     administrator privileges.
   * On Linux the capability CAP_SYS_TIME is required, which typically 
     means that the calling process has to be run as root/superuser.

Differences from QB
   * The Time statement was used QB and the syntax was TIME = newtime.

See also
   * Time
   * SetDate



-------------------------------------------------------------- KeyPgSgn ----
Sgn

Returns the sign part of a number

Syntax
   Declare Function Sgn ( ByVal number As numtype ) As numtype

Usage
   result = Sgn( number )

Parameters
   number
      the number to find the sign of
   numtype
      a numeric type

Return Value
   Returns the sign part of number.
   * If number is greater than zero, then Sgn returns 1.
   * If number is equal to zero, then Sgn returns 0.
   * If number is less than zero, then Sgn returns -1.

Description
   The required number argument can be any valid numeric expression.
   Unsigned numbers of size greater than or equal to SizeOf(Any Ptr) will 
   be treated as if they were signed, i.e. if the highest bit is set the 
   number will be treated as negative, and -1 will be returned.

   Note:
      The return type of Sgn depends on the type of the passed argument 
      (variable or constant, its data type), and of the used backend (gas, 
      gas64, gcc 32-bit, gcc 64-bit):
         - Sgn return type for a variable passed as argument:
                  +---------------------+--------------+----------------+----------------+----------------+
                  | Argument            | gas (32-bit) | gas64 (64-bit) | gcc 32-bit (*) | gcc 64-bit (*) |
                  | [U]BYTE variable    | INTEGER      | INTEGER        | LONG           | LONG           |
                  | [U]SHORT variable   | INTEGER      | INTEGER        | LONG           | LONG           |
                  | [U]LONG variable    | INTEGER      | INTEGER        | LONG           | LONG           |
                  | [U]INTEGER variable | INTEGER      | INTEGER        | LONG           | LONG           |
                  | [U]LONGINT variable | LONGINT      | INTEGER        | LONG           | LONG           |
                  | SINGLE variable     | SINGLE       | LONG           | LONG           | LONG           |
                  | DOUBLE variable     | DOUBLE       | LONG           | LONG           | LONG           |
                  +---------------------+--------------+----------------+----------------+----------------+

         - Sgn return type for a constant passed as argument:
                  +---------------------+--------------+----------------+----------------+----------------+
                  | Argument            | gas (32-bit) | gas64 (64-bit) | gcc 32-bit (*) | gcc 64-bit (*) |
                  | [U]BYTE constant    | INTEGER      | INTEGER        | INTEGER        | INTEGER        |
                  | [U]SHORT constant   | INTEGER      | INTEGER        | INTEGER        | INTEGER        |
                  | [U]LONG constant    | INTEGER      | INTEGER        | INTEGER        | INTEGER        |
                  | [U]INTEGER constant | INTEGER      | INTEGER        | INTEGER        | INTEGER        |
                  | [U]LONGINT constant | LONGINT      | INTEGER        | LONGINT        | INTEGER        |
                  | SINGLE constant     | SINGLE       | SINGLE         | SINGLE         | SINGLE         |
                  | DOUBLE constant     | DOUBLE       | DOUBLE         | DOUBLE         | DOUBLE         |
                  +---------------------+--------------+----------------+----------------+----------------+

         (*): applicable also for clang and llvm

   The Sgn unary Operator can be overloaded with user defined types.

Example
   Dim N As Integer = 0

   Print Sgn ( -1.87 )
   Print Sgn ( 0 )
   Print Sgn ( 42.658 )
   Print Sgn ( N )

      The output would look like:

   -1
   0
   1
   0

Dialect Differences
   * In the -lang qb dialect, this operator cannot be overloaded.

Differences from QB
   * None

See also
   * Abs
   * Operator



-------------------------------------------------------------- KeyPgSfx ----
Sfx

Loads and controls short sound effects through sfxlib.

Syntax
   Sfx Load id, filename
   Sfx Play id
   Sfx Play channel, id[, pitch]
   Sfx Loop id
   Sfx Loop channel, id[, pitch]
   Sfx Stop [ id ]
   Sfx Stop Channel, channel
   Sfx Pause [ id ]
   Sfx Pause Channel, channel
   Sfx Resume [ id ]
   Sfx Resume Channel, channel
   status = Sfx Status()
   status = Sfx Status( id )
   status = Sfx Status( Channel, channel )

Description
   Sfx handles short reusable samples.  Sfx Load places a decoded sample in 
   an id slot.  Sfx Play plays it once, while Sfx Loop repeats it.  The 
   channel forms use the channel number first and the loaded effect id 
   second.  The optional pitch argument scales playback speed.

   With no argument, Sfx Stop, Sfx Pause, and Sfx Resume affect all active 
   sound effects.  Sfx Status returns 0 for stopped, 1 for playing, and 2 
   for paused.

Example
   See examples/sfxlib/sfx-load.bas, examples/sfxlib/sfx-play.bas, 
   examples/sfxlib/sfx-loop.bas, examples/sfxlib/sfx-pitch.bas, and 
   examples/sfxlib/showcase.bas.

Differences from QB
   * New to FreeBASIC.

See also
   * Music
   * Audio
   * Generated Sound Commands



----------------------------------------------------------- KeyPgShared ----
Shared

Variable declaration modifier specifying visibility throughout a module

Syntax
   Dim Shared ...
   ReDim Shared ...
   Common Shared ...
   Static Shared ...
   [Static] Var Shared ...

Description
   Shared makes module-level variables visible inside Subs and Functions.
   If Shared is not used on a module-level variable's declaration, the 
   variable is only visible to the module-level code in that file 
   (furthermore, only a variable declared with Dim without Shared modifier, 
   and not inside a Namespace block, is stored on the stack).

   NOTES (for Shared variables excluding Common variables):
      * Generally a Shared variable may only be initialized with a 
        constant value (its starting value is set at the start of the 
        program in the .data section before any code is run, and so it 
        cannot depend on any variables or functions in it).
      * A first exception is a Shared variable of var-len string type, 
        that never can be initialized, even with a constant string (because 
        of its structure with a descriptor in the .data section, but to 
        point to a dynamic memory block).
      * A second exception is a Shared variable of user-defined type 
        having a constructor even implicit, that can be initialized with a 
        non-constant value (because it's the constructor code, called when 
        the program starts, which writes the "initial" values into the 
        .data section).

   To access from a local scope block to duplicated symbols of Shared 
   variables defined in the global namespace, add one or preferably two 
   dot(s) as prefix: .SomeSymbol or preferably ..SomeSymbol (or only ..
   SomeSymbol if inside a With..End With block).

Example
   '' Compile with -lang qb or fblite

   '$lang: "qb"

   Declare Sub MySub
   Dim Shared x As Integer
   Dim y As Integer

   x = 10
   y = 5

   MySub

   Sub MySub
      Print "x is "; x 'this will report 10 as it is shared
      Print "y is "; y 'this will not report 5 because it is not shared
   End Sub

Differences from QB
   * The Shared statement inside scope blocks -- functions, subs, 
     if/thens, and loops -- is not supported. Use Dim|Redim|Common|Static 
     Shared in the main program instead.  Or if you're inside a scope block 
     and Redimming a variable or array previously set up with Shared, just 
     do a Redim without Shared; it will work fine and won't ruin anything.

See also
   * Common
   * Dim
   * Erase
   * Extern
   * LBound
   * ReDim
   * Preserve
   * Static
   * UBound
   * Var
   * Byref (Variables)



------------------------------------------------------------ KeyPgShell ----
Shell

Sends a command to the system command interpreter

Syntax
   Declare Function Shell ( ByRef command As Const String ) As Long

Usage
   result = Shell( command )

Parameters
   command
      A string specifying the command to send to the command interpreter.

Return Value
   If the command could not be executed, -1 is returned. Otherwise, the 
   command is executed and its exit code is returned.

Description
   Program execution will be suspended until the command interpreter exits.

Example
   'e.g. for windows:
   Shell "dir c:*.*"

   'e.g. for linux:
   Shell "ls"

Platform Differences
   * Linux requires the command case matches the real name of the command. 
     Windows and DOS are case insensitive. The program being shelled may be 
     case sensitive for its command line parameters. 
   * Path separators in Linux are forward slashes / . Windows uses 
     backward slashes \ but it allows for forward slashes.  DOS uses 
     backward  \ slashes.
   * If an empty command string is passed, DOS will open an interactive 
     command prompt.  On Windows, an error may be returned.

Differences from QB
   * QB allowed SHELL on its own without a "command" argument which caused 
     a default command shell to be started.  Execution in the main program 
     would suspend until exit from the command shell.  The behaviour in FB 
     is platform-dependent.

See also
   * Exec
   * Run



------------------------------------------------------ KeyPgOpShiftLeft ----
Operator Shl (Shift Left)

Shifts the bits of a numeric expression to the left

Syntax
   Declare Operator Shl ( ByRef lhs As Integer, ByRef rhs As Integer ) As 
   Integer
   Declare Operator Shl ( ByRef lhs As UInteger, ByRef rhs As UInteger ) As 
   UInteger
   Declare Operator Shl ( ByRef lhs As LongInt, ByRef rhs As LongInt ) As 
   LongInt
   Declare Operator Shl ( ByRef lhs As ULongInt, ByRef rhs As ULongInt ) As 
   ULongInt

Usage
   result = lhs Shl rhs

Parameters
   lhs
      The left-hand side expression.
   rhs
      The right-hand side shift expression.

Return Value
   Returns the result of lhs being shifted left rhs number of times.

Description
   Operator Shl (Shift left) shifts all of the bits in the left-hand side 
   expression (lhs) left a number of times specified by the right-hand side 
   expression (rhs). Numerically, the result is the same as "CInt( lhs * 2 ^
   rhs )". For example, "&b0101 Shl 1" returns the binary number &b01010, 
   and "5 Shl 1" returns 10.

   Neither of the operands are modified in any way.

   If the result is too large to fit inside the result's data type, the 
   leftmost bits are discarded ("shifted out").
   The results of this operation are undefined for values of rhs less than 
   zero, or greater than or equal to the number of bits in the result's 
   data type.

   This operator can be overloaded for user-defined types.

Example
   'Double a number
   For i As Integer = 0 To 10
      
      Print 5 Shl i, Bin(5 Shl i, 16)
      
   Next i

Output:

    5            0000000000000101
    10           0000000000001010
    20           0000000000010100
    40           0000000000101000
    80           0000000001010000
    160          0000000010100000
    320          0000000101000000
    640          0000001010000000
    1280         0000010100000000
    2560         0000101000000000
    5120         0001010000000000

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Shl.

Differences from QB
   * New to FreeBASIC

See also
   * Operator Shl= (Shift Left And Assign)
   * Operator Shr (Shift Right)
   * Bin
   * Mathematical Functions



------------------------------------------------------------ KeyPgShort ----
Short

Standard data type: 16 bit signed

Syntax
   Dim variable As Short

Description
   16-bit signed whole-number data type. Can hold values from -32768 to 
   32767.

Example
     Dim x As Short = CShort(&H8000)
     Dim y As Short = CShort(&H7FFF)
     Print "Short Range = "; x; " to "; y

   Output:
   Short Range = -32768 To  32767

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Short.

Differences from QB
   * The name "short" is new to FreeBASIC, however they are the same as 
     integers in QB

See also
   * UShort
   * CShort
   * Table with variable types overview, limits and suffixes



----------------------------------------------------- KeyPgOpShiftRight ----
Operator Shr (Shift Right)

Shifts the bits of a numeric expression to the right

Syntax
   Declare Operator Shr ( ByRef lhs As Integer, ByRef rhs As Integer ) As 
   Integer
   Declare Operator Shr ( ByRef lhs As UInteger, ByRef rhs As UInteger ) As 
   UInteger
   Declare Operator Shr ( ByRef lhs As LongInt, ByRef rhs As LongInt ) As 
   LongInt
   Declare Operator Shr ( ByRef lhs As ULongInt, ByRef rhs As ULongInt ) As 
   ULongInt

Usage
   result = lhs Shr rhs

Parameters
   lhs
      The left-hand side expression.
   rhs
      The right-hand side shift expression.

Return Value
   Returns the result of lhs being shifted right rhs number of times.

Description
   Operator Shr (Shift right) shifts all of the bits in the left-hand side 
   expression (lhs) right a number of times specified by the right-hand 
   side expression (rhs). Numerically, the result is the same as "Int(lhs / 
   2 ^ rhs)". For example, "&b0101 Shr 1" returns the binary number &b010, 
   and "5 Shr 1" returns 2.

   If the left-hand side expression is signed and negative, the sign bit is 
   copied in the newly created bits on the left after the shift.  For 
   example, "-5 Shr 2" returns -2.

   Neither of the operands are modified in any way.

   The results of this operation are undefined for values of rhs less than 
   zero, or greater than or equal to the number of bits in the result's 
   data type.

   This operator can be overloaded for user-defined types.

Example
   'Halve a number
   For i As Integer = 0 To 10
      
      Print 1000 Shr i, Bin(1000 Shr i, 16)
      
   Next i

Output:

    1000         0000001111101000
    500          0000000111110100
    250          0000000011111010
    125          0000000001111101
    62           0000000000111110
    31           0000000000011111
    15           0000000000001111
    7            0000000000000111
    3            0000000000000011
    1            0000000000000001
    0            0000000000000000

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Shr.

Differences from QB
   * New to FreeBASIC

See also
   * Operator Shr= (Shift Right And Assign)
   * Operator Shl (Shift Left)
   * Bin
   * Mathematical Functions



-------------------------------------------------------------- KeyPgSin ----
Sin

Returns the sine of an angle

Syntax
   Declare Function Sin ( ByVal angle As Double ) As Double

Usage
   result = Sin( angle )

Parameters
   angle
      the angle (in radians)

Return Value
   Returns the sine of the argument angle as a Double within the range of 
   -1.0 to 1.0.

Description
   The argument angle is measured in radians (not degrees).

   The value returned by this function is undefined for values of angle 
   with an absolute value of 2 ^ 63 or greater.

   Sin can be overloaded as operator to accept user-defined types.

Example
   Const PI As Double = 3.1415926535897932
   Dim a As Double
   Dim r As Double
   Input "Please enter an angle in degrees: ", a
   r = a * PI / 180   'Convert the degrees to Radians
   Print ""
   Print "The sine of a" ; a; " degree angle is"; Sin ( r ) 
   Sleep

The output would look like:

   Please enter an angle in degrees: 30
   The sine of a 30 degree angle Is 0.5

Differences from QB
   * None

See also
   * Asin
   * Cos
   * Tan
   * A Brief Introduction To Trigonometry



----------------------------------------------------------- KeyPgSingle ----
Single

Standard data type: 32 bit floating point

Syntax
   Dim variable As Single

Description
   Single is a 32-bit, floating point data type used to store decimal 
   numbers. They can hold positive values in the range 1.401298e-45 to 
   3.402823e+38, or negative values in the range -1.401298e-45 to 
   -3.402823e+38, or zero (0).  They contain at most 24 bits of precision, 
   or about 6 decimal digits.

   They are similar to Double data types, but less precise. 

Example
   'Example of using a single variable.

   Dim a As Single
   a = 1.9857665
   Print a

   Sleep

Differences from QB
   * None

See also
   * Double More precise float type
   * CSng
   * Table with variable types overview, limits and suffixes



----------------------------------------------------------- KeyPgSizeof ----
SizeOf

Returns the size of a variable or type in bytes.

Syntax
   SizeOf ( variable | DataType )

Description
   The SizeOf operator returns an Integer value: the number of bytes taken 
   up by a variable or DataType (including the data fields of a UDT).

   When used with fixed-length strings (including fixed-length ZStrings and 
   WStrings) it will return the number of bytes they use, and when used 
   with variable-length strings, it will return the size of the string 
   descriptor.
   (it is equal to Len only when used with fixed-length strings of STRING*N 
   type and this since fbc version 1.20.0)

   If there is both a user defined type and a variable visible with the 
   same name in the current scope, the user defined type takes precedence 
   over the variable.  To ensure that the SizeOf takes the variable instead 
   of the user defined type, wrap the argument to SizeOf with parentheses 
   to force it to be seen as an expression.  For example Sizeof((variable))
   .

   Note: When used with array names, SizeOf returns the size of the array 
   dadatype, but not the total size of the array. This differs from its 
   behavior in C, where arrays could only be a fixed size, and sizeof() 
   would return the number of it used.
   For clarity, it is recommended that you avoid this potential confusion, 
   and use SizeOf on the array datatype doing SizeOf(Typeof(array)), rather 
   than the array name only doing SizeOf(array).

   Remark: When used with a dereferenced z/wstring pointer, SizeOf always 
   returns the number of bytes taken up by one z/wstring character.

Example
   Print SizeOf(Byte) ' returns 1
      

   Type bar
      a As Integer
      b As Double
   End Type
   Dim foo As bar
   Print SizeOf(foo)
      

Version
   * Before fbc 1.08.0:
         SizeOf was not returning the size of the data fields of a UDT.
         When a variable from a given namespace was accessed with the 
         namespace's name prefix, the argument to SizeOf had to be wrapped 
         with parentheses to force it to be seen as an expression. For 
         example Sizeof((namespace_name.variable)).

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Sizeof.

Differences from QB
   * New to FreeBASIC

See also
   * Len



------------------------------------------------------------ KeyPgSleep ----
Sleep

Waits until a specified time has elapsed, or a key is pressed.

Syntax
   Declare Sub Sleep ( ByVal amount As Long = -1 )
   Declare Function Sleep ( ByVal amount As Long , ByVal keyflag As Long ) 
   As Long

Usage
   Sleep [ amount [, keyflag ]]
   result = Sleep ( amount, keyflag )

Parameters
   amount
      Optional number of milliseconds to wait (default is to wait for a key 
      press).
   keyflag
      Optional flag; give it a value of 0 for a normal sleep, or 1 to 
      specify that the wait cannot be interrupted by a key press.

Return Value
   Returns 1 if keyflag was not a valid value (i.e. something other than 0 
   or 1) to indicate failure, or 0 otherwise.

Description
   Sleep will wait until amount milliseconds (can be seconds in -lang qb, 
   see below) given elapsed (if any value was passed) or until the user 
   presses a key. If amount is below 100 ms then Sleep will always wait the 
   full requested amount (key presses are ignored).

   Include the second parameter, 1, for a "deep" sleep, which cannot be 
   interrupted by pressing a key.

   The accuracy of Sleep is variable depending on the OS cycle time:
      Windows NT/2K/XP: 15 ms, 9x/Me: 50 ms, Linux: 10ms, DOS: 55 ms.
   And using for the amount parameter values lower than these accuracy 
   values does not allow Sleep to produce the corresponding wait values 
   (always higher wait, and of the order of these values) except for the 
   amount value '0'.

   Call Sleep with 25ms or less to release time-slice when waiting for user 
   input or looping inside a thread.  This will prevent the program from 
   unnecessarily hogging the CPU.

   Sleep does not clear the keyboard input buffer and any keys pressed 
   during a call to Sleep are retained and can be later read by Inkey or 
   GetKey or Input.
   When Sleep has no parameters (waiting for a key pressed only), GetKey 
   keyword can be used instead of Sleep.
   For the general form of Sleep (with parameters), if the user want to 
   clear the keyboard input buffer from any eventual keys pressed during 
   the Sleep execution, he can use after the Sleep instruction line 
   something like the following method:
   While Inkey <> "": Wend  '' loop until the keyboard input buffer is empty
         

Example
   Print "press a key"
   Sleep
   GetKey  '' clear the keyboard input buffer, and even in that code case, the 'Sleep' keyword can be outright omitted
   Print "waiting half second"
   Sleep 500
      

   Dim As String s

   Print "wait 3 seconds or press a key"
   Sleep 3000
   Print "outputed by timeout or key pressed"
   While Inkey <> ""  '' loop until the keyboard input buffer is empty
   Wend

   Input "enter a string"; s
   Print "string entered: " & "'" & s & "'"

   Sleep
      

Dialect Differences
   * In the -lang fb and -lang fblite dialects, the amount value is in 
     milliseconds.
   * In the -lang qb dialect, the amount value is in seconds as in QB. If 
     the second parameter keyflag is given, or the keyword is written as 
     __Sleep  the value is expected to be in milliseconds.

Differences from QB
   * None in the -lang qb dialect.
   * In QB, the delay was given in whole seconds only and did not support 
     the keyflag parameter.

See also
   * Timer
   * Inkey



----------------------------------------------------- KeyPgSfxGenerated ----
Generated Sound Commands

Commands for generated sound, PLAY strings, and sfxlib mix settings.

Syntax
   Beep [ duration, pitch ]
   Sound frequency, duration
   Sound channel, frequency, duration, volume
   Tone channel, frequency, duration
   Noise channel, duration, volume
   Noise channel, frequency, duration, volume
   Note name, octave, duration
   Note channel, name, octave, duration
   Play music
   Play channel, music
   Play music1, music2
   Play music1, music2, music3
   Tempo bpm
   bpm = Tempo()
   Channel channel
   channel = Channel()
   Octave octave
   octave = Octave()
   Voice instrument
   instrument = Voice()
   Vol level
   Volume level
   level = Volume()
   Volume channel, level
   level = Volume( channel )
   Balance position
   position = Balance()
   Pan channel, position
   position = Pan( channel )
   Wave id, waveform
   Envelope id, attack, decay, sustain, release
   Instrument id, wave_id, envelope_id
   Instrument channel, instrument_id

Description
   These commands synthesize sound directly through sfxlib.  Sound, Tone, 
   Noise, Note, and Play create voices.  Tempo, Channel, Octave, and Voice 
   set defaults used by PLAY-string and generated-sound commands.  Volume, 
   Vol, Balance, and Pan control mix levels and stereo placement.

   Sound accepts the high-impact classic form Sound frequency, duration and
   the explicit channel form Sound channel, frequency, duration, volume.
   When both arguments are integers, duration is interpreted as the PC BASIC
   timer-tick value.

   Wave defines a waveform id.  The currently supported waveform values 
   are:
      * 0 sine
      * 1 square
      * 2 triangle
      * 3 saw
      * 4 noise

   Envelope defines an ADSR envelope using seconds for attack, decay, and 
   release, and a 0.0 to 1.0 sustain level.  Instrument can define an 
   instrument from a waveform and envelope, or assign an instrument to a 
   channel.

   The channel-oriented commands use sfxlib's channel table.  Channels are 
   zero-based.

Example
   See examples/sfxlib/basics-01-generated-sound.bas, 
   examples/sfxlib/basics-02-play-strings.bas, 
   examples/sfxlib/basics-03-channels-mix.bas, 
   examples/sfxlib/basics-04-instruments.bas, and 
   examples/sfxlib/showcase.bas.

Platform Differences
   * On headless or diagnostic runs, SFXLIB_DRIVER=null can be set before 
     program startup to use the null output driver.

Differences from QB
   * New to FreeBASIC.

See also
   * Beep
   * Music
   * Sfx
   * Sound Library Reference



------------------------------------------------------------ KeyPgSpace ----
Space

Creates a string of a given length filled with spaces (" ")

Syntax
   Declare Function Space( ByVal count As Integer ) As String

Usage
   result = Space[$]( count )

Parameters
   count
      An integer type specifying the length of the string to be created.

Return Value
   The created string. An empty string will be returned if count <= 0.

Description
   Space creates a string with the specified number of spaces.

Example
   Dim a As String
   a = "x" + Space(3) + "x"
   Print a ' prints: x   x

Dialect Differences
   * The string type suffix "$" is required in the -lang qb dialect.
   * The string type suffix "$" is optional in the -lang fblite dialect.
   * The string type suffix "$" is ignored in the -lang fb dialect, warn 
     only with the -w suffix compile option (or -w pedantic compile 
     option).

Differences from QB
   * None

See also
   * WSpace
   * Spc
   * String (Function)



-------------------------------------------------------------- KeyPgSpc ----
Spc

Output function to skip spaces when writing to screen or file

Syntax
   Spc( columns )

Usage
   Print Spc( spaces ) [(, | ;)] ...

Parameters
   spaces
      number of spaces to skip

Description
   Spc skips over the given number of spaces when Printing to screen or to 
   a file.  The character cells skipped over are left unchanged.

Example
   Print "foo"; Spc(5); "bar"
   Print "hello"; Spc(4); "world"

   '' Uses Spc to justify text instead of Tab

   Dim As String A1, B1, A2, B2

   A1 = "Jane"
   B1 = "Doe"
   A2 = "Bob"
   B2 = "Smith"

   Print "FIRST NAME"; Spc(35 - 10); "LAST NAME"
   Print "----------"; Spc(35 - 10); "----------"
   Print A1; Spc(35 - Len(A1)); B1
   Print A2; Spc(35 - Len(A2)); B2

The output would look like:

   FIRST Name                         LAST Name
   ----------                         ----------
   Jane                               Doe
   Bob                                Smith

Differences from QB
   * In QBASIC, spaces were printed in the gap, while in FreeBASIC, the 
     characters are just skipped over and left untouched.  The Space 
     function can still be used to achieve this effect.

See also
   * Tab
   * Space
   * Print
   * ?



-------------------------------------------------------------- KeyPgSqr ----
Sqr

Returns a square root of a number

Syntax
   Declare Function Sqr ( ByVal number As Double ) As Double

Usage
   result = Sqr( number )

Parameters
   number
      the number (greater than or equal to zero)

Return Value
   Returns the square root of the argument number.

   If number equals zero, Sqr returns zero (0.0).

   If number is less than zero, Sqr returns a special value representing 
   "not defined", printing like "NaN" or "IND", exact text is platform 
   dependent.

Description
   This is the same as raising the argument number to the one-half power: y 
   = x ^ (1/2) . The required number argument can be any valid numeric 
   expression greater than or equal zero.

   If a LongInt or ULongInt is passed to Sqr, it may be converted to Double 
   precision first.  For numbers over 2^52, this will cause a very small 
   loss of precision.  Without making any assumptions about the rounding 
   method, the maximum error due to this will be Sqr(2^64) - Sqr(2^64-2^12)
   , which is about 4.8e-7. However this may cause erroneous results if the 
   floor or ceiling of this value is taken, and the result of this may be 
   out by 1, particularly for square numbers and numbers that are close by.

   Sqr can be overloaded as operator to accept user-defined types.

Example
   '' Example of Sqr function: Pythagorean theorem 
   Dim As Single a, b

   Print "Pythagorean theorem, right-angled triangle"
   Print
   Input "Please enter one leg side length: ", a
   Input "Please enter the other leg side length: ", b
   Print 
   Print "The hypotenuse has a length of: " & Sqr( a * a + b * b )

The output would look like:

   Pythagorean theorem, Right-angled triangle

   Please enter one leg side length: 1.5
   Please enter the other leg side length: 2

   The hypotenuse has a length of: 2.5

Differences from QB
   * None

See also
   * Operator ^ (Exponentiate)
   * Arithmetic Operators



----------------------------------------------------------- KeyPgStatic ----
Static

Defines variables, objects and arrays having static storage

Syntax
   Static symbol1 [ (array-dimensions) ] As DataType [ = expression] [, 
   symbol2 [ (array-dimensions) ] As DataType [ = expression], ...]
      or
   Static As DataType symbol1 [ (array-dimensions) ] [ = expression] [, 
   symbol2 [ (array-dimensions) ] [ = expression], ...]
      or
   Static Var symbol1 = expression [, symbol2 = expression, ...]

      or

   Sub|Function procedurename ( parameters ) [[ ByRef ] As DataType] Static
      ...
   End Sub|Function

Parameters
   symbol
      variable or array symbol name.
   array-dimensions
      lower-bound To upper-bound [, ...]
      or
      Any [, Any...]
      or empty.
   expression
      An constant expression, or an array of constant expressions

Description
   Specifies static storage for variables, objects and arrays; they are 
   allocated at program startup and deallocated upon exit. Objects are 
   constructed once when they are defined, and destructed upon program 
   exit.

   When declaring static arrays, only numeric literals, Constants or 
   Enumerations may be used as subscript range values. Static 
   variable-length arrays must be declared empty (no subscript range list) 
   and resized using ReDim before used.

   In both iterative and recursive blocks, like looping 
   control flow statements or procedures, static variables, objects and 
   arrays local to the block are guaranteed to occupy the same storage 
   across all instantiations of the block. For example, procedures that 
   call themselves - either directly or indirectly - share the same 
   instances of their local static variables.

   A static variable may only be initialised with a constant value: its 
   starting value is set at the start of the program before any code is 
   run, and so it cannot depend on any variables or functions in it.

   When used at procedure definition level (forbidden at declaration line 
   level), Static specifies static storage for all local variables, objects 
   and arrays, except temporary types and internal variables (objects not 
   explicitly declared).

   At module-level variable declaration only, the modifier Shared may be 
   used with the keyword Static to make module-level static variables 
   visible inside procedures.

   When used with in a user-defined type, Static creates 
   Static Member Procedures Or Variables.

Example
   Sub f
      '' times called is initially 0
      Static timesCalled As Integer = 0
      timesCalled += 1
      Print "Number of times called: " & timesCalled
   End Sub

   '' the static variable in f() retains its value between
   '' multiple procedure calls.
   f()
   f()

   Will output:


   Number of times called: 1
   Number of times called: 2

Dialect Differences
   * Variables cannot be initialised in the -lang qb dialect.

Differences from QB
   * QuickBASIC allows variables and arrays to be declared using the 
     Static keyword within procedures and DEF FN routines only.
   * Static forces local visibility of variables and arrays in QuickBASIC 
     DEF FN routines. FreeBASIC supports neither DEF FN routines nor this 
     usage of Static.

See also
   * Static (Member)
   * Dim, ReDim
   * Shared
   * Byref (Variables)
   * Sub (Module), Function (Module)
   * Sub (Member), Function (Member)
   * Option Static
   * Storage Classes
   * Pointers to Procedures



----------------------------------------------------- KeyPgStaticMember ----
Static (Member)

Declare a static member procedure or variable

Syntax
   Type typename
      Static variablename As DataType [, ...]
      Declare Static Sub|Function procedurename ...
      ...
   End Type

   Dim typename.variablename As DataType [= initializer] [, ...]

   [Static] Sub|Function typename.procedurename ...
      ...
   End Sub|Function

Description
   * Static member procedures
      Static methods do not have an implicit This instance argument passed 
      to them. This allows them to be used like normal non-member 
      procedures (for example with callback procedure pointers).  An 
      advantage of Static methods are that they are encapsulated in the 
      typename namespace, and therefore have the ability to access the 
      Private or Protected members or methods of instances of typename.

      Static methods can be called directly anywhere in code, like normal 
      non-member procedures, or on objects of type typename, similar to 
      non-static methods, however either way there is no implicit or 
      explicit This (or explicit Base (Member Access)) access possible from 
      within a static method.

      For member procedures with a Static declaration, Static may also be 
      specified on the corresponding procedure bodies, for improved code 
      readability.

   * Static member variables
      Static member variables are created and initialized only once 
      independently of any object construction, in contrast to non-static 
      ("instance") member variables which are created again and again for 
      each separate object. Static members are always Shared, even if Shared
      was not specified in the declaration. Thus, Static member variables 
      are similar to global variables, except that they are declared in a 
      Type namespace.

      Each Static member variable declared in a Type must be explicitly 
      allocated somewhere outside the type by using a Dim statement. The 
      declaration inside the Type is the prototype that is visible to every 
      module seeing the Type declaration. The definition outside the Type 
      allocates and optionally initializes the Static member variable. 
      There can only be one definition per Static member variable: it can 
      only be allocated in a single module, not in multiple ones. This is 
      the same as for Extern variables.

      A Static member variable is subject to member access control except 
      for its definition outside the Type. If a private Static member 
      variable is to be explicitly initialized outside the Type's member 
      procedures, an initializer must be provided with the definition.

Example
   '' Example showing how the actual procedure invoked by a member can be set at runtime.
   '' using static member procedures.
   Type _Object

     Enum handlertype
      ht_default
      ht_A
      ht_B
     End Enum

     Declare Constructor( ByVal ht As handlertype = ht_default)

     Declare Sub handler()

   Private:
     Declare Static Sub handler_default( ByRef obj As _Object )
     Declare Static Sub handler_A( ByRef obj As _Object )
     Declare Static Sub handler_B( ByRef obj As _Object )
     handler_func As Sub( ByRef obj As _Object )

   End Type

   Constructor _Object( ByVal ht As handlertype )
     Select Case ht
     Case ht_A
      handler_func = @_Object.handler_A
     Case ht_B
      handler_func = @_Object.handler_B
     Case Else
      handler_func = @_Object.handler_default
     End Select
   End Constructor

   Sub _Object.handler()
     handler_func(This)
   End Sub

   Sub _Object.handler_default( ByRef obj As _Object )
     Print "Handling using default method"
   End Sub

   Sub _Object.handler_A( ByRef obj As _Object )
     Print "Handling using method A"
   End Sub

   Sub _Object.handler_B( ByRef obj As _Object )
     Print "Handling using method B"
   End Sub

   Dim objects(1 To 4) As _Object => _
     { _
      _Object.handlertype.ht_B, _
      _Object.handlertype.ht_default, _
      _Object.handlertype.ht_A _
     }
     '' 4th array item will be _Object.handlertype.ht_default

   For i As Integer = 1 To 4
     Print i,
     objects(i).handler()
   Next i

   '' Assign an unique ID to every instance of a Type (ID incremented in order of creation)

   Type UDT
     Public:
      Declare Property getID () As Integer
      Declare Constructor ()
     Private:
      Dim As Integer ID
      Static As Integer countID
   End Type
   Dim As Integer UDT.countID = 0

   Property UDT.getID () As Integer
     Property = This.ID
   End Property

   Constructor UDT ()
     This.ID = UDT.countID
     UDT.countID += 1
   End Constructor

   Dim As UDT uFirst
   Dim As UDT uSecond
   Dim As UDT uThird

   Print uFirst.getID
   Print uSecond.getID
   Print uThird.getID

Differences from QB
   * New to FreeBASIC

See also
   * Class
   * Declare
   * Type
   * Static



---------------------------------------------------------- KeyPgStdcall ----
stdcall

Specifies a stdcall-style calling convention in a procedure declaration

Syntax
   Sub name stdcall [Overload] [Alias "alias"] ( parameters )
   Function name stdcall [Overload] [Alias "alias"] ( parameters ) [ ByRef 
   ] As return_type

Description
   In procedure declarations, stdcall specifies that a procedure will use 
   the stdcall calling convention. In the stdcall calling convention, any 
   parameters are to be passed (pushed onto the stack) in the reverse order 
   in which they are listed, that is, from right to left. The procedures 
   need not preserve the EAX, ECX or EDX registers, and must clean up the 
   stack (pop any parameters) before it returns.

   stdcall is not allowed to be used with variadic procedure declarations 
   (those with the last parameter listed as "...").

   stdcall is the default calling convention on Windows, unless another 
   calling convention is explicitly specified or implied by one of the 
   Extern Blocks. stdcall is also the standard (or most common) calling 
   convention used in BASIC languages, and the Windows API.

   If a procedure definition has a declaration (with calling convention 
   explicit or by default) and the definition does not explicitly specify a 
   calling convention, then the calling convention is implied by the 
   declaration.

Example
   Declare Function Example stdcall (param1 As Integer, param2 As Integer) As Integer
   Declare Function Example2 cdecl (param1 As Integer, param2 As Integer) As Integer

   Function Example stdcall (param1 As Integer, param2 As Integer) As Integer
      ' This is an STDCALL function, the first parameter on the stack is param2, since it was pushed last.
      Print param1, param2
      Return param1 Mod param2
   End Function

   Function Example2 cdecl (param1 As Integer, param2 As Integer) As Integer
      ' This is a CDECL function, the first parameter on the stack is param1, since it was pushed last.
      Print param1, param2
      Return param1 Mod param2
   End Function

Platform Differences
   * On Windows systems, stdcall procedures have an "@N" decoration added 
     to their internal/external name, where N is the size of the parameter 
     list, in bytes.

Differences from QB
   * New to FreeBASIC

See also
   * pascal, cdecl
   * Declare
   * Sub, Function



------------------------------------------------------------- KeyPgStep ----
Step

Statement modifier.

Syntax
   For iterator = initial_value To end_value Step increment

   Line [ buffer, ] Step ( x1, y1 ) - Step ( x2, y2 ) [, [ color ][, [ B|BF 
   ][, style ] ] ]

   Circle [ target, ] Step ( x, y ), radius [, [ color ][, [ start ][, [ 
   end ][, [ aspect ][, F] ] ] ] ]

   Paint [ target, ] STEP ( x, y ) [, [ paint ][, [ border_color ] ] ]

Description
   In a For statement, Step specifies the increment of the loop iterator 
   with each loop.

   In a Line, Circle or Paint statement, Step indicates that the following 
   coordinate has values relative to the graphics cursor.

Example
   Dim i As Integer
   For I=10 To 1 Step -1
   Next

   Line -Step(10,10),13

See also
   * For...Next
   * Line
   * Circle
   * Paint



------------------------------------------------------------ KeyPgStick ----
Stick

Reads axis position from attached gaming devices

Syntax
   Declare Function Stick ( ByVal axis As Long ) As Long

Usage
   result = Stick( axis )

Parameters
   axis
      the axis number to query for position

Return Value
   Returns a number between 1 and 200 for specified axis, otherwise zero 
   (0), if the device is not attached.

Description
   Stick will retrieve the axis position for the first and second axes on 
   the first and second gaming devices.  axis must be a number between 0 
   and 3 having the following meaning:

      +----+------------------------------------------------------+
      |Axis|Returns                                               |
      |0   |X position of gaming device A                         |
      |1   |Y position of gaming device A when STICK(0) was called|
      |2   |X position of gaming device B when STICK(0) was called|
      |3   |Y position of gaming device B when STICK(0) was called|
      +----+------------------------------------------------------+

   Stick(0) must first be called to obtain the positions for the other 
   axes.

Example
   '' Compile with -lang qb

   '$lang: "qb"

   Screen 12

   Do
      Locate 1, 1
      Print "Joystick A-X position : "; Stick(0); "   "
      Print "Joystick A-Y position : "; Stick(1); "   "
      Print "Joystick B-X position : "; Stick(2); "   "
      Print "Joystick B-Y position : "; Stick(3); "   "
      Print
      Print "Button A1 was pressed : "; Strig(0); "  "
      Print "Button A1 is pressed  : "; Strig(1); "  "
      Print "Button B1 was pressed : "; Strig(2); "  "
      Print "Button B1 is pressed  : "; Strig(3); "  "
      Print "Button A2 was pressed : "; Strig(4); "  "
      Print "Button A2 is pressed  : "; Strig(5); "  "
      Print "Button B2 was pressed : "; Strig(6); "  "
      Print "Button B2 is pressed  : "; Strig(7); "  "
      Print
      Print "Press ESC to Quit"

      If Inkey$ = Chr$(27) Then
         Exit Do
      End If

      Sleep 1

   Loop

Dialect Differences
   * Only available in the -lang qb dialect.

Differences from QB
   * None

See also
   * GetJoystick
   * Strig



------------------------------------------------------------- KeyPgStop ----
Stop

Halts program execution, and waits for a key press before ending the 
program.

Syntax
   Declare Sub Stop ( ByVal retval As Long = 0 )

Usage
   Stop

Parameters
   retval
      Error code returned to system.

Description
   Halts the execution of the program and stands by. It's  provided as a 
   help to debugging, as it preserves the memory and doesn't close files. 
   For normal program termination the End (Statement) keyword should be 
   used. An optional return value, an integer, can be specified to return 
   an error code to the system. If no return value is given, a value of 0 
   is automatically returned.

   Note: STOP is not implemented properly yet; currently it is the same as 
   System.

Example
   Print "this text is shown"
   Sleep
   Stop
   Print "this text will never be shown"

Differences from QB
   * None

See also
   * End (Statement)



-------------------------------------------------------------- KeyPgStr ----
Str

Returns a string representation of a number, boolean or Unicode character 
string

Syntax
   Declare Function Str ( ByVal n As Byte ) As String
   Declare Function Str ( ByVal n As UByte ) As String
   Declare Function Str ( ByVal n As Short ) As String
   Declare Function Str ( ByVal n As UShort ) As String
   Declare Function Str ( ByVal n As Long ) As String
   Declare Function Str ( ByVal n As ULong ) As String
   Declare Function Str ( ByVal n As LongInt ) As String
   Declare Function Str ( ByVal n As ULongInt ) As String
   Declare Function Str ( ByVal n As Single ) As String
   Declare Function Str ( ByVal n As Double ) As String
   Declare Function Str ( ByVal b As Boolean ) As String
   Declare Function Str ( ByRef str As Const String ) As String
   Declare Function Str ( ByVal str As Const WString ) As String

Usage
   result = Str[$]( number )
      or
   result = Str( string )

Parameters
   number
      Numeric expression to convert to a string.
   string
      String expression to convert to a string.

Description
   Str converts numeric variables to their string representation. Used this 
   way it is the String equivalent to WStr applied to numeric variables, 
   and the opposite of the Val function, which converts a string into a 
   number.

   Str converts boolean variables to their string representation "false" / 
   "true".

   Str also converts Unicode character strings to ASCII character strings. 
   Used this way it does the opposite of WStr. If an ASCII character string 
   is given, that string is returned unmodified.

Example
   Dim a As Integer
   Dim b As String
   a = 8421
   b = Str(a)
   Print a, b

Dialect Differences
   * In the -lang qb dialect, Str will left pad a positive number with a 
     space.
   * The string type suffix "$" is required in the -lang qb dialect.
   * The string type suffix "$" is optional in the -lang fblite dialect.
   * The string type suffix "$" is ignored in the -lang fb dialect, warn 
     only with the -w suffix compile option (or -w pedantic compile 
     option).

Platform Differences
   * DOS version/target of FreeBASIC does not support the wide-character 
     string version of Str.

Differences from QB
   * QB does not support the wide-character string version of Str.

See also
   * Val
   * CBool
   * Chr
   * Asc



------------------------------------------------------------ KeyPgStrig ----
Strig

Reads button state from attached gaming devices

Syntax
   Declare Function Strig ( ByVal button As Long ) As Long

Usage
   result = Strig( button )

Parameters
   button
      the button to query for state

Return Value
   Returns -1 (pressed) or 0 (not-pressed) to indicate the state of the 
   button requested.

Description
   Strig will retrieve the button state for the first and second buttons on 
   the first and second gaming devices.  button must be a number between 0 
   and 7 and has the following meaning:

      +------+------------------------------------------------------------------+
      |Button|State to return                                                   |
      |0     |First button on gaming device A pressed since STICK(0) was called |
      |1     |First button on gaming device A is pressed                        |
      |2     |First button on gaming device B pressed since STICK(0) was called |
      |3     |First button on gaming device B is pressed                        |
      |4     |Second button on gaming device A pressed since STICK(0) was called|
      |5     |Second button on gaming device A is pressed                       |
      |6     |Second button on gaming device B pressed since STICK(0) was called|
      |7     |Second button on gaming device B is pressed                       |
      +------+------------------------------------------------------------------+

   Calling Stick(0) will reset the state returned where button is equal to 
   0, 2, 4, or 6.

Example
   '' Compile with -lang qb

   '$lang: "qb"

   Screen 12

   Do
      Locate 1, 1
      Print "Joystick A-X position : "; Stick(0); "   "
      Print "Joystick A-Y position : "; Stick(1); "   "
      Print "Joystick B-X position : "; Stick(2); "   "
      Print "Joystick B-Y position : "; Stick(3); "   "
      Print
      Print "Button A1 was pressed : "; Strig(0); "  "
      Print "Button A1 is pressed  : "; Strig(1); "  "
      Print "Button B1 was pressed : "; Strig(2); "  "
      Print "Button B1 is pressed  : "; Strig(3); "  "
      Print "Button A2 was pressed : "; Strig(4); "  "
      Print "Button A2 is pressed  : "; Strig(5); "  "
      Print "Button B2 was pressed : "; Strig(6); "  "
      Print "Button B2 is pressed  : "; Strig(7); "  "
      Print
      Print "Press ESC to Quit"

      If Inkey$ = Chr$(27) Then
         Exit Do
      End If

      Sleep 1

   Loop

Dialect Differences
   * Only available in the -lang qb dialect.

Differences from QB
   * None

See also
   * GetJoystick
   * Stick



--------------------------------------------------- KeyPgStringFunction ----
String (Function)

Creates and fills a string of a certain length with a certain character

Syntax
   Declare Function String ( ByVal count As Integer, ByVal ch_code As Long 
   ) As String
   Declare Function String ( ByVal count As Integer, ByRef ch As Const 
   String ) As String

Usage
   result = String[$]( count, ch_code )
      or
   result = String[$]( count, ch )

Parameters
   count
      An integer specifying the length of the string to be created.
   ch_code
      A long specifying the ASCII character code to be used to fill the 
      string.
   ch
      A string whose first character is to be used to fill the string.

Return Value
   The created string. An empty string will be returned if either ch is an 
   empty string, or count <= 0.

Description
   The String function returns a string with a length of count, filled with 
   a given ch_code or ch.

Example
   Print String( 4, 69 )         '' prints "EEEE"
   Print String( 5, "Indeed" )   '' prints "IIIII"
   End 0

Dialect Differences
   * The string type suffix "$" is required in the -lang qb dialect.
   * The string type suffix "$" is optional in the -lang fblite dialect.
   * The string type suffix "$" is ignored in the -lang fb dialect, warn 
     only with the -w suffix compile option (or -w pedantic compile 
     option).

Differences from QB
   * None 

See also
   * String (data type)
   * Space

   


----------------------------------------------------------- KeyPgString ----
String

Standard data type: 8 bit character string

Syntax
   Dim variable As String [ * size]

Description
   A String is an array of characters.

   A String declared without the size parameter is dynamically resized 
   depending on the length of the string. The length can range from 0 bytes 
   to 2 gigabytes. A descriptor contains a pointer to the actual string, 
   the length of the string, and the amount of space allocated for it. 
   VarPtr will return a pointer to the descriptor, while StrPtr will point 
   to the actual string.

   Because of the hidden descriptor with a String, manual allocation of 
   space, for example using the memory allocation function CAllocate 
   (preferentially), for a String is not encouraged. The common way to 
   ensure a certain amount of space is reserved for a String, to prevent 
   unnecessary allocations inside a loop for instance, is to use the Space 
   or String functions.

   Nevertheless if necessary, dynamic allocation may be carefully used by 
   means of the memory allocation functions Allocate, CAllocate, Reallocate 
   (see precautions for use) and string pointer (which is a pointer to a 
   string descriptor, not string data). When memory is allocated to hold 
   string descriptors, the string must always be destroyed (setting to "") 
   before deallocate each string descriptor (allowing to deallocate the 
   memory taken up by the string data), otherwise, it is not possible to 
   deallocate it later, and it may induce memory leak in the program 
   continuation.

   A simpler and safer method for dynamic allocation /deallocation is to 
   use the advanced New / Delete keyword (which itself also calls the 
   constructor / destructor of the string object).

   Despite the use of the descriptor, an implicit NULL character (Chr(0)) 
   is added to the end of the string, to allow passing them to functions in 
   external libraries without making slow copies.  FreeBASIC's internal 
   functions will ignore this character, and not treat it as part of the 
   string.

   A String declared with a fixed size (numeric constant, or expression 
   that can be evaluated at compile time) is a QB-style fixed length 
   string, with the exception that unused characters are set to 0 before 
   fbc version 1.20.0, or set to space since fbc version 1.20.0, regardless 
   of what "-lang" compiler option is used. It has no descriptor and it is 
   not resized to fit its contents. As in QB, if data overflows the size of 
   the string, it is truncated on the right side.
   Only before fbc version 1.20.0, fixed length strings were also 
   terminated with a NULL character, and so they used size + 1 bytes of 
   space. This NULL terminator is removed since fbc version 1.20.0, to 
   prevent the redundant character complicating data layout in user-defined 
   Types.
   Note: Before fbc version 1.20.0, it was not recommended to use explicit 
   NULL character (Chr(0)) in a string expression involving a fixed length 
   string variable because this could lead to different unexpected results 
   depending on usage context (initialization, assignment, concatenation, 
   ...).
   Note: Since fbc version 1.20.0, dereferencing a pointer to a fixed 
   length string can lead to an extension of the string by some pollution, 
   or even to an outright crash (because there is no longer NULL terminal 
   character).

   String variable names need not end in a dollar sign $ as in other 
   dialects of BASIC.  In lang fb variable suffixes, including the dollar 
   sign, are disallowed entirely.

Example

   '' Variable length
   Dim a As String

   a = "Hello"
   Print a

   a += ", world!"
   Print a

   Dim As String b = "Welcome to FreeBASIC"
   Print b + "! " + a

   '' QB-like $ suffixes
   #lang "qb"

   '' DIM based on $ suffix
   Dim a$
   a$ = "Hello"

   '' Implicit declaration based on $ suffix
   b$ = ", world!"

   Print a$ + b$

   '' Variable-length strings as buffers

   '' Reserving space for a string,
   '' using Space() to produce lots of space characters (ASCII 32)
   Dim As String mybigstring = Space(1024)
   Print "buffer address: &h" & Hex( StrPtr( mybigstring ), 8 ) & ", length: " & Len( mybigstring )

   '' Explicitly destroying a string
   mybigstring = ""
   Print "buffer address: &h" & Hex( StrPtr( mybigstring ), 8 ) & ", length: " & Len( mybigstring )

   '' Variable-length string as Const parameter

   '' Const qualifier preventing string from being modified
   Sub silly_print( ByRef printme As Const String )
      Print ".o0( " & printme & " )0o."
      'next line will cause error if uncommented
      'printme = "silly printed"
   End Sub

   Dim As String status = "OK"

   silly_print( "Hello FreeBASIC!" )
   silly_print( "Status: " + status )

Version
   * Before fbc 1.20.0, fixed length strings were terminated with a NULL 
     character, and so they used size + 1 bytes of space.

Differences from QB
   * In QB the strings were limited to 32767 characters.
   * In QB, the unused characters of a fixed-length string were 
     initialized with 32 (space, or " ", in ASCII).
   * In QB static or fixed-size strings were often used in records to 
     represent a number of bytes of data;  for example, a string of 1 
     length to represent 1 byte in a UDT read from a file.  This was not 
     possible in FreeBASIC before fbc version 1.20.0 since strings always 
     had an NULL character following (when converting before fbc version 
     1.20.0 QBasic code that reads UDTs from files, make sure all instances 
     of "As String * n" are replaced with "As uByte (0 to n - 1)" or your 
     files will be incompatible).

See also
   * String (Function)
   * Space
   * ZString
   * WString
   * Str
   * StrPtr
   * VarPtr
   * Standard Data Type Limits
   * Operator [] (String Index)
   * String Operators



--------------------------------------------------------- KeyPgOpStrptr ----
Operator Strptr (String Pointer)

Returns the address of a string's character data.

Syntax
   Declare Operator StrPtr ( ByRef lhs As String ) As ZString Ptr
   Declare Operator StrPtr ( ByRef lhs As WString ) As WString Ptr

Usage
   result = StrPtr ( lhs )

Parameters
   lhs
      A string.

Return Value
   Returns a ZString/WString Ptr to a string/wstring's character data (null 
   value in case of empty string).

Description
   This operator returns a ZString/WString Ptr that points to the beginning 
   of a string/wstring's character data. Operator Strptr is the proper 
   method for acquiring the address of a string's character data.
   In case of empty String (only for variable length strings), Operator 
   Strptr returns a null pointer.

   The related Operator Varptr (Variable Pointer) and 
   Operator @ (Address Of), when used with a String, return the address of 
   the internal string descriptor.
   When a variable length string is modified, the address of its descriptor 
   remains always the same, but the the string's character data address 
   (returned by Operator Strptr) may change (like any allocated memory that 
   must be reallocated).
   When a fixed length string is modified, the string's character data 
   address (returned by Operator Strptr) is unchanged.

   Note: For a variable length string, the operator returns a ZString Const 
   Ptr (because returning by reference the string's characters pointer set 
   in the string descriptor, this one is to be considered as read only). If 
   the keyword Var is used to declare/initialize a user pointer from 
   Operator Strptr, this user pointer is also defined as read only (it can 
   not be modified further).

   Warning: Since fbc version 1.20.0, dereferencing a zstring pointer to a 
   fixed-length string of STRING*N type (which no longer has an additional 
   terminal null character as before) can lead to an extension of the 
   string by some pollution, or even an outright crash.

Example
   '' This example uses Strptr to demonstrate using pointers with strings
   Dim myString As String
   Dim toMyStringDesc As Any Ptr
   Dim toMyString As ZString Ptr

   '' Note that using standard VARPTR notation will return a pointer to the
   '' descriptor, not the string data itself
   myString = "Improper method for Strings"
   toMyStringDesc = @myString
   Print myString
   Print Hex( toMyStringDesc )
   Print

   '' However, using Strptr returns the proper pointer
   myString = "Hello World Examples Are Silly"
   toMyString = StrPtr(myString)
   Print myString
   Print *toMyString
   Print

   '' And the pointer acts like pointers to other types
   myString = "MyString has now changed"
   Print myString
   Print *toMyString
   Print

Differences from QB
   * New to FreeBASIC, but does exactly the same thing as SAdd

See also
   * SAdd
   * VarPtr
   * ProcPtr
   * Pointers



-------------------------------------------------------------- KeyPgSub ----
Sub

Defines a procedure

Syntax
   [Public|Private] Sub identifier [cdecl|pascal|stdcall] [Overload] [Alias 
   external_identifier] [( [parameter_list] )] [Static] [Export]
      statements
      ...
      [Return]
      ...
   End Sub

   [Public] Sub identifier [cdecl|pascal|stdcall] [Overload] [Alias 
   external_identifier] [()] [Constructor|Destructor] [Static]
      statements
      ...
      [Return]
      ...
   End Sub

Parameters
      identifier: the name of the subroutine
      external_identifier: externally visible (to the linker) name enclosed 
      in quotes
      parameter_list: parameter[, parameter[, ...]]
      parameter: [ByRef|ByVal] identifier [As type] [= default_value]
         identifier: the name of the variable referenced in the subroutine. 
         If the argument is an array then the identifier must be followed 
         by an empty parenthesis.
         type: the type of variable
         default_value: the value of the argument if none is specified in 
         the call (default_value can be a literal, or a constant, or a 
         shared variable)
      statements: one or more statements that make up the subroutine body

Description
   A subroutine is a block of code which may be called at any time from a 
   program. This code may need to be executed multiple times, and 
   subroutines provide an invaluable means to simplify code by replacing 
   these blocks of code with a single subroutine call. A subroutine also 
   serves to allow a user to extend the FreeBASIC language to provide 
   custom commands. Many of the functions built into FreeBASIC are merely 
   subroutines part of a "runtime library" linked to by default.

   The Sub keyword marks the beginning of a subroutine, and its end is 
   marked by End Sub. The "name" parameter is the name by which this 
   subroutine is called. For instance, if the declaration is "Sub...End Sub
   ", the user can execute the code in between "Sub foo" and "End Sub" by 
   using "foo" as a statement. This code is executed separate from the code 
   which calls the subroutine, so any variable names, unless they are 
   shared, are not available to the subroutine. Values can, however, be 
   passed using parameters.

   Parameters are the arguments passed to any statement. For instance, if a 
   user executes a statement as "Print 4", the value "4" is passed to the 
   function "Print". Parameters that need to be passed to a subroutine are 
   supplied by one or more parameter arguments in the "Sub" keyword. 
   Creating a subroutine with "Sub mysub(foo, bar)...End Sub", allows the 
   code in between "Sub" and "End Sub" to refer to the first passed 
   argument as "foo" and the second passed argument as "bar". If a 
   parameter is given a default value, that parameter is optional.
   Array parameters are specified by following an identifier with an empty 
   parenthesis. Note that array parameters are always ByRef and the ByRef 
   keyword is neither required nor allowed for array parameters. When 
   calling a subroutine with an array argument the parenthesis must be 
   supplied there too.

   In the default dialect -lang fb, parameters must also have a supplied 
   type, in the form "parameter as type". Type suffixes are not allowed.

   In the -lang qb and -lang fblite dialects only, it will be given a 
   default type if the type is not explicitly given either by name or by 
   type suffix. The default type is Single in the -lang qb dialect and 
   Integer in the -lang fblite dialect.

   A subroutine can also specify how parameters are passed, either as "ByRef
   " or "ByVal", as shown in the syntax definition. If a parameter is "ByRef
   ", the parameter name literally becomes a reference to the original 
   variable passed to the subroutine. Any changes made to that variable 
   will be reflected outside of the subroutine. If a parameter is passed "
   ByVal", however, the value of any passed variable is copied into a new 
   variable, and any changes made to it will not affect the original.

   The Static specifier indicates that the values of all local variables 
   defined in the sub should be preserved between calls. To specify 
   individual local variables as static see the Static keyword.
   To access duplicated symbols defined as global outside the subroutine 
   body, add one or preferably two dot(s) as prefix: .SomeSymbol or 
   preferably ..SomeSymbol (or only ..SomeSymbol if inside a With..End With 
   block).

   Sub is the same as Function, except it does not allow a value to be 
   returned.

   When calling a subroutine, parentheses after the subroutine name 
   (surrounding the argument list if any) are optional.

   The second syntax defines either a constructor or destructor using the 
   Constructor and Destructor keywords, respectively. Constructor 
   subroutines are executed before the first line of code in the module, 
   while destructors execute on module exit. Note the public access 
   specifier and empty parameter list for both constructors and 
   destructors.

   Warning for 64-bit compiler only: See the Identifier Rules page for the 
   choice of user procedure identifier names (and specially the 'Platform 
   Differences' paragraph).

Example
   '' Example of writing colored text using a sub:

   Sub PrintColoredText( ByVal colour As Integer, ByRef text As String )
      Color colour
      Print text
   End Sub

      PrintColoredText( 1, "blue" )        '' a few colors
      PrintColoredText( 2, "green" )
      PrintColoredText( 4, "red" )
      Print
      
      Dim i As Integer
      For i = 0 To 15                        '' all 16 colors
        PrintColoredText( i, ("color " & i) )
      Next i

   ' The following demonstrates optional parameters.

   Sub TestSub(P As String = "Default")
      Print P
   End Sub

   TestSub "Testing:"
   TestSub

Dialect Differences
   * The -lang qb and -lang fblite dialects keep the QB convention: 
     parameters are ByRef by default.
   * In the -lang fb dialect, numeric parameters are passed ByVal by 
     default.  Strings and UDTs are passed ByRef by default.

Differences from QB
   * Public and Private access specifiers are new to FreeBASIC.
   * Constructor subroutines are new to FreeBASIC.

See also
   * Declare
   * Function
   * Exit
   * Public
   * Private
   * Static

   


-------------------------------------------------------- KeyPgMemberSub ----
Sub (Member)

Declares or defines a member procedure

Syntax
   { Type | Class | Union } typename
      Declare [ Static | Const ] Sub fieldname [calling convention 
      specifier] [ Alias external_name ] ( [ parameters ] ) [ Static ] 
   End { Type | Class | Union }

   Sub typename.fieldname ( [ parameters ] ) [ Export ]
      statements
   End Sub

Parameters
   typename 
      name of the Type, Class, or Union
   fieldname 
      name of the procedure
   external_name
      name of field as seen when externally linked
   parameters 
      the parameters to be passed to the procedure
   calling convention specifier	
      can be one of: cdecl, stdcall or pascal

Description
   Sub members are accessed with Operator . (Member Access) or 
   Operator -> (Pointer To Member Access) to call a member procedure and 
   may optionally accept parameters either ByVal or ByRef.  typename be 
   overloaded  without explicit use of the Overload keyword.

   typename is the name of the type for which the Sub method is declared 
   and defined.  Name resolution for typename follows the same rules as 
   procedures when used in a Namespace.

   A hidden This parameter having the same type as typename is passed to 
   non-static member procedures.  This is used to access the fields of the 
   Type, Class, or Union.
   To access duplicated symbols defined as global outside the Type, add one 
   or preferably two dot(s) as prefix: .SomeSymbol or preferably ..
   SomeSymbol (or only ..SomeSymbol if inside a With..End With block).

   A Static (Member) may be declared using the Static specifier.  A 
   Const (Member) may be declared using the Const specifier.

Example
   Type Statistics
     count As Single
     sum As Single
     Declare Sub AddValue( ByVal x As Single )
     Declare Sub ShowResults( )
   End Type

   Sub Statistics.AddValue( ByVal x As Single )
     count += 1
     sum += x
   End Sub

   Sub Statistics.ShowResults( )
     Print "Number of Values = "; count
     Print "Average          = ";
     If( count > 0 ) Then
      Print sum / count
     Else
      Print "N/A"
     End If
   End Sub

   Dim stats As Statistics

   stats.AddValue 17.5
   stats.AddValue 20.1
   stats.AddValue 22.3
   stats.AddValue 16.9

   stats.ShowResults

Output:

   Number of Values =  4
   Average          =  19.2

Dialect Differences
   * Only available in the -lang fb dialect.

See also
   * Class
   * Function (Member)
   * Sub
   * Type



----------------------------------------------------------- KeyPgSubPtr ----
Sub Pointer

Data type that stores a pointer to a Sub procedure

Syntax
   Dim variable As Sub [cdecl|pascal|stdcall] [( [parameter_list] )] [= 
   initializer]

Parameters
      parameter_list: parameter[, parameter[, ...]]
      parameter: [ByRef|ByVal] identifier [As type] [= default_value]
         identifier: the name of the variable referenced in the subroutine
         type: the type of variable
         default_value: the value of the argument if none is specified in 
         the call
      intializer: address of a subroutine to set as the intial value

Description
   A Sub pointer is a procedure pointer that stores the memory location of 
   compiled code.  If no intializer is given the default initial value is 
   zero (0).

   The memory address for the Sub procedure can be assigned to the variable 
   by taking the address of a subroutine with ProcPtr or 
   Operator @ (Address Of).

   The procedure must match the same Sub declaration as the declared Sub 
   pointer.

   To call the subroutine assigned, use the variable name as if it were a 
   normal declared Sub, always with parentheses around the parameter list 
   even empty (without parentheses, only the pointer value, ie the address 
   of the subroutine, would be accessed).

   One of the primary uses for Sub pointers is to create callback 
   procedures:
      - A callback Sub is a Sub that is passed through an argument (a Sub 
      pointer) to another procedure which is expected to call back 
      (execute) the "argument" at a convenient time.
      - If the callback Sub is completely executed before the invocation 
      returns to the caller code, then the callback process is said to be 
      "synchronous".
      - If the invocation immediately returns to the caller code, and the 
      callback Sub and the caller's next code are running in parallel, then 
      the callback process is said to be "asynchronous".

Example
      Sub Hello()
         Print "Hello"
      End Sub

      Sub Goodbye()
         Print "Goodbye"
      End Sub

      Dim x As Sub() = ProcPtr( Hello )

      x()

      x = @Goodbye  '' or procptr(Goodbye)

      x()

   Sub s0 ()
     Print "'s0 ()'"
   End Sub

   Sub s1 (ByVal I As Integer)
     Print "'s1 (Byval As Integer)'", I
   End Sub

   Sub s2 (ByRef S As String, ByVal D As Double)
     Print "'s2 (Byref As String, Byval As Double)'", S, D
   End Sub

   Dim s0_ptr As Sub () = @s0
   Dim s1_ptr As Sub (ByVal I As Integer) = @s1
   Dim s2_ptr As Sub (ByRef S As String, ByVal D As Double) = @s2

   s0_ptr()
   s1_ptr(3)
   s2_ptr("PI", 3.14)

   ' Example of advanced callback Sub mechanism (asynchronous) to implement a key pressed event:
   ' (the user callback Sub address can be modified while the event thread is running)
   '   - An asynchronous thread tests the keyboard in a loop, and calls a user callback Sub each time a key is pressed.
   '   - An UDT groups the common variables used (callback Sub pointer, character of key pressed, thread end flag),
   '       and the static thread Sub plus the thread handle.
   '   - An UDT instance pointer is passed to the thread, which then transmits it to the callback Sub each time.
   '   - The callback Sub prints the character of the key pressed character,
   '       but if the key pressed is <escape> it orders the thread to finish.
   '   - As the user callback pointer is a member field of the UDT, it can be modified while the thread is running.

   '' UDT for thread environment
     Type threadUDT
      Dim As Sub (ByVal As ThreadUDT Ptr) callback             '' callback Sub pointer
      Dim As Integer threadEnd                                 '' thread end flag
      Dim As String s                                          '' character of the key pressed
      Declare Static Sub threadInkey (ByVal p As Any Ptr)      '' static thread Sub
      Dim As Any Ptr threadHandle                              '' handle to the thread
     End Type

   '' thread Sub definition
     Sub threadUDT.threadInkey (ByVal p As Any Ptr)
      Dim As threadUDT Ptr pt = p                              '' convert the any ptr to a threadUDT pointer
      Do
        pt->s = Inkey
        If pt->s <> "" AndAlso pt->callback > 0 Then           '' test condition key pressed & callback Sub defined
         pt->callback(p)
        End If
        Sleep 50, 1
      Loop Until pt->threadEnd                                 '' test condition to finish thread
     End Sub

   '' user callback Sub definition
     Sub printInkey (ByVal pt As threadUDT Ptr)
      If Asc(pt->s) = 27 Then                                  '' test condition key pressed = <escape>
        pt->threadEnd = -1                                     '' order thread to finish
        Print
      Else
        Print pt->s;
      End If
     End Sub

   '' user main code
     Dim As ThreadUDT t                                         '' create an instance of threadUDT
     t.threadHandle = ThreadCreate(@threadUDT.threadInkey, @t)  '' launch the thread, passing the instance address
     t.callback = @printInkey                                   '' initialize the callback Sub pointer
     ThreadWait(t.threadHandle)                                 '' wait for the thread finish

Differences from QB
   * New to FreeBASIC

See also
   * Sub
   * ProcPtr
   * Operator @ (Address Of)



------------------------------------------------------------- KeyPgSwap ----
Swap

Exchanges the values of two variables

Syntax
   Declare Sub Swap  ( ByRef a As Any, ByRef b As Any )

Usage
   Swap a, b

Parameters
   a
      A variable to swap.
   b
      A variable to swap.

Description
   Swaps the value of two variables, including UDT instances (swaps all 
   data members).

   Since fbc version 1.20.0, because a fixed-length string fields of 
   STRING*N type no longer has a terminal null character, Swap will pad 
   values with spaces where one of the arguments is of the STRING*N type.

   Note: When the data are referenced by a pointer, alone or within a 
   descriptive structure (a UDT, for example), Swap only exchanges the 
   values of the pointers or the contents of the descriptive structures 
   without accessing data themselves.
   For var-len strings, Swap only exchanges the descriptors of the strings 
   rather than reallocate memory for exchange all strings data characters.
   For UDTs, Swap simply exchanges the contents of the structures, without 
   any operators or methods being called.

Example
   ' using swap to order 2 numbers:
   Dim a As Integer, b As Integer

   Input "input a number: "; a
   Input "input another number: "; b
   If a > b Then Swap a, b
   Print "the numbers, in ascending order are:"
   Print a, b

Differences from QB
   * None

See also
   * Operator = (Assignment)



----------------------------------------------------------- KeyPgSystem ----
System

Closes all open files and ends the program

Syntax
   Declare Sub System ( ByVal retval As Long = 0 )

Usage
   System( [ retval ] )

Parameters
   retval
      Error code returned to system.

Description
   Closes all open files, exits the program, and returns to the operating 
   system. An optional return value, an integer, can be specified to return 
   an error code to the system. If no return value is given, a value of 0 
   is automatically returned. This is the same as End (Statement) and is 
   here for compatibility between older BASIC dialects. It is recommended 
   to use End (Statement) instead.

   Usage of this statement does not cleanly close scope. Local variables 
   will not have their destructors called automatically, because FreeBASIC 
   does not do stack unwinding. Only the destructors of global variables 
   will be called in this case.

   For this reason, it is discouraged to use System simply to mark the end 
   of a program; the program will come to an end automatically, and in a 
   cleaner fashion, when the last line of module-level code has executed.

Example
   Print "this text is shown"
   System
   Print "this text will never be shown"

Differences from QB
   * None

See also
   * End (Statement)




============================================================================
    T

-------------------------------------------------------------- KeyPgTab ----
Tab

Sets the column when writing to screen or file

Syntax
   Tab( col_num )

Usage
   Print Tab( column ) [(, | ;)] ...

Parameters
   column
      1-based column number to move to

Description
   Tab will move the cursor to given column number when Printing to screen 
   or to a file.  Character cells skipped over between the old and new 
   cursor positions are left unchanged.
   If the current column is greater than column, then Tab will move the 
   cursor to the requested column number on the next line.  If the current 
   column is equal to column, then the cursor will not move anywhere.

Example
   '' Using Print with Tab to justify text in a table

   Dim As String A1, B1, A2, B2

   A1 = "Jane"
   B1 = "Doe"
   A2 = "Bob"
   B2 = "Smith"

   Print "FIRST NAME"; Tab(35); "LAST NAME"
   Print "----------"; Tab(35); "----------"
   Print A1; Tab(35); B1
   Print A2; Tab(35); B2

The output would look like:

   FIRST Name                         LAST Name
   ----------                         ----------
   Jane                               Doe
   Bob                                Smith

Differences from QB
   * In QBASIC, spaces were printed in the gap, while in FreeBASIC, the 
     characters are just skipped over and left untouched.

See also
   * Spc
   * Locate
   * Pos
   * Print
   * ?



-------------------------------------------------------------- KeyPgTan ----
Tan

Returns the tangent of an angle

Syntax
   Declare Function Tan ( ByVal angle As Double ) As Double

Usage
   result = Tan( angle )

Parameters
   angle
      the angle (in radians)

Return Value
   Returns the tangent of the argument angle as a Double within the range 
   of -infinity to infinity.

Description
   The argument angle is measured in radians (not degrees).

   The value returned by this function is undefined for values of angle 
   with an absolute value of 2 ^ 63 or greater.

   Tan can be overloaded as operator to accept user-defined types.

Example
   Const PI As Double = 3.1415926535897932
   Dim a As Double
   Dim r As Double
   Input "Please enter an angle in degrees: ", a
   r = a * PI / 180   'Convert the degrees to Radians
   Print ""
   Print "The tangent of a" ; a; " degree angle is"; Tan ( r ) 
   Sleep

The output would look like:

   Please enter an angle in degrees: 75
   The tangent of a 75 degree angle Is 3.732050807568878

Differences from QB
   * None

See also
   * Atn
   * Atan2
   * Sin
   * Cos
   * A Brief Introduction To Trigonometry



-------------------------------------------------------- KeyPgTcpAccept ----
Tcp Accept

Accepts a connection from an Open Tcp Server file number.

Syntax
   Declare Function Tcp Accept ( [#]serverfilenum As Long ) As Long

Usage
   clientfilenum = Tcp Accept( [#]serverfilenum )

Parameters
   serverfilenum
      A file number previously opened with Open Tcp Server.

Return Value
   Returns a new client file number on success, or zero (0) on failure.

Description
   Tcp Accept waits for the next incoming connection on a TCP server file 
   number.  It chooses a free file number for the accepted client and 
   returns it to the program.  The returned file number should be closed 
   with Close when the connection is no longer needed.

   The server file number remains open and may be passed to Tcp Accept 
   again to accept another connection.

Example
   See examples/network/opentcp/http-server.bas and 
   examples/network/opentcp/two-connections-selftest.bas.

Differences from QB
   * New to FreeBASIC.

See also
   * Open Tcp Server
   * Open Tcp
   * Eoc
   * FreeFile



----------------------------------------------------- KeyPgSfxGenerated ----
Generated Sound Commands

Commands for generated sound, PLAY strings, and sfxlib mix settings.

Syntax
   Beep [ duration, pitch ]
   Sound frequency, duration
   Sound channel, frequency, duration, volume
   Tone channel, frequency, duration
   Noise channel, duration, volume
   Noise channel, frequency, duration, volume
   Note name, octave, duration
   Note channel, name, octave, duration
   Play music
   Play channel, music
   Play music1, music2
   Play music1, music2, music3
   Tempo bpm
   bpm = Tempo()
   Channel channel
   channel = Channel()
   Octave octave
   octave = Octave()
   Voice instrument
   instrument = Voice()
   Vol level
   Volume level
   level = Volume()
   Volume channel, level
   level = Volume( channel )
   Balance position
   position = Balance()
   Pan channel, position
   position = Pan( channel )
   Wave id, waveform
   Envelope id, attack, decay, sustain, release
   Instrument id, wave_id, envelope_id
   Instrument channel, instrument_id

Description
   These commands synthesize sound directly through sfxlib.  Sound, Tone, 
   Noise, Note, and Play create voices.  Tempo, Channel, Octave, and Voice 
   set defaults used by PLAY-string and generated-sound commands.  Volume, 
   Vol, Balance, and Pan control mix levels and stereo placement.

   Sound accepts the high-impact classic form Sound frequency, duration and
   the explicit channel form Sound channel, frequency, duration, volume.
   When both arguments are integers, duration is interpreted as the PC BASIC
   timer-tick value.

   Wave defines a waveform id.  The currently supported waveform values 
   are:
      * 0 sine
      * 1 square
      * 2 triangle
      * 3 saw
      * 4 noise

   Envelope defines an ADSR envelope using seconds for attack, decay, and 
   release, and a 0.0 to 1.0 sustain level.  Instrument can define an 
   instrument from a waveform and envelope, or assign an instrument to a 
   channel.

   The channel-oriented commands use sfxlib's channel table.  Channels are 
   zero-based.

Example
   See examples/sfxlib/basics-01-generated-sound.bas, 
   examples/sfxlib/basics-02-play-strings.bas, 
   examples/sfxlib/basics-03-channels-mix.bas, 
   examples/sfxlib/basics-04-instruments.bas, and 
   examples/sfxlib/showcase.bas.

Platform Differences
   * On headless or diagnostic runs, SFXLIB_DRIVER=null can be set before 
     program startup to use the null output driver.

Differences from QB
   * New to FreeBASIC.

See also
   * Beep
   * Music
   * Sfx
   * Sound Library Reference



------------------------------------------------------------- KeyPgThen ----
Then

Control flow statement for conditional branching.

Syntax
   If expression Then [statement(s)] [Else [statement(s)]] [End If]
or
   If expression Then : [statement(s)] [Else [statement(s)]] : End If
or
   If expression Then
      [statement(s)]
   [ ElseIf expression Then ]
      [statement(s)]
   [ Else ]
      [statement(s)]
   End If

   Remark: EndIf (without blank) is also supported like in QB for backward 
   compatibility.

Example
   See example at If...Then.

Differences from QB
   * None

See also
   * If...Then

   


------------------------------------------------------------- KeyPgThis ----
This

Hidden instance parameter passed to non-static member functions in a Type 
or Class

Syntax
   This.fieldname
or
   With This
      .fieldname
   End With

Description
   This is a reference to an instance of a Type or Class that is passed 
   (through a hidden Byref Parameter) to all non-static member functions of 
   that type or class. Non-static member functions are procedures declared 
   inside the body of a Type or Class and include Sub, Function, Constructor
   , Destructor, assignment or Cast Operator, and Property procedures.

   The This additional parameter also has the same data type as the Type or 
   Class in which the procedure is declared. Therefore using it corresponds 
   to referring to the instance declared name on which the non-static 
   member function is called.

   The This parameter can be used just like any other variable, ie., pass 
   it to procedures taking an object of the same type, call other member 
   procedures and access member data using Operator . (Member Access), etc.

   Most of the time, using This explicitly for member access is 
   unnecessary; member procedures can refer to other members of the 
   instance which they are passed directly by name, without having to 
   qualify it with This and Operator . (Member Access). The only times when 
   you need to qualify member names with This is when the member is 
   shadowed, for example by duplicating its name for a local variable or 
   parameter. In these situations, qualifying the member name is the only 
   way to refer to these masked member names.

Example
   Type sometype
      Declare Sub MyCall()
      value As Integer
   End Type

   Dim example As sometype

   '' Set element test to 0
   example.value = 0
   Print example.value

   example.MyCall()

   '' Output should now be 10
   Print example.value

   End 0

   Sub sometype.MyCall()
      This.value = 10
   End Sub

Differences from QB
   * New to FreeBASIC

See also
   * Base (Member Access)
   * Class
   * Type



--------------------------------------------------------- KeyPgThiscall ----
__Thiscall

Specifies the Thiscall calling convention in a procedure declaration

Syntax
   declare Sub name __Thiscall [Overload] [Alias "alias"] ( parameters )
   declare Function name __Thiscall [Overload] [Alias "alias"] ( parameters 
   ) [ ByRef ] As return_type

   Sub name [__Thiscall] [Overload] [Alias "alias"] ( parameters )
   Function name [__Thiscall] [Overload] [Alias "alias"] ( parameters ) [ 
   ByRef ] As return_type

Description
   Thiscall is a calling convention for x86 targets where the first 
   integral argument is passed in the ECX register instead of on the stack. 
   All other arguments are passed right to left and callee cleans up the 
   stack (like Stdcall).

   On win32 x86, mingw+gcc will use Thiscall as the default calling 
   convention for non-static member procedures in classes passing the 
   hidden This parameter by ECX register instead of pushing to the stack.

   Default calling convention on win32 x86 inside an extern "c++" block for 
   non-static member procedures is Thiscall.

   Thiscall can be explicitly specified for normal procedures and static 
   member procedures to override the default calling convention.
   Other calling conventions (Cdecl/Stdcall/etc) can be explicitly 
   specified to override the default Thiscall calling convention on 
   non-static member procedures.

   Thiscall can be specified at both the declaration and the definition.
   If a procedure definition has a declaration (with calling convention 
   explicit or by default) and the definition does not explicitly specify a 
   calling convention, then the calling convention is implied by the 
   declaration.

Example
   - If inside extern "c++" and also on win32 / x86, and it's a non-static 
   member procedure, and no other calling convention is given, the default 
   is __thiscall:
   Extern "c++"
      Type T Extends Object
         Declare Constructor() '' __thiscall is default
      End Type

      Constructor T()  '' __thiscall is default
      End Constructor   
   End Extern

   - If definition is outside the extern "c++" block, then __thiscall is 
   optional on the definition (if the default for the non-static member 
   procedure was __thiscall):
   Extern "c++"
      Type T Extends Object
         Declare Constructor() '' __thiscall is default
      End Type

   End Extern

   Constructor T() '' __thiscall is implied by declaration
   End Constructor   

Version
   * Since fbc 1.10.0:
         - Thiscall calling convention is used as default for non-static 
         member procedures under extern "c++" / win32 / x86.
         - Thiscall can also be explicitly specified for normal procedures 
         and static member procedures to override the default calling 
         convention.
   * Since fbc 1.08.0

Differences from QB
   * New to FreeBASIC

See also
   * cdecl, stdcall, Fastcall
   * Declare
   * Sub, Function



------------------------------------------------------- KeyPgThreadCall ----
ThreadCall

Starts a user-defined procedure with parameters in a separate execution 
thread

   Threadcall uses LibFFI internally: people who write programs using this 
   functionality should be careful to follow LibFFI's license, which can be 
   found at http://github.com/atgreen/libffi/blob/master/LICENSE.

Syntax
   Function ThreadCall subname([paramlist]) As Any Ptr

Usage
   threadid = ThreadCall subname([paramlist])

Parameters
   subname
      The name of a subroutine
   paramlist
      A list of parameters to pass to the subroutine, as with a normal sub 
      call.	

Return Value
   Threadcall returns an Any Ptr handle to the thread created, or the null 
   pointer (0) on failure.

Description
   Like ThreadCreate, Threadcall creates a thread which runs at the same 
   time as the code calling it.  By placing "Threadcall" before almost any 
   normal call to sub, the sub is called inside of a new thread and returns 
   a pointer to that thread.

   Using Threadcall is simpler method of creating threads, and allows data 
   to be passed to the thread without global variables or pointers which 
   are not type safe.  However, ThreadCreate is more efficient and should 
   be used for programs creating a large number of threads.

   While most subroutines are supported, the following types of subroutines 
   may not be called:
      * Subroutines using Variable Arguments.
      * Subroutines with unions which are passed as arguments.
      * Subroutines with user types containing unions, arrays, strings, or 
        bitfields which are passed as arguments.

   When using Threadcall, parenthesis around the parameter list are 
   required unless the subroutine has no parameters.

   Warning:
      - Presently when Threadcall involves to pass parameters to the 
      thread, there is no guarantee that the corresponding data are still 
      maintained after the end of the Threadcall statement and this until 
      the thread is launched.
      - That can cause bad behavior:
         - see example below where the not displayed parameter id seems to 
         be the consequence of a prematurely destroyed string argument 
         (visible for a fbc version >= 1.00),
         - replace id As String with id As Zstring in the parameters 
         declaration seems to workaround the problem when passing this 
         parameter.
      - Therefore it is more advisable for the moment to use ThreadCreate 
      (100% safe) instead.	

Example
   '' Threading using "ThreadCall"

   Sub thread( id As String, tlock As Any Ptr, count As Integer )
      For i As Integer = 1 To count
         MutexLock tlock
         Print "thread " & id;
         Locate , 20
         Print i & "/" & count
         MutexUnlock tlock
      Next
   End Sub

   Dim tlock As Any Ptr = MutexCreate()
   Dim a As Any Ptr = ThreadCall thread("A", tlock, 6)
   Dim b As Any Ptr = ThreadCall thread("B", tlock, 4)
   ThreadWait a
   ThreadWait b
   MutexDestroy tlock
   Print "All done (and without Dim Shared!)"

Dialect Differences
   * Threading is not allowed in the -lang qb dialect.

Platform Differences
   * Threadcall is not available with the DOS version / target of 
     FreeBASIC, because multithreading is not supported by DOS kernel nor 
     the used extender.
   * In Linux the threads are always started in the order they are 
     created, this can't be assumed in Win32. It's an OS, not a FreeBASIC 
     issue. 
   * In Linux, the stdcall and pascal calling conventions are not 
     supported
   * In Windows, the pascal calling convention is not supported.

Differences from QB
   * New to FreeBASIC

See also
   * ThreadCreate
   * ThreadWait
   * MutexCreate
   * MutexLock
   * MutexUnlock
   * MutexDestroy



----------------------------------------------------- KeyPgThreadCreate ----
ThreadCreate

Starts a user-defined procedure in a separate execution thread

Syntax
   Declare Function ThreadCreate _
      ( _
         ByVal procptr As Sub ( ByVal userdata As Any Ptr ), _
         ByVal param As Any Ptr = 0, _
         ByVal stack_size As Integer = 0 _
      ) As Any Ptr

Usage
   result = ThreadCreate ( procptr [, [ param ] [, stack_size ] ] )

Parameters
   procptr
      A pointer to the Sub intended to work as a thread (see 
      Operator Procptr (Procedure Pointer And Vtable Index) to get a 
      pointer to a sub). The sub must have the following signature (same 
      parameters, same calling convention) to be compatible to procptr:
         Declare Sub myThread ( ByVal userdata As Any Ptr )
   userdata
      The Any Ptr parameter of the Sub intended to work as a thread. 
      FreeBASIC expects this parameter to be present, it must not be 
      omitted! 
   param
      Any Ptr argument that will be passed to the thread Sub pointed to by 
      procptr through its userdata parameter. For example, this can be a 
      pointer to a structure or an array containing various information for 
      the thread sub to work with. If param is not given, 0 (zero) will be 
      passed to the thread sub's userdata parameter instead.
   stack_size
      Optional number of bytes to reserve for this thread's stack.

Return Value
   ThreadCreate returns an Any Ptr handle to the thread created, or a null 
   pointer (0) on failure.

Description
   The sub pointed to by procptr is started as a thread. It will be passed 
   the content of param, or 0 (zero) if not specified, in its userdata 
   parameter.

   The sub that was started as a thread will execute in parallel with the 
   main part of the program. The OS achieves this by assigning it to a 
   different processor if it exists, or by alternating between execution 
   threads on a single processor.
   There is no guarantee about the order in which different threads 
   execute, and no assumptions can be made about the order in which 
   multiple created threads actually start executing.
   The time between ThreadCreate and the actual start of execution of the 
   thread is variable and can be longer or shorter depending on the context 
   (so some statements following the ThreadCreate statement can be executed 
   before the actual launch of the thread).
   In the fastest launch cases, the thread body may start executing even 
   before ThreadCreate returns.

   Each running thread can be identified by its handle which is unique 
   among all running threads. See ThreadSelf.

   Before closing, programs should wait for the termination of all launched 
   threads by using ThreadWait. Alternatively, if it's not necessary to 
   safely wait for a thread to finish execution, ThreadDetach can be used. 
   However, if a program exits while some threads are still active, those 
   threads will be aborted by the system. For every thread created, 
   programs should call either ThreadWait or ThreadDetach to ensure that 
   the system resources associated with the thread handles are released. 
   Otherwise, there may be memory or system resource leaks.

   Due to the nature of threads, no assumptions about execution order can 
   be made. In order to exchange data between multiple threads, including a 
   thread and the main part of the program, mutexes must be used. These 
   mutual exclusion locks can be "owned" by a single thread while doing 
   critical work, causing other threads to wait for their turn. See 
   MutexCreate, MutexLock, MutexUnlock, MutexDestroy.

   stack_size can be used to change the thread's stack size from the 
   system's default. This can be useful when the program requires a big 
   stack, for example due to lots of procedure recursion or when allocating 
   huge strings/arrays on the stack. On some systems (Linux), the stack 
   automatically grows beyond stack_size if more space is needed; on others 
   (Win32), this is the fixed maximum allowed. Behavior is undefined when 
   more stack is used than the reserved size on systems where stacks are 
   not able to grow.

   The intrinsic macro __FB_MT__ is only automatically set from the point 
   of usage of ThreadCreate onward.

   Note:
      - The userdata parameter can be unused in the body of the myThread 
      sub, but declaring it as an Any Ptr parameter is always mandatory in 
      the header. In this case, the corresponding param parameter can then 
      be omitted when calling ThreadCreate, or else a needless argument can 
      still be passed ('0' is commonly used because this value is directly 
      compatible with any pointer). See the 2nd and 3rd example.
      - In the case where data must be passed to myThread, the Any Ptr 
      param can be used to reference them, usually requiring a type 
      conversion (implicit or explicit) into Any Ptr before passing it to 
      ThreadCreate, and a reverse type conversion from Any Ptr in the body 
      of myThread before using it. See the 1st example.

Example
   '' Threading synchronization using Mutexes
   '' If you comment out the lines containing "MutexLock" and "MutexUnlock",
   '' the threads will not be in sync and some of the data may be printed
   '' out of place.

   Const MAX_THREADS = 10

   Dim Shared As Any Ptr ttylock

   '' Teletype unfurls some text across the screen at a given location
   Sub teletype( ByRef text As String, ByVal x As Long, ByVal y As Long )
      ''
      '' This MutexLock makes simultaneously running threads wait for each
      '' other, so only one at a time can continue and print output.
      '' Otherwise, their Locates would interfere, since there is only one
      '' cursor.
      ''
      '' It's impossible to predict the order in which threads will arrive
      '' here and which one will be the first to acquire the lock thus
      '' causing the rest to wait.
      ''
      MutexLock ttylock

      For i As Integer = 0 To (Len(text) - 1)
         Locate x, y + i
         Print Chr(text[i])
         Sleep 25, 1
      Next

      '' MutexUnlock releases the lock and lets other threads acquire it.
      MutexUnlock ttylock
   End Sub

   Sub thread( ByVal userdata As Any Ptr )
      Dim As Integer id = CInt(userdata)
      teletype "Thread (" & id & ").........", 1 + id, 1
   End Sub

      '' Create a mutex to syncronize the threads
      ttylock = MutexCreate()

      '' Create child threads
      Dim As Any Ptr handles(0 To MAX_THREADS-1)
      For i As Integer = 0 To MAX_THREADS-1
         handles(i) = ThreadCreate(@thread, CPtr(Any Ptr, i))
         If handles(i) = 0 Then
            Print "Error creating thread:"; i
            Exit For
         End If
      Next

      '' This is the main thread. Now wait until all child threads have finished.
      For i As Integer = 0 To MAX_THREADS-1
         If handles(i) <> 0 Then
            ThreadWait(handles(i))
         End If
      Next

      '' Clean up when finished
      MutexDestroy(ttylock)

   Sub print_dots(ByRef char As String)
      For i As Integer = 0 To 29
         Print char;
         Sleep CInt(Rnd() * 100), 1
      Next
   End Sub

   Sub mythread(param As Any Ptr)
      '' Work (other thread)
      print_dots("*")
   End Sub

      Randomize(Timer())

      Print " main thread: ."
      Print "other thread: *"

      '' Launch another thread
      Dim As Any Ptr thread = ThreadCreate(@mythread, 0)

      '' Work (main thread)
      print_dots(".")

      '' Wait until other thread has finished, if needed
      ThreadWait(thread)
      Print
      Sleep

   '' Threaded consumer/producer example using mutexes

   Dim Shared As Any Ptr produced, consumed 

   Sub consumer( ByVal param As Any Ptr )
      For i As Integer = 0 To 9
         MutexLock produced
         Print ", consumer gets:", i
         Sleep 500, 1
         MutexUnlock consumed
      Next
   End Sub

   Sub producer( ByVal param As Any Ptr )
      For i As Integer = 0 To 9
         Print "Producer puts:", i;
         Sleep 500, 1
         MutexUnlock produced
         MutexLock consumed
      Next i
   End Sub

      Dim As Any Ptr consumer_id, producer_id

      produced = MutexCreate
      consumed = MutexCreate
      If( ( produced = 0 ) Or ( consumed = 0 ) ) Then
         Print "Error creating mutexes! Exiting..."
         End 1
      End If

      MutexLock produced
      MutexLock consumed
      consumer_id = ThreadCreate(@consumer)
      producer_id = ThreadCreate(@producer)
      If( ( producer_id = 0 ) Or ( consumer_id = 0 ) ) Then
         Print "Error creating threads! Exiting..."
         End 1
      End If

      ThreadWait consumer_id
      ThreadWait producer_id

      MutexDestroy consumed
      MutexDestroy produced

      Sleep

Dialect Differences
   * Threading is not allowed in the -lang qb dialect.

Platform Differences
   * Threadcreate is not available with the DOS version / target of 
     FreeBASIC, because multithreading is not supported by DOS kernel nor 
     the used extender.
   * In Linux the threads are always started in the order they are 
     created, this can't be assumed in Win32. It's an OS, not a FreeBASIC 
     issue. 

Differences from QB
   * New to FreeBASIC

See also
   * ThreadSelf
   * ThreadWait
   * ThreadDetach
   * MutexCreate
   * MutexLock
   * MutexUnlock
   * MutexDestroy
   * Operator Procptr (Procedure Pointer And Vtable Index)



----------------------------------------------------- KeyPgThreadDetach ----
ThreadDetach

Releases a thread handle without waiting for the thread to finish

Syntax
   Declare Sub ThreadDetach ( ByVal id As Any Ptr )

Usage
   #include "fbthread.bi"
   ThreadDetach( id )

Parameters
   id
      Any Ptr handle of a thread created by ThreadCreate or ThreadCall

Description
   ThreadDetach releases resources associated with the thread handle 
   returned by ThreadCreate or ThreadCall. The thread handle will be 
   destroyed by ThreadDetach and cannot be used anymore.
   Unlike ThreadWait, ThreadDetach does not wait for the thread to finish 
   and thread execution continues independently. Any allocated resources 
   will be freed once the thread exits.

   In order to avoid memory leaks, the safe way to end a thread is to 
   always signal to it that it must end, and then call ThreadWait on that 
   thread except if ThreadDetach has previously been called.

   Note: As ThreadDetach destroys the thread handle, ThreadWait can no 
   longer check for the thread ending, and even the use of ThreadWait 
   becomes unpredictable (may crash the program). The use between ThreadWait
   and ThreadDetach must be exclusive.
   But mutexes and conditional variables can also be used with detached 
   threads.

Example
   #include "fbthread.bi"

   Sub mythread( ByVal param As Any Ptr )
      Print "hi!"
   End Sub

   Dim As Any Ptr thread = ThreadCreate( @mythread )
   ThreadDetach( thread )
   '' or
   ThreadDetach( ThreadCreate( @mythread ) )

   Sleep

Dialect Differences
   * Threading is not allowed in the -lang qb dialect.

Platform Differences
   * ThreadDetach is not available with the DOS version of FreeBASIC, 
     because multithreading is not supported by DOS kernel nor the used 
     extender.

Differences from QB
   * New to FreeBASIC

See also
   * ThreadWait
   * ThreadCreate



------------------------------------------------------- KeyPgThreadSelf ----
ThreadSelf

Return the thread handle of the current thread.

Syntax
   Declare Function ThreadSelf ( ) As Any Ptr

Usage
   #include "fbthread.bi"
   result = ThreadSelf

Return Value
   ThreadSelf returns an Any Ptr handle of the current thread.

Description
   ThreadSelf is used to get the handle of the current thread.

   This function can uniquely identify the existing threads:
      - If there are multiple threads, and one thread is completed, then 
      that handle can be reused.
      - So for all the only threads still running, the handles are unique.

   When a new thread is created, a handle to the thread is returned by the 
   creation function.
   When the thread runs code, ThreadSelf allows to return the handle of the 
   thread (the implicit main thread also has its own unique handle).

   ThreadSelf may be used to code some sort of TLS (Thread Local Storage) 
   from the unique handle of each thread (including the implicit main 
   thread).
   Therefore, a same global variable name may be defined, but with a stored 
   value specific to the thread that accesses it.
   This allows generic procedures to be coded, but with parameters 
   depending on the thread which executes them (see 3rd example below).

Example
   #include "fbthread.bi"

   Dim As Any Ptr phandle(1 To 10)

   Sub myThread (ByVal p As Any Ptr)
      Print "Thread handle: " & ThreadSelf()
   End Sub

   For I As Integer = 1 To 10
      phandle(I) = ThreadCreate(@myThread)
   Next I

   For I As Integer = 1 To 10
      ThreadWait(phandle(I))
   Next I

   Sleep
      

   Checking for equality between the thread handle returned by ThreadCreate 
   at thread creation and the one returned by ThreadSelf from thread 
   running:
   #include "fbthread.bi"

   Dim As Any Ptr phandle(1 To 10)
   Dim Shared As Any Ptr pmutex

   Sub myThread (ByVal p As Any Ptr)
      MutexLock(pmutex)  ' to ensure that ThreadCreate line is completed before accessing the handle value
      Dim As Any Ptr phandle1 = *CPtr(Any Ptr Ptr, p)
      MutexUnlock(pmutex)
      Dim As Any Ptr phandle2 = ThreadSelf()
      Print Left("   ThreadCreate: " & phandle1 & Space(18), 36) _
           & "   ThreadSelf: " & phandle2  ' single print with concatenated string avoids using a mutex
      Sleep 100, 1
   End Sub

   Print "Handles returned from:"
   pmutex = MutexCreate()
   For I As Integer = 1 To 10
      MutexLock(pmutex)  ' to ensure that ThreadCreate line is completed before thread accesses the handle value
      phandle(I) = ThreadCreate(@myThread, @phandle(I))
      MutexUnlock(pmutex)
   Next I

   For I As Integer = 1 To 10
      ThreadWait(phandle(I))
   Next I
   MutexDestroy(pmutex)

   Sleep
      

   Example of a sort of TLS (Thread Local Storage):
   (see the end of the "Description" paragraph)
   #include Once "fbthread.bi"

   Function TLSindex() As Integer  ' returning a unique thread index (incremented with each new thread)
      Static As Any Ptr TLSind()
      Dim As Integer index = -1
      For I As Integer = LBound(TLSind) To UBound(TLSind)
         If TLSind(I) = ThreadSelf() Then
            index = I
            Exit For
         End If
      Next I
      If index = -1 Then
         index = UBound(TLSind) + 1
         ReDim Preserve TLSind(index)
         TLSind(index) = ThreadSelf()
      End If
      Return index
   End Function

   Function TLSinteger() ByRef As Integer  ' emulation of global integer with value depending on thread using it
      Static As Integer TLSint()
      Dim As Integer index = TLSindex()
      If index > UBound(TLSint) Then
         ReDim Preserve TLSint(index)
      End If
      Return TLSint(index)
   End Function

   '------------------------------------------------------------------------------

   Type threadData
      Dim As Any Ptr handle
      Dim As String prefix
      Dim As String suffix
      Dim As Double tempo
   End Type

   Function counter() As Integer  ' definition of a generic counter with counting depending on thread calling it
      TLSinteger() += 1
      Return TLSinteger()
   End Function

   Sub Thread(ByVal p As Any Ptr)
      Dim As threadData Ptr ptd = p
      Dim As UInteger c
      Do
         c = counter()
         Print ptd->prefix & c & ptd->suffix & " ";  ' single print with concatenated string avoids using a mutex
         Sleep ptd->tempo, 1
      Loop Until c = 12
   End Sub

   '------------------------------------------------------------------------------

   Print "|x| : counting from thread a"
   Print "(x) : counting from thread b"
   Print "[x] : counting from thread c"
   Print

   Dim As threadData mtlsa
   mtlsa.prefix = "|"
   mtlsa.suffix = "|"
   mtlsa.tempo = 250
   mtlsa.handle = ThreadCreate(@Thread, @mtlsa)

   Dim As threadData mtlsb
   mtlsb.prefix = "("
   mtlsb.suffix = ")"
   mtlsb.tempo = 150
   mtlsb.handle = ThreadCreate(@Thread, @mtlsb)

   Dim As threadData mtlsc
   mtlsc.prefix = "["
   mtlsc.suffix = "]"
   mtlsc.tempo = 100
   mtlsc.handle = ThreadCreate(@Thread, @mtlsc)

   ThreadWait(mtlsa.handle)
   ThreadWait(mtlsb.handle)
   ThreadWait(mtlsc.handle)

   Print
   Print
   Print "end of threads"

   Sleep   

Version
   * Since fbc 1.08.0

Dialect Differences
   * Threading is not allowed in the -lang qb dialect.

Platform Differences
   * ThreadSelf is not available with the DOS version of FreeBASIC, 
     because multithreading is not supported by DOS kernel nor the used 
     extender.

Differences from QB
   * New to FreeBASIC

See also
   * ThreadCreate



------------------------------------------------------- KeyPgThreadWait ----
ThreadWait

Waits for a thread to finish execution and releases the thread handle

Syntax
   Declare Sub ThreadWait ( ByVal id As Any Ptr )

Usage
   ThreadWait( id )

Parameters
   id
      Any Ptr handle of a thread created by ThreadCreate or ThreadCall

Description
   ThreadWait waits for a thread created by ThreadCreate or ThreadCall to 
   finish execution, and then releases the resources associated with the 
   thread handle. ThreadWait does not return until the thread designated by 
   id ends.
   During the wait, no CPU time is consumed by the caller.

   In order to release a thread handle without waiting for the thread to 
   finish, use ThreadDetach.

   ThreadWait does not force the thread to end; if a thread requires a 
   signal to force its end, a mechanism such as shared variables and 
   mutexes must be used.

   In order to avoid memory leaks, the safe way to end a thread is to 
   always signal to it that it must end, and then call ThreadWait on that 
   thread except if ThreadDetach has previously been called.

   The intrinsic macro __FB_MT__ is only automatically set from the point 
   of usage of ThreadWait onward.

Example
   See the ThreadCreate examples.

Dialect Differences
   * Threading is not allowed in the -lang qb dialect.

Platform Differences
   * ThreadWait is not available with the DOS version of FreeBASIC, 
     because multithreading is not supported by DOS kernel nor the used 
     extender.

Differences from QB
   * New to FreeBASIC

See also
   * ThreadCreate
   * ThreadDetach



------------------------------------------------------------- KeyPgTime ----
Time

Returns the current system time as a string

Syntax
   Declare Function Time ( ) As String

Usage
   result = Time[$]

Return Value
   Returns the current system time.

Description
   Returns the current system time in the format hh:mm:ss.

Example
   Print "the current time is: "; Time

Differences from QB
   * The QB TIME statement (to set the system time) is now called SetTime.
   * The string type suffix "$" is required in the -lang qb dialect.
   * The string type suffix "$" is optional in the -lang fblite dialect.
   * The string type suffix "$" is ignored in the -lang fb dialect, warn 
     only with the -w suffix compile option (or -w pedantic compile 
     option).

See also
   * Date
   * Timer



------------------------------------------------------------ KeyPgTimer ----
Timer

Returns the amount of time that has passed since a static reference point.

Syntax
   Declare Function Timer ( ) As Double

Usage
   result = Timer

Return Value
   Returns a Double precision result with the time, in seconds, since a 
   static reference point.

Description
   The Timer function is useful for finding out how long a section of code 
   takes to run, or for control the timing of your code.  To find out how 
   much time has passed between two points in your program, you can record 
   the value of Timer at the start and end points, and then subtract the 
   start value from the end value.

   On some platforms, the value of Timer resets to zero at midnight (see 
   below), so if the start and end time are on either side of the reset 
   point, the difference will be negative.  This could cause unexpected 
   behavior in some programs.  In those cases, adding 86400 (the number of 
   seconds in 24 hours) to the difference should return the correct result. 
   If the time taken is longer than a day, then it will be also be 
   necessary to check the number of days that have elapsed.

   The value returned by Timer is NOT affected by the automatic changing of 
   the system clock, in Spring and Autumn, for DST (Daylight Savings Time).

Example
   '' Example of using TIMER function 
   '' Note: see text about correct waiting strategies
   Dim Start As Double
   Print "Wait 2.5 seconds."
   Start = Timer
   Do
      Sleep 1, 1
   Loop Until (Timer - Start) > 2.5
   Print "Done."

Platform Differences
   * On Win32 and Linux, if the program must wait for periods of 0.1 
     seconds or more, Sleep should be used, this allows other programs to 
     run during the waiting period. For shorter delays, a loop using TIMER 
     can be more precise.
   * The reference point chosen varies, depending on the platform.  On 
     Windows, the time is measured relative to the point the computer was 
     booted up.  On DOS, the time is measured relative to Jan 1 1970.

   Note for DOS users: today, the number of seconds since 1970 is in excess 
   of 10^9, and is therefore unsuitable for storing in Single-precision 
   variables, also it shouldn't be multiplied (to get 1/10 seconds or so) 
   and stored in 32-bit integer variables then

   * The precision of TIMER varies, depending on the computer used.  If 
     the processor has a precision timer (as the Performance Counter 
     Pentium processors from Intel have) and the OS uses it, the precision 
     is linked to the processor clock and microseconds can be expected. 
     With older processors (386, 486), and always in DOS, the resolution is 
     1/18 second.

   * Usage of TIMER can cause disk accesses in DOS, see forum for analysis 
     and solutions

Differences from QB
   * In QB, TIMER returned the number of seconds from last midnight, and 
     its accuracy was 1/18 secs

See also
   * Time
   * Sleep



------------------------------------------------------- KeyPgTimeserial ----
TimeSerial

Gets a Date Serial for the specified hours, minutes, and seconds

Syntax
   Declare Function TimeSerial ( ByVal hour As Long, ByVal minute As Long, 
   ByVal second As Long ) As Double

Usage
   #include "vbcompat.bi"
   result = TimeSerial( hours, minutes, seconds )

Parameters
   hour
      number of hours, in the range 0-23
   minute
      number of minutes
   second
      number of seconds

Return Value
   Returns a date serial containing the time formed by the values in the 
   hours, minutes and seconds parameters.The date serial returned has no 
   integer part.

Description
   hours must be specified in the range 0-23

   The compiler will not recognize this function unless vbcompat.bi or 
   datetime.bi is included.

Example
   #include "vbcompat.bi"

   Dim ds As Double = DateSerial(2005, 11, 28) + TimeSerial(7, 30, 50)

   Print Format(ds, "yyyy/mm/dd hh:mm:ss")

Differences from QB
   * Did not exist in QB. This function appeared in PDS and VBDOS

See also
   * Date Serials
   * DateSerial
   * TimeValue
   * DateValue



-------------------------------------------------------- KeyPgTimeValue ----
TimeValue

Gets a Date Serial from a time string

Syntax
   Declare Function TimeValue ( ByRef timestring As String ) As Double

Usage
   #include "vbcompat.bi"
   result = TimeValue( timestring )

Parameters
   timestring
      the string to convert

Return Value
   Returns a Date Serial from a time string.

Description
   The time string must be in the format "23:59:59" or  "11:59:59PM"

   The compiler will not recognize this function unless vbcompat.bi or 
   datetime.bi is included.

Example
   #include "vbcompat.bi"

   Dim ds As Double = TimeValue("07:12:28AM")

   Print Format(ds, "hh:mm:ss")

Differences from QB
   * Did not exist in QB. This function appeared in PDS and VBDOS

See also
   * Date Serials
   * DateSerial
   * TimeValue
   * DateValue



--------------------------------------------------------------- KeyPgTo ----
To

Statement modifier to specify a range.

Syntax
   For iterator intial_value To ending_value
      statement(s).
   Next [ iterator ]
or
   Select Case case_comparison_value
   Case lower_bound To upper_bound
      statement(s).
   End Select
or
   Dim variable_identifier( lower_bound To upper_bound ) As type_specifier

Description
   The To keyword is used to define a certain numerical range. This keyword 
   is valid only if used with For ... Next, Case and Dim statements.

   In the first syntax, the To keyword defines the initial and ending 
   values of the iterator in a For statement.

   In the second syntax, the To keyword defines lower and upper bounds for 
   Case comparisons.

   In the third syntax, the To keyword defines the array bounds in a Dim 
   statement

   For more information, see For...Next, Dim and Select Case.

Example
   '' this program uses bound variables along with the TO keyword to create an array, store random
   '' temperatures inside the array, and to determine output based upon the value of the temperatures
   Randomize Timer

   '' define minimum and maximum number of temperatures we will create
   Const minimum_temp_count As Integer = 1
   Const maximum_temp_count As Integer = 10

   '' define the range of temperatures zones in which bacteria breed rapidly (in degrees)
   Const min_low_danger As Integer = 40
   Const max_low_danger As Integer = 69
   Const min_medium_danger As Integer = 70
   Const max_medium_danger As Integer = 99
   Const min_high_danger As Integer = 100
   Const max_high_danger As Integer = 130

   '' define array to hold temperatures using our min/max temp count bounds
   Dim As Integer array( minimum_temp_count To maximum_temp_count )

   '' declare a for loop that iterates from minimum to maximum temp count
   Dim As Integer it
   For it = minimum_temp_count To maximum_temp_count

      array( it ) = Int( Rnd( 1 ) * 200 ) + 1

      '' display a message based on temperature using our min/max danger zone bounds
      Select Case array( it )
        Case min_low_danger To max_low_danger
          Color 11
          Print "Temperature" ; it ; " is in the low danger zone at" ; array( it ) ; " degrees!"
        Case min_medium_danger To max_medium_danger
          Color 14
          Print "Temperature" ; it ; " is in the medium danger zone at" ; array( it ) ; " degrees!"
        Case min_high_danger To max_high_danger
          Color 12
          Print "Temperature" ; it ; " is in the high danger zone at" ; array( it ) ; " degrees!"
        Case Else
          Color 3
          Print "Temperature" ; it ; " is safe at" ; array( it ) ; " degrees."
      End Select

   Next it

   Sleep

Differences from QB
   * none

See also
   * For...Next
   * Dim
   * Select Case



----------------------------------------------------- KeyPgSfxGenerated ----
Generated Sound Commands

Commands for generated sound, PLAY strings, and sfxlib mix settings.

Syntax
   Beep [ duration, pitch ]
   Sound frequency, duration
   Sound channel, frequency, duration, volume
   Tone channel, frequency, duration
   Noise channel, duration, volume
   Noise channel, frequency, duration, volume
   Note name, octave, duration
   Note channel, name, octave, duration
   Play music
   Play channel, music
   Play music1, music2
   Play music1, music2, music3
   Tempo bpm
   bpm = Tempo()
   Channel channel
   channel = Channel()
   Octave octave
   octave = Octave()
   Voice instrument
   instrument = Voice()
   Vol level
   Volume level
   level = Volume()
   Volume channel, level
   level = Volume( channel )
   Balance position
   position = Balance()
   Pan channel, position
   position = Pan( channel )
   Wave id, waveform
   Envelope id, attack, decay, sustain, release
   Instrument id, wave_id, envelope_id
   Instrument channel, instrument_id

Description
   These commands synthesize sound directly through sfxlib.  Sound, Tone, 
   Noise, Note, and Play create voices.  Tempo, Channel, Octave, and Voice 
   set defaults used by PLAY-string and generated-sound commands.  Volume, 
   Vol, Balance, and Pan control mix levels and stereo placement.

   Sound accepts the high-impact classic form Sound frequency, duration and
   the explicit channel form Sound channel, frequency, duration, volume.
   When both arguments are integers, duration is interpreted as the PC BASIC
   timer-tick value.

   Wave defines a waveform id.  The currently supported waveform values 
   are:
      * 0 sine
      * 1 square
      * 2 triangle
      * 3 saw
      * 4 noise

   Envelope defines an ADSR envelope using seconds for attack, decay, and 
   release, and a 0.0 to 1.0 sustain level.  Instrument can define an 
   instrument from a waveform and envelope, or assign an instrument to a 
   channel.

   The channel-oriented commands use sfxlib's channel table.  Channels are 
   zero-based.

Example
   See examples/sfxlib/basics-01-generated-sound.bas, 
   examples/sfxlib/basics-02-play-strings.bas, 
   examples/sfxlib/basics-03-channels-mix.bas, 
   examples/sfxlib/basics-04-instruments.bas, and 
   examples/sfxlib/showcase.bas.

Platform Differences
   * On headless or diagnostic runs, SFXLIB_DRIVER=null can be set before 
     program startup to use the null output driver.

Differences from QB
   * New to FreeBASIC.

See also
   * Beep
   * Music
   * Sfx
   * Sound Library Reference



--------------------------------------------------------- KeyPgTransGfx ----
Trans

Parameter to the Put graphics statement which selects transparent 
background as the blitting method

Syntax
   Put [ target, ] [ STEP ] ( x,y ), source [ ,( x1,y1 )-( x2,y2 ) ], Trans

Parameters
   Trans
      Required.

Description
   Trans selects transparent background as the method for blitting an image 
   buffer.  This is similar to the PSET method, but pixels containing the 
   mask color are skipped.
   For 8-bit color images, the mask color is palette index 0.  For 
   16/32-bit color images, the mask color is Magenta, which is RGB(255, 0, 
   255).  The alpha value is ignored when checking for the mask color in 
   32-bit images.

   Note: for 32-bit images, the alpha value of pixels may be changed to 0.  
   This is for efficiency reasons.  To preserve the alpha values, a custom 
   blender may be used, as in the second example below.

Example
   '' set up a screen: 320 * 200, 16 bits per pixel
   ScreenRes 320, 200, 16

   '' set up an image with the mask color as the background.
   Dim img As Any Ptr = ImageCreate( 32, 32, RGB(255, 0, 255) )
   Circle img, (16, 16), 15, RGB(255, 255, 0),     ,     , 1, f
   Circle img, (10, 10), 3,  RGB(  0,   0, 0),     ,     , 2, f
   Circle img, (23, 10), 3,  RGB(  0,   0, 0),     ,     , 2, f
   Circle img, (16, 18), 10, RGB(  0,   0, 0), 3.14, 6.28

   '' Put the image with PSET (gives the exact contents of the image buffer)
   Draw String (110, 50 - 4), "Image put with PSET"
   Put (60 - 16, 50 - 16), img, PSet

   '' Put the image with TRANS
   Draw String (110, 150 - 4), "Image put with TRANS"
   Put (60 - 16, 150 - 16), img, Trans

   '' free the image memory
   ImageDestroy img

   '' wait for a keypress
   Sleep

   Function trans32 ( ByVal source_pixel As ULong, ByVal destination_pixel As ULong, ByVal parameter As Any Ptr ) As ULong
      '' returns the source pixel
      '' unless it is &hff00ff (magenta), then return the destination pixel
      If (source_pixel And &hffffff) <> &hff00ff Then
         Return source_pixel
      Else
         Return destination_pixel
      End If
   End Function

   '' set up a screen: 320 * 200, 16 bits per pixel
   ScreenRes 320, 200, 32

   '' set up an image with the mask color as the background.
   Dim img As Any Ptr = ImageCreate( 32, 32, RGB(255, 0, 255) )
   Circle img, (16, 16), 15, RGB(255, 255, 0),     ,     , 1, f
   Circle img, (10, 10), 3,  RGB(  0,   0, 0),     ,     , 2, f
   Circle img, (23, 10), 3,  RGB(  0,   0, 0),     ,     , 2, f
   Circle img, (16, 18), 10, RGB(  0,   0, 0), 3.14, 6.28

   '' Put the image with PSET (gives the exact contents of the image buffer)
   Draw String (110, 50 - 4), "Image put with PSET"
   Put (60 - 16, 50 - 16), img, PSet

   '' Put the image with TRANS
   Draw String (110, 100 - 4), "Image put with TRANS"
   Put (60 - 16, 100 - 16), img, Trans

   '' Put the image with TRANS
   Draw String (110, 150 - 4), "Image put with trans32"
   Put (60 - 16, 150 - 16), img, Custom, @trans32

   '' free the image memory
   ImageDestroy img

   '' wait for a keypress
   Sleep

Differences from QB
   * New to FreeBASIC

See also
   * Put (Graphics)
   * Custom



------------------------------------------------------------- KeyPgTrim ----
Trim

Removes surrounding substrings or characters on the left and right side of 
a string

Syntax
   Declare Function Trim ( ByRef str As Const String, [ Any ] ByRef trimset 
   As Const String = " " ) As String
   Declare Function Trim ( ByRef str As Const WString, [ Any ] ByRef 
   trimset As Const WString = WStr(" ") ) As WString

Usage
   result = Trim[$]( str [, [ Any ] trimset ] )

Parameters
   str
      The source string.
   trimset
      The substring to trim.

Return Value
   Returns the trimmed string.

Description
   This procedure trims surrounding characters from the left (beginning) 
   and right (end) of a source string:
      * Substrings matching trimset will be trimmed if specified, 
        otherwise spaces (ASCII code 32) are trimmed.
      * If the Any keyword is used, any character matching a character in 
        trimset will be trimmed.
   All comparisons are case-sensitive.

Example
   Dim s1 As String = " ... Stuck in the middle ... "
   Print "'" + Trim(s1) + "'"
   Print "'" + Trim(s1, Any " .") + "'"

   Dim s2 As String = "BaaBaaaaB With You aaBBaaBaa"
   Print "'" + Trim(s2, "Baa") + "'"
   Print "'" + Trim(s2, Any "Ba") + "'"

   will produce the output:


   '... Stuck in the middle ...'
   'Stuck in the middle'
   'aaB With You aaB'
   ' With You '		

Platform Differences
   * DOS version/target of FreeBASIC does not support the wide-character 
     version of Trim.

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Trim.
   * The string type suffix "$" is optional in the -lang fblite dialect.
   * The string type suffix "$" is ignored in the -lang fb dialect, warn 
     only with the -w suffix compile option (or -w pedantic compile 
     option).

Differences from QB
   * New to FreeBASIC

See also
   * LTrim 
   * RTrim



------------------------------------------------------------- KeyPgTrue ----
True

Intrinsic constant set by the compiler

Syntax
   Const True As Boolean

Description
   Gives the True Boolean value where used.

Example
   Dim b As Boolean = True
   If b Then
      Print "b is True"
   Else
      Print "b is False"
   End If


   b Is True

Version
   * Since fbc 1.04.0

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __True.

Differences from QB
   * New to FreeBASIC

See also
   * False
   * Boolean



-------------------------------------------------------- KeyPgTypeAlias ----
Type (Alias)

Declares an alternative name for a type

Syntax
   Type typename As symbol

Parameters
   typename 
      new alternative name.
   symbol 
      symbol or data type declaration to associate with typename. 

Description
   symbol may refer to any declared data type including a built-in data 
   type, Sub or Function pointer, Type declaration, Union declaration, or 
   Enum declaration.

   A Type Alias can be used to allow forward declarations of parameters in 
   procedure declarations, but only used with pointers (whatever their 
   passing mode), or otherwise with parameters (excluding arrays) but 
   passed or returned only by reference. Generally the bodies of such 
   procedures need to be implemented further in the code once the actual 
   types are well defined (for example because of the passing of such a 
   reference; or when such a pointer passed is then dereferenced in any 
   form).
   A Type Alias can also be used to allow forward declarations of data 
   fields in User Defined Types, but only used with pointers.

   A type alias must be used to allow declaration of pointer to a function 
   pointer, otherwise ptr applies on return type and not on function.

   A Type Alias declaration can also be nested inside a UDT structure 
   declaration for a Type or a Union.

Example
   Type ParentFwd As Parent
   Type Child
      Name As ZString * 32
      ParentRef As ParentFwd Ptr
      ''...
   End Type

   Type Parent
      Name As ZString * 32
      ChildList(0 To 9) As Child
      ''...
   End Type

   Dim p As Parent
   p.Name = "Foo"
   With p.ChildList(0)
      .Name = "Jr."
      .ParentRef = @p
      '' ...
   End With   

   With p.ChildList(0)
      Print .Name; " is child of "; .parentRef->Name
   End With

   Function triple (ByVal i As Integer) As Integer
      Return 3 * i
   End Function

   Type As Function (ByVal As Integer) As Integer function_alias

   'Dim As Function (Byval As Integer) As Integer f  ''this syntax works but is less readable than the next code line
   Dim As function_alias f
   f = @triple
   Print f(123)

   'Dim As Function (Byval As Integer) As Integer Ptr pf  ''this syntax does not work because Ptr applies on Integer and not on function
   Dim As function_alias Ptr pf                           ''this syntax works
   pf = @f
   Print (*pf)(123)  ''the dereferenced pointer to procedure pointer must be enclosed in parentheses

Version
   * Since fbc 1.10.0: Nesting of a Type Alias declaration inside a 
     structure declaring a UDT (Type or Union) is allowed.

Differences from QB
   * New to FreeBASIC

See also
   * Type...End Type
   * Type (Temporary)



--------------------------------------------------------- KeyPgTypeTemp ----
Type (Temporary)

Creates a temporary copy of a user defined type

Syntax
   result = Type( initializers, ... )
      or
   result = Type<typename>( initializers, ... )

Parameters
   initializers
      Initial values for the type (or only the firsts)
   typename
      The name of the Type or Union

Return Value
   A temporary copy of the type.

Description
   Used to create a temporary type.  If typename is not explicitly given, 
   it will be inferred from its usage if possible.  Usage of the temporary 
   copy may include assigning it to a variable, passing it as a parameter 
   to a procedure, or returning it as a value from a procedure.

   For a type without own or inherited constructor (excluding also any type 
   that is directly or indirectly derived from Object), the temporary type 
   syntax is allowed if all type data-fields (including those inherited) 
   are numeric primitives only and without any default initializers.
   If at same time the type is without destructor, the compiler does a 
   direct assignment instead of using a temporary copy.

   The Constructor for the type, if there is one with parameters matching 
   with the initializers provided, will be called when the temporary copy 
   is created, and the Destructor for the type, if there is one, will be 
   called immediately after its use. But when there is a matching 
   constructor, the temporary type expression may be simply replaced by 
   typename( initializers, ... ).
   If there is a constructor at least but none which matches with the 
   initializers, the temporary type syntax is obviously disallowed.

   It can create not only a temporary copy of an user defined type, but 
   also a temporary copy of predefined data-type as a variable-length 
   string or any numeric data-type (all standard data-types excluding 
   fixed-length strings).

   It can also be used as an even shorter shortcut than With (see below) if 
   you are changing all the data-fields (or the n firsts only).

   A temporary object is destroyed at the end of execution of the statement 
   (where it's defined), but its corresponding allocated memory is not 
   released and remains available (unused) until going out the scope where 
   statement is.
   In the particular case where a temporary type is used in a With 
   expression, the destruction of the temporary type is deferred to the end 
   of the With scope.

   Note: Static qualifier used at procedure definition level does not apply 
   to temporary types.

Example
   Type Example
      As Integer field1
      As Integer field2
   End Type

   Dim myexample As Example

   '' Filling the type by setting each field
   myexample.field1 = 1
   myexample.field2 = 2

   '' Filling the type by setting each field using WITH
   With myexample
      .field1 = 1
      .field2 = 2
   End With

   '' Fill the variable's fields with a  temporary type
   myexample = Type( 1, 2 )

   '' Passing a user-defined types to a procedure using a temporary type
   '' where the type can be inferred.

   Type S
     As Single x, y
   End Type

   Sub test ( v As S )
     Print "S", v.x, v.y
   End Sub

   test( Type( 1, 2 ) )

   '' Passing a user-defined type to a procedure using temporary types
   '' where the type is ambiguous and the name of the type must be specified.

   Type S
     As Single x, y
   End Type

   Type T
     As Integer x, y
   End Type

   Union U
     As Integer x, y
   End Union

   '' Overloaded procedure test()
   Sub test Overload ( v As S )
     Print "S", v.x, v.y
   End Sub

   Sub test ( v As T )
     Print "T", v.x, v.y
   End Sub

   Sub test ( v As U )
     Print "U", v.x, v.y
   End Sub

   '' Won't work: ambiguous
   '' test( type( 1, 2 ) )

   '' Specify name of type instead
   test( Type<S>( 1, 2 ) )
   test( Type<T>( 1, 2 ) )
   test( Type<U>( 1 ) )

Differences from QB
   * New to FreeBASIC

See also
   * Type...End Type
   * Type (Alias)



------------------------------------------------------------- KeyPgType ----
Type (Udt)

Declares a user-defined type.

Syntax
   Type typename
      fieldname1 As DataType
      fieldname2 As DataType
      As DataType fieldname3, fieldname4
      ...
   End Type

   Type typename [Alias "alternatename"] [Extends base_typename] [Field = 
   alignment]
      [Private:|Public:|Protected:]

      Declare Sub|Function|Constructor|Destructor|Property|Operator ...
      Static variablename As DataType
      ReDim arrayname(array dimensions) As DataType

      fieldname As DataType [= initializer]
      fieldname(array dimensions) As DataType [= initializer]
      fieldname(Any [, Any...]) As DataType
      fieldname : bits As DataType [= initializer]

      As DataType fieldname [= initializer], ...
      As DataType fieldname(array dimensions) [= initializer], ...
      As DataType fieldname(Any [, Any...])
      As DataType fieldname : bits [= initializer], ...

      Union
         fieldname As DataType
         Type
            fieldname As DataType
            ...
         End Type
         ...
      End Union

      Type typename2 ...
         ...
      End Type

      ...
   End Type

Description
   Type is used to declare custom data types containing one or more data 
   fields, including integer types, floating point types, fixed-size or 
   variable-length (dynamic) arrays, fixed-size or variable-length strings, 
   bitfields, or other user-defined types.

   Types support various functionality related to object-oriented 
   programming:
      * Inheritance through the use of the Extends keyword.
      * Member procedures such as Subs or Functions, including Abstract or 
        Virtual ones.
      * Member procedures with special semantic meaning such as 
        Constructors or a Destructor.
      * Static member variables.
      * Member visibility specifiers: Public:, Private:, Protected:.

   A Type can also contain nested Types or Unions, of different kinds:
      * Nested Anonymous Type/Union:
            - Nested Anonymous Type/Union allows data members to be grouped 
            as desired.
            - Anonymous Type or Anonymous Union can be nested on condition 
            of alternating their nesting.
            - Nested Anonymous Type/Union can not have procedure members or 
            static data members (same restriction than for a local scope 
            named Type/Union).
      * Nested Named Type/Union:
            - Nested Named Type/Union allows declaration of an inner 
            structure inside a (named) Type/Union namespace and according 
            to the access right of the place
            - Mostly everything it can be done in a Named Type/Union can 
            also be done in a Nested Named Type/Union.
            - When there are circular dependencies between Types/Unions, 
            Nested Named Type/Union usage can avoid using type aliases and 
            forward referencing.
      * Nested Type-Def:
            - Nested Type-Def allows declaration of an inner Type (Alias) 
            inside a Type/Union and according to the access right of the 
            place.
   The main structure (Type/Union) must be always named, the other (nested) 
   structures can be anonymous or named.

   Alias "alternatename" specifies that if typename must be encoded 
   (mangled) in to a public symbol (as in an object module or library), 
   then specifically use alternate name instead of the usual encoding 
   (mangling) of typename.

   Memory layout
   Types lay out their fields consecutively in memory, following the native 
   alignment and padding rules (described on the Field page). Special care 
   must be taken when using Types for file I/O or interacting with other 
   programs or programming languages, in case the alignment and padding 
   rules are different. The optional Field = number specifier can be used 
   to change the behavior on the FreeBASIC side.

   Variable-length data
   In FreeBASIC, Type data structures must ultimately be fixed-size, such 
   that the compiler knows how much memory to allocate for objects of that 
   Type. Nevertheless, Types may contain variable-length (dynamic) string 
   or array data members. However, the string's/array's data will not be 
   embedded in the Type directly. Instead, the Type will only contain a 
   String/array descriptor structure, which FreeBASIC uses behind the 
   scenes to manage the variable-length string/array data. For sizing the 
   structure of the array descriptor in the Type, a variable-length 
   (dynamic) array data member must be always declared by using Any(S) in 
   place of the array bounds, in order to fix the amount of dimensions 
   based on the number of Anys specified. A variable-length (dynamic) array 
   data member can also be pre-sized in its declaration by using syntax 
   with ReDim.
   Variable-length array fields are considered as pseudo-objects when they 
   are declared in a Type, just like variable-length strings (the implicit 
   copy constructor and the implicit let operator themselves support 
   [re]sizing and copying such arrays, or their erasing).

   Because of that, saving such a Type into a file will write out the 
   descriptor, not the actual string/array data. In order to embed 
   strings/arrays into Types directly, fixed-length strings/arrays must be 
   used.

   Similarly, when maintaining dynamic data manually through the use of 
   pointers within a Type, it does usually not make sense to save the Type 
   to a file, because the address stored in the pointer field will be 
   written to file, not the actual memory it points to. Addresses are 
   meaningful to a specific process only though, and cannot be shared that 
   way.

   Special note on fixed-length strings
   Since fbc version 1.20.0, fixed-length string fields of String * N type 
   no longer have extra null terminator at their end, making them 
   compatible with QB strings inside Types, because they actually use just 
   N bytes.
   Before fbc version 1.20.0, fixed-length string fields of String * N type 
   had an extra null terminator at their end, for compatibility with C 
   strings, making them incompatible with QB strings inside Types, because 
   they actually used up N+1 bytes, instead of just N bytes. A possible 
   work-around was to declare the field As String * (N-1), though this will 
   not work in future releases if the null terminator is removed.  Another 
   alternative was to use a Byte or UByte array with the proper size.

   Note on bitfields ( fieldname : bits )
   Bitfields can only be declared inside a type or a union, and allow to 
   specify some very small objects of a given number of bits in length. 
   Each field is accessed and manipulated as if it were an ordinary member 
   of the structure.
   Only integer data-types (up to 32-bit for 32-bit development or 64-bit 
   for 64-bit development) are valid. The sizes of the declared data-types, 
   large enough to contain the bit patterns, affect how the bitfields are 
   placed in memory.
   Bitfield members in a type are packed together, unless the next member 
   is a non-bitfield (nested union is considered a non-bitfield).
   A bitfield does not have any address (one cannot get a pointer to it and 
   its offset inside the structure).

Example
   This is an example of a QB-style type, not including procedure 
   definitions
   Type clr
      red As UByte
      green As UByte
      blue As UByte
   End Type

   Dim c As clr
   c.red = 255
   c.green = 128
   c.blue = 64

   /'
   Alternatively (See 'Type (Temporary)' page) we could use
   Dim c As clr
   c = Type <clr> (255, 128, 64)
   or
   c = Type(255, 128, 64)  '' implicit typename
   '/

   And this is an example of a type working as an object:
   '' Example showing the problems with fixed length string fields in UDTs and fbc version < 1.20.0
   '' Suppose we have read a GIF header from a file
   ''                        signature         width        height
   Dim As ZString*(10+1) z => "GIF89a" + MKShort(10) + MKShort(11)

   Print "Using fixed-length string"

   Type hdr1 Field = 1
      #if __FB_VERSION__ < "1.20.0"
        As String*(6-1) sig /' We have to dimension the string with 1 char
   						   '  less to avoid misalignments '/
      #else
        As String*(6) sig
      #endif
      As UShort wid, hei
   End Type

   Dim As hdr1 Ptr h1 = CPtr(hdr1 Ptr, @z)
   Print h1->sig, h1->wid, h1->hei '' Prints GIF89 (misses a char!)  10  11

   '' We can do comparisons only with the 5 visible chars and creating a temporary string with LEFT

   If Left(h1->sig, 5) = "GIF89" Then Print "ok" Else Print "error"

   '' Using a ubyte array, we need an auxiliary function to convert it to a string
   Function ub2str( ub() As UByte ) As String
      Dim As String res = Space(UBound(ub) - LBound(ub) + 1)
      For i As Integer = LBound(ub) To UBound(ub)
         res[i - LBound(ub)] = ub(i)
      Next
      Function = res
   End Function

   Print
   Print "Using an array of ubytes"

   Type hdr2 Field = 1
      sig(0 To 6-1) As UByte '' Dimension 6
      As UShort wid, hei
   End Type

   Dim As hdr2 Ptr h2 = CPtr(hdr2 Ptr, @z)
   '' Viewing and comparing is correct but a conversion to string is required

   Print ub2str(h2->sig()), h2->wid, h2->hei '' Prints GIF89a  10  11 (ok)
   If ub2str(h2->sig()) = "GIF89a" Then Print "ok" Else Print "error" '' Prints ok

   This is an example of conversion from an Ubyte to a digit string in base 
   8 (octal string), by using bitfields in a local UDT (conversion 
   equivalent to 'Oct(x, 3)'):
   Function UbyteToOctalString (ByVal b As UByte) As String
    
      Union UbyteOctal
         number As UByte
         Type
            d0 : 3 As UByte
            d1 : 3 As UByte
            d2 : 2 As UByte
         End Type
      End Union
    
      Dim uo As UbyteOctal
      uo.number = b
      Return uo.d2 & uo.d1 & uo.d0
    
   End Function

   For I As Integer = 0 To 255
      Print Using "###: "; I;
   ''    Print Oct(I, 3),
      Print UbyteToOctalString(I),  '' this line is thus equivalent to the previous one
   Next I
   Print

   Sleep

   This is an example with Nested Named Type:
   Type Parent
      Private:
         Dim As String nameParent
         Declare Constructor()
         Declare Constructor(ByRef As Parent)
         Type Child
            Dim As String nameChild
            Dim As Parent Ptr ptrParent
            Declare Sub kinship()
         End Type
         Dim As Child listChild(Any)
      Public:
         Declare Constructor(ByRef _nameParent As String)
         Declare Sub addChild(ByRef _nameChild As String)
         Declare Sub kinship()
   End Type

   Constructor Parent(ByRef _nameParent As String)
      This.nameParent = _nameParent
   End Constructor

   Sub Parent.addChild(ByRef _nameChild As String)
      ReDim Preserve This.listChild(UBound(This.listChild) + 1)
      This.listChild(UBound(This.listChild)).nameChild = _nameChild
      This.listChild(UBound(This.listChild)).ptrParent = @This
   End Sub

   Sub Parent.Child.kinship()
      Print "'" & This.nameChild & "'" & " is child of " & "'" & This.ptrParent->nameParent & "'"
   End Sub

   Sub Parent.kinship()
      For i As Integer = 0 To UBound(This.listChild)
         This.listChild(i).kinship()
      Next i
   End Sub

   Dim As Parent p = Parent("Kennedy")
   p.addChild("John Jr.")
   p.addChild("Caroline")
   p.addChild("Patrick")
   p.kinship()

   Sleep

Version
   * Since fbc 1.10.0: Nested Named Type/Union capability added.

Platform Differences
   * The default Field alignment parameter is 4 bytes for DOS and Linux 
     targets.
   * The default Field alignment parameter is 8 bytes for Windows targets 
     (this difference with regard to 4 bytes applies only to Longint and 
     Double members).

Dialect Differences
   * Object-related features such as functions declared inside Type blocks 
     are supported only with the -lang fb dialect since version 0.17b
   * In the -lang fb and -lang fblite dialects, the default Field 
     alignment parameter depends on the target platform.
   * With the -lang qb dialect the fields are aligned to byte boundaries 
     by default, unless otherwise specified.
   * To force byte alignment use FIELD=1.

Differences from QB
   * Since fbc version 1.20.0, fixed-length strings of STRING*N type have 
     no extra, redundant character on the end, which means they take same 
     number of bytes than they do in QB.
   * Before fbc version 1.20.0, all fixed-length strings have an extra, 
     redundant character on the end, which means they take up one more byte 
     than they do in QB. For this reason, UDTs that use them are not 
     compatible with QB when used for file I/O.

See also
   * Type (Alias)
   * Type (Temporary)
   * Union
   * Enum
   * TypeOf
   * OffsetOf
   * Alias (Name)
   * Field
   * Extends
   * Extends Zstring
   * Extends Wstring
   * With
   * Standard Data Type Limits
   * Coercion and Conversion



----------------------------------------------------------- KeyPgTypeof ----
TypeOf

Returns the type of a variable.

Syntax
   TypeOf ( variable | datatype )

Parameters
   variable
      A variable of any type.
   datatype
      A DataType.

Description
   TypeOf is a compiler intrinsic that replaces itself with the type of the 
   variable passed to it. It can either be used in a variable declaration 
   (Example 1) or it can be used in the preprocessor for comparison, 
   printing. (Example 2)

   TypeOf also supports passing any intrinsic data type, or user-defined 
   type (and its data fields), not only variables defined as those types. 
   Also supported are expressions, the type is inferred from the expression 
   (much like Var).

   If there is both a user defined type and a variable visible with the 
   same name in the current scope, the user defined type takes precedence 
   over the variable.  To ensure that the TypeOf takes the variable instead 
   of the user defined type, wrap the argument to TypeOf with parentheses 
   to force it to be seen as an expression.  For example Typeof((variable))
   .

Example
   Example 1:
   Dim As Integer foo
   Dim As TypeOf(67.2) bar '' '67.2' is a literal double
   Dim As TypeOf( foo + bar ) teh_double '' double + integer results in double
   Print SizeOf(teh_double)
         

   Example 2:
   Dim As String foo
   #print TypeOf(foo)
   #if TypeOf(foo) = TypeOf(Integer)
     #print "Never happened!"
   #endif

   #if TypeOf(foo) = TypeOf(String)
     #print "It's a String!"
   #endif
         

Version
   * Before fbc 1.10.0, TypeOf was not returning the type of the 
     non-static member procedures of a UDT.
   * Before fbc 1.08.0:
         TypeOf was not returning the type of the data fields of a UDT.
         When a variable from a given namespace was accessed with the 
         namespace's name prefix, the argument to TypeOf had to be wrapped 
         with parentheses to force it to be seen as an expression. For 
         example Typeof((namespace_name.variable)).

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Typeof.

Differences from QB
   * New to FreeBASIC

See also
   * SizeOf
   * Var
   * Type (Alias)
   * Type...End Type




============================================================================
    U

----------------------------------------------------------- KeyPgUbound ----
UBound

Returns the upper bound of an array's dimension

Syntax
   Declare Function UBound ( array() As Any, ByVal dimension As Integer = 1 
   ) As Integer

Usage
   result = UBound( array [, dimension ] )

Parameters
   array
      an array of any type
   dimension
      the dimension to get upper bound of

Return Value
   Returns the upper bound of an array's dimension.
 
Description
   UBound returns the largest value that can be used as an index into a 
   particular dimension of an array.

   Array dimensions are numbered from one (1) to n, where n is the total 
   number of dimensions. If dimension is not specified, UBound will return 
   the upper bound of the first dimension.

   If dimension is zero (0), UBound returns n, the number of dimensions in 
   the array. For any other dimension values outside of the valid range 1..
   n, the result is -1. This can be used to detect the number of dimensions 
   of variable-length arrays, and in combination with the result of 
   Lbound() for such cases, whether a given dimension exists, or whether 
   the array is empty (zero dimensions). See the LBound page for more 
   information.

Example

   Dim array(-10 To 10, 5 To 15, 1 To 2) As Integer

   Print UBound(array) 'returns 10
   Print UBound(array, 2) 'returns 15
   Print UBound(array, 3) 'returns 2

   '' determining the size of an array
   Dim As Short array(0 To 9)
   Dim As Integer arraylen, arraysize

   arraylen = UBound(array) - LBound(array) + 1
   arraysize = arraylen * SizeOf( Short )

   Print "Number of elements in array:", arraylen    '10
   Print "Number of bytes used in array:", arraysize '10 * 2 = 20 

   '' determining the size of a multi-dimensional array
   Dim As Long array4D(1 To 2, 1 To 3, 1 To 4, 1 To 5)
   Dim As Integer arraylen, arraysize

   arraylen = (UBound(array4D, 4) - LBound(array4D, 4) + 1) _
          * (UBound(array4D, 3) - LBound(array4D, 3) + 1) _
          * (UBound(array4D, 2) - LBound(array4D, 2) + 1) _
          * (UBound(array4D, 1) - LBound(array4D, 1) + 1)

   arraysize = arraylen * SizeOf( Long )

   Print "Number of elements in array:", arraylen    '2 * 3 * 4 * 5 = 120
   Print "Number of bytes used in array:", arraysize '120 * 4 = 480

   '' determining whether an array is empty
   Dim array() As Integer

   Print "lbound: "; LBound( array ), "ubound: "; UBound( array )  ''  0 and -1

   If LBound( array ) > UBound( array ) Then
      Print "array is empty"
   Else
      Print "array is not empty"
   End If

   Sub printArrayDimensions( array() As Integer )
      Print "dimensions: " & UBound( array, 0 )

      '' For each dimension...
      For d As Integer = LBound( array, 0 ) To UBound( array, 0 )
         Print "dimension " & d & ": " & LBound( array, d ) & " to " & UBound( array, d )
      Next
   End Sub

   Dim array() As Integer
   printArrayDimensions( array() )

   Print "---"

   ReDim array(10 To 11, 20 To 22)
   printArrayDimensions( array() )

See also
   * LBound
   * Static
   * Dim
   * ReDim
   * SizeOf



------------------------------------------------------------ KeyPgUbyte ----
UByte

Standard data type: 8 bit unsigned.
Equivalent to Unsigned Byte.

Syntax
   Dim variable As UByte

Description
   8-bit unsigned whole-number data type. Can hold a value in the range of 
   0 to 255.

Example
   Dim ubytevar As UByte
   ubytevar = 200
   Print "ubytevar= ", ubytevar

Example
     Dim x As UByte = 0
     Dim y As UByte = &HFF
     Print "UByte Range = "; x; " to "; y

   Output:
   UByte Range = 0 To 255

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Ubyte.

Differences from QB
   * New to FreeBASIC

See also
   * Byte
   * CUByte
   * Table with variable types overview, limits and suffixes



------------------------------------------------------------ KeyPgUcase ----
UCase

Returns an upper case copy of a string

Syntax
   Declare Function UCase ( ByRef str As Const String, ByVal mode As Long = 
   0 ) As String
   Declare Function UCase ( ByRef str As Const WString, ByVal mode As Long 
   = 0 ) As WString

Usage
   result = UCase[$]( str [ , mode ] )

Parameters
   str
      String to convert to uppercase.
   mode
      The conversion mode: 0 = current locale, 1 = ASCII only

Return Value
   Uppercase copy of str.

Description
   Returns a copy of str with all of the letters converted to upper case.

   If str is empty, the null string ("") is returned.

Example
   Print UCase("AbCdEfG")

   will produce the output:

   ABCDEFG

Platform Differences
   * The wide-character string version of UCase is not supported for DOS 
     target.

Dialect Differences
   * The string type suffix "$" is required in the -lang qb dialect.
   * The string type suffix "$" is optional in the -lang fblite dialect.
   * The string type suffix "$" is ignored in the -lang fb dialect, warn 
     only with the -w suffix compile option (or -w pedantic compile 
     option).

Differences from QB
   * QB does not support Unicode.

See also
   * LCase



--------------------------------------------------------- KeyPgUinteger ----
UInteger

Standard data type: 32-bit or 64-bit unsigned, same size as SizeOf(Any Ptr).
Equivalent to Unsigned Integer.

Syntax
   Dim variable As UInteger
   Dim variable As UInteger<bits>

Parameters
   bits
      A numeric constant expression indicating the size in bits of unsigned 
      integer desired.  The values allowed are 8, 16, 32 or 64.

Description
   32-bit or 64-bit unsigned whole-number data type, depending on the 
   platform.

   If an explicit bit size is given, a data type is provided that can hold 
   values from 0 up to (1ULL Shl (bits)) - 1. The selected data type is 
   UByte for UInteger<8>, UShort for UInteger<16>, ULong for UInteger<32> 
   and ULongInt for UInteger<64>.

Example
   #ifdef __FB_64BIT__
      Dim x As UInteger = 0
      Dim y As UInteger = &HFFFFFFFFFFFFFFFF
      Print "UInteger Range = "; x; " to "; y
   #else
      Dim x As UInteger = 0
      Dim y As UInteger = &HFFFFFFFF
      Print "UInteger Range = "; x; " to "; y
   #endif

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Uinteger.

Differences from QB
   * New to FreeBASIC

See also
   * Integer
   * Unsigned
   * CUInt
   * Table with variable types overview, limits and suffixes



------------------------------------------------------------ KeyPgUlong ----
ULong

Standard data type: 32-bit unsigned integer.
Equivalent to Unsigned Long.

Syntax
   Dim variable As ULong

Description
   32-bit unsigned whole-number data type. Can hold values from 0 to 
   4294967295. Corresponds to an unsigned DWORD.

Example
     Dim x As ULong = 0
     Dim y As ULong = &HFFFFFFFF
     Print "ULong Range = "; x; " to "; y

   Output:
   ULong Range = 0 To 4294967295

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Ulong.

Differences from QB
   * New to FreeBASIC

See also
   * Long
   * UInteger
   * ULongInt
   * Table with variable types overview, limits and suffixes



--------------------------------------------------------- KeyPgUlongint ----
ULongInt

Standard data type: 64 bit unsigned.
Equivalent to Unsigned LongInt.

Syntax
   Dim variable As ULongInt

Description
   A 64-bit unsigned whole-number data type. Can hold values from 0 to 18 
   446 744 073 709 551 615. Corresponds to an unsigned QWORD.

Example
   Dim x As ULongInt = 0
   Dim y As ULongInt = &HFFFFFFFFFFFFFFFFull
   Print "ULongInt Range = "; x; " to "; y

   Output:
   ULongInt Range = 0 To 18446744073709551615

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Ulongint.

Differences from QB
   * New to FreeBASIC

See also
   * LongInt
   * CULngInt
   * Table with variable types overview, limits and suffixes



------------------------------------------------------------ KeyPgUnion ----
Union

Declares a union user defined type.

Syntax
   Union typename
      fieldname as datatype
      Declare member function declaration ...
      ...
   End Union

Parameters
   typename
      Name of the Union
   fieldname
      Name of a data field member
   member function declaration
      Any of the supported member functions

Description
   The data elements of a Union occupy a common space in memory (same 
   memory address for all data elements of the Union). A data element of a 
   Union can be a simple data field or an anonymous Type block of data 
   fields.
   The size of the Union is the size of the largest data element.
   Since they occupy a common memory space, only one data element can 
   usually be used at a given time (when a given data element is written, 
   the other data elements sharing the common union space may be 
   overwritten or mutilated).

   Like Type, Union can use the optional Field = number specifier for field 
   alignment, and supports also inheritance through the use of the Extends 
   keyword.
   Unlike Type, Union can not contain variable-length strings and arrays, 
   and more generally can not have object fields (or bases) with 
   constructors or destructors. Therefore, Union does not support to 
   inherit from the Object built-in type.

   A Union supports member procedures including Constructor, Destructor, 
   Function, Operator, Property and Sub. All members of a Union are public 
   and access modifiers are not supported. 

   Initializer elements for UNION's should pair with only the first member 
   of the UNION and skip the rest.

   A Union can also contain nested Types or Unions, of different kinds:
      * Nested Anonymous Type/Union:
            - Nested Anonymous Type/Union allows data members to be grouped 
            as desired.
            - Anonymous Type or Anonymous Union can be nested on condition 
            of alternating their nesting.
            - Nested Anonymous Type/Union can not have procedure members or 
            static data members (same restriction than for a local scope 
            named Type/Union).
      * Nested Named Type/Union:
            - Nested Named Type/Union allows declaration of an inner 
            structure inside a (named) Type/Union namespace and according 
            to the access right of the place
            - Mostly everything it can be done in a Named Type/Union can 
            also be done in a Nested Named Type/Union.
            - When there are circular dependencies between Types/Unions, 
            Nested Named Type/Union usage can avoid using type aliases and 
            forward referencing.
      * Nested Type-Def:
            - Nested Type-Def allows declaration of an inner Type (Alias) 
            inside a Type/Union and according to the access right of the 
            place.
   The main structure (Type/Union) must be always named, the other (nested) 
   structures can be anonymous or named.

   A Union can be passed in a similar way of a User Defined Type to 
   overloaded operator procedures.

   Note: When Union extends a base, it can be confusing because no new 
   fields are added to the base, but instead the base is added to the 
   derived Union. This means that data elements in the derived Union can 
   share the same memory space like the base (here it doesn't matter 
   whether the base is a Union or not). Of course it can be dangerous, but 
   that is always the problem with Unions.
   If only the base is a Union, then it won't be affected by data elements 
   from the derived UDT.
   Since Union is not allowed to have complex data elements (i.e. UDTs with 
   constructor/destructor, or dynamic strings), a derived Union can not be 
   allowed to have (contain) a complex base.

   Note: Since fbc version 1.20.0, unions containing STRING*N fields will 
   initialize to spaces if the first field is a STRING*N type, otherwise 
   will initialize to zero (as for a STRING*N field before fbc version 
   1.20.0).

Example
   ' Example 0: Little-endianness
   ' For larger integer values (as the following Ulong data type),
   '   bytes are arranged in memory in 'little-endian' byte order
   '   (the least significant byte gets stored first).

   Union UDU
      ul As ULong      ' 32-bit data type
      Type
        ub0 As UByte  ' 8-bit data type
        ub1 As UByte  ' 8-bit data type
        ub2 As UByte  ' 8-bit data type
        ub3 As UByte  ' 8-bit data type
      End Type
   End Union

   Dim As UDU u
   u.ul = &h12345678
   Print Hex(u.ul)                                       ' Result: 12345678
   Print Hex(u.ub3), Hex(u.ub2), Hex(u.ub1), Hex(u.ub0)  ' Result: 12   34   56   78

   Sleep

   ' Example 1: Only one union member can be relevantly accessed at a time
   Union member
     username As String * 32
     posts As ULong
   End Union

   Dim As member userX
   userX.username = "Samantha"
   userX.posts = 1234

   Print userX.username  ' value of username corrupted because final value assigned to posts occupies same memory location
   '                     ' (and this is reason that value of posts is displayed well)
   Print userX.posts
   Print

   Dim As member userY
   userY.posts = 4321
   userY.username = "Alexander"

   Print userY.username
   Print userY.posts  ' value of posts corrupted because final value assigned to username occupies same memory location
   '                  ' (and this is reason that value of username is displayed well)
   Print

   Sleep

   ' Example 2: Alternative to RGBA keyword and allowing to retrieve elementary colors values
   Union BGRA_UNION
      colour As ULong
      Type
        blue  As UByte
        green As UByte
        red   As UByte
        Alpha As UByte
      End Type
   End Union

   Dim ubgra As BGRA_UNION

   ' Setting the individual color values...
   ubgra.red = &h33
   ubgra.green = &hcc
   ubgra.blue = &h66
   ' We can get a ULONG value
   Print Hex(ubgra.colour)  ' Result: 33CC66
   Print

   ' Setting a ULONG value...
   ubgra.colour = &h228844
   ' We can get the individual color values
   Print Hex(ubgra.red)    ' Result: 22
   Print Hex(ubgra.green)  ' Result: 88
   Print Hex(ubgra.blue)   ' Result: 44
   Print

   Sleep

   ' Example 3.
   ' Define a simple union.
   Union AUnion
      a As UByte
      b As UInteger
   End Union
   ' Define a composite type with an unnamed union.
   Type CompType
      s As String * 20
      ui As UByte 'Flag to tell us what to use in union.
      Union
         au As UByte
         bu As UInteger
      End Union
   End Type

   ' Flags to let us know what to use in union,
   ' because it's relevant to only use a single element of a union at a given time.
   Const IsInteger = 1
   Const IsUByte = 2

   Dim MyUnion As AUnion
   Dim MyComposite As CompType

   ' Only one field within the union is set, without choice criterion.
   MyUnion.a = 128

   MyComposite.s = "Type + Union"
   MyComposite.ui = IsInteger ' Tells us this is an integer union.
   MyComposite.bu = 1500      ' Field set according to the above flag.

   Print "Simple Union: ";MyUnion.a

   Print MyComposite.s & ": ";
   If MyComposite.ui = IsInteger Then
      Print MyComposite.bu
   ElseIf MyComposite.ui = IsUByte Then
      Print MyComposite.au
   Else
      Print "Unknown Type."
   End If
   Print

   Sleep

   ' Example 4: Using Nested Named Union
   Type T
      Union U
         a As Short
         Type
            b1 As Byte
            b2 As Byte
         End Type
         Declare Sub proc(ByVal _b1 As Byte, ByVal _b2 As Byte)
      End Union
      m As U   
      Declare Sub proc()
   End Type

   Sub T.U.proc(ByVal _b1 As Byte, ByVal _b2 As Byte)
      This.b1 = _b1
      This.b2 = _b2
   End Sub

   Sub T.proc()
      Print This.m.b1, This.m.b2, This.m.a
   End Sub

   Dim x As T
   x.m.proc(1, 2)
   x.proc()

   Sleep

Version
   * Since fbc 1.10.0: Nested Named Type/Union capability added.

Dialect Differences
   * Object-related features as functions defined inside the Union block 
     are supported only in the -lang fb dialect.
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Union.

Differences from QB
   * New to FreeBASIC

See also
   * Type
   * Coercion and Conversion



----------------------------------------------------------- KeyPgUnlock ----
Unlock

Removes a previous access restriction (lock) on a file

Syntax
   Unlock #filenum, record
   Unlock #filenum, start To end

Parameters
   filenum
      The file number used to Open the file.
   record
      The record (Random files) to unlock.
   start
      The first byte position (Binary files) in a range to unlock.
   end
      The last byte position (Binary files) in a range to unlock.

Description
   Unlock removes the temporary access restriction set by Lock.

   It is strongly recommended to use the same arguments used in the 
   previous Lock.

   Note: This command does not always work, neither as documented nor as 
   expected. It appears to be broken at the moment.

Example
       For an example see Lock.

Differences from QB
   * Currently, FB cannot implicitly unlock the entire file
   * In Random mode, FB cannot unlock a range of records

See also
   * Lock
   * Open
   * ScreenUnlock



--------------------------------------------------------- KeyPgUnsigned ----
Unsigned

Integer data type modifier

Syntax
   Dim variable As Unsigned {integer-based data type}

Description
   Forces an integer-based data type to be unsigned (cannot contain 
   negative numbers, but has its maximum value doubled).

Example
   'e.g. notice what is displayed:

   Dim x As Unsigned Integer
   x = -1
   Print x 

   'output is 4294967295

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Unsigned.

Differences from QB
   * New to FreeBASIC

See also
   * UInteger



------------------------------------------------------------ KeyPgUntil ----
Until

Conditional clause used in Do..Loop statements.

Syntax
   Do Until condition
      or
   Loop Until condition

Description
   Until is used with the Do...Loop structure.

Example
   Dim a As Integer

   a = 1
   Do
      Print "hello"
   a = a + 1
   Loop Until a > 10

   'This will continue to print "hello" on the screen until the condition (a > 10) is met. 

Differences from QB
   * None

See also
   * Do...Loop

   


----------------------------------------------------------- KeyPgUshort ----
UShort

Standard data type: 16 bit unsigned.
Equivalent to Unsigned Short.

Syntax
   Dim variable As UShort

Description
   16-bit unsigned whole-number data type. Can hold values from 0 to 65535.

Example
     Dim x As UShort = 0
     Dim y As UShort = &HFFFF
     Print "UShort Range = "; x; " to "; y

   Output:
   UShort Range = 0 To 65535

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Ushort.

Differences from QB
   * New to FreeBASIC

See also
   * Short
   * CUShort
   * Table with variable types overview, limits and suffixes



------------------------------------------------------- KeyPgPrintusing ----
(Print | ?) Using

Outputs formatted text to the screen or output device.

Syntax
   (Print | ?) [# filenum ,] [ printexpressionlist {,|;} ] Using 
   formatstring ; [ expressionlist [ ; ] ]

Parameters
   filenum
      The file number of a file or device opened for Output or Append.  
      (Alternatively LPrint may be used where appropriate, instead of 
      Print #)
   printexpressionlist
      Optional preceding list of items to print, separated by commas (,) or 
      semi-colons (;) (see Print for more details).
   formatstring
      Format string to use.
   expressionlist
      List of items to format, separated by semi-colons (;).

Description
   Print to screen various expressions using a format determined by the 
   formatstring parameter. Internally, Print Using uses a buffer size of 
   2048 bytes: while it is highly unlikely that this buffer would be 
   filled, it should be noted that output would be truncated should this 
   limit be reached.

   If no expression list is given, the format string will be printed up to 
   the first special marker.  Note that the semi-colon after formatstring 
   is still necessary, even if no expression list is given.

   The format string dictates how the expressions are to be formatted when 
   output to the screen, indicated by the use of special marker characters. 
   There are markers for formatting both string and numeric output:

   String formatting

         +------+------------------------------------------------------------------------------------------------------------------------------------+
         |Marker|Formatting                                                                                                                          |
         |!     |prints the first character of a string                                                                                              |
         |\   \ |prints two or more characters of a string - as many as are occupied by the backslashes ('\') and any enclosed space characters (' ')|
         |&     |prints the entire string                                                                                                            |
         +------+------------------------------------------------------------------------------------------------------------------------------------+

   If an exact amount of characters is specified (with "!" or "\ \"), the 
   string will be truncated or padded with spaces on the right as needed to 
   output that many characters.

   Numeric formatting

         +------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
         |Marker|Formatting                                                                                                                                                            |
         |#     |placeholder for either an integer digit, or a decimal digit if a decimal point precedes it                                                                            |
         |,     |placed after integer digit indicates groups of 3 digits should be separated by commas in fixed-point notation                                                         |
         |.     |placed near # indicates place for the decimal point                                                                                                                   |
         |^^^   |uses exponential notation (E+/-#) when placed after the digit characters                                                                                              |
         |^^^^  |uses exponential notation (E+/-##) when placed after the digit characters                                                                                             |
         |^^^^^ |uses exponential notation (E+/-###) when placed after the digit characters                                                                                            |
         |+     |placed before/after the format string, controls whether the sign of a number is prepended/appended, and causes an explicit '+' sign to be printed for positive numbers|
         |-     |placed after the format string, causes the sign of the number to be appended rather than prepended, appending a space/negative sign for positive/negative numbers     |
         |$$    |placed at the start of integer digits, causes a dollar sign to be prepended to the number (after the sign if one is prepended)                                        |
         |**    |placed at the start of integer digits, causes any padding on the left to be changed from spaces to asterisks                                                          |
         |**$   |placed at the start of integer digits, pads on the left with asterisks, and prepends a dollar sign after the asterisks                                                |
         |&     |prints a number intelligently, using the exact number of digits required (new to version 0.21.0b)                                                                     |
         +------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------+

   All of the special marker characters can be escaped by preceding them 
   with the underscore character "_", allowing them to be printed directly. 
   For example, "_!" is printed as "!", and "__" is printed as "_".

   If a numerical value cannot fit in the number of digits indicated by the 
   format string, the formatting is adapted to fit the number, possibly 
   switching to scientific notation, and the number is printed preceded by 
   the percent "%" character. E.g., the number 1234 with a formatstring of 
   "##.##" would be printed as "%1234.00".

   All other characters within the format string are printed as they 
   appear.

   A new-line character is printed after the values in the expression list 
   unless the expression list is followed by a semicolon (;).

Example

   Print Using "The value is #.## seconds"; 1.019
   Print Using "The ASCII code for the pound sign (_#) is ###"; Asc("#")
   Print Using "The last day in the year is & \ \"; 31; "December"
   Print
   For exponent As Integer = 1 To 5
      Print Using "10 ^ # = ######"; exponent; 10 ^ exponent
   Next exponent

   will produce the output:

   The value Is 1.02 seconds
   The ASCII code For the pound sign (#) Is  35
   The last Day in the Year Is 31 Dec

   10 ^ 1 =     10
   10 ^ 2 =    100
   10 ^ 3 =   1000
   10 ^ 4 =  10000
   10 ^ 5 = 100000

Differences from QB
   * QB didn't allow "&" to be used for printing numbers.

See also
   * Print
   * ?
   * Print #
   * ? #
   * Format
   * Using
   * Palette Using

			

------------------------------------------------------------ KeyPgUsing ----
Using (Namespaces)

Brings namespace symbols into the current scope

Syntax
   Using identifier [, identifier [, ...] ]

Parameters
   identifier: The name of the Namespace that you want to use.

Description
   The Using command allows all symbols from a given namespace to be 
   accessed without the namespace's name prefix. Unlike C++ but like C#, 
   the Namespace keyword is not needed after Using, because individual 
   symbols cannot be inherited from a namespace.

   Using is allowed in namespaces and procedures only (not in type or union 
   or enum declarations).

   Inheriting a whole namespace can save typing, but sometimes some meaning 
   of the code can be lost, and conflicts with other symbols could be 
   created.

Example
   Namespace Sample
      Type T
         x As Integer
      End Type
   End Namespace

   '' Just using the name T would not find the symbol,
   '' because it is inside a namespace.
   Dim SomeVariable As Sample.T

   '' Now the whole namespace has been inherited into
   '' the global namespace.
   Using Sample

   '' This statement is valid now, since T exists
   '' without the "Sample." prefix.
   Dim OtherVariable As T 

Version
   * Before fbc 1.09.0, if there is duplicated symbol in the global 
     namespace (unnamed namespace), access to local symbol is captured by 
     duplicated global symbol (in that case, full prefixing is required to 
     access local symbol).

Differences from QB
   * QB had the Using keyword, but for other purposes. Namespaces did not 
     exist in QB.

See also
   * Print Using
   * ? Using
   * Palette Using
   * Namespace




============================================================================
    V

------------------------------------------------------------ KeyPgVaArg ----
va_arg

Returns the current argument from a variable argument list.

Syntax
   variable = va_arg ( argument_list, datatype )

Description
   The va_arg macro allows the use of a variable number of arguments within 
   a function:
      * 	va_arg returns the current argument in the list, argument_list, 
        with an expected data type of datatype.
      * 	Before first va_arg use, argument_list must be initialized with 
        the command va_first.
      * 	Unlike the C macro with the same name, va_arg does not 
        automatically increment argument_list to the next argument within 
        the list. Instead va_next must be used to find the next argument in 
        adjusting argument_list.

   Not supported when using -gen gcc.  Use Cva_List variadic argument list 
   type for cross platform compatibility.

Example
   See the Va_First() examples.

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __va_arg.

Differences from QB
   * New to FreeBASIC

See also
   * ... (Ellipsis)
   * va_first
   * va_next



---------------------------------------------------------- KeyPgVaFirst ----
va_first

Returns a pointer to the first argument in a variable argument list

Syntax
   pointer_variable = va_first()

Description
   The va_first function provides an untyped pointer value that points to 
   the first variable argument passed to a function.

   Not supported when using -gen gcc.  Use Cva_List variadic argument list 
   type for cross platform compatibility.

Example
   Function average cdecl(count As Integer, ... ) As Double
      Dim arg As Any Ptr
      Dim sum As Double = 0
      Dim i As Integer
      
      arg = va_first()

      For i = 1 To count
         sum += va_arg(arg, Double)
         arg = va_next(arg, Double)
      Next
      
      Return sum / count
   End Function

   Print average(4, 3.4,5.0,3.2,4.1)  '' all passed variable arguments must be of type double
   Print average(2, 65.2,454.65481)   '' all passed variable arguments must be of type double
   Sleep

The output would look like:

   3.925
   259.927405

   '' Example of a simple custom printf
   Sub myprintf cdecl(ByRef formatstring As String, ...)
      '' Get the pointer to the first var-arg
      Dim As Any Ptr arg = va_first()

      '' For each char in format string...
      Dim As UByte Ptr p = StrPtr(formatstring)
      Dim As Integer todo = Len(formatstring)
      While (todo > 0)
         Dim As Integer char = *p
         p += 1
         todo -= 1

         '' Is it a format char?
         If (char = Asc("%")) Then
            If (todo = 0) Then
               '' % at the end
               Print "%";
               Exit While
            End If

            '' The next char should tell the type
            char = *p
            p += 1
            todo -= 1

            '' Print var-arg, depending on the type
            Select Case char
            '' integer?
            Case Asc("i")
               Print Str(va_arg(arg, Integer));
               '' Note, different from C: va_next() must be
               '' used as va_arg() won't update the pointer.
               arg = va_next(arg, Integer)

            '' long integer? (64-bit)
            Case Asc("l")
               Print Str(va_arg(arg, LongInt));
               arg = va_next(arg, LongInt)

            '' single or double?
            '' Note: because the C ABI, all singles passed on
            '' var-args are converted to doubles.
            Case Asc( "f" ), Asc( "d" )
               Print Str(va_arg(arg, Double));
               arg = va_next(arg, Double)

            '' string?
            Case Asc("s")
               '' Strings are passed byval, so the length is unknown
               Print *va_arg(arg, ZString Ptr);
               arg = va_next(arg, ZString Ptr)

            End Select

         '' Ordinary char, just print as-is
         Else
            Print Chr( char );
         End If
      Wend
   End Sub

      Dim As String s = "bar"

      myprintf(!"integer=%i, longint=%l single=%f, double=%d, string=%s, string=%s\n", _
             1, 1ll Shl 32, 2.2, 3.3, "foo", s)

      Sleep

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Va_first.

Differences from QB
   * New to FreeBASIC

See also
   * ... (Ellipsis)
   * va_arg
   * va_next



----------------------------------------------------------- KeyPgVaNext ----
va_next

Returns a pointer to the next argument in a variable argument list

Syntax
   Argument_Pointer = va_next ( Argument_List, datatype )

Description
   The va_next macro provides a datatype pointer value that points to the 
   next argument within the list Argument_List, datatype being the type of 
   the current argument being stepped over.

   Not supported when using -gen gcc.  Use Cva_List variadic argument list 
   type for cross platform compatibility.

Example
   See the Va_First() examples.

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Va_next.

Differences from QB
   * New to FreeBASIC

See also
   * ... (Ellipsis)
   * va_arg
   * va_first



-------------------------------------------------------------- KeyPgVal ----
Val

Converts a string to a floating point number

Syntax
   Declare Function Val ( ByRef str As Const String ) As Double
   Declare Function Val ( ByRef str As Const WString ) As Double

Usage
   result = Val( strnum )

Parameters
   strnum
      the string containing a number to convert

Return Value
   Returns a converted Double precision number

   If the first character of the string is invalid, Val will return 0.

Description
   Val("10") will return 10.0, and Val("10.10") will return 10.1. The 
   function parses the string from the left, skipping any white space, and 
   returns the longest number it can read, stopping at the first 
   non-suitable character it finds.  Scientific notation is recognized, 
   with "D" or "E" used to specify the exponent.

   Val can be used to convert integer numbers in binary / octal / 
   hexadecimal format, if they have the relevant identifier ("&B" / "&O" / 
   "&H") prefixed, for example: Val("&HFF") returns 255.

   Note:
   If you want to get an integer value from a string, consider using ValInt 
   or ValLng instead.  They are faster, since they don't use floating-point 
   numbers, and only ValLng provides full 64-bit precision for LongInt 
   types.

   If you want to convert a number into string format, use the Str 
   function.

Example
   Dim a As String, b As Double
   a = "2.1E+30xa211"
   b = Val(a)
   Print a, b


   2.1E+30xa211   2.1e+030

Differences from QB
   * None

See also
   * CDbl
   * ValInt
   * ValUInt
   * ValLng
   * ValULng
   * Str
   * Chr
   * Asc



----------------------------------------------------------- KeyPgVallng ----
ValLng

Converts a string to a 64bit integer

Syntax
   Declare Function ValLng ( ByRef strnum As Const String ) As LongInt
   Declare Function ValLng ( ByRef strnum As Const WString ) As LongInt

Usage
   result = ValLng ( strnum )

Parameters
   strnum
      the string to convert

Return Value
   Returns a LongInt of the converted string

   If the first character of the string is invalid, ValLng will return 0.

Description
   For example, ValLng("10") will return 10, and ValLng("10.60") will 
   return 10 as well. The function parses the string from the left, 
   skipping any white space, and returns the longest number it can read, 
   stopping at the first non-suitable character it finds.  Any non-numeric 
   characters, including decimal points and exponent specifiers, are 
   considered non-suitable, for example, ValLng("23.1E+6") will just return 
   23.

   ValLng can be used to convert integer numbers in Binary / Octal / 
   Hexadecimal format, if they have the relevant identifier ("&B" / "&O" / 
   "&H") prefixed, for example: ValLng("&HFF") returns 255.

   If you want to convert a number into string format, use the Str 
   function.

Example
   Dim a As String, b As LongInt
   a = "20xa211"
   b = ValLng(a)
   Print a, b


   20xa211   20

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Vallng.

Differences from QB
   * New to FreeBASIC

See also
   * CLngInt
   * Val
   * ValInt
   * ValULng
   * Str
   * Chr
   * Asc



----------------------------------------------------------- KeyPgValint ----
ValInt

Converts a string to a 32bit integer

Syntax
   Declare Function ValInt ( ByRef strnum As Const String ) As Long
   Declare Function ValInt ( ByRef strnum As Const WString ) As Long

Usage
   result = ValInt ( strnum )

Parameters
   strnum
      the string to convert

Return Value
   Returns a Long value of the converted string

   If the first character of the string is invalid, ValInt will return 0.

Description
   For example, ValInt("10") will return 10, and ValInt("10.60") will 
   return 10 as well. The function parses the string from the left, 
   skipping any white space, and returns the longest number it can read, 
   stopping at the first non-suitable character it finds.  Any non-numeric 
   characters, including decimal points and exponent specifiers, are 
   considered non-suitable, for example, ValInt("23.1E+6") will just return 
   23.

   ValInt can be used to convert integer numbers in Binary / Octal / 
   Hexadecimal format, if they have the relevant identifier ("&B" / "&O" / 
   "&H") prefixed, for example: ValInt("&HFF") returns 255.

   If you want to convert a number into string format, use the Str 
   function.

Example
   Dim a As String, b As Long
   a = "20xa211"
   b = ValInt(a)
   Print a, b


   20xa211   20

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Valint.

Differences from QB
   * New to FreeBASIC

See also
   * CLng
   * Val
   * ValUInt
   * ValLng
   * Str
   * Chr
   * Asc



---------------------------------------------------------- KeyPgValuint ----
ValUInt

Converts a string to an unsigned 32bit integer

Syntax
   Declare Function ValUInt ( ByRef strnum As Const String ) As ULong
   Declare Function ValUInt ( ByRef strnum As Const WString ) As ULong

Usage
   result = ValUInt ( strnum )

Parameters
   strnum
      the string to convert

Return Value
   Returns a ULong value of the converted string

   If the first character of the string is invalid, ValUInt will return 0.

Description
   For example, ValUInt("10") will return 10, and ValUInt("10.60") will 
   return 10 as well. The function parses the string from the left, 
   skipping any white space, and returns the longest number it can read, 
   stopping at the first non-suitable character it finds.  Any non-numeric 
   characters, including decimal points and exponent specifiers, are 
   considered non-suitable, for example, ValUInt("23.1E+6") will just 
   return 23.

   ValUInt can be used to convert integer numbers in Binary / Octal / 
   Hexadecimal format, if they have the relevant identifier ("&B" / "&O" / 
   "&H") prefixed, for example: ValUInt("&HFF") returns 255.

   If you want to convert a number into string format, use the Str 
   function.

Example
   Dim a As String, b As ULong
   a = "20xa211"
   b = ValUInt(a)
   Print a, b


   20xa211   20

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Valuint.

Differences from QB
   * New to FreeBASIC

See also
   * Val
   * ValInt
   * ValULng
   * CULng
   * Str
   * Chr
   * Asc



---------------------------------------------------------- KeyPgValulng ----
ValULng

Converts a string to a unsigned 64bit integer

Syntax
   Declare Function ValULng ( ByRef strnum As Const String ) As ULongInt
   Declare Function ValULng ( ByRef strnum As Const WString ) As ULongInt

Usage
   result = ValULng ( strnum )

Parameters
   strnum
      the string to convert

Return Value
   Returns a ULongInt of the converted string

   If the first character of the string is invalid, ValULng will return 0.

Description
   For example, ValULng("10") will return 10, and ValULng("10.60") will 
   return 10 as well. The function parses the string from the left, 
   skipping any white space, and returns the longest number it can read, 
   stopping at the first non-suitable character it finds.  Any non-numeric 
   characters, including decimal points and exponent specifiers, are 
   considered non-suitable, for example, ValULng("23.1E+6") will just 
   return 23.

   ValULng can be used to convert integer numbers in Binary / Octal / 
   Hexadecimal format, if they have the relevant identifier ("&B" / "&O" / 
   "&H") prefixed, for example: ValULng("&HFF") returns 255.

   If you want to convert a number into string format, use the Str 
   function.

Example
   Dim a As String, b As ULongInt
   a = "20xa211"
   b = ValULng(a)
   Print a, b


   20xa211   20

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Valulng.

Differences from QB
   * New to FreeBASIC

See also
   * CULngInt
   * Val
   * ValUInt
   * ValLng
   * Str
   * Chr
   * Asc



-------------------------------------------------------------- KeyPgVar ----
Var

Declares a variable whose type is implied from the initializer expression

Syntax
   [Static] Var [Shared] symbolname = expression[, symbolname = expression]

Description
   Var declares a variable whose type is implied from the initializer 
   expression. It is illegal to specify an explicit type in a Var 
   declaration. The initializer expression can be either a constant or any 
   variable of any type.

   Note: WString is not supported with Var, due to the fact that there is 
   no var-len WString type. This isn't likely to change, due to the 
   complexities involved with handling Unicode.

   Since the type of the variable is inferred from what you assign into it, 
   it's helpful to know how literals work. Any literal number without a 
   decimal point defaults to Integer. A literal number with a decimal point 
   defaults to Double.  See Literals for further information.

   All ZString expressions, including string literals and dereferenced 
   ZString Ptrs, will be given the String variable type.

   Explicit suffixes may be used on literal variables, to change/clarify 
   their type. See Literals and Variable Types for some more information 
   about suffixes that can be used on literals.

   Note: Suffixes must appear on the initializer, not on the variable. 
   Trying to use Var with a variable that has a suffix will throw a compile 
   error.

Example
   Var a  = Cast(Byte, 0)
   Var b  = Cast(Short, 0)
   Var c  = Cast(Integer, 0)
   Var d  = Cast(LongInt, 0)
   Var au = Cast(UByte, 0)   
   Var bu = Cast(UShort, 0)  
   Var cu = Cast(UInteger, 0)
   Var du = Cast(ULongInt, 0)
   Var e  = Cast(Single, 0.0)
   Var f  = Cast(Double, 0.0)
   Var g  = @c      '' integer ptr
   Var h  = @a      '' byte ptr
   Var s2 = "hello" '' var-len string

   Var ii = 6728   '' implicit integer
   Var id = 6728.0 '' implicit double

   Print "Byte: ";Len(a)
   Print "Short: ";Len(b)
   Print "Integer: ";Len(c)
   Print "Longint: ";Len(d)
   Print "UByte: ";Len(au)
   Print "UShort: ";Len(bu)
   Print "UInteger: ";Len(cu)
   Print "ULongint: ";Len(du)
   Print "Single: ";Len(e)
   Print "Double: ";Len(f)
   Print "Integer Pointer: ";Len(g)
   Print "Byte Pointer: ";Len(h)
   Print "Variable String: ";Len(s2)
   Print
   Print "Integer: ";Len(ii)
   Print "Double: ";Len(id)

   Sleep

Differences from QB
   * New to FreeBASIC

Dialect Differences
   * Only valid in the -lang fb dialect.

See also
   * Common
   * Dim
   * Erase
   * Extern
   * LBound
   * ReDim
   * Preserve
   * Shared
   * Static
   * Byref (Variables)
   * UBound
   * Pointers to Procedures



--------------------------------------------------------- KeyPgOpVarptr ----
Operator Varptr (Variable Pointer)

Returns the address of a variable or object

Syntax
   Declare Operator VarPtr ( ByRef lhs As T ) As T Ptr

Syntax
   result = VarPtr ( lhs )

Parameters
   lhs
      A variable or object.
   T
      Any data type.

Return Value
   Returns the address of a variable or object.

Description
   This operator returns the address of its operand.

   When the operand is of type String, the address of the internal string 
   descriptor is returned. Use Operator Strptr (String Pointer) to retrieve 
   the address of the string data.

   The operand cannot be an array, but may be an array element. For 
   example, "VarPtr(myarray(0))" returns the address of "myarray(0)".

   Operator @ (Address Of), when used with variables or objects, has 
   identical behavior.

Example
   Dim a As Integer, addr As Integer
   a = 10

   '' place the address of a in addr
   addr = CInt( VarPtr(a) )

   '' change all 4 bytes (size of INTEGER) of a
   Poke Integer, addr, -1000 
   Print a

   '' place the address of a in addr (same as above)
   addr = CInt( @a )

   '' print the least or most significant byte, depending on the CPU endianess
   Print Peek( addr ) 

Differences from QB
   * None

See also
   * Pointers
   * Peek
   * Poke



--------------------------------------------------------- KeyPgViewtext ----
View Print

Sets the printable text area of the screen

Syntax
   View Print [ firstrow To lastrow ]

Parameters
   firstrow
      first row of print area
   lastrow
      last row of print area

Description
   Sets the boundaries of the text printing area on the screen (in console 
   mode or in graphics mode) to the lines starting at first up to and 
   including last (the number of the available text lines on the screen 
   depends on the screen mode). Text lines are counted starting with 1. The 
   text cursor is moved to the beginning of the first line specified.
   If the row numbers are omitted, the entire screen is used as the text 
   printing area.

Example
   Cls
   View Print 5 To 6
   Color , 1 
   '' clear only View Print area
   Cls 

View Print can be used in graphics mode to avoid the text output 
overwriting graphics:
   Screen 12
   Dim As Integer R,Y,x,y1
   Dim As Single y2
   View Print 20 To 27
   Line (0,0)-(639,300),1,BF
   Line (100,50)-(540,200),0,BF
   Do
    r = (r + 1) And 15
    For y = 1 To 99
      y1 = ((1190 \ y + r) And 15)
      y2 = 6 / y
      For x = 100 To 540
      PSet (x, y + 100), CInt((319 - x) * y2) And 15 Xor y1 
     Next x,y
    If r=0 Then Color Int(Rnd*16): Print "blah"
   Loop Until Len(Inkey)

Differences from QB
   * None.

See also
   * Cls
   * Print
   * ?
   * Color



----------------------------------------------------- KeyPgViewgraphics ----
View (Graphics)

Sets new physical coordinate mapping and clipping region for graphics 
keywords

Syntax
   View
   View ( x1, y1 )-( x2, y2 ) [ [, fill_color ] [, border_color ] ]
   View Screen ( x1, y1 )-( x2, y2 ) [ [, fill_color ] [, border_color ] ]

Parameters
   x1 As Integer, y1 As Integer
      The horizontal and vertical offsets, in pixels, of one corner of the 
      viewport relative to the top-left corner of the screen.
   x2 As Integer, y2 As Integer
      The horizontal and vertical offsets, in pixels, of the opposite 
      corner of the viewport relative to the top-left corner of the screen.
   fill_color As ULong
      The color to fill the new viewport.
   border_color As ULong
      The color of the border to draw around the new viewport.

Description
   The viewport, or clipping region, is a rectangular area of the graphics 
   screen, outside of which no graphics drawing will be done. That is, only 
   graphics drawing done within this area will be shown. A graphics screen 
   must be created with Screen (Graphics) or ScreenRes before calling View 
   or View Screen.

   The first statement (View) sets the viewport to encompass the entire 
   screen, which is the default viewport for a new graphics screen.

   The second and third statements (View parameters and View Screen 
   parameters) both allow a new viewport to be defined. The indicated 
   effects for each parameter only occur if that parameter is specified:
      * The corners of the viewport are specified by the x1, y1, x2 and y2 
        parameters.
      * fill_color and border_color are both in the format accepted by 
        Color.
      * The second statement (View parameters) modifies the coordinate 
        mapping of the graphics screen such that coordinates specified for 
        graphics drawing statements and procedures are relative to the 
        top-left corner of the viewport.
      * The third statement (View Screen parameters) modifies the 
        coordinate mapping of the graphics screen such that coordinates 
        specified for graphics drawing statements and procedures are 
        relative to the top-left corner of the screen.
      * In both cases no new scale factor is applied (see Window for 
        that).

Example
   Screen 12
   Dim ip As Any Ptr
   Dim As Integer x, y

   'simple sprite
   ip = ImageCreate(64,64)
   For y = 0 To 63
     For x = 0 To 63
      PSet ip, (x, y), (x\4) Xor (y\4)
     Next x
   Next y

   'viewport with blue border
   Line (215,135)-(425,345), 1, bf
   View (220,140)-(420,340)

   'move sprite around the viewport
   Do

     x = 100*Sin(Timer*2.0)+50
     y = 100*Sin(Timer*2.7)+50
     
     ScreenSync
     ScreenLock
     
     'clear viewport and put image
     Cls 1
     Put (x, y), ip, PSet
      
     ScreenUnlock

   Loop While Inkey = ""

   ImageDestroy(ip)

Differences from QB
   * QBASIC preserves the WINDOW coordinate mapping after subsequent calls 
     to VIEW.
   * FreeBASIC's current behavior is to preserve the WINDOW coordinates 
     after calls to VIEW, or when working on images, meaning that the 
     coordinate mapping may undergo scaling/translations if the viewport 
     changes. (If a WINDOW hasn't been set, there is no coordinate mapping, 
     and so it doesn't change after calls to VIEW.)  The behavior may 
     change in future, but consistent behavior can be assured over 
     inconstent viewport coordinates by re-calling WINDOW whenever you 
     change the VIEW.

See also
   * View Print
   * Screen (Graphics)
   * Window
   * PMap



---------------------------------------------------------- KeyPgVirtual ----
Virtual

Declare virtual methods

Syntax
   Type typename Extends base_typename
      Declare Virtual Sub|Function|Property|Operator|Destructor ...
   End Type

Description
   Virtual methods are methods that can be overridden by data types derived 
   from the type they were declared in, allowing for dynamic polymorphism. 
   In contrast to Abstract methods, virtual methods must have an 
   implementation, which is used when the virtual is not overridden.

   A derived type can override virtual methods declared in its base type by 
   declaring a non-static method with the same identifier and signature, 
   meaning same number and type of parameters (invariant parameters), same 
   calling convention, and if any, same return type (or a covariant return 
   type for return by reference or by pointer):
      * if that differs only in parameter passing mode or calling 
        convention or return type, then an overriding error is returned at 
        compile time,
      * otherwise, only shadowing is allowed for any other signature 
        difference, corresponding to case where both methods would be 
        overloadable (if within the same type).
   The property of being a virtual method is not implicitly inherited by 
   the overriding method in the derived type. If this overriding method 
   must be overridden in turn in a lower level derived type, it must also 
   be declared as virtual.
   On the other hand, since a derived static method can never override a 
   base virtual/abstract method, it can therefore shadow any base method 
   (including virtual/abstract) with same identifier and regardless of the 
   signature.

   When calling virtual methods, the compiler may need to do a vtable 
   lookup in order to find out which method must be called for a given 
   object. This requires an extra hidden vtable pointer field to be added 
   at the top of each type with virtual methods. This hidden vptr is 
   provided by the built-in Object type. Because of that, virtual methods 
   can only be declared in a type that directly or indirectly Extends Object
   .

   Dynamic polymorphism by using override procedures:
      * Normally only a typename procedure (or upper in hierarchy) is 
        accessible through a base-typename reference/pointer even if this 
        one refers to an object derived from typename.
      * But when the procedure is virtual, this tells the running program 
        to resolve the override procedure the most derived relating to the 
        real object type by vtable lookup (dynamic binding at runtime), 
        rather than procedure normally accessible from the raw base-type of 
        the reference/pointer (static binding at compile time).

   Constructors cannot be virtual because they create objects, while 
   virtual methods require an already-existing object with a specific type. 
   The type of the constructor to call is determined at compile-time from 
   the code.
   In addition, when calling a virtual method inside a constructor, only 
   the version of the method corresponding to an object of type of this 
   constructor is used. That is because the vptr has not yet been set up by 
   the derived type constructor, but only by the local type constructor.

   Destructors often must be virtual when deleting an object manipulated 
   through a pointer to its base type, so that the destruction starts at 
   the most derived type and works its way down to the base type. To do 
   this, it may be necessary to add virtual destructors with an empty body 
   anywhere an explicit destruction was not yet required, in order to 
   supersede each non-virtual implicit destructor built by the compiler.
   On the other hand, when calling a virtual (or abstract) method inside a 
   destructor (virtual or not), only the version of the method 
   corresponding to an object of type of this destructor is used because 
   the vptr is reset at the top of the destructor according to its own 
   type's vtable. This avoids to access child methods and so to refer to 
   child members previously destroyed by the child destructor execution.

   For member methods with Virtual in their declaration, Virtual can also 
   be specified on the corresponding method bodies, for improved code 
   readability.

   Caution: In a multi-level inheritance, a same named method (same 
   identifier and signature) can be declared Abstract, Virtual or normal 
   (without specifier) at each inheritance hierarchy level. When there is 
   mixing of  specifiers, the usual order is abstract -> virtual -> normal, 
   from top to bottom of the inheritance hierarchy.
   The access control (Public/Protected/Private) of an overriding method is 
   not taken into account by the internal polymorphism process, but only 
   for the initial call at compile-time.
   Base (Member Access).method() calls always the base's own method, never 
   the overriding method.

   Note: Virtual is also used as qualifier for ProcPtr to request it to 
   return the index in the vtable for a virtual/abstract member procedure 
   or member operator.
         ProcPtr ( identifier, Virtual [ Any|user_proctype ] )

Example

   '' Example with overriding subroutines

   Type Hello Extends Object
      Declare Virtual Sub hi( )
   End Type

   Type HelloEnglish Extends Hello
      Declare Sub hi( )            '' overriding subroutine
   End Type

   Type HelloFrench Extends Hello
      Declare Sub hi( )            '' overriding subroutine
   End Type

   Type HelloGerman Extends Hello
      Declare Sub hi( )            '' overriding subroutine
   End Type

   Sub Hello.hi( )
      Print "hi!"
   End Sub

   Sub HelloEnglish.hi( )           '' overriding subroutine
      Print "hello!"
   End Sub

   Sub HelloFrench.hi( )            '' overriding subroutine
      Print "Salut!"
   End Sub

   Sub HelloGerman.hi( )            '' overriding subroutine
      Print "Hallo!"
   End Sub

   Randomize( Timer( ) )

   Dim As Hello Ptr h

   For i As Integer = 0 To 9
      Select Case( Int( Rnd( ) * 4 ) + 1 )
      Case 1
         h = New HelloEnglish
      Case 2
         h = New HelloFrench
      Case 3
         h = New HelloGerman
      Case Else
         h = New Hello
      End Select

      h->hi( )
      Delete h
   Next

   Sleep

   '' Example with overriding destructor and
   ''              overriding function with covariant return

   Type myBase Extends Object
     Declare Virtual Function clone () As myBase Ptr
     Declare Virtual Sub Destroy ()
   End Type

   Function myBase.clone () As myBase Ptr
     Dim As myBase Ptr pp = New myBase(This)
     Print "myBase.clone() As myBase Ptr", pp
     Function = pp
   End Function

   Sub myBase.Destroy ()
     Print "myBase.Destroy()", , @This
     Delete @This
   End Sub

   Type myDerived Extends myBase
     Declare Function clone () As myDerived Ptr     '' overriding member function with covariant return
     Declare Sub Destroy ()                         '' overriding member subroutine
   End Type

   Function myDerived.clone () As myDerived Ptr     '' overriding member function with covariant return
     Dim As myDerived Ptr pc = New myDerived(This)
     Print "myDerived.clone() As myDerived Ptr", pc
     Function = pc
   End Function

   Sub myDerived.Destroy ()                         '' overriding member subroutine
     Print "myDerived.Destroy()", , @This
     Delete @This
   End Sub

   Dim As myDerived c

   Dim As myBase Ptr ppc = @c
   Dim As myDerived Ptr pcc = @c

   Dim As myBase Ptr ppc1 = ppc->clone()            '' using base pointers and polymorphism
   Dim As myDerived Ptr pcc1 = pcc->clone()         '' using derived pointers and covariance of return value
   Print
   ppc1->Destroy()                                  '' using base pointer and polymorphism
   pcc1->Destroy()                                  '' using derived pointer

   Sleep

Dialect Differences
   * Only available in the -lang fb dialect.

Differences from QB
   * New to FreeBASIC

See also
   * Type
   * Object
   * Extends
   * Extends Zstring
   * Extends Wstring
   * Abstract
   * Override



----------------------------------------------------- KeyPgSfxGenerated ----
Generated Sound Commands

Commands for generated sound, PLAY strings, and sfxlib mix settings.

Syntax
   Beep [ duration, pitch ]
   Sound frequency, duration
   Sound channel, frequency, duration, volume
   Tone channel, frequency, duration
   Noise channel, duration, volume
   Noise channel, frequency, duration, volume
   Note name, octave, duration
   Note channel, name, octave, duration
   Play music
   Play channel, music
   Play music1, music2
   Play music1, music2, music3
   Tempo bpm
   bpm = Tempo()
   Channel channel
   channel = Channel()
   Octave octave
   octave = Octave()
   Voice instrument
   instrument = Voice()
   Vol level
   Volume level
   level = Volume()
   Volume channel, level
   level = Volume( channel )
   Balance position
   position = Balance()
   Pan channel, position
   position = Pan( channel )
   Wave id, waveform
   Envelope id, attack, decay, sustain, release
   Instrument id, wave_id, envelope_id
   Instrument channel, instrument_id

Description
   These commands synthesize sound directly through sfxlib.  Sound, Tone, 
   Noise, Note, and Play create voices.  Tempo, Channel, Octave, and Voice 
   set defaults used by PLAY-string and generated-sound commands.  Volume, 
   Vol, Balance, and Pan control mix levels and stereo placement.

   Sound accepts the high-impact classic form Sound frequency, duration and
   the explicit channel form Sound channel, frequency, duration, volume.
   When both arguments are integers, duration is interpreted as the PC BASIC
   timer-tick value.

   Wave defines a waveform id.  The currently supported waveform values 
   are:
      * 0 sine
      * 1 square
      * 2 triangle
      * 3 saw
      * 4 noise

   Envelope defines an ADSR envelope using seconds for attack, decay, and 
   release, and a 0.0 to 1.0 sustain level.  Instrument can define an 
   instrument from a waveform and envelope, or assign an instrument to a 
   channel.

   The channel-oriented commands use sfxlib's channel table.  Channels are 
   zero-based.

Example
   See examples/sfxlib/basics-01-generated-sound.bas, 
   examples/sfxlib/basics-02-play-strings.bas, 
   examples/sfxlib/basics-03-channels-mix.bas, 
   examples/sfxlib/basics-04-instruments.bas, and 
   examples/sfxlib/showcase.bas.

Platform Differences
   * On headless or diagnostic runs, SFXLIB_DRIVER=null can be set before 
     program startup to use the null output driver.

Differences from QB
   * New to FreeBASIC.

See also
   * Beep
   * Music
   * Sfx
   * Sound Library Reference



----------------------------------------------------- KeyPgSfxGenerated ----
Generated Sound Commands

Commands for generated sound, PLAY strings, and sfxlib mix settings.

Syntax
   Beep [ duration, pitch ]
   Sound frequency, duration
   Sound channel, frequency, duration, volume
   Tone channel, frequency, duration
   Noise channel, duration, volume
   Noise channel, frequency, duration, volume
   Note name, octave, duration
   Note channel, name, octave, duration
   Play music
   Play channel, music
   Play music1, music2
   Play music1, music2, music3
   Tempo bpm
   bpm = Tempo()
   Channel channel
   channel = Channel()
   Octave octave
   octave = Octave()
   Voice instrument
   instrument = Voice()
   Vol level
   Volume level
   level = Volume()
   Volume channel, level
   level = Volume( channel )
   Balance position
   position = Balance()
   Pan channel, position
   position = Pan( channel )
   Wave id, waveform
   Envelope id, attack, decay, sustain, release
   Instrument id, wave_id, envelope_id
   Instrument channel, instrument_id

Description
   These commands synthesize sound directly through sfxlib.  Sound, Tone, 
   Noise, Note, and Play create voices.  Tempo, Channel, Octave, and Voice 
   set defaults used by PLAY-string and generated-sound commands.  Volume, 
   Vol, Balance, and Pan control mix levels and stereo placement.

   Sound accepts the high-impact classic form Sound frequency, duration and
   the explicit channel form Sound channel, frequency, duration, volume.
   When both arguments are integers, duration is interpreted as the PC BASIC
   timer-tick value.

   Wave defines a waveform id.  The currently supported waveform values 
   are:
      * 0 sine
      * 1 square
      * 2 triangle
      * 3 saw
      * 4 noise

   Envelope defines an ADSR envelope using seconds for attack, decay, and 
   release, and a 0.0 to 1.0 sustain level.  Instrument can define an 
   instrument from a waveform and envelope, or assign an instrument to a 
   channel.

   The channel-oriented commands use sfxlib's channel table.  Channels are 
   zero-based.

Example
   See examples/sfxlib/basics-01-generated-sound.bas, 
   examples/sfxlib/basics-02-play-strings.bas, 
   examples/sfxlib/basics-03-channels-mix.bas, 
   examples/sfxlib/basics-04-instruments.bas, and 
   examples/sfxlib/showcase.bas.

Platform Differences
   * On headless or diagnostic runs, SFXLIB_DRIVER=null can be set before 
     program startup to use the null output driver.

Differences from QB
   * New to FreeBASIC.

See also
   * Beep
   * Music
   * Sfx
   * Sound Library Reference



----------------------------------------------------- KeyPgSfxGenerated ----
Generated Sound Commands

Commands for generated sound, PLAY strings, and sfxlib mix settings.

Syntax
   Beep [ duration, pitch ]
   Sound frequency, duration
   Sound channel, frequency, duration, volume
   Tone channel, frequency, duration
   Noise channel, duration, volume
   Noise channel, frequency, duration, volume
   Note name, octave, duration
   Note channel, name, octave, duration
   Play music
   Play channel, music
   Play music1, music2
   Play music1, music2, music3
   Tempo bpm
   bpm = Tempo()
   Channel channel
   channel = Channel()
   Octave octave
   octave = Octave()
   Voice instrument
   instrument = Voice()
   Vol level
   Volume level
   level = Volume()
   Volume channel, level
   level = Volume( channel )
   Balance position
   position = Balance()
   Pan channel, position
   position = Pan( channel )
   Wave id, waveform
   Envelope id, attack, decay, sustain, release
   Instrument id, wave_id, envelope_id
   Instrument channel, instrument_id

Description
   These commands synthesize sound directly through sfxlib.  Sound, Tone, 
   Noise, Note, and Play create voices.  Tempo, Channel, Octave, and Voice 
   set defaults used by PLAY-string and generated-sound commands.  Volume, 
   Vol, Balance, and Pan control mix levels and stereo placement.

   Sound accepts the high-impact classic form Sound frequency, duration and
   the explicit channel form Sound channel, frequency, duration, volume.
   When both arguments are integers, duration is interpreted as the PC BASIC
   timer-tick value.

   Wave defines a waveform id.  The currently supported waveform values 
   are:
      * 0 sine
      * 1 square
      * 2 triangle
      * 3 saw
      * 4 noise

   Envelope defines an ADSR envelope using seconds for attack, decay, and 
   release, and a 0.0 to 1.0 sustain level.  Instrument can define an 
   instrument from a waveform and envelope, or assign an instrument to a 
   channel.

   The channel-oriented commands use sfxlib's channel table.  Channels are 
   zero-based.

Example
   See examples/sfxlib/basics-01-generated-sound.bas, 
   examples/sfxlib/basics-02-play-strings.bas, 
   examples/sfxlib/basics-03-channels-mix.bas, 
   examples/sfxlib/basics-04-instruments.bas, and 
   examples/sfxlib/showcase.bas.

Platform Differences
   * On headless or diagnostic runs, SFXLIB_DRIVER=null can be set before 
     program startup to use the null output driver.

Differences from QB
   * New to FreeBASIC.

See also
   * Beep
   * Music
   * Sfx
   * Sound Library Reference




============================================================================
    W

------------------------------------------------------------- KeyPgWait ----
Wait

Reads from a hardware port with a mask.

Syntax
   Declare Function Wait ( ByVal port As UShort, ByVal and_mask As Long, 
   ByVal xor_mask As Long = 0 ) As Long

Usage
   Wait port, and_value [, xor_value]

Parameters
   port
      Port to read.
   and_mask
      Mask value to And the port value with.
   xor_mask
      Mask value to Xor the port value with.

Return Value
   0 if successful, -1 on failure.

Description
   Wait keeps reading port until the reading ANDed with and_mask and 
   optionally XORed with xor_mask gives a non-zero result.

   Example
   Wait &h3da, &h8 'Old Qbasic way of waiting for the monitor's vsync
   ScreenSync 'FreeBASIC way of accomplishing the same thing

Platform Differences
   * In the Windows and Linux versions three port numbers (&H3C7, &H3C8, 
     &H3C9) are hooked by the graphics library when a graphics mode is in 
     use to emulate VGA palette handling as in QB. This use is deprecated; 
     use Palette to retrieve and set palette colors.

   * Using true port access in the Windows version requires the program to 
     install a device driver for the present session. For that reason, 
     Windows executables using hardware port access should be run with 
     administrator permits each time the computer is restarted. Further 
     runs don't require admin rights as they just use the already installed 
     driver. The driver is only 3K in size and is embedded in the 
     executable.

See also
   * Inp
   * Out

   


----------------------------------------------------- KeyPgSfxGenerated ----
Generated Sound Commands

Commands for generated sound, PLAY strings, and sfxlib mix settings.

Syntax
   Beep [ duration, pitch ]
   Sound frequency, duration
   Sound channel, frequency, duration, volume
   Tone channel, frequency, duration
   Noise channel, duration, volume
   Noise channel, frequency, duration, volume
   Note name, octave, duration
   Note channel, name, octave, duration
   Play music
   Play channel, music
   Play music1, music2
   Play music1, music2, music3
   Tempo bpm
   bpm = Tempo()
   Channel channel
   channel = Channel()
   Octave octave
   octave = Octave()
   Voice instrument
   instrument = Voice()
   Vol level
   Volume level
   level = Volume()
   Volume channel, level
   level = Volume( channel )
   Balance position
   position = Balance()
   Pan channel, position
   position = Pan( channel )
   Wave id, waveform
   Envelope id, attack, decay, sustain, release
   Instrument id, wave_id, envelope_id
   Instrument channel, instrument_id

Description
   These commands synthesize sound directly through sfxlib.  Sound, Tone, 
   Noise, Note, and Play create voices.  Tempo, Channel, Octave, and Voice 
   set defaults used by PLAY-string and generated-sound commands.  Volume, 
   Vol, Balance, and Pan control mix levels and stereo placement.

   Sound accepts the high-impact classic form Sound frequency, duration and
   the explicit channel form Sound channel, frequency, duration, volume.
   When both arguments are integers, duration is interpreted as the PC BASIC
   timer-tick value.

   Wave defines a waveform id.  The currently supported waveform values 
   are:
      * 0 sine
      * 1 square
      * 2 triangle
      * 3 saw
      * 4 noise

   Envelope defines an ADSR envelope using seconds for attack, decay, and 
   release, and a 0.0 to 1.0 sustain level.  Instrument can define an 
   instrument from a waveform and envelope, or assign an instrument to a 
   channel.

   The channel-oriented commands use sfxlib's channel table.  Channels are 
   zero-based.

Example
   See examples/sfxlib/basics-01-generated-sound.bas, 
   examples/sfxlib/basics-02-play-strings.bas, 
   examples/sfxlib/basics-03-channels-mix.bas, 
   examples/sfxlib/basics-04-instruments.bas, and 
   examples/sfxlib/showcase.bas.

Platform Differences
   * On headless or diagnostic runs, SFXLIB_DRIVER=null can be set before 
     program startup to use the null output driver.

Differences from QB
   * New to FreeBASIC.

See also
   * Beep
   * Music
   * Sfx
   * Sound Library Reference



------------------------------------------------------------- KeyPgWbin ----
WBin

Returns the binary WString (Unicode) representation of a number

Syntax
   Declare Function WBin ( ByVal number As UByte ) As WString
   Declare Function WBin ( ByVal number As UShort ) As WString
   Declare Function WBin ( ByVal number As ULong ) As WString
   Declare Function WBin ( ByVal number As ULongInt ) As WString
   Declare Function WBin ( ByVal number As Const Any Ptr ) As WString

   Declare Function WBin ( ByVal number As UByte, ByVal digits As Long ) As 
   WString
   Declare Function WBin ( ByVal number As UShort, ByVal digits As Long ) As
   WString
   Declare Function WBin ( ByVal number As ULong, ByVal digits As Long ) As 
   WString
   Declare Function WBin ( ByVal number As ULongInt, ByVal digits As Long ) 
   As WString
   Declare Function WBin ( ByVal number As Const Any Ptr, ByVal digits As 
   Long ) As WString

Usage
   result = WBin( number [, digits] )

Parameters
   number
      A whole number or expression evaluating to a whole number.
   digits
      Optional number of digits to return.

Return Value
   Returns a binary WString representation of number, truncated or padded 
   with zeros ("0") to fit the number of digits, if specified.

Description
   Returns a WString (Unicode) representing the binary value of the integer 
   number. Binary digits range from 0 to 1.

   If you specify digits > 0, the result wstring will be exactly that 
   length.  It will be truncated or padded with zeros on the left, if 
   necessary.

   The length of the returned string will not be longer than the maximum 
   number of digits required for the type of expression (32 for a Long, 64 
   for floating point or LongInt)

Example
   Print WBin(54321)
   Print WBin(54321, 5)
   Print WBin(54321, 20)

   will produce the output:

   1101010000110001
   10001
   00001101010000110001

Platform Differences
   * Unicode strings are not supported in the DOS port of FreeBASIC.

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Wbin.

Differences from QB
   * New to FreeBASIC

See also
   * Bin
   * WHex
   * WOct



------------------------------------------------------------- KeyPgWchr ----
WChr

Returns a wide-character string containing one or more Unicode characters

Syntax
   Declare Function Wchr ( ByVal ch As Integer [, ... ] ) As WString

Usage
   result = WChr( ch0 [, ch1 ... chN ] )

Parameters
   ch
      The Unicode integer value of a character (up to 32 characters).

Return Value
   Returns a wide-character string.

Description
   WChr returns a wide-character string containing the character(s) 
   represented by the Unicode values passed to it.

   When WChr is used with numerical constants or literals, the result is 
   evaluated at compile-time, so it can be used in variable initializers.

   Not all Unicode characters can be displayed on any machine, the 
   characters available depend on the font presently in use in the console. 
   Graphics modes can't display Unicode characters, as the GfxLib built-in 
   font is not Unicode.
 
Example
   Print "The character represented by the UNICODE code of 934 is: "; WChr(934)
   Print "Multiple UNICODE characters: "; WChr(933, 934, 935)

   will produce the output:
The character represented by the UNICODE code of 934 is: Î¦
   Multiple UNICODE characters: Î¥Î¦Î§

Platform Differences
   * DOS does not support WChr.

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Wchr.

Differences from QB
   * New to FreeBASIC

See also
   * Chr
   * WStr



---------------------------------------------------------- KeyPgWeekday ----
Weekday

Gets the number of day of the week from a Date Serial

Syntax
   Declare Function Weekday ( ByVal serial As Double , ByVal firstdayofweek 
   As Long = fbusesystem ) As Long

Usage
   #include "vbcompat.bi"
   result = Weekday( date_serial [, firstdayofweek ] )

Parameters
   date_serial
      the date
   firstdayofweek
      the first day of the week

Return Value
   Returns the week day number from a variable containing a date in 
   Date Serial format.

Description
   The week day values must be in the range 1-7, its meaning depends on the 
   firstdayofweek parameter

   firstdayofweek is optional.

         +-------+-----------------+-----------+
         |value  |first day of week|constant   |
         |omitted|sunday           |           |
         |0      |local settings   |fbUseSystem|
         |1      |sunday           |fbSunday   |
         |2      |monday           |fbMonday   |
         |3      |tuesday          |fbTuesday  |
         |4      |wednesday        |fbWednesday|
         |5      |thursday         |fbThursday |
         |6      |friday           |fbFriday   |
         |7      |saturday         |fbSaturday |
         +-------+-----------------+-----------+

   The compiler will not recognize this function unless vbcompat.bi is 
   included.

Example
   #include "vbcompat.bi"

   Dim a As Double = DateSerial (2005, 11, 28) + TimeSerial(7, 30, 50)

   Print Format(a, "yyyy/mm/dd hh:mm:ss "); Weekday(a)

Differences from QB
   * Did not exist in QB. This function appeared in PDS and VBDOS

See also
   * Date Serials



------------------------------------------------------ KeyPgWeekdayname ----
WeekdayName

Gets the name of a week day from its integral representation

Syntax
   Declare Function WeekdayName ( ByVal weekday As Long, ByVal abbreviate As
   Long = 0, ByVal firstdayofweek As Long = fbUseSystem ) As String

Usage
   #include "vbcompat.bi"
   result = WeekdayName( weekday [, abbreviate [, firstdayofweek ] ] )

Parameters
   weekday
      the number of the day of the week
   abbreviate
      flag to indicate that name should be abbreviated
   firstdayofweek
      first day of the week

Return Value
   Returns the local operating system language day of week name from the 
   weekday value 1 to 7.

Description
   How weekday is interpreted depends on the firstdayofweek parameter.

   If abbreviate is true, a 3 letter abbreviation is returned, if false or 
   omitted, the whole name is returned.

   firstdayofweek is an optional parameter specified as follows:

         +-------+-----------------+-----------+
         |value  |first day of week|constant   |
         |omitted|sunday           |           |
         |0      |local settings   |fbUseSystem|
         |1      |sunday           |fbSunday   |
         |2      |monday           |fbMonday   |
         |3      |tuesday          |fbTuesday  |
         |4      |wednesday        |fbWednesday|
         |5      |thursday         |fbThursday |
         |6      |friday           |fbFriday   |
         |7      |saturday         |fbSaturday |
         +-------+-----------------+-----------+

   The compiler will not recognize this function unless vbcompat.bi or 
   datetime.bi is included.

Example
   #include "vbcompat.bi"

   Dim a As Double = DateSerial(2005, 11, 28) + TimeSerial(7, 30, 50)

   Print Format(a, "yyyy/mm/dd hh:mm:ss "); WeekdayName(Weekday(a))

Differences from QB
   * Did not exist in QB. This function appeared in Visual Basic.

See also
   * Date Serials



------------------------------------------------------------- KeyPgWend ----
Wend

Control flow statement.

Syntax
   While [condition]
      [statement block]
   Wend

Description
   Wend specifies the end of a While...Wend loop block.

Example
   See example at While...Wend.

Differences from QB
   * None

See also
   * While...Wend

   

------------------------------------------------------------ KeyPgWhile ----
While

Control flow statement.

Syntax
   Do While condition
      [statement block]
   Loop
or
   Do
      [statement block]
   Loop While condition
or
   While [condition]
      [statement block]
   Wend

Description
   While specifies that a loop block will continue if the condition 
   following it evaluates as true. This condition is checked during each 
   loop iteration.

Example
   Dim a As Integer

   a = 0
   Do While a < 10
      Print "hello"
   a = a + 1
   Loop

   'This will continue to print "hello" on the screen while the condition (a < 10) is met.
      

Differences from QB
   * None

See also
   * Do...Loop
   * While...Wend

   

-------------------------------------------------------- KeyPgWhilewend ----
While...Wend

Control flow statement for looping

Syntax
   While [condition]
      [statement block]
   Wend

Description
   The While statement will cause the following set of statements in the 
   statement block to execute repeatedly if and while the expression 
   condition evaluates to true.

   If condition evaluates to false when the While statement is first 
   executed, then the statement block is skipped and execution resumes 
   immediately following the enclosing Wend statement.

   If an Exit While statement is encountered inside the statement block, 
   the loop is terminated, and execution resumes immediately following the 
   enclosing Wend statement. If a Continue While statement is encountered, 
   the rest of the statement block is skipped and execution resumes at the 
   While statement.

   Like all control flow statements, the While statement can be nested, 
   that is, it can be used in a statement block of another While statement.

   note: the While keyword is also used in the Do...Loop statement to 
   indicate the type of comparison. Used in this way, the Do statement 
   becomes functionally equivalent to the While statement, so do not 
   confuse their enclosing keywords Loop and Wend, respectively.

Example
   In this example, a While loop is used to reverse a string by iterating 
   through it backward. The loop stops if index is less than 0 (0 being the 
   first index in the string).
   Dim As String sentence                          '' string to reverse
   sentence = "The quick brown fox jumps over the lazy dog."

   Dim As String ecnetnes
   Dim As Integer index
   index = Len( sentence ) - 1                     '' point to last character
   While( index >= 0 )                             '' stop after first character
     ecnetnes += Chr( sentence[index] )           '' append character to new string
     index -= 1
   Wend

   Print "original: """ ; sentence ; """"
   Print "reversed: """ ; ecnetnes ; """"

   End 0

Dialect Differences
   * In the -lang qb and -lang fblite dialects, variables declared inside 
     a While..Wend loop have a function-wide scope as in QB 
   * In the -lang fb and -lang deprecated dialects, variables declared 
     inside a While..Wend block are visible only inside the block, and 
     can't be accessed outside it. To access duplicated symbols defined as 
     global outside this block, add one or preferably two dot(s) as prefix: 
     .SomeSymbol or preferably ..SomeSymbol (or only ..SomeSymbol if inside 
     a With..End With block).

Differences from QB
   * None

See also
   * Exit
   * Continue
   * Do...Loop



------------------------------------------------------------- KeyPgWhex ----
WHex

Returns the hexadecimal WString (Unicode) representation of a number

Syntax
   Declare Function WHex ( ByVal number As UByte ) As WString
   Declare Function WHex ( ByVal number As UShort ) As WString
   Declare Function WHex ( ByVal number As ULong ) As WString
   Declare Function WHex ( ByVal number As ULongInt ) As WString
   Declare Function WHex ( ByVal number As Const Any Ptr ) As WString

   Declare Function WHex ( ByVal number As UByte, ByVal digits As Long ) As 
   WString
   Declare Function WHex ( ByVal number As UShort, ByVal digits As Long ) As
   WString
   Declare Function WHex ( ByVal number As ULong, ByVal digits As Long ) As 
   WString
   Declare Function WHex ( ByVal number As ULongInt, ByVal digits As Long ) 
   As WString
   Declare Function WHex ( ByVal number As Const Any Ptr, ByVal digits As 
   Long ) As WString

Usage
   result = WHex( number [, digits ] )

Parameters
   number
      A whole number or expression evaluating to a whole number.
   digits
      Optional number of digits to return.

Return Value
   Returns a hexadecimal WString representation of number, truncated or 
   padded with zeros ("0") to fit the number of digits, if specified.

Description
   Hexadecimal digits range from 0-9, or A-F.

   If you specify digits > 0, the resulting WString will be exactly that 
   length.  It will be truncated or padded with zeros on the left, if 
   necessary.

   The length of the wstring will not go longer than the maximum number of 
   digits required for the type of expression (8 for a Long, 16 for 
   floating point or LongInt)

Example
   Print Hex(54321)
   Print Hex(54321, 2)
   Print Hex(54321, 5)

   will produce the output:
   D431
   31
   0D431

Platform Differences
   * Unicode strings are not supported in the DOS port of FreeBASIC.

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Whex.

Differences from QB
   * New to FreeBASIC.

See also
   * Hex
   * WBin
   * WOct



------------------------------------------------------------ KeyPgWidth ----
Width

Sets or gets the number of rows and columns of the display

Syntax
   Width [columns] [, rows]
   Width LPrint columns
   Width { #filenum | devicename }, columns
   result = Width( )

Parameters
   columns
      columns (in characters) for output
   rows
      rows (in characters) for output
   filenum
      file number to apply to
   devicename
      device name to apply to

Return Value
   Returns a 32 bit Long where the High Word is the number of rows and the 
   Low Word is the number of columns currently set.

Description
   Sets the maximum number of columns of characters of an output device 
   (console, printer or text file). If text sent to the device reaches the 
   width an automatic carriage return is generated.

   Using Width as a function returns the current console width in the low 
   word and the current height in the high word.

   If a device is not given then Width takes effect on the active 
   console/graphics screen, and a second argument specifying maximum number 
   of rows is allowed.

   In graphics modes Width is used to indirectly select the font size by 
   setting one of the character height * width pairs allowed (See 
   Screen (Graphics)). If  rows / cols is an invalid combination, no 
   changes are made to the screen display.
   Valid font heights are 8 pixels, 14 pixels and 16 pixels.  The fonts all 
   have a fixed width of 8 pixels.
   (see second example)

   Using the Width command in graphic mode also forces a screen clear (Cls
   ).

Example
   Dim As Long w
   w = Width
   Print "rows: " & HiWord(w)
   Print "cols: " & LoWord(w)

   ''Set up a graphics screen
   Const W = 320, H = 200
   ScreenRes W, H

   Dim As Long twid
   Dim As UInteger tw, th

   '' Fetch and print current text width/height:
   twid = Width()
   tw = LoWord(twid): th = HiWord(twid)
   Print "Default for current screen (8*8)"
   Print "Width:  " & tw
   Print "Height: " & th
   Sleep

   Width W\8, H\16 '' Use 8*16 font

   twid = Width()
   tw = LoWord(twid): th = HiWord(twid)
   Print "Set to 8*16 font"
   Print "Width:  " & tw
   Print "Height: " & th
   Sleep

   Width W\8, H\14 '' Use 8*14 font

   twid = Width()
   tw = LoWord(twid): th = HiWord(twid)
   Print "Set to 8*14 font"
   Print "Width:  " & tw
   Print "Height: " & th
   Sleep

   Width W\8, H\8 '' Use 8*8 font

   twid = Width()
   tw = LoWord(twid): th = HiWord(twid)
   Print "Set to 8*8 font"
   Print "Width:  " & tw
   Print "Height: " & th
   Sleep

Platform Differences
   * In a Windows console any values > 0 can be used in windowed mode.
   * On a DOS or Windows full-screen console, the valid dimensions depend 
     on the capabilities of the hardware.
   * Linux doesn't allow applications to change the console size.

Differences from QB
   * columns was limited to 40 or 80, while rows could be 25, 30, 43, 50 
     or 60, depending on the graphics hardware and screen mode being used.

See also
   * LoWord
   * HiWord
   * CsrLin
   * Pos



----------------------------------------------------------- KeyPgWindow ----
Window

Sets new view coordinates mapping for current viewport

Syntax
   Window [ [Screen] ( x1, y1 )-( x2, y2 ) ]

Parameters
   Screen
      Optional argument specifying y coordinates increase from top to 
      bottom.
   ( x1, y1 )-( x2, y2 )
      New floating point values corresponding to the opposite corners of 
      the current viewport.  If omitted, the Window coordinate mapping is 
      removed.

Description
   Window is used to define a new coordinates system. (x1, y1) and (x2, y2) 
   are the new coordinates to be mapped to the opposite corners of the 
   current viewport; all future coordinates passed to graphics primitive 
   statements will be affected by this new mapping. If Screen is omitted, 
   the new coordinates system will be Cartesian, that is, with y 
   coordinates increasing from bottom to top. Call Window with no argument 
   to disable the coordinates transformation.

   FreeBASIC's current behavior is to keep track of the corners of the 
   Window, rather than a specific coordinate mapping.  This means that the 
   coordinate mapping can change after calls to View.
   The Window corners are also currently taken into account when working on 
   image buffers, so when a Window is in effect, the coordinate mapping 
   will be different from image to image.

   When there is no Window in effect, there is no coordinate mapping in 
   effect, so the effective coordinate system is constant, independent of 
   image buffer sizes or View coordinates (if any).

Example
   '' The program shows how changing the view coordinates mapping for the current viewport changes the size of a figure drawn on the screen.
   '' The effect is one of zooming in and out:
   ''   - As the viewport coordinates get smaller, the figure appears larger on the screen, until parts of it are finally clipped,
   ''        because they lie outside the window.
   ''   - As the viewport coordinates get larger, the figure appears smaller on the screen.

   Declare Sub Zoom (ByVal X As Integer)
   Dim As Integer X = 500, Xdelta = 50

   Screen 12
   Do
     Do While X < 525 And X > 50
      X += Xdelta                      '' Change window size.
      Zoom(X)
      If Inkey <> "" Then Exit Do, Do  '' Stop if key pressed.
      Sleep 100
     Loop
     X -= Xdelta
     Xdelta *= -1                       '' Reverse size change.
   Loop

   Sub Zoom (ByVal X As Integer)
     Window (-X,-X)-(X,X)               '' Define new window.
     ScreenLock
     Cls
     Circle (0,0), 60, 11, , , 0.5, F   '' Draw ellipse with x-radius 60.
     ScreenUnlock
   End Sub

   Screen 13

   '' define clipping area
   View ( 10, 10 ) - ( 310, 150 ), 1, 15    

   '' set view coordinates
   Window ( -1, -1 ) - ( 1, 1 )             

   '' Draw X axis
   Line (-1,0)-(1,0),7
   Draw String ( 0.8, -0.1 ), "X"

   '' Draw Y axis
   Line (0,-1)-(0,1),7
   Draw String ( 0.1, 0.8 ), "Y"

   Dim As Single x, y, s

   '' compute step size (corresponds to a step of 1 pixel on x coordinate)
   s = 2 / PMap( 1, 0 )

   '' plot the function
   For x = -1 To 1 Step s
     y = x ^ 3
     PSet( x, y ), 14
   Next x

   '' revert to screen coordinates
   Window

   '' remove the clipping area
   View

   '' draw title
   Draw String ( 120, 160 ), "Y = X ^ 3"

   Sleep

Differences from QB
   * QBASIC preserves the coordinate mapping after subsequent calls to 
     VIEW.
   * FreeBASIC's current behavior is to preserve the WINDOW coordinates 
     after calls to VIEW, or when working on images, meaning that the 
     coordinate mapping may undergo scaling/translations. (If a WINDOW 
     hasn't been set, there is no coordinate mapping, and so it doesn't 
     change after calls to VIEW.)  The behavior may change in future, but 
     consistent behavior can be be assured over inconstent viewport 
     coordinates by re-calling WINDOW when you change the VIEW.

See also
   * Screen (Graphics)
   * View (Graphics)
   * PMap



------------------------------------------------------ KeyPgWindowtitle ----
WindowTitle

Sets the program window title

Syntax
   Declare Sub WindowTitle ( ByRef title As Const String )

Usage
   WindowTitle title

Parameters
   title
      the string to be assigned as new window title.

Description
   This statement is useful to change the program window title. The new 
   title set will become active immediately if the program already runs in 
   windowed mode, otherwise will become the new title for any window 
   produced by subsequent calls to the Screen (Graphics) or ScreenRes 
   statement. If this function is not called before setting a new windowed 
   mode via Screen (Graphics) or ScreenRes, the program window will use the 
   executable file name (without the extension) as title by default.
   This command has no effect in consoles.

Example
   'Set screen mode 
   Screen 13

   'Set the window title
   WindowTitle "FreeBASIC example program"

   Sleep

Platform Differences
   * Not present in DOS version / target of FreeBASIC

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Windowtitle.

Differences from QB
   * New to FreeBASIC

See also
   * ScreenControl (function SET_WINDOW_TITLE or GET_WINDOW_TITLE)
   * Screen (Graphics)
   * ScreenRes



----------------------------------------------------------- KeyPgWinput ----
Winput()

Reads a number of wide-characters from console or file

Syntax
   Declare Function WInput( ByVal num As Integer ) As WString
   Declare Function WInput( ByVal num As Integer, ByVal filenum As Long = 0 
   ) As WString

Usage
   result = WInput( num [, [#]filenum } )

Parameters
   num
      Number of characters to read.
   filenum
      File number of bound file or device.

Return Value
   Returns a WString of the characters read.

Description
   Reads a number of wide-characters from the console, or a bound 
   file/device specified by filenum.

   The first version waits for and reads n wide characters from the 
   keyboard buffer. Extended keys are not read. The characters are not 
   echoed to the screen.

   The second version waits for and reads n wide characters from a file or 
   device. The file position is updated.

   Note: FreeBASIC does not currently support reading wide-characters from 
   the console.

   Note: Using Winput() is dedicated to Input Access file mode, but it is 
   also allowed in Binary/Random Access file mode with some restrictions on 
   the values of num (for random mode, num must be equal to the record 
   length set by the LEN clause (or implicit value) in the OPEN statement).

Example
   Dim char As WString * 2

   Dim filename As String, enc As String
   Dim f As Long

   Line Input "Please enter a file name: ", filename
   Line Input "Please enter an encoding type (optional): ", enc
   If enc = "" Then enc = "ascii"

   f = FreeFile
   If Open(filename For Input Encoding enc As #f) = 0 Then
      
      Print "Press space to read a character from the file, or escape to exit."
      
      Do
         
         Select Case Input(1)
         
         Case " " 'Space
            
            If EOF(f) Then
               
               Print "You have reached the end of the file."
               Exit Do
               
            End If
            
            char = WInput(1, f)
            Print char & " (char no " & Asc(char) & ")"
            
         Case Chr(27) 'Escape
            
            Exit Do
            
         End Select
         
      Loop
      
      Close #f
      
   Else
      
      Print "There was an error opening the file."
      
   End If

Dialect Differences
   * Not available in the -lang qb dialect.

Differences from QB
   * QB does not support Unicode

See also
   * Input()
   * Open



------------------------------------------------------------- KeyPgWith ----
With

Statement block to allow implicit access to fields in a user defined type 
variable

Syntax
   With user_defined_var
      statements
   End With

Description
   The With...End With block allows the omission of the name of a variable 
   of a user-defined Type when referring to its fields. The fields may then 
   be accessed with just a single period (.) before them, e.g. if the Type 
   contains an field element called "element", then it could be accessed 
   within the With block as ".element".

   It can be used as a shorthand to save typing and avoid cluttering the 
   source.
   With can also be used with dereferenced pointers as the second example 
   shows, with temporary instances (with explicit or implicit constructor) 
   as the third example, and even with temporary types (without any 
   constructor), because destruction of such temporary instances/types is 
   deferred to the end of the With scope.
   But returns byref of functions from temporary instances/types taken as 
   arguments are not supported (and no error message).

   With blocks may be nested.  In this case, only the innermost With block 
   is active, and any outer ones are ignored until the inner one is closed 
   again.  See the third example for an illustration of this.

   Internally, the address of the variable is taken at the start of the 
   With block, and then is used to calculate any element accesses within 
   the block.
   Note that this means that Goto should not be used to jump into a With 
   block, otherwise the address will not have been set, and the results of 
   trying to access it will be undefined.

   Note for With block used inside member procedure:
   To access duplicated symbols defined as global outside the Type, add two 
   dots as prefix: "..SomeSymbol" (inside a With...End With block).

Example
   Type rect_type
      x As Single
      y As Single
   End Type

   Dim the_rectangle As rect_type
   Dim As Integer temp, t

   With the_rectangle
      temp = .x
      .x = 234 * t + 48 + .y
      .y = 321 * t + 2
   End With

   Type rect_type
      x As Single
      y As Single
   End Type

   Dim the_rectangle As rect_type Ptr

   the_rectangle = CAllocate( 5 * Len( rect_type ) )

   Dim As Integer loopvar, temp, t

   For loopvar = 0 To 4

     With the_rectangle[loopvar]  '' dereferenced pointer

      temp = .x
      .x = 234 * t + 48 + .y
      .y = 321 * t + 2

     End With

   Next

   Type rect_type
      x As Single
      y As Single
      Declare Constructor()
      Declare Constructor(ByVal x0 As Single, ByVal y0 As Single)
   End Type

   Constructor rect_type()
   End Constructor

   Constructor rect_type(ByVal x0 As Single, ByVal y0 As Single)
      This.x = x0
      This.y = y0
   End Constructor

   Dim the_rectangle As rect_type

   With rect_type(1, 2)  '' temporary instance created here held up to 'End With'
      the_rectangle.x = .x + .y  '' 1 + 2 = 3
      the_rectangle.y = .x - .y  '' 1 - 2 = -1
   End With

   Type rect_type
      x As Single
      y As Single
   End Type

   Dim As rect_type rect1, rect2

   '' Nested With blocks
   With rect1

      .x = 1
      .y = 2

      With rect2

         .x = 3
         .y = 4

      End With

   End With

   Print rect1.x, rect1.y '' 1,  2
   Print rect2.x, rect2.y '' 3,  4

Version
   * Before fbc 1.10.0, temporary types (without any constructor) were not 
     supported (because destruction of such temporary types was called 
     immediately after the With statement).

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __With.
   * In the -lang qb and -lang fblite dialects, variables declared inside 
     a With..End With block have a function-wide scope as in QB.
   * In the -lang fb and -lang deprecated dialects, variables declared 
     inside a With..End With block are visible only inside the block, and 
     can't be accessed outside it.

Differences from QB
   * New to FreeBASIC

See also
   * Type



------------------------------------------------------------- KeyPgWoct ----
WOct

Converts a number to a Unicode octal representation

Syntax
   Declare Function WOct ( ByVal number As UByte ) As WString
   Declare Function WOct ( ByVal number As UShort ) As WString
   Declare Function WOct ( ByVal number As ULong ) As WString
   Declare Function WOct ( ByVal number As ULongInt ) As WString
   Declare Function WOct ( ByVal number As Const Any Ptr ) As WString

   Declare Function WOct ( ByVal number As UByte, ByVal digits As Long ) As 
   WString
   Declare Function WOct ( ByVal number As UShort, ByVal digits As Long ) As
   WString
   Declare Function WOct ( ByVal number As ULong, ByVal digits As Long ) As 
   WString
   Declare Function WOct ( ByVal number As ULongInt, ByVal digits As Long ) 
   As WString
   Declare Function WOct ( ByVal number As Const Any Ptr, ByVal digits As 
   Long ) As WString

Usage
   result = WOct( number [, digits ] )

Parameters
   number
      Number to convert to octal representation.
   digits
      Desired number of digits in the returned string.

Return Value
   The Unicode octal representation of the number, truncated or padded with 
   zeros ("0") to fit the number of digits, if specified.

Description
   Returns the octal WString (Unicode) representation of number. Octal 
   digits range from 0 to 7.

   If you specify digits > 0, the result string will be exactly that 
   length.  It will be truncated or padded with zeros on the left, if 
   necessary.

   The length of the returned string will not be longer than the maximum 
   number of digits required for the type of number (3 characters for Byte, 
   6 for Short, 11 for Long, and 22 for LongInt)

Example
   Print WOct(54321)
   Print WOct(54321, 4)
   Print WOct(54321, 8)

   will produce the output:

   152061
   2061
   00152061

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Woct.

Platform Differences
   * Unicode strings are not supported in the DOS port of FreeBASIC.

Differences from QB
   * In QBASIC Unicode was not supported.

See also
   * WBin
   * WHex



------------------------------------------------------------ KeyPgWrite ----
Write

Outputs a comma-separated list of values to the screen

Syntax
   Write [ expressionlist ]

Parameters
   expressionlist
      Comma-separated list of items to print

Description
   Outputs the values in expressionlist to the screen. The values are 
   separated with commas, and strings are enclosed in double quotes. 
   Numeric values with an absolute value of less than one are prefixed with 
   a zero (0) if none is given (e.g. 0.5, -0.123).  Floating-point numbers 
   with absolute values greater than or equal to 10^16, or with absolute 
   values greater than 0 and less than 10^-5 are printed in scientific 
   notation (e.g. 1.8e+019, 3e-005)

   If no expression list is given, Write outputs a carriage return.

Example

   Dim i As Integer = 10
   Dim d As Double = 123.456
   Dim s As String = "text"

   Write 123, "text", -.45600
   Write
   Write i, d, s

   will produce the output:


   123,"text",-0.456

   10,123.456,"text"

Differences from QB
   * QBASIC might print format floating-point values in slightly different 
     ways.

See also
   * Write #
   * Print
   * ?



---------------------------------------------------------- KeyPgWritePp ----
Write #

Outputs a comma-separated list of values to a text file or device

Syntax
   Write # filenum , [ expressionlist ]

Parameters
   filenum
      File number of an open file or device opened for Output or Append.
   expressionlist
      Comma-separated list of items to print

Description
   Outputs the values in expressionlist to the text file or device bound to 
   filenum. The values are separated with commas, and strings are enclosed 
   in double quotes. Numeric values greater than zero (0) and less than one 
   (1) are prefixed with a zero (0) if none is given (e.g., a value of 
   -.123 will be output as -0.123). Extra zeroes are truncated.

   If no expression list is given, Write # outputs a carriage return (note 
   that the comma after filenum is still necessary, even if no expression 
   list is given).
   The purpose of Write # is to create a file that can be read back by 
   using Input #.

   Note:
      - Using Write # is naturally dedicated to Output/Append Access file 
      mode.
      - It is also allowed in Binary/Random Access file mode, but this was 
      never well tested and results may vary.

Example

   Const filename As String = "file.txt"

   Dim filenum As Integer = FreeFile()
   If 0 <> Open(filename, For Output, As filenum) Then
      Print "error opening " & filename & " for output."
      End -1
   End If

   Dim i As Integer = 10
   Dim d As Double = 123.456
   Dim s As String = "text"

   Write #filenum, 123, "text", -.45600
   Write #filenum,
   Write #filenum, i, d, s

   will produce the file:


   123,"text",-0.456

   10,123.456,"text"

Differences from QB
   * None

See also
   * Write
   * Print #
   * ? #
   * Input #



-------------------------------------------------------- KeyPgWriteFile ----
Write (File Access)

File access specifier

Syntax
   Open filename As String For Binary Access Write As #filenum As Integer

Description
   Specifier for the Access clause in the Open statement.  Write specifies 
   that the file is accessible for output.

Example
   See example at Access

Differences from QB
   * None known.

See also
   * Access
   * Open



----------------------------------------------------------- KeyPgWspace ----
WSpace

Creates a WString of a given length filled with spaces (" ")

Syntax
   Declare Function WSpace( ByVal count As Integer ) As WString

Usage
   result = WSpace( count )

Parameters
   count
      An integer type specifying the length of the string to be created.

Return Value
   The created WString. An empty string will be returned if count <= 0.

Description
   WSpace creates a wstring (wide character string- Unicode) with the 
   specified number of spaces.

Example
   Dim a As WString * 10
   a = "x" + WSpace(3) + "x"
   Print a ' prints: x   x

Platform Differences
   * Unicode strings are not supported in the DOS port of FreeBASIC.

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Wspace.

Differences from QB
   * New to FreeBASIC

See also
   * Space
   * WString



------------------------------------------------------------- KeyPgWstr ----
WStr

Returns a wide-character string representation of a number or ASCII 
character string

Syntax
   Declare Function WStr ( ByVal n As Byte ) As WString
   Declare Function WStr ( ByVal n As UByte ) As WString
   Declare Function WStr ( ByVal n As Short ) As WString
   Declare Function WStr ( ByVal n As UShort ) As WString
   Declare Function WStr ( ByVal n As Long ) As WString
   Declare Function WStr ( ByVal n As ULong ) As WString
   Declare Function WStr ( ByVal n As LongInt ) As WString
   Declare Function WStr ( ByVal n As ULongInt ) As WString
   Declare Function WStr ( ByVal n As Single ) As WString
   Declare Function WStr ( ByVal n As Double ) As WString
   Declare Function WStr ( ByRef str As Const String ) As WString
   Declare Function WStr ( ByVal str As Const WString Ptr ) As WString

Usage
   result = WStr( number )
      or
   result = WStr( string )

Parameters
   number
      Numeric expression to convert to a wide-character string.
   string
      String expression to convert to a wide-character string.

Return Value
   Returns the wide-character representation of the numeric or string 
   expression.

Description
   WStr converts numeric variables to their wide-character string 
   representation. It is the wide-character equivalent to Str.

   WStr also converts ASCII character strings to Unicode character strings. 
   If a wide-character string is given, that string is returned unmodified.

Example
   #if defined( __FB_WIN32__ )
   #include "windows.bi"
   #endif

   Dim zs As ZString * 20
   Dim ws As WString * 20

   zs = "Hello World"
   ws = WStr(zs)

   #if defined( __FB_WIN32__ )

   MessageBox(null, ws, WStr("Unicode 'Hello World'"), MB_OK Or MB_ICONINFORMATION)

   #else

   Print ws
   Print WStr("Unicode 'Hello World'")

   #endif

Platform Differences
   * DOS does not support WStr.

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Wstr.

Differences from QB
   * New to FreeBASIC

See also
   * Str
   * WString



---------------------------------------------------------- KeyPgWstring ----
WString

Standard data type: wide character string

Syntax
   Dim variable As WString * size
   Dim variable As WString Ptr

Description
   A WString is a fixed-size array of wide-chars that never overflows if 
   the size is known at compile-time. It has no descriptor, and does never 
   resize unless it's a pointer and Allocate/Reallocate/Deallocate are used 
   directly. When the variable has a fixed size (numeric constant, or 
   expression that can be evaluated at compile time), FreeBASIC avoids any 
   overflow that could occur on assignment, by truncating the contents to a 
   length of size - 1.

   The end of the string is marked by the character 0 automatically added 
   by the FreeBASIC string handling functions, so that character must never 
   be part of a WString or the content will be truncated. The character 0 
   will be appended when the string is created, and the length will be 
   calculated by scanning the string for the first null character.

   In a WString, Len returns the size of the contained string and SizeOf 
   returns the space allocated to the WString.  SizeOf only works if the 
   size is known by the compiler, i.e. a fixed-size WString variable is 
   passed directly, not as a dereferenced pointer or a ByRef function 
   argument.

   This type is provided for support non-Latin based alphabets. Any 
   intrinsic string function like Left will work with WStrings too, as will 
   any string operator.

   When processing source files, FreeBASIC can parse ASCII files with 
   Unicode escape sequences (\u),  or UTF-8, UTF-16LE, UTF-16BE, UTF-32LE 
   and UTF-32BE files, as long as they were saved with Byte Order Mark 
   (BOM).
   Note: The most reliable cross-platform code is obtained by encoding 
   without BOM in ASCII/UTF-8 characters.

   The FreeBASIC text file functions can read and write Unicode files in 
   different encodings, provided the Encoding is specified when the file is 
   opened. The text is automatically converted to the internal encoding at 
   read and converted back to the file encoding at write.

   SizeOf( WString ) returns the number of bytes used by a WString 
   character in the current platform.

   When allocating dynamic memory for a WString, the safest is to use 
   CAllocate (or at worst, to use Allocate followed by an immediate 
   assignment of the string data, as in the second example), in order to 
   avoid creating string data without any null character (the terminal 
   character for a WString).

   Note : When any operand of a binary operator (as assignment, equal, +, 
   *, ...) consists in dereferencing a 'Wstring Ptr' pointer ('pw'), this 
   can give a 'Wstring' string or a 'Numeric' variable, depending on the 
   other operand. If the other operand is numeric, so the dereferenced '
   Wstring Ptr' pointer ('*pw') will be treated as a 'Numeric' reference to 
   the one character pointed. If a 'Wstring' pointer indexing '[]' operator 
   is used as dereferencing syntax ('pw[n]'), it is basically a short-cut 
   version of the 'String' indexing '[]' operator ('(*pw)[n]').

Example
   Dim As WString * 13 str1 => "hello, world"
   Print str1
   Print Len(str1)    'returns 12, the length of the string it contains 
   Print SizeOf(str1) 'returns 13 * sizeof(wstring), the number of bytes used by the variable

   Dim As WString Ptr str2
   str2 = Allocate( 13 * Len(WString) )
   *str2 = "hello, world"
   Print *str2
   Print Len(*str2)      'returns 12, the length of the string it points to

Platform Differences
   Support for wstrings relies in the C runtime library available in the 
   platform and the internal format may vary.
      * Unicode is not supported in the DOS port of FreeBASIC. In this 
        port a character takes up always 1 byte and Wstrings will behave as 
        standard ASCII Zstrings
      * On Win32, FreeBASIC wstrings are encoded in UCS-2 which uses two 
        bytes (16 bits) for each character and, as such, can only encode 
        the first 65,536 code points of Unicode, that is, the Basic 
        Multilingual Plane (BMP). FreeBASIC does not support Win32 UTF-16 
        4-byte surrogate encoding beyond the BMP.
      * On Linux wstrings are encoded in UCS-4 and a character takes up 4 
        bytes.

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Wstring.

Differences from QB
   * New to FreeBASIC

See also
   * String (data type)
   * ZString (data type)
   * String (function)
   * WString (function)
   * WSpace
   * WStr
   * WChr
   * WBin
   * WHex
   * WOct
   * Winput()
   * Standard Data Type Limits
   * Extends Wstring



-------------------------------------------------- KeyPgWstringFunction ----
Wstring (Function)

Fills a WString with a certain length of a certain wide character

Syntax
   Declare Function WString ( ByVal count As Integer, ByVal ch_code As Long 
   ) As WString
   Declare Function WString ( ByVal count As Integer, ByRef ch As Const 
   WString ) As WString

Usage
   result = WString( count, ch_code )
      or
   result = WString( count, ch )

Parameters
   count
      An Integer specifying the length of the string to be created.
   ch_code
      A Long specifying the Unicode char to be used to fill the string.
   ch
      A WString whose first character is to be used to fill the string.

Return Value
   The created WString. An empty string will be returned if either ch is an 
   empty string, or count <= 0.

Description
   WString generates a temporary WString filled with count copies of a 
   Unicode character. This string can be printed or assigned to a 
   previously Dimed WString.

Example
   Print WString( 4, 934 )         
   Print WString( 5, WStr("Indeed") )   
   End 0

   &#934;&#934;&#934;&#934;
   IIIII
   
Platform Differences
   * Unicode strings are not supported in the DOS port of FreeBASIC.

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Wstring.

Differences from QB
   * QBasic does not support Unicode

See also
   * String (data type)
   * WSpace
   * WString (data type)




============================================================================
    X

------------------------------------------------------------ KeyPgOpXor ----
Operator Xor (Exclusive Disjunction)

Returns the bitwise-xor (exclusive disjunction) of two numeric values

Syntax
   Declare Operator Xor ( ByRef lhs As T1, ByRef rhs As T2 ) As Ret

Usage
   result = lhs Xor rhs

Parameters
   lhs
      The left-hand side expression.
   T1
      Any numeric or boolean type.
   rhs
      The right-hand side expression.
   T2
      Any numeric or boolean type.
   Ret
      A numeric or boolean type (varies with T1 and T2).

Return Value
   Returns the bitwise-xor of the two operands.

Description
   This operator returns the bitwise-exclusion of its operands, a logical 
   operation that results in a value with bits set depending on the bits of 
   the operands (for conversion of a boolean to an integer, false or true 
   boolean value becomes 0 or -1 integer value).

   The truth table below demonstrates all combinations of a 
   boolean-exclusion operation:

      +-------+-------+------+
      |Lhs Bit|Rhs Bit|Result|
      |0      |0      |0     |
      |1      |0      |1     |
      |0      |1      |1     |
      |1      |1      |0     |
      +-------+-------+------+

   No short-circuiting is performed - both expressions are always 
   evaluated.

   The return type depends on the types of values passed. Byte, UByte and 
   floating-point type values are first converted to Integer. If the left 
   and right-hand side types differ only in signedness, then the return 
   type is the same as the left-hand side type (T1), otherwise, the larger 
   of the two types is returned. Only if the left and right-hand side types 
   are both Boolean, the return type is also Boolean.

   This operator can be overloaded for user-defined types.

Example
   ' Using the XOR operator on two numeric values
   Dim As UByte numeric_value1, numeric_value2
   numeric_value1 = 15 '00001111
   numeric_value2 = 30 '00011110

   'Result =  17  =     00010001
   Print numeric_value1 Xor numeric_value2
   Sleep

   ' Using the XOR operator on two conditional expressions
   Dim As UByte numeric_value1, numeric_value2
   numeric_value1 = 10
   numeric_value2 = 15

   If numeric_value1 = 10 Xor numeric_value2 = 20 Then Print "Numeric_Value1 equals 10 or Numeric_Value2 equals 20"
   Sleep

   ' This will output "Numeric_Value1 equals 10 or Numeric_Value2 equals 20"
   ' because only the first condition of the IF statement is true

Dialect Differences
   * In the -lang qb dialect, this operator cannot be overloaded.

Differences from QB
   * None

See also
   * Operator Truth Tables



----------------------------------------------------------- KeyPgXorGfx ----
Xor (Graphics Put)

Parameter to the Put graphics statement which uses a bit-wise Xor as the 
blitting method

Syntax
   Put [ target, ] [ STEP ] ( x,y ), source [ ,( x1,y1 )-( x2,y2 ) ], Xor

Parameters
   Xor
      Required.

Description
   The Xor method combines each source pixel with the corresponding 
   destination pixel, using the bit-wise Xor function.  The result of this 
   is output as the destination pixel.
   This method works in all graphics modes.  There is no mask color, 
   although color values of 0 (RGBA(0, 0, 0, 0) in full-color modes) will 
   have no effect, because of the behavior of Xor.

   In full-color modes, each component (red, green, blue and alpha) is kept 
   in a discrete set of bits, so the operation can be made to only affect 
   some of the channels, by making sure the all the values of the other 
   channels are set to 0.

Example
   ''open a graphics window
   ScreenRes 320, 200, 16

   ''create a sprite containing a circle
   Const As Integer r = 32
   Dim c As Any Ptr = ImageCreate(r * 2 + 1, r * 2 + 1, 0)
   Circle c, (r, r), r, RGBA(255, 255, 255, 0), , , 1, f

   ''put the three sprites, overlapping each other in the middle
   Put (146 - r, 108 - r), c, Xor
   Put (174 - r, 108 - r), c, Xor
   Put (160 - r,  84 - r), c, Xor

   ''free the memory used by the sprite
   ImageDestroy c

   ''pause the program before closing
   Sleep

Differences from QB
   * None

See also
   * Xor
   * Put (Graphics)




============================================================================
    Y

------------------------------------------------------------- KeyPgYear ----
Year

Gets the year from a Date Serial

Syntax
   Declare Function Year ( ByVal date_serial As Double ) As Long

Usage
   #include "vbcompat.bi"
   result = Year( date_serial )

Parameters
   date_serial
      the date

Return Value
   Returns the year from a  variable containing a date in  Date Serial  
   format. 

Description

   The compiler will not recognize this function unless vbcompat.bi is 
   included.

Example
   #include "vbcompat.bi"

   Dim a As Double = DateSerial (2005, 11, 28) + TimeSerial(7, 30, 50)

   Print Format(a, "yyyy/mm/dd hh:mm:ss "); Year(a)

Differences from QB
   * Did not exist in QB. This function appeared in PDS and VBDOS

See also
   * Date Serials




============================================================================
    Z

---------------------------------------------------------- KeyPgZstring ----
ZString

Standard data type: 8 bit character string

Syntax
   Dim variable As ZString * size
   Dim variable As ZString Ptr

Description
   A ZString is a C-style fixed-size array of chars.  It has no descriptor 
   so its length is calculated faster to pass it as an argument to 
   functions. When the variable has a fixed size (numeric constant, or 
   expression that can be evaluated at compile time), FreeBASIC avoids any 
   overflow that could occur on assignment, by truncating the contents to a 
   length of size - 1.

   A ZString Ptr can point to a standard ZString, also can be used to 
   implement an "user-managed" ZString, in this case Allocate/Reallocate/
   Deallocate must be used to size-resize-dispose it and is up  to the user 
   to avoid overflows . 

   The end of the string is marked by a null character (0 ASCII). This is 
   automatically added by the FreeBASIC string handling functions.  A null 
   character will be appended when the string is created, and the length 
   will be calculated by scanning the string for the first null character. 
   A null character (e.g. Chr(0)) may never be contained in the text of a 
   ZString or the rest of the string will be truncated.

   In a ZString, Len returns the size of the contained string and SizeOf 
   returns the space allocated to the ZString.  SizeOf only works if the 
   size is known by the compiler, i.e. a fixed-size ZString variable is 
   passed directly, not as a dereferenced pointer or a ByRef function 
   argument.

   Any intrinsic string functions like Left will work with ZString's too, 
   plus any string operator.

   This type is provided for easy interfacing with C libraries and to also 
   replace the fixed-length strings, that can't be managed through 
   pointers.
   Any string type argument may be directly passed to a procedure referring 
   to a parameter declared as ZString Ptr. The compiler performs itself an 
   automatic conversion (without warning message) between any string type 
   argument and the ZString Ptr type parameter.

   When allocating dynamic memory for a ZString, the safest is to use 
   CAllocate (or at worst, to use Allocate followed by an immediate 
   assignment of the string data, as in the second example), in order to 
   avoid creating string data without any null character (the terminal 
   character for a ZString).

   Note : When any operand of a binary operator (as assignment, equal, +, 
   *, ...) consists in dereferencing a 'Zstring Ptr' pointer ('pz'), this 
   can give a 'Zstring' string or a 'Ubyte' variable, depending on the 
   other operand. If the other operand is numeric, so the dereferenced '
   Zstring Ptr' pointer ('*pz') will be treated as a 'Ubyte' reference to 
   the one character pointed. If a 'Zstring' pointer indexing '[]' operator 
   is used as dereferencing syntax ('pz[n]'), it is basically a short-cut 
   version of the 'String' indexing '[]' operator ('(*pz)[n]').

Example
   Dim As ZString * 13 str1 => "hello, world"
   Print str1
   Print Len(str1)     'returns 12, the size of the string it contains 
   Print SizeOf(str1)  'returns 13, the size of the variable

   Dim As ZString Ptr str2
   str2 = Allocate( 13 )
   *str2 = "hello, world"
   Print *str2
   Print Len(*str2)     'returns 12, the size of the string it contains 

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Zstring.

Differences from QB
   * New to FreeBASIC

See also
   * String
   * WString
   * Standard Data Type Limits
   * Extends Zstring



---------------------------------------------------------- CatPgOpIndex ----
Operator List

List of operators used in FreeBASIC.

Assignment Operators
   * =[>] (Assignment)
   * &= (Concatenate And Assign)
   * += (Add And Assign)
   * -= (Subtract And Assign)
   * *= (Multiply And Assign)
   * /= (Divide And Assign)
   * \= (Integer Divide And Assign)
   * ^= (Exponentiate And Assign)
   * Mod= (Modulus And Assign)
   * And= (Conjunction And Assign)
   * Eqv= (Equivalence And Assign)
   * Imp= (Implication And Assign)
   * Or= (Inclusive Disjunction And Assign)
   * Xor= (Exclusive Disjunction And Assign)
   * Shl= (Shift Left And Assign)
   * Shr= (Shift Right And Assign)
   * Let (Assign)
   * Let() (Assignment)

Type Cast Operators
   * Cast (Operator)
   * CPtr

Arithmetic Operators
   * + (Add)
   * - (Subtract)
   * * (Multiply)
   * / (Divide)
   * \ (Integer Divide)
   * ^ (Exponentiate)
   * Mod (Modulus)
   * - (Negate)
   * Shl (Shift Left)
   * Shr (Shift Right)

Indexing Operators
   * () (Array Index)
   * [] (String Index)
   * [] (Pointer Index)

String Operators
   * + (String Concatenation)
   * & (String Concatenation With Conversion)
   * Strptr (String Pointer)
Relational Operators
   * = (Equal)
   * <> (Not Equal)
   * < (Less Than)
   * <= (Less Than Or Equal)
   * >= (Greater Than Or Equal)
   * > (Greater Than)

Bitwise Operators
   * And (Conjunction)
   * Eqv (Equivalence)
   * Imp (Implication)
   * Not (Complement)
   * Or (Inclusive Disjunction)
   * Xor (Exclusive Disjunction)

Short Circuit Operators
   * Andalso (Short Circuit Conjunction)
   * Orelse (Short Circuit Inclusive Disjunction)

Preprocessor Operators
   * # (Argument Stringize)
   * ## (Argument Concatenation)
   * ! (Escaped String Literal)
   * $ (Non-Escaped String Literal)

Pointer Operators
   * @ (Address Of)
   * * (Value Of)
   * Varptr (Variable Pointer)
   * Procptr (Procedure Pointer And Vtable Index)

Type or Class Operators
   * . (Member Access)
   * -> (Pointer To Member Access)
   * Is (Run-Time Type Information Operator)

Memory Operators
   * New Expression
      * New Overload
   * Placement New
   * Delete Statement
      * Delete Overload

Iteration Operators
   * For, Next, and Step




============================================================================
    Variables and Data Types

-------------------------------------------------------- CatPgVariables ----
Variable Declarations

Statements to declare and allocate space for variables.

Dim
   Declares a variable at the current scope.
Const
   Declares a non-modifiable variable.
Scope
   Begins a new scope block.
Static
   Declares variables in a procedure that retain their value between calls.
Shared
   Used with Dim allows variables to be visible throughout a module.
Var
   Declares variables where the data type is implied from an initializer.
Byref (Variables)
   Used with Dim or Static or Var allows to declare references.



----------------------------------------------------- CatPgUserDefTypes ----
User Defined Types

Declaration
   Declaring and describing user defined types
Referencing
   Accessing data in a user defined type
Member Procedures
   Declaring and defining methods related to a user defined type
Member Access Control
   Controlling when data and member procedures are accessed

Declarations
   Enum...End Enum
      User defined enumeration of values
   Type...End Type
      User defined structure of non overlapping data and member procedures
   Class...End Class
      Not implemented.  Keyword reserved.
   Union...End Union
      User defined structure of overlapping data
   Extends
      Extends an user defined type to derive another
   Extends Wstring
      Extends an user defined type to inherits Wstring behavior
   Extends Zstring
      Extends an user defined type to inherits Zstring behavior
   Implements
      Not implemented.  Keyword reserved.
   Field
      Specifies field alignment within a user defined type
   Object
      Built-in type providing run-time type information

Referencing
   Temporary Types
      Creates a temporary copy of a user defined type
   This
      Built-in, hidden, parameter passed to non-static member procedures to 
      access the user defined type instance
   Base (Member Access)
      Built-in, hidden, variable to access the base user defined type 
      instance in derived user defined types
   Type Alias
      Declares a user defined type from other user defined or standard data 
      types
   With
      Compound statement to access the data and members of a user defined 
      type

Member Procedures
   Base (Initialization)
      Specifies an initializer for the base user defined type in derived 
      user defined type constructors
   Constructor
      Declares or defines a member procedure that is automatically called 
      when a user defined type is created
   Destructor
      Declares or defines a member procedure that is automatically called 
      when a user defined type is destroyed or goes out of scope
   Function
      Declares or defines a member procedure returning a value
   Operator
      Declares or defines an overloaded operator
   Override
      Member method attribute that specifies that the method is expected to 
      override a virtual method in the base user defined type
   Property
      Declares or defines property member procedures for a user defined 
      type
   Sub
      Declare or defines a member procedure
   Static (Member)
      Declares or defines a member procedure or variable is static
   Virtual
      Member method attribute that declares that a member must have an 
      implementation
   Abstract
      Member method attribute that declares that a member must be 
      implemented in a derived user defined type
   Const (Member)
      Member method attribute that declares or defines that the method is 
      readonly and does not modify the user defined types's data

Member Access Control
   Public: (Access Control)
      Data and members in a user defined type have public visibility
   Private: (Access Control)
      Data and members in a user defined type have private visibility
   Protected: (Access Control)
      Data and members in a user defined type have protected visibility



----------------------------------------------------- CatPgStdDataTypes ----
Standard Data Types

Built-in data types

Integer types
   Types that store integer values, whose range is determined by the size 
   of the data type and its signedness.
Floating-point types
   Types that store real number values, whose range and precision is 
   determined by the size of the data type.
Boolean types
   Types that store boolean values.
Procedure Types
   Types that store pointers to procedures
Data Type Modifiers
   Specifies additional characteristics of a standard or user-defined data 
   type.
String types
   Types that store or point to an array of characters.
Class types
   Types that provide special capabilities to be used directly or to be 
   extended by user-defined types

Integer types
   Byte and UByte
      8-bit wide data types that store integer values.
   Short and UShort
      16-bit wide data types that store integer values.
   Long and ULong
      32-bit wide data types that store integer values.
   Integer and UInteger
      32-bit or 64-bit wide data types that store integer values.
   LongInt and ULongInt
      64-bit wide data types that store integer values.

Floating-point types
   Single
      32-bit wide data types that store real number values.
   Double
      64-bit wide data types that store real number values.

Boolean types
   Boolean
      1-bit wide data types that store boolean values.

Procedure Types
   Function Pointer
      Types that store a pointer to a function procedure
   Sub Pointer
      Types that store a pointer to a sub procedure
Data Type Modifiers
   Const
      Specifies a read only type.
   Pointer and Ptr (Shortcut For 'Pointer')
      Modifies types to be pointer types.
   Unsigned
      Specifies an unsigned integer type.
   Alias (Modifier)
      Modifies how a datatype is linked with other languages (Name 
      mangling).

String types
   String
      Fixed-length and variable-length strings with built-in memory 
      management.
   ZString
      Fixed-length and variable-length null-terminated strings.
   WString
      Fixed-length and variable-length null-terminated strings of wide 
      characters.

Class types
   Object
      Super class providing run-time type information

See also
   * Variable types and limits
   * Pointers to Procedures



----------------------------------------------------------- TblVarTypes ----
Standard Data Type Limits

Standard variable types and limits.

Numeric Types

         +---------+--------------+-----------------+--------------------------------------------------+---------------------------------------------------+----------------+-------------+
         | Type    | Size in bits | Format          | Minimum Value                                    | Maximum Value                                     | Literal Suffix | Sig. Digits |
         | BYTE    | 8            | signed   integer|-128                                              |+127                                               |                |2+           |
         |UBYTE    | 8            | unsigned integer|0                                                 |+255                                               |                |2+           |
         |SHORT    |16            |signed   integer |-32768                                            |+32767                                             |                |4+           |
         |USHORT   |16            | unsigned integer|0                                                 |65535                                              |                |4+           |
         |LONG     |32            |signed   integer |-2147483648                                       |+2147483647                                        |&, l            |9+           |
         |ULONG    | 32           |unsigned integer |0                                                 |+4294967295                                        |ul              |9+           |
         |INTEGER  |32/64 [*]     | signed   integer|[*]32bit: -2147483648, 64bit: -9223372036854775808|[*]32bit: +2147483647, 64bit: +9223372036854775807 |%               |[*]          |
         |UINTEGER |32/64 [*]     | unsigned integer|0                                                 |[*]32bit: +4294967295, 64bit: +18446744073709551615|u               |[*]          |
         |LONGINT  | 64           |signed   integer |-9223372036854775808                              |+9223372036854775807                               |ll              |18+          |
         | ULONGINT|64            |unsigned integer |0                                                 |+18446744073709551615                              | ull            |19+          |
         |SINGLE   | 32           |floating point   |[**]+/-1.401 298 E-45                             |[**]+/-3.402 823 E+38                              |!, f            |6+           |
         |DOUBLE   |64            | floating point  |[**]+/-4.940 656 458 412 465 E-324                |[**]+/-1.797 693 134 862 316 E+308                 |#, d            |15+          |
         |enums    |32/64 [*]     | signed integer  |[*]32bit: -2147483648, 64bit: -9223372036854775808|[*]32bit: +2147483647, 64bit: +9223372036854775807 |                |[*]          |
         +---------+--------------+-----------------+--------------------------------------------------+---------------------------------------------------+----------------+-------------+

   [*] Integer and UInteger data types vary with platform, matching the 
   size of pointers.
   [**] The minimum and maximum values for the floating-point types Single 
   and Double are, respectively, the values closest to zero and the values 
   closest to positive and negative infinity.

String Types

         +-----------+---------------------------+------------------------------+-------------------------------------------------------------+----------------+
         |Type       | Character Size (in bytes) | Minimum Size (in characters) | Maximum Size (in characters), including terminating padding | Literal Suffix |
         | String    | 1                         | 0                            | [**]32bit: +2147483647, 64bit: +9223372036854775807         | $              |
         | String*N  | 1                         | 1                            | [**,***]+2147483647                                         | $              |
         | Zstring*N | 1                         | 1                            | [**,***]+2147483647                                         | [N/A]          |
         | Wstring*N | [*]                       | [*]1                         | [*,**,***]+2147483647                                       | [N/A]          |
         +-----------+---------------------------+------------------------------+-------------------------------------------------------------+----------------+

   [*] Unicode, or "wide", characters vary in both size and availability 
   with platform.
   [**] All runtime library string procedures take and produce Integer 
   values for sizes and positions. The actual maximum size will vary 
   (smaller) with storage location and/or platform.
   [***] Before fbc version 1.20.0, fixed-length strings had the same 
   maximum size limits as variable strings.

Boolean Type

         +---------+-----------------------------+-------------------+
         | Type    | Internal size in bits       | Value             |
         | Boolean | 1-bit wide data (in a Byte) | 'False' or 'True' |
         +---------+-----------------------------+-------------------+

Arrays

         +---------+-------------------------------------------------+--------------------------------+----------------------------+-------------------------+
         |Platform | Maximum Subscript Range                         | Maximum Elements per Dimension | Minimum/Maximum Dimensions | Maximum Size (in bytes) |
         | 32bit   | [*][-2147483648, +2147483647]                   | [*]+2147483647                 | 1/8                        | [*]+2147483647          |
         | 64bit   | [*][-9223372036854775808, +9223372036854775807] | [*]+9223372036854775807        | 1/8                        | [*]+9223372036854775807 |
         +---------+-------------------------------------------------+--------------------------------+----------------------------+-------------------------+

   [*] All runtime library array procedures take and produce Integer values 
   for subscripts and indexes. The actual limits will vary (smaller) with 
   the number of dimensions, element size, storage location and/or 
   platform.

UDTs

         +---------+-------------------------+
         |Platform | Maximum Size (in bytes) |
         | 32bit   | [*]+2147483647          |
         | 64bit   | [*]+2147483647          |
         +---------+-------------------------+

   [*] The actual maximum size will vary (smaller) with storage location 
   and/or platform.

See also
   Usage of suffixes for variables
   Usage of suffixes for literals / numbers



---------------------------------------------------------- CatPgCasting ----
Converting Data Types

Operators and procedures that convert between different types.

Generic conversions
   Operators to convert between arbitrary types.
Conversions to integral types
   Operators to convert to integral types.
Conversions to floating-point types
   Operators to convert to floating-point types.
Conversions to/from string types
   Operators to convert top an from string types.
Conversion to boolean types
   Operators to convert to boolean types.

Generic conversions
   Cast and CPtr
      Converts expressions between different types.

Conversions to integral types
   CByte and CUByte
      Converts numeric expressions to 8-bit values.
   CShort and CUShort
      Converts numeric expressions to 16-bit values.
   CLng and CULng
      Converts numeric expressions to 32-bit values.
   CInt and CUInt
      Converts numeric expressions to 32-bit or 64-bit values.
   CLngInt and CULngInt
      Converts numeric expressions to 64-bit values.
   CSign
      Converts a numeric expression to a signed-type value.
   CUnsg
      Converts a numeric expression to an unsigned-type value.
Conversions to floating-point types
   CSng and CDbl
      Converts a numeric or string expression to floating-point values.

Conversions to/from string types
   Str and WStr
      Converts numeric expressions or booleans to their string 
      representation.
   Val
      Converts a numeric string expression to a floating-point value.
   ValInt and ValUInt
      Converts numeric string expressions to integer values.
   ValLng and ValULng
      Converts numeric string expressions to long values.

Conversion to boolean types
   CBool
      Converts a numeric or string expression to a boolean value.




============================================================================
    Assignment operators

----------------------------------------------------- KeyPgOpAssignment ----
Operator =[>] (Assign)

Assigns a value to a variable

Syntax
   Declare Operator Let ( ByRef lhs As T1, ByRef rhs As T2 )

Usage
   lhs = rhs
      or
   lhs => rhs

         or, in the QB dialect,

   [ Let ] lhs = rhs
      or
   [ Let ] lhs => rhs

Parameters
   lhs
      The variable to assign to.
   T1
      Any numeric, boolean, string or pointer type.
   rhs
      The value to assign to lhs.
   T2
      Any type convertible to T2.

Description
   This operator assigns the value of its right-hand side operand (rhs) to 
   its left-hand side operand (lhs). The right-hand side operand must be 
   implicitly convertible to the left-hand side type (T1) (for conversion 
   of a boolean to an integer, false or true boolean value becomes 0 or -1 
   integer value). For example, you cannot assign a numeric value to a 
   string type; to do that, first convert the numeric value to a string 
   using Str or WStr.
   Assignment between arrays is not supported presently.

   Avoid confusion with Operator = (Equal), which also uses the '=' symbol.
   For this purpose and for solving some cases of ambiguity of the parser 
   (see Byref (Function Results)), the alternative symbol '=>' can be used 
   for assignments in place of '=' (same as already for the initializers).
      Note: the '=>' symbol has been chosen against '<=' (already the 
      operator 'Less Than Or Equal') and ':=' (':' used as statement 
      separator).

   This operator can be overloaded for user-defined types as a member 
   Operator using the appropriate syntax.

Example
   Dim i As Integer
   i = 420    ' <- this is the assignment operator

   If  i = 69 Then   '<-this is the equivalence operator 
     Print "ERROR: i should equal 420"
     End -1
   End If

   Print "All is good."
   End 0

   ' compile with -lang fblite or qb

   #lang "fblite"

   Dim i As Integer
   Let i = 300 ' <-alternate syntax

Dialect Differences
   * In the -lang qb dialect, this operator cannot be overloaded.
   * In the -lang qb dialect, an assignment expression can be preceded by 
     the Let keyword.

Differences from QB
   * None

See also 
   * Operator = (Equal)
   * Operator Let (Assignment)
   * Swap
   * Coercion and Conversion



-------------------------------------------------- KeyPgOpCombineConcat ----
Operator &= (Concatenate And Assign)

Appends and assigns a string onto another string

Syntax
   Declare Operator &= ( ByRef lhs As String, ByRef rhs As T2 )
   Declare Operator &= ( ByRef lhs As WString, ByRef rhs As T2 )

Usage
   lhs &= rhs

Parameters
   lhs
      The string to assign to.
   rhs
      The value to append to lhs.
   T2
      Any numeric, string or user-defined type that can be converted to a 
      string.

Description
   This operator appends one string onto another. The right-hand side 
   expression (rhs) is converted to a string before concatenation. It is 
   functionally equivalent to,

      lhs = lhs & rhs

   where the result is assigned back to the left-hand side string.

   This operator can be overloaded for user-defined types as a member 
   Operator using the appropriate syntax.

   Note: This operator exists in C/C++ with a different meaning - there it 
   performs a bitwise And=.
   Note: Similarly to the operator '=[>]' (assign), the alternative symbol 
   '&=>' can be also used.

Example
   Dim s As String = "Hello, "
   s &= " world!"
   Print s

   will produce the output:


   Hello, world!

Dialect Differences
   * In the -lang qb dialect, this operator cannot be overloaded.

Differences from QB
   * New to FreeBASIC

See also
   * Operator & (String Concatenation With Conversion)
   * Operator +=  (Add And Assign)



----------------------------------------------------- KeyPgOpCombineAdd ----
Operator += (Add And Assign)

Adds and assigns a value to a variable

Syntax
   Declare Operator += ( ByRef lhs As T1, ByRef rhs As T2 )

   Declare Operator += ( ByRef lhs As T Ptr, ByRef rhs As Integer )

   Declare Operator += ( ByRef lhs As String, ByRef rhs As String )
   Declare Operator += ( ByRef lhs As WString, ByRef rhs As WString )

Usage
   lhs += rhs

Parameters
   lhs
      The variable to assign to.
   T1
      Any numeric type.
   rhs
      The value to add to lhs.
   T2
      Any numeric type.
   T
      Any data type.

Description
   This operator adds and assigns a value to a variable. It is functionally 
   equivalent to:

      lhs = lhs + rhs

   For numeric types, the right-hand side expression (rhs) will be 
   converted to the left-hand side type (T1).

   For string types, this operator is functionally equivalent to 
   Operator &= (Concatenate And Assign).

   This operator can be overloaded for user-defined types as a member 
   Operator using the appropriate syntax.

   Note: Similarly to the operator '=[>]' (assign), the alternative symbol 
   '+=>' can be also used.

Example
   Dim n As Double
   n = 6
   n += 1
   Print n
   Sleep

Output:

   7

Dialect Differences
   * In the -lang qb dialect, this operator cannot be overloaded.

Differences from QB
   * New to FreeBASIC

See also
   * Operator + (Add)
   * Mathematical Functions



----------------------------------------------------- KeyPgOpCombineSub ----
Operator -= (Subtract And Assign)

Subtracts and assigns a value to a variable

Syntax
   Declare Operator -= ( ByRef lhs As T1, ByRef rhs As T2 )
   Declare Operator -= ( ByRef lhs As T Ptr, ByRef rhs As Integer )

Usage
   lhs -= rhs

Parameters
   lhs
      The variable to assign to.
   T1
      Any numeric type.
   rhs
      The value to subtract from lhs.
   T2
      Any numeric type.
   T
      Any data type.

Description
   This operator subtracts and assigns a value to a variable. It is 
   functionally equivalent to:
      lhs = lhs - rhs

   For numeric types, the right-hand side expression (rhs) will be 
   converted to the left-hand side type (T1).

   This operator can be overloaded for user-defined types as a member 
   Operator using the appropriate syntax.

   Note: Similarly to the operator '=[>]' (assign), the alternative symbol 
   '-=>' can be also used.

Example
   Dim n As Double
   n = 6
   n -= 2.2
   Print n
   Sleep

Output:

   3.8

Dialect Differences
   * In the -lang qb dialect, this operator cannot be overloaded.

Differences from QB
   * New to FreeBASIC

See also
   * Operator - (Subtract)
   * Mathematical Functions



------------------------------------------------ KeyPgOpCombineMultiply ----
Operator *= (Multiply And Assign)

Multiplies and assigns a value to a variable

Syntax
   Declare Operator *= ( ByRef lhs As T1, ByRef rhs As T2 )

Usage
   lhs *= rhs

Parameters
   lhs
      The variable to assign to.
   T1
      Any numeric type.
   rhs
      The value to multiply lhs by.
   T2
      Any numeric type.

Description
   This operator multiplies and assigns a value to a variable. It is 
   functionally equivalent to:
      lhs = lhs * rhs

   The right-hand side expression (rhs) will be converted to the left-hand 
   side type (T1).

   This operator can be overloaded for user-defined types as a member 
   Operator using the appropriate syntax.

   Note: Similarly to the operator '=[>]' (assign), the alternative symbol 
   '*=>' can be also used.

Example
   Dim n As Double
   n = 6
   n *= 2
   Print n
   Sleep

Output:

   12

Dialect Differences
   * In the -lang qb dialect, this operator cannot be overloaded.

Differences from QB
   * New to FreeBASIC

See also
   * Operator * (Multiply)
   * Mathematical Functions



-------------------------------------------------- KeyPgOpCombineDivide ----
Operator /= (Divide And Assign)

Divides and assigns a value to a variable

Syntax
   Declare Operator /= ( ByRef lhs As T1, ByRef rhs As T2 )

Usage
   lhs /= rhs

Parameters
   lhs
      The variable to assign to.
   T1
      Any numeric type.
   rhs
      The value to divide lhs by.
   T2
      Any numeric type.

Description
   This operator divides and assigns a value to a variable. It is 
   functionally equivalent to:
      lhs = lhs / rhs

   This operator can be overloaded for user-defined types as a member 
   Operator using the appropriate syntax.

   Note: Similarly to the operator '=[>]' (assign), the alternative symbol 
   '/=>' can be also used.

Example
   Dim n As Double
   n = 6
   n /= 2.2
   Print n
   Sleep

Output:

   2.727272727272727

Dialect Differences
   * In the -lang qb dialect, this operator cannot be overloaded.

Differences from QB
   * New to FreeBASIC

See also
   * Operator / (Divide)
   * Mathematical Functions



------------------------------------------- KeyPgOpCombineIntegerDivide ----
Operator \= (Integer Divide And Assign)

Integer divides and assigns a value to a variable

Syntax
   Declare Operator \= ( ByRef lhs As T1, ByRef rhs As T2 )

Usage
   lhs \= rhs

Parameters
   lhs
      The variable to assign to.
   T1
      Any numeric type.
   rhs
      The value to divide lhs by.
   T2
      Any numeric type.

Description
   This operator divides (integer division) and assigns a value to a 
   variable. It is functionally equivalent to:
      lhs = lhs \ rhs

   This operator can be overloaded for user-defined types as a member 
   Operator using the appropriate syntax.

   Note: Similarly to the operator '=[>]' (assign), the alternative symbol 
   '\=>' can be also used.

Example
   Dim n As Double
   n = 6
   n \= 2.2
   Print n
   Sleep

Output:

   3

Dialect Differences
   * In the -lang qb dialect, this operator cannot be overloaded.

Differences from QB
   * New to FreeBASIC

See also
   * Operator \ (Integer Divide)
   * Mathematical Functions



-------------------------------------------- KeyPgOpCombineExponentiate ----
Operator ^= (Exponentiate And Assign)

Exponentiates and assigns a value to a variable

Syntax
   Declare Operator ^= ( ByRef lhs As Double, ByRef rhs As Double )

Usage
   lhs ^= rhs

Parameters
   lhs
      The variable to assign to.
   rhs
      The value to exponentiate lhs by.

Description
   This operator exponentiates and assigns a value to a variable. It is 
   functionally equivalent to:
      lhs = lhs ^ rhs

   This operator can be overloaded for user-defined types as a member 
   Operator using the appropriate syntax.

   Note: This operator exists in C/C++ with a different meaning - there it 
   performs a Bitwise Xor=.
   Note: Similarly to the operator '=[>]' (assign), the alternative symbol 
   '^=>' can be also used.

Example
   Dim n As Double
   n = 6
   n ^= 2
   Print n
   Sleep

Output:

   36

Dialect Differences
   * In the -lang qb dialect, this operator cannot be overloaded.

Differences from QB
   * New to FreeBASIC

See also
   * Operator ^ (Exponentiate)
   * Mathematical Functions



------------------------------------------------------------ KeyPgOpLet ----
Operator Let (Assign)

Indicates the assignment operator when overloading Operator = (Assignment)

Syntax
   { Type | Class | Union } typename
      Declare Operator Let ( [ ByRef | ByVal ] rhs As datatype )
   End { Type | Class | Union }

   Operator typename.Let ( [ ByRef | ByVal ] rhs As datatype )

Usage
   lhs = rhs
      or
   lhs => rhs

Parameters
   typename 
      name of the Type, Class, or Union.
   lhs
      The variable to assign to.
   rhs
      The value to assign.

Description
   Let is used to overload the Operator =[>] (Assignment) operator and to 
   distinguish it from the comparison operator Operator = (Equal).

   lhs =[>] rhs will assign the rhs to lhs by invoking the Let operator 
   procedure defined in typename.
   This includes the case of an object returned from a function by value, 
   by using Function =[>] rhs (or function_identifier =[>] rhs) assignment.

   An operator Let (assign) must be defined if the shallow implicit copy is 
   not sufficient. This happens in cases when the object manages 
   dynamically allocated memory or other resources which need to be 
   specially copied (for example if a member pointer points to dynamically 
   allocated memory, the implicit assignment operator will simply copy the 
   pointer value instead of allocate memory and then perform the copy of 
   data).
      Note: It is safe to do a check for self-assignment at the top of the 
      Let body (by comparing the address of implicit 'this' instance with 
      the address of 'rhs' parameter) to avoid object destruction if 
      previously allocated memory is first deallocated (see example below).

   When the operator Let (assign) is defined for copy assignment, its 
   parameter (the object to clone) can not be passed by value.

Example
   Type UDT
     Public:
      Declare Constructor (ByVal zp As Const ZString Ptr)  ''constructor with string initializer
      Declare Operator Let (ByRef rhs As UDT)              ''operator Let (assignment)
      Declare Function getString () As String              ''function to get string
      Declare Destructor ()                                ''destructor
     Private:         
      Dim zp As ZString Ptr                                ''private pointer to avoid direct access
   End Type

   Constructor UDT (ByVal zp As Const ZString Ptr)
     This.zp = CAllocate(Len(*zp) + 1)
     *This.zp = *zp
   End Constructor

   Operator UDT.Let (ByRef rhs As UDT)
     If @This <> @rhs Then  '' check for self-assignment to avoid object destruction
      Deallocate(This.zp)
      This.zp = CAllocate(Len(*rhs.zp) + 1)
      *This.zp = *rhs.zp
     End If
   End Operator

   Function UDT.getString () As String
     Return *This.zp
   End Function

   Destructor UDT ()
     Deallocate(This.zp)
   End Destructor

   Dim u As UDT = UDT("")
   u = Type<UDT>("Thanks to the overloading operator Let (assign)")
   Print u.getString
   Sleep

Output:

   Thanks To the overloading Operator Let (assign)

Version
   * Before fbc version 1.20.0, assigning one array was not supported.

Dialect Differences
   * In the -lang qb and -lang fblite dialects, this operator cannot be 
     overloaded.
   * In the -lang qb and -lang fblite dialects, an assignment expression 
     can be preceded by the Let keyword.

Differences from QB
   * None.

See also
   * Let
   * Operator Let() (Assignment)
   * Operator =[>] (Assignment)
   * Operator = (Equal)
   * Coercion and Conversion



-------------------------------------------------------- KeyPgOpLetlist ----
Operator Let() (Assignment)

Assigns fields of a user defined type to a list of variables

Syntax
   Let( variable1 [, variable2 [, ... ]] ) = UDT_var
      or
   Let( variable1 [, variable2 [, ... ]] ) => UDT_var

Parameters
   variable1 [, variable2 [, ... ]]
      Comma separated list of variables to receive the values of the UDT 
      variable's fields.
   UDT_var
      A user defined type variable.

Description
   Assigns the values from the UDT_var variable's fields to the list of 
   variables.

   When the UDT Extends a Base, the first variable (variable1) assigned by 
   the operator then corresponds to a Base instance (only the other 
   variables are those to receive the values of the data fields of the UDT
   ).

   Union is not supported.

Example
   Type Vector3D
      x As Double
      y As Double
      z As Double
   End Type

   Dim a As Vector3D = ( 5, 7, 9 )

   Dim x As Double, y As Double

   '' Get the first two fields only
   Let( x, y ) = a

   Print "x = "; x
   Print "y = "; y

Output:

   x =  5
   y =  7

   Type Parent
      Dim As Integer p1, p2
   End Type

   Type Child Extends Parent
      Dim As Integer c1, c2
   End Type

   Type GrandChild Extends Child
      Dim As Integer gc1, gc2
   End Type

   Dim As GrandChild gc = Type(1, 2, 3, 4, 5, 6)

   Dim As Integer i1, i2
   Dim As Integer j1, j2
   Dim As Parent p
   Dim As Child c

   Let(c, i1, i2) = gc
   Print c.p1, c.p2, c.c1, c.c2, i1, i2

   Let(p, j1, j2) = gc
   Print p.p1, p.p2, j1, j2

Output:

    1             2             3             4             5             6
    1             2             5             6

Dialect Differences
   * Only available in the -lang fb dialect.

Differences from QB
   * New to FreeBASIC

See also
   * Let
   * Operator =[>] (Assignment)
   * Operator Let (Assignment)



------------------------------------------------- KeyPgOpCombineModulus ----
Operator Mod= (Modulus And Assign)

Divides a value and assigns the remainder to a variable

Syntax
   Declare Operator Mod= ( ByRef lhs As Integer, ByRef rhs As Integer )

Usage
   lhs Mod= rhs

Parameters
   lhs
      The variable to assign to.
   rhs
      The value to divide lhs by.

Description
   This operator divides two values of Integer type and assigns the 
   remainder to its left-hand side (lhs) variable. It is functionally 
   equivalent to:
      lhs = lhs Mod rhs

   This operator can be overloaded for user-defined types as a member 
   Operator using the appropriate syntax.

   Note: Similarly to the operator '=[>]' (assign), the alternative symbol 
   'Mod=>' can be also used.

Example
   Dim n As Integer
   n = 11
   n Mod= 3
   '' The result is 2
   Print n
   Sleep

Dialect Differences
   * In the -lang qb dialect, this operator cannot be overloaded.

Differences from QB
   * New to FreeBASIC

See also
   * Operator Mod (Modulus)
   * Mathematical Functions



----------------------------------------------------- KeyPgOpCombineAnd ----
Operator And= (Conjunction And Assign)

Performs a bitwise-and (conjunction) and assigns the result to a variable

Syntax
   Declare Operator And= ( ByRef lhs As T1, ByRef rhs As T2 )

Usage
   lhs And= rhs

Parameters
   lhs
      The variable to assign to.
   T1
      Any numeric or boolean type.
   rhs
      The value to perform a bitwise-and (conjunction) with lhs.
   T2
      Any numeric or boolean type.

Description
   This operator performs a bitwise-and and assigns the result to a 
   variable (for conversion of a boolean to an integer, false or true 
   boolean value becomes 0 or -1 integer value). It is functionally 
   equivalent to:
      lhs = lhs And rhs

   And= compares each bit of its operands, lhs and rhs, and if both bits 
   are 1, then the corresponding bit in the first operand, lhs, is set to 
   1, otherwise it is set to 0.

   And= cannot be used in conditional expressions.

   This operator can be overloaded for user-defined types as a member 
   Operator using the appropriate syntax.

   Note: Similarly to the operator '=[>]' (assign), the alternative symbol 
   'And=>' can be also used.

Example
   ' Using the AND= operator on two numeric values
   Dim As UByte numeric_value1, numeric_value2
   numeric_value1 = 15 '' 00001111
   numeric_value2 = 30 '' 00011110

   numeric_value1 And= numeric_value2

   '' Result =  14  =     00001110
   Print numeric_value1
   Sleep

Dialect Differences
   * In the -lang qb dialect, this operator cannot be overloaded.

Differences from QB
   * New to FreeBASIC

See also
   * And



----------------------------------------------------- KeyPgOpCombineEqv ----
Operator Eqv= (Equivalence And Assign)

Performs a bitwise-eqv (equivalence) and assigns the result to a variable

Syntax
   Declare Operator Eqv= ( ByRef lhs As T1, ByRef rhs As T2 )

Usage
   lhs Eqv= rhs

Parameters
   lhs
      The variable to assign to.
   T1
      Any numeric or boolean type.
   rhs
      The value to perform a bitwise-eqv (equivalence) with lhs.
   T2
      Any numeric or boolean type.

Description
   This operator performs a bitwise-eqv and assigns the result to a 
   variable (for conversion of a boolean to an integer, false or true 
   boolean value becomes 0 or -1 integer value). It is functionally 
   equivalent to:
      lhs = lhs Eqv rhs

   Eqv= compares each bit of its operands, lhs and rhs, and if both bits 
   are the same (either both 0 or both 1), then the corresponding bit in 
   the first operand, lhs, is set to 1, otherwise it is set to 0.

   This operator can be overloaded for user-defined types as a member 
   Operator using the appropriate syntax.

   Note: Similarly to the operator '=[>]' (assign), the alternative symbol 
   'Eqv=>' can be also used.

Example
   Dim As UByte a = &b00110011
   Dim As UByte b = &b01010101
   a Eqv= b
   '' Result    a = &b10011001
   Print Bin(a)

Dialect Differences
   * In the -lang qb dialect, this operator cannot be overloaded.

Differences from QB
   * New to FreeBASIC

See also
   * Eqv



----------------------------------------------------- KeyPgOpCombineImp ----
Operator Imp= (Implication And Assign)

Performs a bitwise-imp (implication) and assigns the result to a variable

Syntax
   Declare Operator Imp= ( ByRef lhs As T1, ByRef rhs As T2 )

Usage
   lhs Imp= rhs

Parameters
   lhs
      The variable to assign to.
   T1
      Any numeric or boolean type.
   rhs
      The value to perform a bitwise-imp (implication) with lhs.
   T2
      Any numeric or boolean type.

Description
   This operator performs a bitwise-imp and assigns the result to a 
   variable (for conversion of a boolean to an integer, false or true 
   boolean value becomes 0 or -1 integer value). It is functionally 
   equivalent to:
      lhs = lhs Imp rhs

   Imp is a bitwise operator which is the same as (Not lhs) Or rhs.  Imp= 
   compares each bit of its operands, lhs and rhs, and if the bit in lhs is 
   0 or the bit in rhs is 1, then the corresponding bit in the first 
   operand, lhs, is set to 1, otherwise it is set to 0.

   This operator can be overloaded for user-defined types as a member 
   Operator using the appropriate syntax.

   Note: Similarly to the operator '=[>]' (assign), the alternative symbol 
   'Imp=>' can be also used.

Example
   Dim As UByte a = &b00110011
   Dim As UByte b = &b01010101
   a Imp= b
   '' Result    a = &b11011101
   Print Bin(a)

Dialect Differences
   * In the -lang qb dialect, this operator cannot be overloaded.

Differences from QB
   * New to FreeBASIC

See also
   * Imp
   * Assignment Operators



------------------------------------------------------ KeyPgOpCombineOr ----
Operator Or= (Inclusive Disjunction And Assign)

Performs a bitwise-or (inclusive disjunction) and assigns the result to a 
variable

Syntax
   Declare Operator Or= ( ByRef lhs As T1, ByRef rhs As T2 )

Usage
   lhs Or= rhs

Parameters
   lhs
      The variable to assign to.
   T1
      Any numeric or boolean type.
   rhs
      The value to perform a bitwise-or (inclusive disjunction) with lhs.
   T2
      Any numeric or boolean type.

Description
   This operator performs a bitwise-or and assigns the result to a variable 
   (for conversion of a boolean to an integer, false or true boolean value 
   becomes 0 or -1 integer value). It is functionally equivalent to:
      lhs = lhs Or rhs

   Or= compares each bit of its operands, lhs and rhs, and if either bits 
   are 1, then the corresponding bit in the first operand, lhs, is set to 
   1, otherwise it is set to 0.

   This operator can be overloaded for user-defined types as a member 
   Operator using the appropriate syntax.

   Note: Similarly to the operator '=[>]' (assign), the alternative symbol 
   'Or=>' can be also used.

Example
   Dim As UByte a = &b00110011
   Dim As UByte b = &b01010101
   a Or= b
   '' Result    a = &b01110111
   Print Bin(a)

Dialect Differences
   * In the -lang qb dialect, this operator cannot be overloaded.

Differences from QB
   * New to FreeBASIC

See also
   * Or



----------------------------------------------------- KeyPgOpCombineXor ----
Operator Xor= (Exclusive Disjunction And Assign)

Performs a bitwise-xor (exclusive disjunction) and assigns the result to a 
variable

Syntax
   Declare Operator Xor= ( ByRef lhs As T1, ByRef rhs As T2 )

Usage
   lhs Xor= rhs

Parameters
   lhs
      The variable to assign to.
   T1
      Any numeric or boolean type.
   rhs
      The value to perform a bitwise-xor (exclusive or) with lhs.
   T2
      Any numeric or boolean type.

Description
   This operator performs a bitwise-or and assigns the result to a variable 
   (for conversion of a boolean to an integer, false or true boolean value 
   becomes 0 or -1 integer value). It is functionally equivalent to:
      lhs = lhs Xor rhs

   Xor= compares each bit of its operands, lhs and rhs, and if both bits 
   are the same (both 1 or both 0), then the corresponding bit in the first 
   operand, lhs, is set to 0, otherwise it is set to 1.

   This operator can be overloaded for user-defined types as a member 
   Operator using the appropriate syntax.

   Note: Similarly to the operator '=[>]' (assign), the alternative symbol 
   'Xor=>' can be also used.

Example
   Dim As UByte a = &b00110011
   Dim As UByte b = &b01010101
   a Xor= b
   '' Result    a = &b01100110
   Print Bin(a)

Dialect Differences
   * In the -lang qb dialect, this operator cannot be overloaded.

Differences from QB
   * New to FreeBASIC

See also
   * Xor



----------------------------------------------- KeyPgOpCombineShiftLeft ----
Operator Shl= (Shift Left And Assign)

Shifts left and assigns a value to a variable

Syntax
   Declare Operator Shl= ( ByRef lhs As Integer, ByRef rhs As Integer )
   Declare Operator Shl= ( ByRef lhs As UInteger, ByRef rhs As UInteger )
   Declare Operator Shl= ( ByRef lhs As LongInt, ByRef rhs As LongInt )
   Declare Operator Shl= ( ByRef lhs As ULongInt, ByRef rhs As ULongInt )

Usage
   lhs shl= rhs

Parameters
   lhs
      The variable to assign to.
   rhs
      The value to shift lhs left by.

Description
   This operator shifts the bits in its left-hand side (lhs) parameter a 
   number of times specified by its right-hand side (rhs) parameter, and 
   assigns the result to lhs. It is functionally equivalent to:
      lhs = lhs Shl rhs

   This operator can be overloaded for user-defined types as a member 
   Operator using the appropriate syntax.

   Note: Similarly to the operator '=[>]' (assign), the alternative symbol 
   'Shl=>' can be also used.

Example
   Dim i As Integer
   i = &b00000011   '' = 3
   i Shl= 3         '' = i*2^3
   '' Result: 11000          24            24
   Print Bin(i), i, 3*2^3
   Sleep

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Shl=.

Differences from QB
   * New to FreeBASIC

See also
   * Operator Shl (Shift Left)
   * Operator Shr= (Shift Right And Assign)
   * Mathematical Functions



---------------------------------------------- KeyPgOpCombineShiftRight ----
Operator Shr= (Shift Right And Assign)

Shifts right and assigns a value to a variable

Syntax
   Declare Operator Shr= ( ByRef lhs As Integer, ByRef rhs As Integer )
   Declare Operator Shr= ( ByRef lhs As UInteger, ByRef rhs As UInteger )
   Declare Operator Shr= ( ByRef lhs As LongInt, ByRef rhs As LongInt )
   Declare Operator Shr= ( ByRef lhs As ULongInt, ByRef rhs As ULongInt )

Usage
   lhs shr= rhs

Parameters
   lhs
      The variable to assign to.
   rhs
      The value to shift lhs right by.

Description
   This operator shifts the bits in its left-hand side (lhs) parameter a 
   number of times specified by its right-hand side (rhs) parameter, and 
   assigns the result to lhs. It is functionally equivalent to:
      lhs = lhs Shr rhs

   This operator can be overloaded for user-defined types as a member 
   Operator using the appropriate syntax.

   Note: Similarly to the operator '=[>]' (assign), the alternative symbol 
   'Shr=>' can be also used.

Example
   Dim i As Integer
   i = &b00011000   '' = 24
   i Shr= 3         '' = i\2^3
   '' Result: 11          3            3
   Print Bin(i), i, 24\2^3
   Sleep

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Shr=.

Differences from QB
   * New to FreeBASIC

See also
   * Operator Shr (Shift Right)
   * Operator Shl= (Shift Left And Assign)
   * Mathematical Functions




============================================================================
    Arithmetic operators

------------------------------------------------------------ KeyPgOpAdd ----
Operator + (Addition)

Sums two expressions

Syntax
   Declare Operator + ( ByRef lhs As Integer, ByRef rhs As Integer ) As 
   Integer
   Declare Operator + ( ByRef lhs As UInteger, ByRef rhs As UInteger ) As 
   UInteger

   Declare Operator + ( ByRef lhs As Single, ByRef rhs As Single ) As Single
   Declare Operator + ( ByRef lhs As Double, ByRef rhs As Double ) As Double

   Declare Operator + ( ByRef lhs As T Pointer, ByRef rhs As Integer ) As T 
   Pointer
   Declare Operator + ( ByRef rhs As Integer, ByRef lhs As T Pointer ) As T 
   Pointer

   Declare Operator + ( ByRef lhs As T, ByRef rhs As Integer ) As T
   Declare Operator + ( ByRef lhs As Integer, ByRef rhs As T ) As T

Usage
   result = lhs + rhs

Parameters
   lhs
      The left-hand side expression to sum.
   rhs
      The right-hand side expression to sum.
   T
      Any pointer type.

Return Value
   Returns the sum of two expressions.

Description
   When the left and right-hand side expressions are numeric values, 
   Operator + (Add) returns the sum of the two values.

   When the left and right-hand side expressions are string values, 
   Operator + (Add) concatenates the two strings and returns the result.

   If an integral value n is added to a T Pointer type, the operator 
   performs pointer arithmetic on the address, returning the memory 
   position of a T value, n indices away (assuming n is within bounds of a 
   contiguous array of T values).  This behaves differently from numeric 
   addition, because the Integer value is scaled by SizeOf( T ).

   Neither operand is modified in any way.

   This operator can be overloaded to accept user-defined types.

Example
   Dim n As Single
   n = 4.75 + 5.25
   Print n

   will produce the output:


   10

Dialect Differences
   * In the -lang qb dialect, this operator cannot be overloaded.

Differences from QB
   * None

See also
   * Operator + (String Concatenation)
   * Mathematical Functions



------------------------------------------------------- KeyPgOpSubtract ----
Operator - (Subtract)

Subtracts two expressions

Syntax
   Declare Operator - ( ByRef lhs As Integer, ByRef rhs As Integer ) As 
   Integer
   Declare Operator - ( ByRef lhs As UInteger, ByRef rhs As UInteger ) As 
   UInteger

   Declare Operator - ( ByRef lhs As Single, ByRef rhs As Single ) As Single
   Declare Operator - ( ByRef lhs As Double, ByRef rhs As Double ) As Double

   Declare Operator - ( ByRef lhs As T Pointer, ByRef rhs As T Pointer ) As 
   Integer
   Declare Operator - ( ByRef lhs As T Pointer, ByRef rhs As Integer ) As T 
   Pointer

   Declare Operator - ( ByRef lhs As T, ByRef rhs As T ) As Integer
   Declare Operator - ( ByRef lhs As T, ByRef rhs As Integer ) As T
   Declare Operator - ( ByRef lhs As Integer, ByRef rhs As T ) As T

Usage
   result = lhs - rhs

Parameters
   lhs
      The left-hand side expression to subtract from.
   rhs
      The right-hand side expression to subtract.
   T
      Any pointer type.

Return Value
   Returns the subtraction of two expressions.

Description
   When the left and right-hand side expressions are numeric values, 
   Operator - (Subtract) returns the subtraction of the two values.

   If the left and right-hand side expressions are both of the T Pointer 
   type, for some type T, the operator performs pointer subtraction on the 
   address, returning the result.  This is different from numeric 
   subtraction because the difference is divided by SizeOf( T ).

   If an integral value n is subtracted from a T Pointer type, the operator 
   performs pointer arithmetic on the address, returning the memory 
   position of a T value, n indices before (assuming (-n) is within bounds 
   of a contiguous array of T values).  This behaves differently from 
   numeric subtraction, because the Integer value is scaled by SizeOf( T ).

   Neither operand is modified in any way.

   This operator can be overloaded to accept user-defined types.

Example
   Dim n As Single
   n = 4 - 5
   Print n

   will produce the output:


   -1

Dialect Differences
   * In the -lang qb dialect, this operator cannot be overloaded.

Differences from QB
   * None

See also
   * Mathematical Functions



------------------------------------------------------- KeyPgOpMultiply ----
Operator * (Multiply)

Multiplies two numeric expressions

Syntax
   Declare Operator * ( ByRef lhs As Integer, ByRef rhs As Integer ) As 
   Integer
   Declare Operator * ( ByRef lhs As UInteger, ByRef rhs As UInteger ) As 
   UInteger

   Declare Operator * ( ByRef lhs As Single, ByRef rhs As Single ) As Single
   Declare Operator * ( ByRef lhs As Double, ByRef rhs As Double ) As Double

Usage
   result = lhs * rhs

Parameters
   lhs
      The left-hand side multiplicand expression.
   rhs
      The right-hand side multiplicand expression.

Return Value
   Returns the product of two multiplicands.

Description
   Operator * (Multiply) returns the product of two multiplicands.

   Neither operand is modified in any way.

   This operator can be overloaded to accept user-defined types.

Example
   Dim n As Double
   n = 4 * 5
   Print n
   Sleep

Output:

   20

Dialect Differences
   * In the -lang qb dialect, this operator cannot be overloaded.

Differences from QB
   * None

See also
   * Mathematical Functions



--------------------------------------------------------- KeyPgOpDivide ----
Operator / (Divide)

Divides two numeric expressions

Syntax
   Declare Operator / ( ByRef lhs As Single, ByRef rhs As Single ) As Single
   Declare Operator / ( ByRef lhs As Double, ByRef rhs As Double ) As Double

Usage
   result = lhs / rhs

Parameters
   lhs
      The left-hand side dividend expression.
   rhs
      The right-hand side divisor expression.

Return Value
   Returns the quotient of a dividend and divisor.

Description
   Operator / (Divide) returns the quotient of a dividend and divisor.

   Neither operand is modified in any way. Unlike with integer division, 
   float division by zero is safe to perform, the quotient will hold a 
   special value representing infinity, converting it to a string returns 
   something like "Inf" or "INF", exact text is platform specific. 

   This operator can be overloaded to accept user-defined types.

Example
   Dim n As Double
   Print n / 5
   n = 6 / 2.3
   Print n
   Sleep

Output:

   0
   2.608695652173913

Dialect Differences
   * In the -lang qb dialect, this operator cannot be overloaded.

Differences from QB
   * None

See also
   * Operator \ (Integer Divide)
   * Mathematical Functions



-------------------------------------------------- KeyPgOpIntegerDivide ----
Operator \ (Integer Divide)

Divides two Integer expressions

Syntax
   Declare Operator \ ( ByRef lhs As Integer, ByRef rhs As Integer ) As 
   Integer
   Declare Operator \ ( ByRef lhs As UInteger, ByRef rhs As UInteger ) As 
   UInteger

Usage
   result = lhs \ rhs

Parameters
   lhs
      The left-hand side dividend expression.
   rhs
      The right-hand side divisor expression.

Return Value
   Returns the quotient of an Integer dividend and divisor.

Description
   Operator \ (Integer division) divides two Integer expressions and 
   returns the result. Float numeric values are converted to Integer by 
   rounding up or down, and the fractional part of the resulting quotient 
   is truncated.

   If the divisor (rhs) is zero (0), a division by zero error (crash) will 
   be raised.

   Neither of the operands are modified in any way.

   This operator can be overloaded for user-defined types.

Example
   Dim n As Double
   Print n \ 5
   n = 7 \ 2.6  '' => 7 \ 3  => 2.33333  => 2
   Print n
   n = 7 \ 2.4  '' => 7 \ 2 => 3.5 => 3
   Print n
   Sleep

Output:

   0
   2
   3

Dialect Differences
   * In the -lang qb dialect, this operator cannot be overloaded.

Differences from QB
   * None

See also
   * Operator / (Floating-Point Divide)
   * Operator Mod (Modulus)
   * Mathematical Functions



--------------------------------------------------- KeyPgOpExponentiate ----
Operator ^ (Exponentiate)

Raises a numeric expression to some power

Syntax
   Declare Operator ^ ( ByRef lhs As Double, ByRef rhs As Double ) As Double

Usage
   result = lhs ^ rhs

Parameters
   lhs
      The left-hand side base expression.
   rhs
      The right-hand side exponent expression.

Return Value
   Returns the exponentiation of a base expression raised to some exponent.

Description
   Operator ^ (Exponentiate) returns the result of a base expression (lhs) 
   raised to some exponent expression (rhs). ^ works with double float 
   numbers only, operands of other types will be converted into double 
   before performing the exponentiation. Exponent of a fractional value (1/
   n) is the same as taking nth root from the base, for example, 2 ^ (1/3) 
   is the cube root of 2.

   Neither of the operands are modified in any way.

   This operator can be overloaded for user-defined types.

   This operation is for Double precision data types only (53 significant 
   bits), and suffers from some inaccuracies in the least significant bits 
   of the number, especially when converting from other data types (e.g. 
   64-bit data types).  This inaccuracy is particularly noticeable when the 
   result is expected to be an exact number, but then finding the result is 
   out by a very small amount.  For this reason, never assume that an 
   exponentiation expression will be exactly equal to the value expected, 
   but rather close within some small amount of error.  Be wary of using 
   rounding methods such as Int and Fix on the result: if you expect the 
   result to be an integer value, then there's a chance that it might be 
   slightly lower, and will round down to a value that is one less than 
   expected.

   This operator exists in C/C++ with a different meaning; in C/C++ it 
   performs a Bitwise Xor.

Example
   Dim As Double n
   Input "Please enter a positive number: ", n
   Print 
   Print n;" squared is "; n ^ 2
   Print "The fifth root of "; n;" is "; n ^ 0.2
   Sleep

Output:

   Please enter a positive number: 3.4

    3.4 squared Is 11.56
   The fifth root of 3.4 Is 1.27730844458754

Dialect Differences
   * In the -lang qb dialect, this operator cannot be overloaded.

Differences from QB
   * None

See also
   * Mathematical Functions



-------------------------------------------------------- KeyPgOpModulus ----
Operator Mod (Modulus)

Finds the remainder from a division operation

Syntax
   Declare Operator Mod ( ByRef lhs As Integer, ByRef rhs As Integer ) As 
   Integer

Usage
   result = lhs Mod rhs

Parameters
   lhs
      The left-hand side dividend expression.
   rhs
      The right-hand side divisor expression.

Return Value
   Returns the remainder of a division operation.

Description
   Operator Mod (Modulus) divides two Integer expressions and returns the 
   remainder. Float numeric values are converted to Integer by rounding up 
   or down.

   Neither of the operands are modified in any way.

   This operator can be overloaded for user-defined types.

Example
   Print 47 Mod 7
   Print 5.6 Mod 2.1
   Print 5.1 Mod 2.8

Output:

   5
   0
   2

This is because: 
   * 47 divided by 7 gives a remainder of 5
   * 5.6 is rounded to 6 while 2.1 is rounded to 2. This makes the problem 
     6 MOD 2 which means 6 divided by 2 which gives a remainder of 0
   * 5.1 is rounded to 5 while 2.8 is rounded to 3. This makes the problem 
     5 MOD 3 which means 5 divided by 3 which gives a remainder of 2

Dialect Differences
   * In the -lang qb dialect, this operator cannot be overloaded.

Differences from QB
   * None

See also
   * Mathematical Functions



--------------------------------------------------------- KeyPgOpNegate ----
Operator - (Negate)

Changes the sign of a numeric expression

Syntax
   Declare Operator - ( ByRef rhs As Integer ) As Integer
   Declare Operator - ( ByRef rhs As Single ) As Single
   Declare Operator - ( ByRef rhs As Double ) As Double

Usage
   result = - rhs

Parameters
   rhs
      The right-hand side numeric expression to negate.

Return Value
   Returns the negative of the expression.

Description
   Operator - (Negate) is a unary operator that negates the value of its 
   operand.

   The operand is not modified in any way.

   This operator can be overloaded for user-defined types.

Example
   Dim n As LongInt
   Print -5
   n = 65432568459
   n = - n
   Print n
   Sleep

Output:

   -5
   -65432568459

Dialect Differences
   * In the -lang qb dialect, this operator cannot be overloaded.

Differences from QB
   * None

See also
   * Mathematical Functions



------------------------------------------------------ KeyPgOpShiftLeft ----
Operator Shl (Shift Left)

Shifts the bits of a numeric expression to the left

Syntax
   Declare Operator Shl ( ByRef lhs As Integer, ByRef rhs As Integer ) As 
   Integer
   Declare Operator Shl ( ByRef lhs As UInteger, ByRef rhs As UInteger ) As 
   UInteger
   Declare Operator Shl ( ByRef lhs As LongInt, ByRef rhs As LongInt ) As 
   LongInt
   Declare Operator Shl ( ByRef lhs As ULongInt, ByRef rhs As ULongInt ) As 
   ULongInt

Usage
   result = lhs Shl rhs

Parameters
   lhs
      The left-hand side expression.
   rhs
      The right-hand side shift expression.

Return Value
   Returns the result of lhs being shifted left rhs number of times.

Description
   Operator Shl (Shift left) shifts all of the bits in the left-hand side 
   expression (lhs) left a number of times specified by the right-hand side 
   expression (rhs). Numerically, the result is the same as "CInt( lhs * 2 ^
   rhs )". For example, "&b0101 Shl 1" returns the binary number &b01010, 
   and "5 Shl 1" returns 10.

   Neither of the operands are modified in any way.

   If the result is too large to fit inside the result's data type, the 
   leftmost bits are discarded ("shifted out").
   The results of this operation are undefined for values of rhs less than 
   zero, or greater than or equal to the number of bits in the result's 
   data type.

   This operator can be overloaded for user-defined types.

Example
   'Double a number
   For i As Integer = 0 To 10
      
      Print 5 Shl i, Bin(5 Shl i, 16)
      
   Next i

Output:

    5            0000000000000101
    10           0000000000001010
    20           0000000000010100
    40           0000000000101000
    80           0000000001010000
    160          0000000010100000
    320          0000000101000000
    640          0000001010000000
    1280         0000010100000000
    2560         0000101000000000
    5120         0001010000000000

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Shl.

Differences from QB
   * New to FreeBASIC

See also
   * Operator Shl= (Shift Left And Assign)
   * Operator Shr (Shift Right)
   * Bin
   * Mathematical Functions



----------------------------------------------------- KeyPgOpShiftRight ----
Operator Shr (Shift Right)

Shifts the bits of a numeric expression to the right

Syntax
   Declare Operator Shr ( ByRef lhs As Integer, ByRef rhs As Integer ) As 
   Integer
   Declare Operator Shr ( ByRef lhs As UInteger, ByRef rhs As UInteger ) As 
   UInteger
   Declare Operator Shr ( ByRef lhs As LongInt, ByRef rhs As LongInt ) As 
   LongInt
   Declare Operator Shr ( ByRef lhs As ULongInt, ByRef rhs As ULongInt ) As 
   ULongInt

Usage
   result = lhs Shr rhs

Parameters
   lhs
      The left-hand side expression.
   rhs
      The right-hand side shift expression.

Return Value
   Returns the result of lhs being shifted right rhs number of times.

Description
   Operator Shr (Shift right) shifts all of the bits in the left-hand side 
   expression (lhs) right a number of times specified by the right-hand 
   side expression (rhs). Numerically, the result is the same as "Int(lhs / 
   2 ^ rhs)". For example, "&b0101 Shr 1" returns the binary number &b010, 
   and "5 Shr 1" returns 2.

   If the left-hand side expression is signed and negative, the sign bit is 
   copied in the newly created bits on the left after the shift.  For 
   example, "-5 Shr 2" returns -2.

   Neither of the operands are modified in any way.

   The results of this operation are undefined for values of rhs less than 
   zero, or greater than or equal to the number of bits in the result's 
   data type.

   This operator can be overloaded for user-defined types.

Example
   'Halve a number
   For i As Integer = 0 To 10
      
      Print 1000 Shr i, Bin(1000 Shr i, 16)
      
   Next i

Output:

    1000         0000001111101000
    500          0000000111110100
    250          0000000011111010
    125          0000000001111101
    62           0000000000111110
    31           0000000000011111
    15           0000000000001111
    7            0000000000000111
    3            0000000000000011
    1            0000000000000001
    0            0000000000000000

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Shr.

Differences from QB
   * New to FreeBASIC

See also
   * Operator Shr= (Shift Right And Assign)
   * Operator Shl (Shift Left)
   * Bin
   * Mathematical Functions




============================================================================
    Conditional operators

---------------------------------------------------------- KeyPgOpEqual ----
Operator = (Equal)

Compares two expressions for equality

Syntax
   Declare Operator = ( ByRef lhs As Byte, ByRef rhs As Byte ) As Integer
   Declare Operator = ( ByRef lhs As UByte, ByRef rhs As UByte ) As Integer
   Declare Operator = ( ByRef lhs As Short, ByRef rhs As Short ) As Integer
   Declare Operator = ( ByRef lhs As UShort, ByRef rhs As UShort ) As 
   Integer
   Declare Operator = ( ByRef lhs As Integer, ByRef rhs As Integer ) As 
   Integer
   Declare Operator = ( ByRef lhs As UInteger, ByRef rhs As UInteger ) As 
   Integer
   Declare Operator = ( ByRef lhs As LongInt, ByRef rhs As LongInt ) As 
   Integer
   Declare Operator = ( ByRef lhs As ULongInt, ByRef rhs As ULongInt ) As 
   Integer

   Declare Operator = ( ByRef lhs As Single, ByRef rhs As Single ) As 
   Integer
   Declare Operator = ( ByRef lhs As Double, ByRef rhs As Double ) As 
   Integer

   Declare Operator = ( ByRef lhs As String, ByRef rhs As String ) As 
   Integer
   Declare Operator = ( ByRef lhs As ZString, ByRef rhs As ZString ) As 
   Integer
   Declare Operator = ( ByRef lhs As WString, ByRef rhs As WString ) As 
   Integer

   Declare Operator = ( ByRef lhs As T, ByRef rhs As T ) As Integer

   Declare Operator = ( ByRef lhs As Boolean, ByRef rhs As Boolean ) As 
   Boolean

Usage
   result = lhs = rhs

Parameters
   lhs
      The left-hand side expression to compare to.
   rhs
      The right-hand side expression to compare to.
   T
      Any pointer type.

Return Value
   Returns negative one (-1) if expressions are equal, or zero (0) if 
   unequal.

Description
   Operator = (Equality) is a binary operator that compares two expressions 
   for equality and returns the result - a boolean value mainly in the form 
   of an Integer: negative one (-1) for true and zero (0) for false. Only 
   if the left and right-hand side types are both Boolean, the return type 
   is also Boolean. The arguments are not modified in any way.

   This operator can be overloaded to accept user-defined types as well.

   Operator = (Equality) should not be confused with initializations or 
   assignments, both of which also use the "=" symbol.

Example

   Dim i As Integer = 0    '' initialization: initialise i with a value of 0
   i = 420                 '' assignment: assign to i the value of 420

   If (i = 69) Then        '' equation: compare the equality of the value of i and 69
      Print "serious error: i should equal 420"
      End -1
   End If

   Operator <> (Inequality) is complement to Operator = (Equality), and is 
   functionally identical when combined with Operator Not (Bit-wise 
   Complement).

      If (420 = 420) Then Print "(420 = 420) is true."
      If Not (69 <> 69) Then Print "not (69 <> 69) is true."

Dialect Differences
   * In the -lang qb dialect, this operator cannot be overloaded.

Differences from QB
   * none

See also
   * Operator <> (Inequality)
   * Operator =[>] (Assignment)
 


------------------------------------------------------- KeyPgOpNotEqual ----
Operator <> (Not Equal)

Compares two expressions for inequality

Syntax
   Declare Operator <> ( ByRef lhs As Byte, ByRef rhs As Byte ) As Integer
   Declare Operator <> ( ByRef lhs As UByte, ByRef rhs As UByte ) As Integer
   Declare Operator <> ( ByRef lhs As Short, ByRef rhs As Short ) As Integer
   Declare Operator <> ( ByRef lhs As UShort, ByRef rhs As UShort ) As 
   Integer
   Declare Operator <> ( ByRef lhs As Integer, ByRef rhs As Integer ) As 
   Integer
   Declare Operator <> ( ByRef lhs As UInteger, ByRef rhs As UInteger ) As 
   Integer
   Declare Operator <> ( ByRef lhs As LongInt, ByRef rhs As LongInt ) As 
   Integer
   Declare Operator <> ( ByRef lhs As ULongInt, ByRef rhs As ULongInt ) As 
   Integer

   Declare Operator <> ( ByRef lhs As Single, ByRef rhs As Single ) As 
   Integer
   Declare Operator <> ( ByRef lhs As Double, ByRef rhs As Double ) As 
   Integer

   Declare Operator <> ( ByRef lhs As String, ByRef rhs As String ) As 
   Integer
   Declare Operator <> ( ByRef lhs As ZString, ByRef rhs As ZString ) As 
   Integer
   Declare Operator <> ( ByRef lhs As WString, ByRef rhs As WString ) As 
   Integer

   Declare Operator <> ( ByRef lhs As T, ByRef rhs As T ) As Integer

   Declare Operator <> ( ByRef lhs As Boolean, ByRef rhs As Boolean ) As 
   Boolean

Usage
   result = lhs <> rhs

Parameters
   lhs
      The left-hand side expression to compare to.
   rhs
      The right-hand side expression to compare to.
   T
      Any pointer type.

Return Value
   Returns negative one (-1) if expressions are not equal, or zero (0) if 
   equal.

Description
   Operator <> (Not equal) is a binary operator that compares two 
   expressions for inequality and returns the result - a boolean value 
   mainly in the form of an Integer: negative one (-1) for true and zero 
   (0) for false. Only if the left and right-hand side types are both 
   Boolean, the return type is also Boolean. The arguments are not modified 
   in any way.

   This operator can be overloaded to accept user-defined types as well.

Example

   Dim As String a = "hello", b = "world"
   Dim As Integer i = 10, j = i

   If (a <> b) Then
     Print a & " does not equal " & b
   End If

   If (i <> j) Then
     Print "error: " & i & " does not equal " & j
   End If

   Operator = (Equal) is complement to Operator <> (Not equal), and is 
   functionally identical when combined with Operator Not (Bit-wise 
   Complement).

      If (69 <> 420) Then Print "(69 <> 420) is true."
      If Not (69 = 420) Then Print "not (69 = 420) is true."

Dialect Differences
   * In the -lang qb dialect, this operator cannot be overloaded.

Differences from QB
   * none

See also
   * Operator = (Equal)



------------------------------------------------------- KeyPgOpLessThan ----
Operator < (Less Than)

Compares an expression less than another expression

Syntax
   Declare Operator < ( ByRef lhs As Byte, ByRef rhs As Byte ) As Integer
   Declare Operator < ( ByRef lhs As UByte, ByRef rhs As UByte ) As Integer
   Declare Operator < ( ByRef lhs As Short, ByRef rhs As Short ) As Integer
   Declare Operator < ( ByRef lhs As UShort, ByRef rhs As UShort ) As 
   Integer
   Declare Operator < ( ByRef lhs As Integer, ByRef rhs As Integer ) As 
   Integer
   Declare Operator < ( ByRef lhs As UInteger, ByRef rhs As UInteger ) As 
   Integer
   Declare Operator < ( ByRef lhs As LongInt, ByRef rhs As LongInt ) As 
   Integer
   Declare Operator < ( ByRef lhs As ULongInt, ByRef rhs As ULongInt ) As 
   Integer

   Declare Operator < ( ByRef lhs As Single, ByRef rhs As Single ) As 
   Integer
   Declare Operator < ( ByRef lhs As Double, ByRef rhs As Double ) As 
   Integer

   Declare Operator < ( ByRef lhs As String, ByRef rhs As String ) As 
   Integer
   Declare Operator < ( ByRef lhs As ZString, ByRef rhs As ZString ) As 
   Integer
   Declare Operator < ( ByRef lhs As WString, ByRef rhs As WString ) As 
   Integer

   Declare Operator < ( ByRef lhs As T, ByRef rhs As T ) As Integer

Usage
   result = lhs < rhs

Parameters
   lhs
      The left-hand side expression to compare to.
   rhs
      The right-hand side expression to compare to.
   T
      Any pointer type.

Return Value
   Returns negative one (-1) if the left-hand side expression is less than 
   the right-hand side expression, or zero (0) if greater than or equal.

Description
   Operator < (Less than) is a binary operator that compares two 
   expressions for inequality and returns the result - a boolean value in 
   the form of an Integer: negative one (-1) for true and zero (0) for 
   false. The arguments are not modified in any way.

   When this operator is applied to string type data, then a 
   lexicographic/alphabetic order comparison is performed (ordered from the 
   numeric ASCII values of the characters of the two strings).

   This operator can be overloaded to accept user-defined types as well.

Example

   Const size As Integer = 4
   Dim array(size - 1) As Integer = { 1, 2, 3, 4 }

   Dim index As Integer = 0
   While (index < size)
      Print array(index)
      index += 1
   Wend

   Operator >= (Greater than or equal) is complement to Operator < (Less 
   than), and is functionally identical when combined with Operator Not 
   (Bit-wise Complement).

      If (69 < 420) Then Print "(69 < 420) is true."
      If Not (69 >= 420) Then Print "not (69 >= 420) is true."

Dialect Differences
   * In the -lang qb dialect, this operator cannot be overloaded.

Differences from QB
   * none

See also
   * Operator >= (Greater than or equal)



------------------------------------------------ KeyPgOpLessThanOrEqual ----
Operator <= (Less Than Or Equal)

Compares an expression less than or equal to another expression

Syntax
   Declare Operator <= ( ByRef lhs As Byte, ByRef rhs As Byte ) As Integer
   Declare Operator <= ( ByRef lhs As UByte, ByRef rhs As UByte ) As Integer
   Declare Operator <= ( ByRef lhs As Short, ByRef rhs As Short ) As Integer
   Declare Operator <= ( ByRef lhs As UShort, ByRef rhs As UShort ) As 
   Integer
   Declare Operator <= ( ByRef lhs As Integer, ByRef rhs As Integer ) As 
   Integer
   Declare Operator <= ( ByRef lhs As UInteger, ByRef rhs As UInteger ) As 
   Integer
   Declare Operator <= ( ByRef lhs As LongInt, ByRef rhs As LongInt ) As 
   Integer
   Declare Operator <= ( ByRef lhs As ULongInt, ByRef rhs As ULongInt ) As 
   Integer

   Declare Operator <= ( ByRef lhs As Single, ByRef rhs As Single ) As 
   Integer
   Declare Operator <= ( ByRef lhs As Double, ByRef rhs As Double ) As 
   Integer

   Declare Operator <= ( ByRef lhs As String, ByRef rhs As String ) As 
   Integer
   Declare Operator <= ( ByRef lhs As ZString, ByRef rhs As ZString ) As 
   Integer
   Declare Operator <= ( ByRef lhs As WString, ByRef rhs As WString ) As 
   Integer

   Declare Operator <= ( ByRef lhs As T, ByRef rhs As T ) As Integer

Usage
   result = lhs <= rhs

Parameters
   lhs
      The left-hand side expression to compare to.
   rhs
      The right-hand side expression to compare to.
   T
      Any pointer type.

Return Value
   Returns negative one (-1) if the left-hand side expression is less than 
   or equal to the right-hand side expression, or zero (0) if greater than.

Description
   Operator <= (Less than or Equal) is a binary operator that compares an 
   expression less than or equal to another expression and returns the 
   result - a boolean value in the form of an Integer: negative one (-1) 
   for true and zero (0) for false. The arguments are not modified in any 
   way.

   When this operator is applied to string type data, then a 
   lexicographic/alphabetic order comparison is performed (ordered from the 
   numeric ASCII values of the characters of the two strings).

   This operator can be overloaded to accept user-defined types as well.

Example
   Operator > (Greater than) is complement to Operator <= (Less than or 
   Equal), and is functionally identical when combined with Operator Not 
   (Bit-wise Complement).

      If (69 <= 420) Then Print "(69 <= 420) is true."
      If Not (60 > 420) Then Print "not (420 > 69) is true."

Dialect Differences
   * In the -lang qb dialect, this operator cannot be overloaded.

Differences from QB
   * none

See also
   * Operator > (Greater than)



--------------------------------------------- KeyPgOpGreaterThanOrEqual ----
Operator >= (Greater Than Or Equal)

Compares an expression greater than or equal to another expression

Syntax
   Declare Operator >= ( ByRef lhs As Byte, ByRef rhs As Byte ) As Integer
   Declare Operator >= ( ByRef lhs As UByte, ByRef rhs As UByte ) As Integer
   Declare Operator >= ( ByRef lhs As Short, ByRef rhs As Short ) As Integer
   Declare Operator >= ( ByRef lhs As UShort, ByRef rhs As UShort ) As 
   Integer
   Declare Operator >= ( ByRef lhs As Integer, ByRef rhs As Integer ) As 
   Integer
   Declare Operator >= ( ByRef lhs As UInteger, ByRef rhs As UInteger ) As 
   Integer
   Declare Operator >= ( ByRef lhs As LongInt, ByRef rhs As LongInt ) As 
   Integer
   Declare Operator >= ( ByRef lhs As ULongInt, ByRef rhs As ULongInt ) As 
   Integer

   Declare Operator >= ( ByRef lhs As Single, ByRef rhs As Single ) As 
   Integer
   Declare Operator >= ( ByRef lhs As Double, ByRef rhs As Double ) As 
   Integer

   Declare Operator >= ( ByRef lhs As String, ByRef rhs As String ) As 
   Integer
   Declare Operator >= ( ByRef lhs As ZString, ByRef rhs As ZString ) As 
   Integer
   Declare Operator >= ( ByRef lhs As WString, ByRef rhs As WString ) As 
   Integer

   Declare Operator >= ( ByRef lhs As T, ByRef rhs As T ) As Integer

Usage
   result = lhs >= rhs

Parameters
   lhs
      The left-hand side expression to compare to.
   rhs
      The right-hand side expression to compare to.
   T
      Any pointer type.

Return Value
   Returns negative one (-1) if the left-hand side expression is greater 
   than or equal to the right-hand side expression, or zero (0) if less 
   than.

Description
   Operator >= (Greater than or Equal) is a binary operator that compares 
   an expression greater than or equal to another expression and returns 
   the result - a boolean value in the form of an Integer: negative one 
   (-1) for true and zero (0) for false. The arguments are not modified in 
   any way.

   When this operator is applied to string type data, then a 
   lexicographic/alphabetic order comparison is performed (ordered from the 
   numeric ASCII values of the characters of the two strings).

   This operator can be overloaded to accept user-defined types as well.

Example
   Operator < (Less than) is complement to Operator >= (Greater than or 
   Equal), and is functionally identical when combined with Operator Not 
   (Bit-wise Complement).

      If (420 >= 69) Then Print "(420 >= 69) is true."
      If Not (420 < 69) Then Print "not (420 < 69) is true."

Dialect Differences
   * In the -lang qb dialect, this operator cannot be overloaded.

Differences from QB
   * none

See also
   * Operator < (Less than)



---------------------------------------------------- KeyPgOpGreaterThan ----
Operator > (Greater Than)

Compares an expression greater than another expression

Syntax
   Declare Operator > ( ByRef lhs As Byte, ByRef rhs As Byte ) As Integer
   Declare Operator > ( ByRef lhs As UByte, ByRef rhs As UByte ) As Integer
   Declare Operator > ( ByRef lhs As Short, ByRef rhs As Short ) As Integer
   Declare Operator > ( ByRef lhs As UShort, ByRef rhs As UShort ) As 
   Integer
   Declare Operator > ( ByRef lhs As Integer, ByRef rhs As Integer ) As 
   Integer
   Declare Operator > ( ByRef lhs As UInteger, ByRef rhs As UInteger ) As 
   Integer
   Declare Operator > ( ByRef lhs As LongInt, ByRef rhs As LongInt ) As 
   Integer
   Declare Operator > ( ByRef lhs As ULongInt, ByRef rhs As ULongInt ) As 
   Integer

   Declare Operator > ( ByRef lhs As Single, ByRef rhs As Single ) As 
   Integer
   Declare Operator > ( ByRef lhs As Double, ByRef rhs As Double ) As 
   Integer

   Declare Operator > ( ByRef lhs As String, ByRef rhs As String ) As 
   Integer
   Declare Operator > ( ByRef lhs As ZString, ByRef rhs As ZString ) As 
   Integer
   Declare Operator > ( ByRef lhs As WString, ByRef rhs As WString ) As 
   Integer

   Declare Operator > ( ByRef lhs As T, ByRef rhs As T ) As Integer

Usage
   result = lhs > rhs

Parameters
   lhs
      The left-hand side expression to compare to.
   rhs
      The right-hand side expression to compare to.
   T
      Any pointer type.

Return Value
   Returns negative one (-1) if the left-hand side expression is greater 
   than the right-hand side expression, or zero (0) if less than or equal.

Description
   Operator > (Greater than) is a binary operator that compares an 
   expression greater than another expression and returns the result - a 
   boolean value in the form of an Integer: negative one (-1) for true and 
   zero (0) for false. The arguments are not modified in any way.

   When this operator is applied to string type data, then a 
   lexicographic/alphabetic order comparison is performed (ordered from the 
   numeric ASCII values of the characters of the two strings).

   This operator can be overloaded to accept user-defined types as well.

Example
   Operator <= (Less than or equal) is complement to Operator > (Greater 
   than), and is functionally identical when combined with Operator Not 
   (Bit-wise Complement).

      If (420 > 69) Then Print "(420 > 69) is true."
      If Not (420 <= 69) Then Print "not (420 <= 69) is true."

Dialect Differences
   * In the -lang qb dialect, this operator cannot be overloaded.

Differences from QB
   * none

See also
   * Operator <= (Less than or equal)



------------------------------------------------------------- KeyPgOpIs ----
Operator Is (Run-Time Type Information)

Check if an object is compatible to a type derived from its compile-time 
type
(in the context of inheritance)

Syntax
   result = expression Is  typename

Parameters
   expression
      The expression to check, an object of a type that is directly or 
      indirectly derived from Object using Extends.
   typename
      The child type to check for. This type must be directly or indirectly 
      derived from the type of expression (the compile-time type of the 
      object).

Return Value
   Returns negative one (-1) if the expression is an object of real-type 
   typename or one of its base-types derived from the expression type, or 
   zero (0) if it's an object of an incompatible type.

Description
   The Is operator must be used in conjunction with inheritance in order to 
   check compatibility between objects and types from an inheritance 
   structure extending the built-in Object type.

   The Is operator is a binary operator that checks whether an object is 
   compatible to its derived types at run-time. Because Is relies on 
   Run-Time Type Information (RTTI), it can only be used with types that 
   are derived from the built-in Object type using Extends. The compiler 
   disallows using Is for checks that can be solved at compile-time.

   The Is operator is successful not only for the real-type (the "lowest"), 
   but also for its base-types, as long as they are still below the type of 
   expression (the compile-time type). In order to determine the real-type, 
   all possibilities from lowest to highest must be checked.

   Extending the built-in Object type allows to add an extra hidden vtable 
   pointer field at the top of the Type. The vtable is used to access 
   information for run-time type identification used by the Is operator.

   This operator cannot be overloaded.

Example
   Type Vehicle Extends Object
      As String Name
   End Type

   Type Car Extends Vehicle
   End Type

   Type Cabriolet Extends Car
   End Type

   Type Bike Extends Vehicle
   End Type

   Sub identify(ByVal p As Object Ptr)
      Print "Identifying:"

      '' Not a Vehicle object?
      If Not (*p Is Vehicle) Then
         Print , "unknown object"
         Return
      End If

      '' The cast is safe, because we know it's a Vehicle object
      Print , "name: " & CPtr(Vehicle Ptr, p)->Name

      If *p Is Car Then
         Print , "It's a car"
      End If

      If *p Is Cabriolet Then
         Print , "It's a cabriolet"
      End If

      If *p Is Bike Then
         Print , "It's a bike"
      End If
   End Sub

   Dim As Car ford
   ford.name = "Ford"
   identify(@ford)

   Dim As Cabriolet porsche
   porsche.name = "Porsche"
   identify(@porsche)

   Dim As Bike mountainbike
   mountainbike.name = "Mountain Bike"
   identify(@mountainbike)

   Dim As Vehicle v
   v.name = "some unknown vehicle"
   identify(@v)

   Dim As Object o
   identify(@o)

Differences from QB
   * New to FreeBASIC

See also
   * Extends
   * Extends Zstring
   * Extends Wstring
   * Object
   * Is (Select Case)
   * TypeOf
 



============================================================================
    Logical operators

------------------------------------------------------------ KeyPgOpAnd ----
Operator And (Conjunction)

Returns the bitwise-and (conjunction) of two numeric values

Syntax
   Declare Operator And ( ByRef lhs As T1, ByRef rhs As T2 ) As Ret

Usage
   result = lhs And rhs

Parameters
   lhs
      The left-hand side expression.
   T1
      Any numeric or boolean type.
   rhs
      The right-hand side expression.
   T2
      Any numeric or boolean type.
   Ret
      A numeric or boolean type (varies with T1 and T2).

Return Value
   Returns the bitwise-and (conjunction) of the two operands.

Description
   This operator returns the bitwise-and of its operands, a logical 
   operation that results in a value with bits set depending on the bits of 
   the operands (for conversion of a boolean to an integer, false or true 
   boolean value becomes 0 or -1 integer value).

   The truth table below demonstrates all combinations of a boolean-and 
   operation:

      +-------+-------+------+
      |Lhs Bit|Rhs Bit|Result|
      |0      |0      |0     |
      |1      |0      |0     |
      |0      |1      |0     |
      |1      |1      |1     |
      +-------+-------+------+

   No short-circuiting is performed - both expressions are always 
   evaluated.

   The return type depends on the types of values passed. Byte, UByte and 
   floating-point type values are first converted to Integer. If the left 
   and right-hand side types differ only in signedness, then the return 
   type is the same as the left-hand side type (T1), otherwise, the larger 
   of the two types is returned. Only if the left and right-hand side types 
   are both Boolean, the return type is also Boolean.

   This operator can be overloaded for user-defined types.

Example
   ' Using the AND operator on two numeric values
   Dim As UByte numeric_value1, numeric_value2
   numeric_value1 = 15 '00001111
   numeric_value2 = 30 '00011110

   'Result =  14  =     00001110
   Print numeric_value1 And numeric_value2
   Sleep

   ' Using the AND operator on two conditional expressions
   Dim As UByte numeric_value1, numeric_value2
   numeric_value1 = 15
   numeric_value2 = 25

   If numeric_value1 > 10 And numeric_value1 < 20 Then Print "Numeric_Value1 is between 10 and 20"
   If numeric_value2 > 10 And numeric_value2 < 20 Then Print "Numeric_Value2 is between 10 and 20"
   Sleep

   ' This will output "Numeric_Value1 is between 10 and 20" because
   ' both conditions of the IF statement is true
   ' It will not output the result of the second IF statement because the first
   ' condition is true and the second is false.

Dialect Differences
   * In the -lang qb dialect, this operator cannot be overloaded.

Differences from QB
   * None

See also
   * AndAlso
   * Operator Truth Tables



------------------------------------------------------------ KeyPgOpEqv ----
Operator Eqv (Equivalence)

Returns the bitwise-and (equivalence) of two numeric values

Syntax
   Declare Operator Eqv ( ByRef lhs As T1, ByRef rhs As T2 ) As Ret

Usage
   result = lhs Eqv rhs

Parameters
   lhs
      The left-hand side expression.
   T1
      Any numeric or boolean type.
   rhs
      The right-hand side expression.
   T2
      Any numeric or boolean type.
   Ret
      A numeric or boolean type (varies with T1 and T2).

Return Value
   Returns the bitwise-equivalence of the two operands.

Description
   This operator returns the bitwise-equivalence of its operands, a logical 
   operation that results in a value with bits set depending on the bits of 
   the operands (for conversion of a boolean to an integer, false or true 
   boolean value becomes 0 or -1 integer value).

   The truth table below demonstrates all combinations of a 
   boolean-equivalence operation:

      +-------+-------+------+
      |Lhs Bit|Rhs Bit|Result|
      |0      |0      |1     |
      |1      |0      |0     |
      |0      |1      |0     |
      |1      |1      |1     |
      +-------+-------+------+

   No short-circuiting is performed - both expressions are always 
   evaluated.

   The return type depends on the types of values passed. Byte, UByte and 
   floating-point type values are first converted to Integer. If the left 
   and right-hand side types differ only in signedness, then the return 
   type is the same as the left-hand side type (T1), otherwise, the larger 
   of the two types is returned. Only if the left and right-hand side types 
   are both Boolean, the return type is also Boolean.

   This operator can be overloaded for user-defined types.

Example
   Dim As UByte a = &b00110011
   Dim As UByte b = &b01010101, c
   c = a Eqv b '' c = &b10011001

Dialect Differences
   * In the -lang qb dialect, this operator cannot be overloaded.

Differences from QB
   * None

See also
   * Operator Truth Tables



------------------------------------------------------------ KeyPgOpImp ----
Operator Imp (Implication)

Returns the bitwise-and (implication) of two numeric values

Syntax
   Declare Operator Imp ( ByRef lhs As T1, ByRef rhs As T2 ) As Ret

Usage
   result = lhs Imp rhs

Parameters
   lhs
      The left-hand side expression.
   T1
      Any numeric or boolean type.
   rhs
      The right-hand side expression.
   T2
      Any numeric or boolean type.
   Ret
      A numeric or boolean type (varies with T1 and T2).

Return Value
   Returns the bitwise-implication of the two operands.

Description
   This operator returns the bitwise-implication of its operands, a logical 
   operation that results in a value with bits set depending on the bits of 
   the operands (for conversion of a boolean to an integer, false or true 
   boolean value becomes 0 or -1 integer value).

   The truth table below demonstrates all combinations of a 
   boolean-implication operation:

      +-------+-------+------+
      |Lhs Bit|Rhs Bit|Result|
      |0      |0      |1     |
      |1      |0      |0     |
      |0      |1      |1     |
      |1      |1      |1     |
      +-------+-------+------+

   No short-circuiting is performed - both expressions are always 
   evaluated.

   The return type depends on the types of values passed. Byte, UByte and 
   floating-point type values are first converted to Integer. If the left 
   and right-hand side types differ only in signedness, then the return 
   type is the same as the left-hand side type (T1), otherwise, the larger 
   of the two types is returned. Only if the left and right-hand side types 
   are both Boolean, the return type is also Boolean.

   This operator can be overloaded for user-defined types.

Example
   Dim As UByte a, b, c
   a = &b00001111
   b = &b01010101
   c = a Imp b '' c = &b11110101

Dialect Differences
   * In the -lang qb dialect, this operator cannot be overloaded.

Differences from QB
   * None

See also
   * Operator Truth Tables



------------------------------------------------------------ KeyPgOpNot ----
Operator Not (Complement)

Returns the bitwise-not (complement) of a numeric value

Syntax
   Declare Operator Not ( ByRef rhs As Byte ) As Integer
   Declare Operator Not ( ByRef rhs As UByte ) As Integer
   Declare Operator Not ( ByRef rhs As Single ) As Integer
   Declare Operator Not ( ByRef rhs As Double ) As Integer

   Declare Operator Not ( ByRef rhs As T ) As T

Usage
   result = Not rhs

Parameters
   rhs
      The right-hand side expression.
   T
      Any numeric or boolean type.

Return Value
   Returns the bitwise-complement of its operand.

Description
   This operator returns the bitwise-complement of its operand, a logical 
   operation that results in a value with bits set depending on the bits of 
   the operand.
   (for a boolean type, 'Not false' returns 'true' and 'Not true' returns 
   'false')

   The truth table below demonstrates all combinations of a 
   boolean-complement operation:

      +-------+------+
      |Rhs Bit|Result|
      |0      |1     |
      |1      |0     |
      +-------+------+

   This operator can be overloaded for user-defined types.

Example
   ' Using the NOT operator on a numeric value

   Dim numeric_value As Byte
   numeric_value = 15 '00001111

   'Result = -16 =     11110000
   Print Not numeric_value

   ' Using the NOT operator on conditional expressions
   Dim As UByte numeric_value1, numeric_value2
   numeric_value1 = 15
   numeric_value2 = 25

   If Not numeric_value1 = 10 Then Print "Numeric_Value1 is not equal to 10"
   If Not numeric_value2 = 25 Then Print "Numeric_Value2 is not equal to 25"

   ' This will output "Numeric_Value1 is not equal to 10" because
   ' the first IF statement is false.
   ' It will not output the result of the second IF statement because the
   ' condition is true. 

Dialect Differences
   * In the -lang qb dialect, this operator cannot be overloaded.

Differences from QB
   * None

See also
   * Operator Truth Tables



------------------------------------------------------------- KeyPgOpOr ----
Operator Or (Inclusive Disjunction)

Returns the bitwise-or (inclusive disjunction) of two numeric values

Syntax
   Declare Operator Or ( ByRef lhs As T1, ByRef rhs As T2 ) As Ret

Usage
   result = lhs Or rhs

Parameters
   lhs
      The left-hand side expression.
   T1
      Any numeric or boolean type.
   rhs
      The right-hand side expression.
   T2
      Any numeric or boolean type.
   Ret
      A numeric or boolean type (varies with T1 and T2).

Return Value
   Returns the bitwise-disjunction of the two operands.

Description
   This operator returns the bitwise-disjunction of its operands, a logical 
   operation that results in a value with bits set depending on the bits of 
   the operands (for conversion of a boolean to an integer, false or true 
   boolean value becomes 0 or -1 integer value).

   The truth table below demonstrates all combinations of a 
   boolean-disjunction operation:

      +-------+-------+------+
      |Lhs Bit|Rhs Bit|Result|
      |0      |0      |0     |
      |1      |0      |1     |
      |0      |1      |1     |
      |1      |1      |1     |
      +-------+-------+------+

   No short-circuiting is performed - both expressions are always 
   evaluated.

   The return type depends on the types of values passed. Byte, UByte and 
   floating-point type values are first converted to Integer. If the left 
   and right-hand side types differ only in signedness, then the return 
   type is the same as the left-hand side type (T1), otherwise, the larger 
   of the two types is returned. Only if the left and right-hand side types 
   are both Boolean, the return type is also Boolean.

   This operator can be overloaded for user-defined types.

Example
   ' Using the OR operator on two numeric values
   Dim As UByte numeric_value1, numeric_value2
   numeric_value1 = 15 '00001111
   numeric_value2 = 30 '00011110

   'Result =  31  =     00011111       
   Print numeric_value1 Or numeric_value2
   Sleep

   ' Using the OR operator on two conditional expressions
   Dim As UByte numeric_value
   numeric_value = 10

   If numeric_value = 5 Or numeric_value = 10 Then Print "Numeric_Value equals 5 or 10"
   Sleep

   ' This will output "Numeric_Value equals 5 or 10" because
   ' while the first condition of the first IF statement is false, the second is true

Dialect Differences
   * In the -lang qb dialect, this operator cannot be overloaded.

Differences from QB
   * None

See also
   * OrElse
   * Operator Truth Tables



------------------------------------------------------------ KeyPgOpXor ----
Operator Xor (Exclusive Disjunction)

Returns the bitwise-xor (exclusive disjunction) of two numeric values

Syntax
   Declare Operator Xor ( ByRef lhs As T1, ByRef rhs As T2 ) As Ret

Usage
   result = lhs Xor rhs

Parameters
   lhs
      The left-hand side expression.
   T1
      Any numeric or boolean type.
   rhs
      The right-hand side expression.
   T2
      Any numeric or boolean type.
   Ret
      A numeric or boolean type (varies with T1 and T2).

Return Value
   Returns the bitwise-xor of the two operands.

Description
   This operator returns the bitwise-exclusion of its operands, a logical 
   operation that results in a value with bits set depending on the bits of 
   the operands (for conversion of a boolean to an integer, false or true 
   boolean value becomes 0 or -1 integer value).

   The truth table below demonstrates all combinations of a 
   boolean-exclusion operation:

      +-------+-------+------+
      |Lhs Bit|Rhs Bit|Result|
      |0      |0      |0     |
      |1      |0      |1     |
      |0      |1      |1     |
      |1      |1      |0     |
      +-------+-------+------+

   No short-circuiting is performed - both expressions are always 
   evaluated.

   The return type depends on the types of values passed. Byte, UByte and 
   floating-point type values are first converted to Integer. If the left 
   and right-hand side types differ only in signedness, then the return 
   type is the same as the left-hand side type (T1), otherwise, the larger 
   of the two types is returned. Only if the left and right-hand side types 
   are both Boolean, the return type is also Boolean.

   This operator can be overloaded for user-defined types.

Example
   ' Using the XOR operator on two numeric values
   Dim As UByte numeric_value1, numeric_value2
   numeric_value1 = 15 '00001111
   numeric_value2 = 30 '00011110

   'Result =  17  =     00010001
   Print numeric_value1 Xor numeric_value2
   Sleep

   ' Using the XOR operator on two conditional expressions
   Dim As UByte numeric_value1, numeric_value2
   numeric_value1 = 10
   numeric_value2 = 15

   If numeric_value1 = 10 Xor numeric_value2 = 20 Then Print "Numeric_Value1 equals 10 or Numeric_Value2 equals 20"
   Sleep

   ' This will output "Numeric_Value1 equals 10 or Numeric_Value2 equals 20"
   ' because only the first condition of the IF statement is true

Dialect Differences
   * In the -lang qb dialect, this operator cannot be overloaded.

Differences from QB
   * None

See also
   * Operator Truth Tables




============================================================================
    Short circuit operators

-------------------------------------------------------- KeyPgOpAndAlso ----
Operator Andalso (Short Circuit Conjunction)

Returns the short circuit-and (conjunction) of two numeric values

Syntax
   Declare Operator AndAlso ( ByRef lhs As T1, ByRef rhs As T2 ) As Ret

Usage
   result = lhs AndAlso rhs

Parameters
   lhs
      The left-hand side expression.
   T1
      Any numeric or boolean type.
   rhs
      The right-hand side expression.
   T2
      Any numeric or boolean type.
   Ret
      A numeric or boolean type (varies with T1 and T2).

Return Value
   Returns the short circuit-and (conjunction) of the two operands.

Description
   This operator evaluates the left hand side expression.  If the result is 
   zero, then zero is immediately returned.  If the result is nonzero then 
   the right hand side is evaluated, and the logical result from that is 
   returned.
   (for conversion of a boolean to an integer, false or true boolean value 
   becomes 0 or -1 integer value) 

   The truth table below demonstrates all combinations of a short 
   circuit-and operation, the '-' denotes that the operand is not 
   evaluated.

      +---------+---------------+------+
      |Lhs Value|Rhs Value      |Result|
      |0        |(not evaluated)|0     |
      |nonzero  |0              |0     |
      |nonzero  |nonzero        |-1    |
      +---------+---------------+------+

   AndAlso equivalent to:
   Iif( Lhs <> 0, Rhs <> 0, 0 )

   Short-circuiting is performed - only expressions needed to calculate the 
   result are evaluated.  The left hand side lhs is evaluated first, and 
   only if it evaluates to non-zero (true) is the right hand side rhs also 
   evaluated.  If the left hand side evaluation lhs returns zero (false), 
   it is known that at that point that the overall condition is false, so 
   the right hand side rhs is not evaluated (skipped).

   The return type is almost always an Integer, of the value 0 or -1, 
   denoting false and true respectively. Except if the left and right-hand 
   side types are both Boolean, then the return type is also Boolean.

   This operator cannot be overloaded for user-defined types.

Example
   '' Using the ANDALSO operator to guard against array access
   '' when the index is out of range

   Dim As Integer isprime(1 To 10) = { _
      _ ' 1  2  3  4  5  6  7  8  9  10    (2, 3, 5 and 7 are the only prime numbers)
         0, 1, 1, 0, 1, 0, 1, 0, 0, 0 _
      }

   Dim As Integer n
   Input "Enter a number between 1 and 10: ", n

   '' isprime() array will only be accessed if n is in range
   If (n >= 1 And n <= 10) AndAlso isprime(n) Then
      Print "n is prime"
   Else
      Print "n is not prime, or out of range"
   End If
   Sleep

Differences from QB
   * This operator was not available in QB.

See also
   * OrElse
   * And
   * Operator Truth Tables



--------------------------------------------------------- KeyPgOpOrElse ----
Operator Orelse (Short Circuit Inclusive Disjunction)

Returns the short circuit-or (Inclusive Disjunction) of two numeric values

Syntax
   Declare Operator OrElse ( ByRef lhs As T1, ByRef rhs As T2 ) As Ret

Usage
   result = lhs OrElse rhs

Parameters
   lhs
      The left-hand side expression.
   T1
      Any numeric or boolean type.
   rhs
      The right-hand side expression.
   T2
      Any numeric or boolean type.
   Ret
      A numeric or boolean type (varies with T1 and T2).

Return Value
   Returns the short circuit-or (inclusive disjunction) of the two 
   operands.

Description
   This operator evaluates the left hand side expression.  If the result is 
   nonzero, then -1 (true) is immediately returned.  If the result is zero 
   then the right hand side is evaluated, and the logical result from that 
   is returned, returning -1 (true) for a nonzero value or 0 (false) for 
   zero.
   (for conversion of a boolean to an integer, false or true boolean value 
   becomes 0 or -1 integer value)

   The truth table below demonstrates all combinations of a short 
   circuit-or operation, the '-' denotes that the operand is not evaluated.

      +---------+---------------+------+
      |Lhs Value|Rhs Value      |Result|
      |0        |0              |0     |
      |0        |nonzero        |-1    |
      |nonzero  |(not evaluated)|-1    |
      +---------+---------------+------+

   OrElse equivalent to:
   Iif( Lhs = 0, Rhs <> 0 , -1 )

   Short-circuiting is performed - only expressions needed to calculate the 
   result are evaluated.  The left hand side lhs is evaluated first, and 
   only if it evaluates to zero (false) is the right hand side rhs also 
   evaluated. If the left hand side evaluation lhs returns non-zero (true), 
   it is known that at that point that the overall condition is true, so 
   the right hand side rhs is not evaluated (skipped).

   The return type is almost always an Integer, of the value 0 or -1, 
   denoting false and true respectively. Except if the left and right-hand 
   side types are both Boolean, then the return type is also Boolean.

   This operator cannot be overloaded for user-defined types.

Example
   '' Using the ORELSE operator to test
   '' if a value is out of range

   Dim As Integer n
   Input "Enter a number between 1 and 10: ", n

   Function test(ByVal n As Integer) As Integer
      Print "expression evaluated"
      Return n
   End Function

   '' print value only if n is in range [1, 10]
   If test(n) < 1 OrElse test(n) > 10 Then  '' if n < 1, second expression is not evaluated
      Print "   => out of range"
   Else
      Print "   => n ="; n
   End If
   Sleep

Differences from QB
   * This operator was not available in QB.

See also
   * AndAlso
   * Or
   * Operator Truth Tables




============================================================================
    Indexing operators

----------------------------------------------------- KeyPgOpArrayIndex ----
Operator () (Array Index)

Returns a reference to an element in an array

Syntax
   Declare Operator () ( lhs() As T, ByRef rhs As Integer, ... ) ByRef As T

Usage
      result = lhs ( rhs [, ...] )
   or
      lhs ( rhs [, ...] ) = value

Parameters
   lhs
      An array.
   rhs
      An index of an element in the array.
   T
      Any data type.

Description
   This operator returns a reference to an element in an array. For 
   multidimensional arrays, multiple indexes must be specified (up to the 
   total number of dimensions of the array).

   For any dimension d in array a, any index less than LBound(a, d) or 
   greater than UBound(a, d) will result in a runtime error.

Example

   Dim array(0 To 4) As Integer = { 0, 1, 2, 3, 4 }

   For index As Integer = 0 To 4
      Print array(index);
   Next
   Print

   will produce the output:


    0 1 2 3 4

Differences from QB
   * None

See also
   * Operator [] (Pointer Index)



---------------------------------------------------- KeyPgOpStringIndex ----
Operator [] (String Index)

Returns a reference to the numeric value of a character in a string

Syntax
   Declare Operator [] ( ByRef lhs As String, ByRef rhs As Integer ) ByRef 
   As UByte
   Declare Operator [] ( ByRef lhs As ZString, ByRef rhs As Integer ) ByRef 
   As UByte
   Declare Operator [] ( ByRef lhs As WString, ByRef rhs As Integer ) ByRef 
   As T

Usage
      result = lhs [ rhs ]
   or
      lhs [ rhs ] = value

Parameters
   lhs
      The string variable or a string reference (not for example a constant 
      or a string returned as a local copy).
   rhs
      A zero-based offset from the first character.
   T
      The wide-character type (varies per platform).

Description
   This operator returns a reference to the numeric value of a specific 
   character in a string:
      * For a String or a ZString:
            a UByte (containing the ASCII value of the character).
      * For a WString:
            a numeric type depending on platform, for example UShort for 
            Windows or ULong for Linux (containing the numeric value of the 
            character).

   This operator must not be used in case of empty string because reference 
   is undefined (inducing runtime error).
   Otherwise, the user must ensure that the index does not exceed the range 
   "[0, Len(lhs) - 1]". Outside this range, results are undefined.

   Unlike 'return by value' (where only a copy is returned), 'return by 
   reference' allows you to also modify the referenced variable.
   'Return by reference' is implemented under the hood as a pointer 
   implicitly dereferenced:
      - In case of a String or a ZString 's':
         s[n] is equivalent to *CPtr(Ubyte Ptr, StrPtr(s) + n)
      - In case of a WString 's':
         s[n] is equivalent to *CPtr(T Ptr, StrPtr(s) + n)

   Note: The fact that this operator returns a reference greatly 
   differentiates it from Asc( str [, position ] ) which allows to return 
   the numeric representation of a character, but not to modify it.

Example
   Dim a As String = "Hello, world!"
   Dim i As Integer

   For i = 0 To Len(a) - 1
      Print Chr(a[i]) & " ";
   Next i
   Print
   Print

   For i = 1 To 4
      a[i] = a[i] - 32  ' converting lowercase alphabetic characters to uppercase
   Next i
   For i = 7 To 11
      a[i] = a[i] - 32  ' converting lowercase alphabetic characters to uppercase
   Next i
   Print a
      
Will print:

   H e l l o ,   w o r l d !

   HELLO, WORLD!
   		

Differences from QB
   * New to FreeBASIC

See also
   * String Operators



------------------------------------------------------- KeyPgOpPtrIndex ----
Operator [] (Pointer Index)

Returns a reference to memory offset from an address

Syntax
   Declare Operator [] ( ByRef lhs As T Pointer, ByRef rhs As Integer ) 
   ByRef As T

Usage
      result = lhs [ rhs ]
   or
      lhs [ rhs ] = value

Parameters
   lhs
      The base address.
   rhs
      A signed offset from lhs.
   T
      Any data type.

Description
   This operator returns a reference to a value some distance in memory 
   from a base address. It is essentially shorthand for "*(lhs + rhs)" 
   because the reference can be thought of as a pointer having as value the 
   memory location "(lhs + rhs)", and which is implicitly dereferenced; 
   both do exactly the same thing.
   Like pointer arithmetic, any type of Pointer can be indexed except for 
   an Any Pointer. Also, like pointer arithmetic, it is up to the user to 
   make sure meaningful data is being accessed.

   When indexing a '2-dimensional' pointer (i.e. a T Ptr Ptr), the first 
   (leftmost) index is applied before the second: For example, Pt[I1][I2] = 
   *(Pt[I1] + I2) = *(*(Pt + I1) + I2)
   In general, when using an 'n-dimensional' pointer: Pt[I1][I2].....[In], 
   the index order (from left to right) corresponds to the dereferencing 
   order.

   This operator must not be used in case of null pointer because reference 
   is undefined (inducing runtime error).
   Otherwise, the user must ensure that the offset value (rhs) is in a 
   range that allows an access to valid memory. Outside this range, results 
   are undefined.

   This operator can be overloaded for user-defined types as a member 
   Operator using the appropriate syntax.

Example
   '' initialize a 5-element array
   Dim array(4) As Integer = { 0, 1, 2, 3, 4 }

   '' point to the first element
   Dim p As Integer Ptr = @array(0)

   '' use pointer indexing to output array elements
   For index As Integer = 0 To 4
      Print p[index];
   Next
   Print

   Will give the output,

    0 1 2 3 4

Differences from QB
   * New to FreeBASIC

See also
   * Pointer Arithmetic
   * Operator * (Value Of)
   * Operator [] (String Index)
   * Operator () (Array Index)
   * Operator + (Add)
   * Operator - (Subtract)
   * Pointer Operators




============================================================================
    String operators

--------------------------------------------------------- KeyPgOpConcat ----
Operator + (String Concatenation)

Concatenates two strings

Syntax
   Declare Operator + ( ByRef lhs As String, ByRef rhs As String ) As String
   Declare Operator + ( ByRef lhs As ZString, ByRef rhs As ZString ) As 
   ZString
   Declare Operator + ( ByRef lhs As WString, ByRef rhs As WString ) As 
   WString

Usage
   result = lhs + rhs

Parameters
   lhs
      The left-hand side string to concatenate.
   rhs
      The right-hand side string to concatenate.

Description
   This operator concatenates two strings.  Unlike 
   Operator & (String Concatenation With Conversion) both expressions must 
   be strings, and may not be converted (in fact, any attempt to 
   concatenate a string with a non-string or two non-strings will result in 
   a type mismatch error, with the exception of when operator overloading 
   is used in a UDT).

Example
   Dim As String a = "Hello, ", b = "World!"
   Dim As String c
   c = a + b
   Print c

Output:

   Hello, World!

Differences from QB
   * None

See also
   * Operator + (Add)
   * Operator & (String Concatenation With Conversion)
   * Str



-------------------------------------------------- KeyPgOpConcatConvert ----
Operator & (String Concatenation With Conversion)

Concatenates two strings, converting non-strings to strings as needed

Syntax
   Declare Operator & ( ByRef lhs As T, ByRef rhs As U ) As V

Usage
   result = lhs & rhs

Parameters
   lhs
      The left-hand side expression to concatenate.
   T
      Any standard data type or user-defined type that can be converted to 
      a standard data type.
   rhs
      The right-hand side expression to concatenate.
   U
      Any standard data type or user-defined type that can be converted to 
      a standard data type.
   V
      The resultant string type (varies with operands).

Description
   This operator concatenates two expressions. If either of the expressions 
   is not a string type, it is converted to String with Str.

   If either of the expressions is a WString, a WString is returned, 
   otherwise a String is returned.

   This operator can be overloaded to accept user-defined types.

   Note: This operator exists in C/C++ with a different meaning - there it 
   performs a bitwise And.

Example
   Dim As String A,C
   Dim As Single B
   A="The result is: "
   B=124.3
   C=A & B
   Print C
   Sleep

Output:

   The result Is: 124.3

Differences from QB
   * New to FreeBASIC

See also
   * Operator + (String Concatenation)
   * Str



--------------------------------------------------------- KeyPgOpStrptr ----
Operator Strptr (String Pointer)

Returns the address of a string's character data.

Syntax
   Declare Operator StrPtr ( ByRef lhs As String ) As ZString Ptr
   Declare Operator StrPtr ( ByRef lhs As WString ) As WString Ptr

Usage
   result = StrPtr ( lhs )

Parameters
   lhs
      A string.

Return Value
   Returns a ZString/WString Ptr to a string/wstring's character data (null 
   value in case of empty string).

Description
   This operator returns a ZString/WString Ptr that points to the beginning 
   of a string/wstring's character data. Operator Strptr is the proper 
   method for acquiring the address of a string's character data.
   In case of empty String (only for variable length strings), Operator 
   Strptr returns a null pointer.

   The related Operator Varptr (Variable Pointer) and 
   Operator @ (Address Of), when used with a String, return the address of 
   the internal string descriptor.
   When a variable length string is modified, the address of its descriptor 
   remains always the same, but the the string's character data address 
   (returned by Operator Strptr) may change (like any allocated memory that 
   must be reallocated).
   When a fixed length string is modified, the string's character data 
   address (returned by Operator Strptr) is unchanged.

   Note: For a variable length string, the operator returns a ZString Const 
   Ptr (because returning by reference the string's characters pointer set 
   in the string descriptor, this one is to be considered as read only). If 
   the keyword Var is used to declare/initialize a user pointer from 
   Operator Strptr, this user pointer is also defined as read only (it can 
   not be modified further).

   Warning: Since fbc version 1.20.0, dereferencing a zstring pointer to a 
   fixed-length string of STRING*N type (which no longer has an additional 
   terminal null character as before) can lead to an extension of the 
   string by some pollution, or even an outright crash.

Example
   '' This example uses Strptr to demonstrate using pointers with strings
   Dim myString As String
   Dim toMyStringDesc As Any Ptr
   Dim toMyString As ZString Ptr

   '' Note that using standard VARPTR notation will return a pointer to the
   '' descriptor, not the string data itself
   myString = "Improper method for Strings"
   toMyStringDesc = @myString
   Print myString
   Print Hex( toMyStringDesc )
   Print

   '' However, using Strptr returns the proper pointer
   myString = "Hello World Examples Are Silly"
   toMyString = StrPtr(myString)
   Print myString
   Print *toMyString
   Print

   '' And the pointer acts like pointers to other types
   myString = "MyString has now changed"
   Print myString
   Print *toMyString
   Print

Differences from QB
   * New to FreeBASIC, but does exactly the same thing as SAdd

See also
   * SAdd
   * VarPtr
   * ProcPtr
   * Pointers




============================================================================
    Preprocessor operators

---------------------------------------------------- KeyPgOpPpStringize ----
Operator # (Preprocessor Stringize)

Preprocessor operator to convert macro arguments to strings

Syntax
   #macro_argument

Description
   This operator converts the macro_argument into a string whose value is 
   the name of the argument. This substitution is made during the macro 
   expansion, previous to compilation.

   Note: because of this feature, care should be taken when using 
   file-handling statements in a macro.  Because of potential ambiguity 
   with file-handling statements that take a "#filenum" parameter, if 
   filenum is one of the macro parameters, it may be necessary to wrap the 
   filenum expression in parenthesis (e.g. "#(filenum)"), to separate it 
   from the # sign.  Otherwise, filenum will be stringized in the macro.

Example
   #define SEE(x) Print #x ;" = "; x
   Dim variable As Integer, another_one As Integer
   variable=1
   another_one=2
   SEE(variable)
   SEE(another_one)

Output:

   variable = 1
   another_one = 2

Differences from QB
   * New to FreeBASIC

See also
   * Preprocessor



------------------------------------------------------- KeyPgOpPpConcat ----
Operator ## (Preprocessor Concatenate)

Preprocessor operator to concatenate strings

Syntax
   text##text

Description
   This operator creates a new token by concatenating the texts at both 
   sides of it.  This text can be recognized by other macros and further 
   expanded.  One use, is to create a macro that expands to different macro 
   names, variable names, and function names depending on the arguments 
   received.

   Note:
      In macro/define's use '##_' to escape line continuation character '_' 
      to allow multiple lines of macro expanded code to be combined into a 
      single statement.

Example
   #define Concat(t,n) t##n

   Print concat (12,34)

   Dim Concat (hello,world) As Integer
   Concat (hello,world)=99
   Print helloworld

   Output:

   1234
   99

Version
   * Before fbc 1.08.0, '##_' did not allow to escape line continuation 
     character '_'.

Differences from QB
   * New to FreeBASIC

See also
   * Preprocessor



------------------------------------------------------- KeyPgOpPpEscape ----
Operator ! (Escaped String Literal)

Explicitly indicates that a string literal should be processed for escape 
sequences.

Syntax
   !"text"

Parameters
   !
      The preprocessor escaped string operator
   "text"	
      The string literal containing escape characters

Description
   This operator explicitly indicates that the string literal following it 
   (wrapped in double quotes) should be processed for escape sequences.  
   This a preprocessor operator and can only be used with string literals 
   at compile time.

   The default behavior for string literals is that they not be processed 
   for escape sequences.  Option Escape can be used in the -lang fblite 
   dialect to override this default behaviour causing all strings to be 
   processed for escape sequences.

   Use the $ Operator (Non-Escaped String Literal) operator to explicitly 
   indicate that a string should not be processed for escape sequences.

Example
   Print "Some escape sequence examples:"
   Print !"1.\tsingle quote (\\\') : \'"
   Print !"2.\tdouble quote (\\\") : \""
   Print !"3.\tbackslash    (\\\\) : \\"
   Print !"4.\tascii char   (\\65): \65"

   '' OUTPUT:
   ''
   '' Some escape sequence examples:
   '' 1.	single quote (\') : '
   '' 2.	double quote (\") : "
   '' 3.	backslash    (\\) : \
   '' 4.	ascii char   (\65): A

Differences from QB
   * New to FreeBASIC

See also
   * Operator $ (Non-Escaped String Literal)
   * Option Escape
   * Preprocessor
   * Literals
   * Escape Sequences



----------------------------------------------------- KeyPgOpPpNoescape ----
Operator $ (Non-Escaped String Literal)

Explicitly indicates that a string literal should not be processed for 
escape sequences.

Syntax
   $"text"

Parameters
   $
      The preprocessor non-escaped operator
   "text"	
      The string literal

Description
   This operator explicitly indicates that the string literal following it 
   (wrapped in double quotes) should not be processed for escape sequences. 
   This a preprocessor operator and can only be used with string literals 
   at compile time.

   The default behavior for string literals is that they not be processed 
   for escape sequences.  However, Option Escape in the -lang fblite 
   dialect can be used to override this default behaviour causing all 
   strings to be processed for escape sequences.

   Use the ! Operator (Escaped String Literal) to explicitly indicate that 
   a string should be processed for escape sequences.

Example
   '' Compile with -lang fblite or qb

   #lang "fblite"

   Print "Default"
   Print "Backslash  : \\"
   Print !"Backslash !: \\"
   Print $"Backslash $: \\"
   Print

   Option Escape

   Print "Option Escape"
   Print "Backslash  : \\"
   Print !"Backslash !: \\"
   Print $"Backslash $: \\"
   Print

   '' OUTPUT:

   '' Default
   '' Backslash  : \\
   '' Backslash !: \
   '' Backslash $: \\

   '' Option Escape
   '' Backslash  : \
   '' Backslash !: \
   '' Backslash $: \\

Differences from QB
   * New to FreeBASIC

See also
   * Operator ! (Escaped String Literal)
   * Option Escape
   * Preprocessor
   * Literals
   * Escape Sequences




============================================================================
    Pointer operators

--------------------------------------------------------- KeyPgOpVarptr ----
Operator Varptr (Variable Pointer)

Returns the address of a variable or object

Syntax
   Declare Operator VarPtr ( ByRef lhs As T ) As T Ptr

Syntax
   result = VarPtr ( lhs )

Parameters
   lhs
      A variable or object.
   T
      Any data type.

Return Value
   Returns the address of a variable or object.

Description
   This operator returns the address of its operand.

   When the operand is of type String, the address of the internal string 
   descriptor is returned. Use Operator Strptr (String Pointer) to retrieve 
   the address of the string data.

   The operand cannot be an array, but may be an array element. For 
   example, "VarPtr(myarray(0))" returns the address of "myarray(0)".

   Operator @ (Address Of), when used with variables or objects, has 
   identical behavior.

Example
   Dim a As Integer, addr As Integer
   a = 10

   '' place the address of a in addr
   addr = CInt( VarPtr(a) )

   '' change all 4 bytes (size of INTEGER) of a
   Poke Integer, addr, -1000 
   Print a

   '' place the address of a in addr (same as above)
   addr = CInt( @a )

   '' print the least or most significant byte, depending on the CPU endianess
   Print Peek( addr ) 

Differences from QB
   * None

See also
   * Pointers
   * Peek
   * Poke



--------------------------------------------------------- KeyPgOpStrptr ----
Operator Strptr (String Pointer)

Returns the address of a string's character data.

Syntax
   Declare Operator StrPtr ( ByRef lhs As String ) As ZString Ptr
   Declare Operator StrPtr ( ByRef lhs As WString ) As WString Ptr

Usage
   result = StrPtr ( lhs )

Parameters
   lhs
      A string.

Return Value
   Returns a ZString/WString Ptr to a string/wstring's character data (null 
   value in case of empty string).

Description
   This operator returns a ZString/WString Ptr that points to the beginning 
   of a string/wstring's character data. Operator Strptr is the proper 
   method for acquiring the address of a string's character data.
   In case of empty String (only for variable length strings), Operator 
   Strptr returns a null pointer.

   The related Operator Varptr (Variable Pointer) and 
   Operator @ (Address Of), when used with a String, return the address of 
   the internal string descriptor.
   When a variable length string is modified, the address of its descriptor 
   remains always the same, but the the string's character data address 
   (returned by Operator Strptr) may change (like any allocated memory that 
   must be reallocated).
   When a fixed length string is modified, the string's character data 
   address (returned by Operator Strptr) is unchanged.

   Note: For a variable length string, the operator returns a ZString Const 
   Ptr (because returning by reference the string's characters pointer set 
   in the string descriptor, this one is to be considered as read only). If 
   the keyword Var is used to declare/initialize a user pointer from 
   Operator Strptr, this user pointer is also defined as read only (it can 
   not be modified further).

   Warning: Since fbc version 1.20.0, dereferencing a zstring pointer to a 
   fixed-length string of STRING*N type (which no longer has an additional 
   terminal null character as before) can lead to an extension of the 
   string by some pollution, or even an outright crash.

Example
   '' This example uses Strptr to demonstrate using pointers with strings
   Dim myString As String
   Dim toMyStringDesc As Any Ptr
   Dim toMyString As ZString Ptr

   '' Note that using standard VARPTR notation will return a pointer to the
   '' descriptor, not the string data itself
   myString = "Improper method for Strings"
   toMyStringDesc = @myString
   Print myString
   Print Hex( toMyStringDesc )
   Print

   '' However, using Strptr returns the proper pointer
   myString = "Hello World Examples Are Silly"
   toMyString = StrPtr(myString)
   Print myString
   Print *toMyString
   Print

   '' And the pointer acts like pointers to other types
   myString = "MyString has now changed"
   Print myString
   Print *toMyString
   Print

Differences from QB
   * New to FreeBASIC, but does exactly the same thing as SAdd

See also
   * SAdd
   * VarPtr
   * ProcPtr
   * Pointers



-------------------------------------------------------- KeyPgOpProcptr ----
Operator Procptr (Procedure Pointer And Vtable Index)

Returns the address of any procedure, and the index in the vtable for a 
virtual/abstract member procedure.

Syntax
   Declare Operator ProcPtr ( ByRef identifier As proctype [, Any|
   user_proctype ] ) As internal_proctype Ptr
   Declare Operator ProcPtr ( ByRef identifier As proctype, virtual [ Any|
   user_proctype ] ) As Integer

Usage
   result = ProcPtr ( identifier [, [virtual] [any|user_proctype] ] )

Parameters
   identifier
      A procedure identifier.
   user_proctype
      Any user type of procedure (sub/function, static/member, 
      normal/virtual).
      (internal_proctype has a supplementary first parameter byref as 
      udt_name only for the member procedures of UDT udt_name)

Return Value
   Returns the address of any procedure (first syntax), or the index in the 
   vtable for a virtual/abstract member procedure (second syntax with 
   additional qualifier virtual).
   (any, ie any procedure signature, does not induce any particular 
   selection (compared to its non-use), but just allows for writing ProcPtr 
   always with 2 arguments)

Description
   First syntax:
      - This operator returns the address of a Sub or Function 
      static/member procedure or member operator.
      - The type of the return value corresponds to the internal signature 
      of the procedure (user signature, plus a supplementary first 
      parameter byref as udt_name for a member procedure) .
   Second syntax (with qualifier virtual):
      - This operator returns the zero based index in the vtable for a 
      virtual/abstract member procedure or member operator.
      - In case of overridden member procedure (polymorphism), the vtable 
      index allows access, from the vtable of the used instance, to the 
      address of the most derived override member procedure.

   When using the user_proctype argument, ProcPtr syntax allows of getting 
   procedure pointer or vtable index for based on parameter types 
   (including sub/function type and return type if any).
   This makes it possible to explicitly specify the right procedure to 
   resolve procedure overloads, or make a check for parameter types 
   (including sub/function type and return type if any) on non-overloaded 
   procedures.

   Operator @ (Address Of), when used with procedures, behaves the same as 
   the first ProcPtr syntax without second argument.

   Note:
      - If the procedure member is abstract, then  ProcPtr ( identifier [, 
      any|user_proctype ] )  returns a null procedure pointer of the member 
      procedure call signature (internal_proctype).
      - If there is no vtable entry (or no vtable at all) then  ProcPtr ( 
      identifier , virtual [any|user_proctype] )  returns the special value 
      of -1.

Example
   ' This example uses ProcPtr to demonstrate function pointers
   Declare Function Subtract( x As Integer, y As Integer) As Integer
   Declare Function Add( x As Integer, y As Integer) As Integer
   Dim myFunction As Function( x As Integer, y As Integer) As Integer

   ' myFunction will now be assigned to Add
   myFunction = ProcPtr( Add )
   Print myFunction(2, 3)

   ' myFunction will now be assigned to Subtract.  Notice the different output.
   myFunction = ProcPtr( Subtract )
   Print myFunction(2, 3)

   Function Add( x As Integer, y As Integer) As Integer
      Return x + y
   End Function

   Function Subtract( x As Integer, y As Integer) As Integer
      Return x - y
   End Function

   Sub s Overload()
   End Sub

   Sub s( ByVal i As Integer )
   End Sub

   '----- since fbc 1.09.0, ProcPtr supports a second parameter (optional):
   Var s1 = ProcPtr( s, Sub() )
   Var s2 = ProcPtr( s, Sub( ByVal i As Integer ) )

   '----- before fbc 1.09.0, it was only possible with:
   'Dim s1 As Sub()
   's1 = ProcPtr( s )
   'Dim s2 As Sub( Byval i As Integer)
   's2 = ProcPtr( s )

   ' Since fbc 1.10.0, ProcPtr supports the member procedures/operators with various syntaxes

   Type UDT Extends Object
      Dim As String s1
      Dim As String s2
      Declare Virtual Sub test()
      Declare Virtual Operator Cast() As String
   End Type

   Sub UDT.test()
      Print This.s1
   End Sub

   Operator UDT.Cast() As String
      Return This.s2
   End Operator

   Var testPtr1 = ProcPtr(UDT.test)
   Var testPtr2 = ProcPtr(UDT.test, Any)
   Var testPtr3 = ProcPtr(UDT.test, Sub())

   Dim As Function(ByRef As UDT) As String castPtr1 = ProcPtr(UDT.cast)
   Dim As Function(ByRef As UDT) As String castPtr2 = ProcPtr(UDT.cast, Any)
   Dim As Function(ByRef As UDT) As String castPtr3 =  ProcPtr(UDT.cast, Function() As String)

   Var testIndex1 = ProcPtr(UDT.test, Virtual)
   Var testIndex2 = ProcPtr(UDT.test, Virtual Any)
   Var testIndex3 = ProcPtr(UDT.test, Virtual Sub())

   Dim As Integer castIndex1 = ProcPtr(UDT.cast, Virtual)
   Dim As Integer castIndex2 = ProcPtr(UDT.cast, Virtual Any)
   Dim As Integer castIndex3 = ProcPtr(UDT.cast, Virtual Function() As String)

   Print testPtr1  '' absolue address value of UDT.test pointer
   Print testPtr2  '' absolue address value of UDT.test pointer
   Print testPtr3  '' absolue address value of UDT.test pointer
   Print

   Print castPtr1  '' absolue address value of UDT.Cast pointer
   Print castPtr2  '' absolue address value of UDT.Cast pointer
   Print castPtr3  '' absolue address value of UDT.Cast pointer
   Print

   Print testIndex1  '' vtable index of UDT.test
   Print testIndex2  '' vtable index of UDT.test
   Print testIndex3  '' vtable index of UDT.test
   Print

   Print castIndex1  '' vtable index of UDT.Cast
   Print castIndex2  '' vtable index of UDT.Cast
   Print castIndex3  '' vtable index of UDT.Cast
   Print

   Dim As UDT u
   u.s1 = "Virtual Sub test()"
   u.s2 = "Virtual Operator Cast() As String"

   testPtr1(u)  '' execute u.test() through its procedure pointer
   testPtr2(u)  '' execute u.test() through its procedure pointer
   testPtr3(u)  '' execute u.test() through its procedure pointer
   Print

   Print castPtr1(u)  '' execute Cast(UDT, u) through its procedure pointer
   Print castPtr2(u)  '' execute Cast(UDT, u) through its procedure pointer
   Print castPtr3(u)  '' execute Cast(UDT, u) through its procedure pointer
   Print

   CPtr(Sub(ByRef As UDT), CPtr(Any Ptr Ptr Ptr, @u)[0][testIndex1])(u)  '' execute u.test() through its vtable index
   CPtr(Sub(ByRef As UDT), CPtr(Any Ptr Ptr Ptr, @u)[0][testIndex2])(u)  '' execute u.test() through its vtable index
   CPtr(Sub(ByRef As UDT), CPtr(Any Ptr Ptr Ptr, @u)[0][testIndex3])(u)  '' execute u.test() through its vtable index
   Print

   Print CPtr(Function(ByRef As UDT) As String, CPtr(Any Ptr Ptr Ptr, @u)[0][castIndex1])(u)  '' execute Cast(UDT, u) through its vtable index
   Print CPtr(Function(ByRef As UDT) As String, CPtr(Any Ptr Ptr Ptr, @u)[0][castIndex2])(u)  '' execute Cast(UDT, u) through its vtable index
   Print CPtr(Function(ByRef As UDT) As String, CPtr(Any Ptr Ptr Ptr, @u)[0][castIndex3])(u)  '' execute Cast(UDT, u) through its vtable index
   Print

   Sleep

   ' Since fbc 1.10.0, ProcPtr also allows to access the vtable index of a virtual/abstract member procedure/operator

   Type Parent Extends Object
      Declare Abstract Sub VirtualTest()
      Declare Virtual Operator Cast() As String
      Declare Sub NormalTest()
   End Type

   Operator Parent.Cast() As String
      Return "Parent.Cast() As String"
   End Operator

   Sub Parent.NormalTest()
      Print "Parent.NormalTest()"
   End Sub

   Type Child Extends Parent
      Declare Virtual Sub VirtualTest()          '' or Declare Sub test()
      Declare Virtual Operator Cast() As String  '' or Declare Operator Cast() As String
      Declare Sub NormalTest()
   End Type

   Sub Child.VirtualTest()
      Print "Child.VirtualTest"
   End Sub

   Operator Child.Cast() As String
      Return "Child.Cast() As String"
   End Operator

   Sub Child.NormalTest()
      Print "Child.NormalTest()"
   End Sub

   Dim As Parent Ptr p = New Child

   (*p).VirtualTest()      '' or p->VirtualTest()
   Print Cast(Parent, *p)  '' or Print *p
   (*p).NormalTest()       '' or p->NormalTest()
   Print

   #define RuntimeProcPtr(instance, procedure, signature...) _   '' pointer to procedure
      __FB_IIF__(ProcPtr(procedure, Virtual signature) >= 0, _  '' (the most derived override if exists)
               CPtr(TypeOf(ProcPtr(procedure, signature)), _
                  CPtr(Any Ptr Ptr Ptr, @(instance)) _
                  [0][ProcPtr(procedure, Virtual signature)]), _
               ProcPtr(procedure, signature))

   '' Here, providing the procedure signature to the macro is useless
   '' (because there are no procedure overloads to solve in this case)
   RuntimeProcPtr(*p, Parent.VirtualTest)(*p)  '' execute (*p).VirtualTest() through its vtable index
   Print RuntimeProcPtr(*p, Parent.Cast)(*p)   '' execute Cast(Parent, *p) through its vtable index
   RuntimeProcPtr(*p, Parent.NormalTest)(*p)   '' execute (*p).NormalTest() through its compile address
   Print

   Delete p
   Sleep

Version
   * Before fbc 1.10.0, the member procedures/operators were not 
     supported.
   * Before fbc 1.09.0, the second argument (the optional) was not 
     supported.

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Procptr (but does not support qualifier virtual).

Differences from QB
   * New to FreeBASIC

See also
   * Sub
   * VarPtr
   * StrPtr
   * Any
   * Virtual
   * Pointers



------------------------------------------------------------- KeyPgOpAt ----
Operator @ (Address Of)

Returns the address of a string literal, variable, object or procedure

Syntax
   Declare Operator @ ( ByRef rhs As T ) As T Pointer

Usage
   result = @ rhs

Parameters
   rhs
      The string literal, variable, object or procedure to retrieve the 
      address of.
   T
      Any standard, user-defined or procedure type.

Return Value
   Returns the address of the right-hand side (rhs) operand.

Description
   Operator @ (Address of) returns the memory address of its operand.

   When the operand is of type String, the address of the internal string 
   descriptor is returned. Use Operator Strptr (String pointer) to retrieve 
   the address of the string data.

   The operand cannot be an array, but may be an array element. For 
   example, "@myarray(0)" returns the address of "myarray(0)".

   This operator can be overloaded for user-defined types as a member 
   Operator using the appropriate syntax.

Example
   'This program demonstrates the use of the @ operator.

   Dim a As Integer
   Dim b As Integer

   Dim addr As Integer Ptr

   a = 5   'Here we place the values 5 and 10 into a and b, respectively.
   b = 10

   'Here, we print the value of the variables, then where in memory they are stored.
   Print "The value in A is ";a;" but the pointer to a is ";@a
   Print "The value in B is ";b;" but the pointer to b is ";@b

   'Now, we will take the integer ptr above, and use @ to place a value into it.
   'Note that the * will check the value in the ptr, just as @ checked the ptr 
   'for a normal variable.

   addr = @a

   Print "The pointer addr is now pointing at the memory address to a, value: ";*addr

   addr = @b

   Print "The pointer addr is now pointing at the memory address to b, value: ";*addr

   'This program demonstrates how the @ symbol can be used
   'to create pointers to subroutines.

   Declare Sub mySubroutine ()

   Dim say_Hello As Sub() 

   say_Hello = @mySubroutine   'We tell say_Hello to point to mySubroutine.
                        'The sub() datatype acts as a pointer here.

   say_Hello() 'Now we can run say_Hello just like mySubroutine.

   Sub mySubroutine
      Print "hi"
   End Sub

Dialect Differences
   * In the -lang qb dialect, this operator cannot be overloaded.

Differences from QB
   * New to FreeBASIC

See also
   * VarPtr
   * ProcPtr
   * Operator * (Value Of)
   * Pointers



-------------------------------------------------------- KeyPgOpValueOf ----
Operator * (Value Of)

Dereferences a pointer

Syntax
   Declare Operator * ( ByRef rhs As T Pointer ) ByRef As T

Usage
      result = * rhs
   or
      * rhs = value

Parameters
   rhs
      The address to dereference.
   T
      Any standard, user-defined or procedure type.

Return Value
   Returns a reference to the value stored at the address rhs.

Description
   Operator * (Value of) returns a reference to the value stored at an 
   address, and is often called the dereference operator. The operand is 
   not modified in any way.
   Any type of Pointer can be dereferenced except for an Any Pointer.

   As a reference, the result of this operator can be used on the left-hand 
   side of assignments.

   This operator must not be used in case of null pointer because reference 
   is undefined (inducing runtime error).
   Otherwise, the user must ensure that the pointer value induces access to 
   a valid memory. Otherwise, results are undefined.

   This operator can be overloaded for user-defined types.

Example
   'This program demonstrates the use of * to utilize the value a pointer points to.
   Dim a As Integer
   Dim pa As Integer Ptr

   pa=@a 'Here, we use the @ operator to point our integer ptr at 'a'.
   ' 'a' is, in this case, a standard integer variable.

   a=9     'Here we give 'a' a value of 9.

   Print "The value of 'a' is";*pa 'Here, we display the value of 'a' using a pointer. 

   *pa = 1 'Here we use our pointer to change the value of 'a'
   Print "The new value of 'a' is";a 'Here we display the new value of 'a'.

Output:

   The value of 'a' is 9
   The New value of 'a' is 1

Dialect Differences
   * In the -lang qb dialect, this operator cannot be overloaded.

Differences from QB
   * New to FreeBASIC

See also
   * Operator @ (Address Of)
   * Operator [] (Pointer Index)
   * Pointers




============================================================================
    Type or Class operators

--------------------------------------------------- KeyPgOpMemberAccess ----
Operator . (Member Access)

Returns a reference to a member from a reference to an object

Syntax
   Declare Operator . ( ByRef lhs As T ) ByRef As U

Usage
   result = lhs . rhs

Parameters
   lhs
      An object.
   T
      A user-defined type.
   rhs
      The name of a member to access.
   U
      The type that rhs refers to.

Return Value
   Returns a reference to the member specified by rhs.

Description
   Operator . (Member access) returns a reference to a member of an object.

   Operator . (Member access) can also be used to access members of an 
   implicit object inside a With..End With block.

   This operator cannot be overloaded.

Example

   Type T
      As Integer a, b
   End Type

   Dim x As T

   '' Access the member 'a' of x.
   x.a = 10

   '' Access the member 'b' of x.
   With x
      .b = 20
   End With

Dialect Differences
   * None

Differences from QB
   * None

See also
   * Operator -> (Pointer To Member Access)
   * Operator @ (Address Of)
   * Operator * (Value Of)
   * With..End With

   

   


------------------------------------------------ KeyPgOpPtrMemberAccess ----
Operator -> (Pointer To Member Access)

Returns a reference to a member from a pointer to an object

Syntax
   Declare Operator -> ( ByRef lhs As T Ptr ) ByRef As U

Usage
   result = lhs -> rhs

Parameters
   lhs
      The address of an object.
   T
      A user-defined type.
   rhs
      The name of a member to access.
   U
      The type that rhs refers to.

Return Value
   Returns a reference to the member specified by rhs.

Description
   Operator -> (Pointer to member access) returns a reference to a member 
   of an object through a pointer to that object. It has the effect of 
   dereferencing a pointer to an object, then using 
   Operator . (Member Access). For example, "p->member" is equivalent to "x
   .member", if x is an object of user-defined type and p is a pointer to 
   an object of the same type. "p->member" is equivalent to "(*p).member".

   This operator can be overloaded for user-defined types.

Example

   Type rect
      x As Integer
      y As Integer
   End Type

   Dim r As rect
   Dim rp As rect Pointer = @r

   rp->x = 4
   rp->y = 2

   Print "x = " & rp->x & ", y = " & rp->y
   Sleep

Dialect Differences
   * Not available in the -lang qb dialect.

Differences from QB
   * New to FreeBASIC

See also
   * Operator . (Member Access)
   * Operator @ (Address Of)
   * Operator * (Value Of)



------------------------------------------------------------- KeyPgOpIs ----
Operator Is (Run-Time Type Information)

Check if an object is compatible to a type derived from its compile-time 
type
(in the context of inheritance)

Syntax
   result = expression Is  typename

Parameters
   expression
      The expression to check, an object of a type that is directly or 
      indirectly derived from Object using Extends.
   typename
      The child type to check for. This type must be directly or indirectly 
      derived from the type of expression (the compile-time type of the 
      object).

Return Value
   Returns negative one (-1) if the expression is an object of real-type 
   typename or one of its base-types derived from the expression type, or 
   zero (0) if it's an object of an incompatible type.

Description
   The Is operator must be used in conjunction with inheritance in order to 
   check compatibility between objects and types from an inheritance 
   structure extending the built-in Object type.

   The Is operator is a binary operator that checks whether an object is 
   compatible to its derived types at run-time. Because Is relies on 
   Run-Time Type Information (RTTI), it can only be used with types that 
   are derived from the built-in Object type using Extends. The compiler 
   disallows using Is for checks that can be solved at compile-time.

   The Is operator is successful not only for the real-type (the "lowest"), 
   but also for its base-types, as long as they are still below the type of 
   expression (the compile-time type). In order to determine the real-type, 
   all possibilities from lowest to highest must be checked.

   Extending the built-in Object type allows to add an extra hidden vtable 
   pointer field at the top of the Type. The vtable is used to access 
   information for run-time type identification used by the Is operator.

   This operator cannot be overloaded.

Example
   Type Vehicle Extends Object
      As String Name
   End Type

   Type Car Extends Vehicle
   End Type

   Type Cabriolet Extends Car
   End Type

   Type Bike Extends Vehicle
   End Type

   Sub identify(ByVal p As Object Ptr)
      Print "Identifying:"

      '' Not a Vehicle object?
      If Not (*p Is Vehicle) Then
         Print , "unknown object"
         Return
      End If

      '' The cast is safe, because we know it's a Vehicle object
      Print , "name: " & CPtr(Vehicle Ptr, p)->Name

      If *p Is Car Then
         Print , "It's a car"
      End If

      If *p Is Cabriolet Then
         Print , "It's a cabriolet"
      End If

      If *p Is Bike Then
         Print , "It's a bike"
      End If
   End Sub

   Dim As Car ford
   ford.name = "Ford"
   identify(@ford)

   Dim As Cabriolet porsche
   porsche.name = "Porsche"
   identify(@porsche)

   Dim As Bike mountainbike
   mountainbike.name = "Mountain Bike"
   identify(@mountainbike)

   Dim As Vehicle v
   v.name = "some unknown vehicle"
   identify(@v)

   Dim As Object o
   identify(@o)

Differences from QB
   * New to FreeBASIC

See also
   * Extends
   * Extends Zstring
   * Extends Wstring
   * Object
   * Is (Select Case)
   * TypeOf
 



============================================================================
    Memory operators

------------------------------------------------------------ KeyPgOpNew ----
Operator New Expression

Operator to dynamically allocate memory and construct data of a specified 
type.

Usage
   result = New datatype
      or
   result = New datatype ( initializers, ... )
      or
   result = New datatype[ count ]

Parameters
   datatype
      Name of the data type to create.
   initializers
      Initial value(s) for the variable.
   count
      Exact number of elements to allocate.

Return Value
   A pointer of type datatype to the newly allocated data, or null pointer 
   if the memory allocation failed.

Description
   The New Expression operator dynamically allocates memory and constructs 
   a specified data type.

   For simple types, like integers, an initial value can be given. For 
   types without constructors, initial values can be specified for each 
   field (either with default initializer at data-field declaration, or 
   with initializer list as in New datatype (initializers, ..) if all type 
   data-fields are numeric primitives only and without any default 
   initializers). For types with at least one constructor, the initialize 
   list (if any) must match an existing constructor. If no initializers are 
   given, the default values for those types will be set.

   New[] Expression operator is the (one-dimensional) array-version of the 
   New Expression operator and allocates enough memory for the specified 
   number of objects. The default constructor for the type will be used to 
   set the initial values for each item.

   Objects created with New Expression operator must be freed with 
   Delete Statement operator. Object array created with New[] Expression 
   operator must be freed with Delete[] Statement operator, the 
   array-version of Delete Statement operator. You cannot mix and match the 
   different versions of the operators.

   Specifying an initial value of Any, as in New datatype (Any) will 
   allocate memory for the type, but not initialize the data.  This is only 
   valid on data types that do not have constructors (otherwise for data 
   types with constructors, syntax of simple memory allocation with pointer 
   conversion, like Cptr(datatype Ptr, Allocate(Sizeof(datatype))), can be 
   substituted to the invalid use of New...Any).

   Specifying an initial value of Any, as in New datatype[count] {Any} will 
   allocate memory for the array, but not initialize the data.  This is 
   only valid on data types that do not have constructors (otherwise for 
   data types with constructors, syntax of simple memory allocation with 
   pointer conversion, like Cptr(datatype Ptr, Allocate(count * 
   Sizeof(datatype))), can be substituted to the invalid use of New...Any).

   The total memory, in bytes, to be allocated with New datatype[count] 
   expression is calculated as sizeof(datatype) * count, plus 
   sizeof(uinteger) if there is an implicit or explicit Destructor.  The 
   total memory requested in bytes to be allocated must not overflow the 
   value that can be held by a UInteger.  The extra uinteger, if allocated, 
   stores the number of elements as part of the allocation, so that 
   Delete Statement can determine the count of destructors to call.

   If the memory allocation fails, a null pointer is returned and no 
   constructors are called.

   The dynamic memory allocation process part provided by the New 
   Expression operator can be overloaded for user-defined types as a member 
   operator New Overload. The following process part for data construction 
   can never be modified.

   Note: Using pointer = New datatype[count] may be unsafe if pointer was 
   declared with a type different from datatype (for sub-type polymorphism 
   purpose for example), because the pointer arithmetic fails to access the 
   elements if the pointer type size is different from the size of datatype 
   (when using Operator [] (Pointer Index) or adding an offset (element 
   number) to the pointer, or even when Delete[] Statement itself (the 
   array-version of Delete Statement) must destroy the elements).

Example
   Type Rational
      As Integer numerator, denominator
   End Type

   ' Create and initialize a "rational" and store its address.
   Dim p As Rational Ptr = New Rational(3, 4)

   ' Test if null return pointer
   If (p = 0) Then
      Print "Error: unable to allocate memory"
   Else
      Print p->numerator & "/" & p->denominator
      ' Destroy the rational and give its memory back to the system.
      Delete p
   End If

   Sleep

   ' Allocate memory for 100 integers and store the address of the first one.
   Dim p As Integer Ptr = New Integer[100]

   ' Test if null return pointer
   If (p = 0) Then
      Print "Error: unable to allocate memory"
   Else
      ' Assign some values to the integers in the array.
      For i As Integer = 0 To 99
         p[i] = i
      Next
      ' Free the entire integer array.
      Delete[] p
   End If

   Print "Done."
   Sleep

   '' Example of nested New [] to get a 2-dimentional object array (4*3)

   Type UDT
      Dim As Integer N
      Declare Constructor ()
      Declare Destructor ()
   End Type

   Constructor UDT ()
      Print "Constructor",
   End Constructor

   Destructor UDT ()
      Print "Destructor",
   End Destructor

   Dim As UDT Ptr Ptr p = New UDT Ptr [4]  '' New [] allocation for the first dimension:
                                 ''   no internal allocation of extra uinteger because
                                 ''   allocation of array of pointers (to UDT objects with destructor)
   For I As Integer = 0 To 3
      p[I] = New UDT [5]                  '' New [] allocations for the last dimension:
                                 ''   internal allocation of an extra uinteger for each New [],
                                 ''   because allocation of an array of UDT objects with destructor
      Print
   Next I

   For I As Integer = 0 To 3
      For J As Integer = 0 To 4
         p[I][J].N = I * 10 + J  '' assignment of each object array element
      Next J
   Next I

   Print
   For I As Integer = 0 To 3
      For J As Integer = 0 To 4
         Print p[I][J].N,        '' display of each object array element
      Next J
      Print
   Next I
   Print

   For I As Integer = 0 To 3
      Delete [] p[I]  '' Delete [] deallocations for the last dimension
      Print
   Next I
   Delete [] p         '' Delete [] deallocation for the first dimension)
   Print

   Sleep

      Output example:

   Constructor   Constructor   Constructor   Constructor   Constructor
   Constructor   Constructor   Constructor   Constructor   Constructor
   Constructor   Constructor   Constructor   Constructor   Constructor
   Constructor   Constructor   Constructor   Constructor   Constructor

    0             1             2             3             4
    10            11            12            13            14
    20            21            22            23            24
    30            31            32            33            34

   Destructor    Destructor    Destructor    Destructor    Destructor
   Destructor    Destructor    Destructor    Destructor    Destructor
   Destructor    Destructor    Destructor    Destructor    Destructor
   Destructor    Destructor    Destructor    Destructor    Destructor

Dialect Differences
   * Only available in the -lang fb dialect.

Differences from QB
   * New to FreeBASIC

See also
   * Delete Statement
   * Placement New
   * New Overload



---------------------------------------------------- KeyPgOpNewOverload ----
Operator New Overload

Member operator to overload dynamic memory allocation process part provided 
by Operator New Expression when applying to a UDT (User Defined Type).

Syntax
   Declare Operator New ( size As UInteger ) As Any Ptr
   Declare Operator new[] ( size As UInteger ) As Any Ptr

Parameters
   size 
      Number of bytes to allocate.

Return Value
   A pointer of type Any Ptr to the start of the newly allocated memory.

Description
   The member operator New Overload overloads the dynamic memory allocation 
   process part provided by the New Expression operator when applying to a 
   UDT (User Defined Type). So the user can define its own dynamic memory 
   allocation process part.
   But after that, the UDT instance construction process part provided by 
   the New Expression operator is not modified.

   New[] Overload operator is the (one-dimensional) array-version of the 
   New Overload operator and overloads the dynamic memory allocation 
   process provided by the  New[] Expression operator when applying to a 
   UDT (User Defined Type).

   Memory allocated with New Overload operator must be freed by also 
   defining a Delete Overload operator. Memory allocated with New[] 
   Overload operator must be freed by also defining a Delete[] Overload 
   operator, the array-version of Delete Overload operator. You cannot mix 
   and match the different versions of the operators.

   Member operators New Overload, and New[] Overload are always static, 
   even if not explicitly declared (Static keyword is unnecessary but 
   allowed). Thus, they do not have an implicit This instance argument 
   passed to them (because instance not yet been constructed).

Example
   Dynamic allocation displayer for UDT, by using the member operators 
   "New([]) Overload" and "Delete([]) Overload" (very simple example, only 
   for syntax usage):
      * displaying of memory allocations: addresses, sizes,
      * displaying of memory deallocations: addresses.

   Type UDTdisplayer
     '' user UDT fields:
      Dim As Byte b(1 To 1024*1024)
     '' display fields:
      Public:
        Declare Operator New (ByVal size As UInteger) As Any Ptr
        Declare Operator Delete (ByVal buf As Any Ptr)
        Declare Operator New[] (ByVal size As UInteger) As Any Ptr
        Declare Operator Delete[] (ByVal buf As Any Ptr)
      Private:
        Declare Static Function allocation (ByRef N As String, ByVal size As UInteger) As Any Ptr
        Declare Static Sub deallocation (ByRef D As String, ByVal p As Any Ptr)
   End Type

   Operator UDTdisplayer.New (ByVal size As UInteger) As Any Ptr
     Return UDTdisplayer.allocation("New", size)
   End Operator

   Operator UDTdisplayer.Delete (ByVal buf As Any Ptr)
     UDTdisplayer.deallocation("Delete", buf)
   End Operator

   Operator UDTdisplayer.New[] (ByVal size As UInteger) As Any Ptr
     Return UDTdisplayer.allocation("New[]", size)
   End Operator

   Operator UDTdisplayer.Delete[] (ByVal buf As Any Ptr)
     UDTdisplayer.deallocation("Delete[]", buf)
   End Operator

   Function UDTdisplayer.allocation (ByRef N As String, ByVal size As UInteger) As Any Ptr
     Dim As Any Ptr p = Allocate(size)
     Print "memory allocation for " & size & " bytes from '" & N & "' at address: " & p
     Return p
   End Function

   Sub UDTdisplayer.deallocation (ByRef D As String, ByVal p As Any Ptr)
     Print "memory deallocation from '" & D & "' at address " & p
     Deallocate p
   End Sub

   Dim As UDTdisplayer Ptr pu1 = New UDTdisplayer
   Dim As UDTdisplayer Ptr pu2 = New UDTdisplayer[3]
   Delete pu1
   Delete[] pu2

   Sleep

      Output example:

   memory allocation For 1048576 bytes from 'New' at address: 32677920
   memory allocation For 3145728 bytes from 'New[]' at address: 33775648
   memory deallocation from 'Delete' at address 32677920
   memory deallocation from 'Delete[]' at address 33775648

   Aligned memory allocator:
      * by using the member operators "New Overload" and "Delete 
        Overload", any created User object is aligned to a multiple of 
        "ALIGN" bytes (256 bytes in this example),
      * the real pointer of the allocated memory is saved just above the 
        User pointer, in the padding block.

   Const ALIGN = 256

   Type UDT
     Dim As Byte a(0 To 10 * 1024 * 1024 - 1) '' 10 megabyte fixed array
     Declare Operator New (ByVal size As UInteger) As Any Ptr
     Declare Operator Delete (ByVal buffer As Any Ptr)
     Declare Constructor ()
     Declare Destructor ()
   End Type

   Operator UDT.New (ByVal size As UInteger) As Any Ptr
     Print "  Overloaded New operator, with parameter size = &h" & Hex(size)
     Dim pOrig As Any Ptr = CAllocate(ALIGN-1 + SizeOf(UDT Ptr) + size)
     Dim pMin As Any Ptr = pOrig + SizeOf(UDT Ptr) 
     Dim p As Any Ptr = pMin + ALIGN-1 - (CUInt(pMin + ALIGN-1) Mod ALIGN)
     Cast(Any Ptr Ptr, p)[-1] = pOrig
     Operator = p
     Print "  real pointer = &h" & Hex(pOrig), "return pointer = &h" & Hex(p)
   End Operator

   Operator UDT.Delete (ByVal buffer As Any Ptr)
     Print "  Overloaded Delete operator, with parameter buffer = &h" & Hex(buffer)
     Dim pOrig As Any Ptr = Cast(Any Ptr Ptr, buffer)[-1]
     Deallocate(pOrig)
     Print "  real pointer = &h" & Hex(pOrig)
   End Operator

   Constructor UDT ()
     Print "  Constructor, @This = &h" & Hex(@This)
   End Constructor

   Destructor UDT ()
     Print "  Destructor, @This = &h" & Hex(@This)
   End Destructor

   Print "'Dim As UDT Ptr p = New UDT'"
   Dim As UDT Ptr p = New UDT

   Print "  p = &h" & Hex(p)

   Print "'Delete p'"
   Delete p

   Sleep

      Output example:

   'Dim As UDT Ptr p = New UDT'
     Overloaded New Operator, With parameter size = &hA00000
     real Pointer = &h420020   Return Pointer = &h420100
     Constructor, @This = &h420100
     p = &h420100
   'Delete p'
     Destructor, @This = &h420100
     Overloaded Delete Operator, With parameter buffer = &h420100
     real Pointer = &h420020

   Dynamic allocation manager for UDT, by using the member operators "New[] 
   Overload" and "Delete[] Overload":
      * monitoring of memory allocations/deallocations: addresses, sizes 
        and total memory used,
      * detection of abnormal deallocation requests,
      * detection of a failed allocation (Allocate() returning null 
        pointer),
      * detection of total allocated memory size exceeding a threshold,
      * the last two detection cases induces an automatic memory freeing 
        before forcing the program to end.
   The principle is to manage a dynamic list of successful allocations, but 
   not yet freed, containing the allocated addresses with their requested 
   sizes:

   Type UDTmanager
     '' user UDT fields:
      Dim As Byte b(1 To 1024*1024)
     '' manager fields:
      Public:
        Declare Operator New[] (ByVal size As UInteger) As Any Ptr
        Declare Operator Delete[] (ByVal buf As Any Ptr)
        Static As UInteger maxmemory
      Private:
        Static As Any Ptr address()
        Static As UInteger bytes()
        Static upbound As UInteger
        Declare Static Function printLine (ByRef text As String, ByVal index As UInteger, ByVal sign As Integer) As UInteger
        Declare Static Sub endProgram ()
   End Type

   Dim As UInteger UDTmanager.maxmemory = 3 * 1024 * 1024 * 1024
   ReDim UDTmanager.address(0)
   ReDim UDTmanager.bytes(0)
   Dim UDTmanager.upbound As UInteger = 0

   Function UDTmanager.printLine (ByRef text As String, ByVal index As UInteger, ByVal sign As Integer) As UInteger
     Dim As UInteger total = 0
     For I As UInteger = 1 To UDTmanager.upbound
      If I <> index OrElse Sgn(sign) > 0 Then
        total += UDTmanager.bytes(I)
      End If
     Next I
     Print text, "&h" & Hex(UDTmanager.address(index), SizeOf(Any Ptr) * 2),
     If sign <> 0 Then
      Print Using " +####.## MB"; Sgn(sign) * Cast(Integer, UDTmanager.bytes(index) / 1024) / 1024;
     Else
      Print Using "( ####.## MB)"; UDTmanager.bytes(index) / 1024 / 1024;
     End If
     Print,
     Print Using "###.## GB"; total / 1024 / 1024 / 1024
     Return total
   End Function

   Sub UDTmanager.endProgram ()
     Do While UDTmanager.upbound > 0
      Deallocate UDTmanager.address(UDTmanager.upbound)
      UDTmanager.printLine("memory deallocation forced", UDTmanager.upbound, -1)
      UDTmanager.upbound -= 1
      ReDim Preserve UDTmanager.address(UDTmanager.upbound)
      ReDim Preserve UDTmanager.bytes(UDTmanager.upbound)
     Loop
     Print "end program forced"
     Print
     Sleep
     End
   End Sub

   Operator UDTmanager.New[] (ByVal size As UInteger) As Any Ptr
     Dim As Any Ptr p = Allocate(size)
     If p > 0 Then
      UDTmanager.upbound += 1
      ReDim Preserve UDTmanager.address(UDTmanager.upbound)
      ReDim Preserve UDTmanager.bytes(UDTmanager.upbound)
      UDTmanager.address(UDTmanager.upbound) = p
      UDTmanager.bytes(UDTmanager.upbound) = size
      If UDTmanager.printLine("memory allocation", UDTmanager.upbound, +1) > UDTmanager.maxmemory Then
        UDTmanager.address(0) = p
        UDTmanager.bytes(0) = size
        Print
        UDTmanager.printLine("memory allocation exceeded", 0, 0)
        UDTmanager.endProgram()
      End If
      Return p
     Else
      UDTmanager.address(0) = p
      UDTmanager.bytes(0) = size
      Print
      UDTmanager.printLine("memory allocation failed", 0, 0)
      UDTmanager.endProgram()
     End If
   End Operator

   Operator UDTmanager.Delete[] (ByVal buf As Any Ptr)
     Dim As UInteger found = 0
     For I As UInteger = 1 To UDTmanager.upbound
      If UDTmanager.address(I) = buf Then
        Deallocate buf
        UDTmanager.printLine("memory deallocation", I, -1)
        For J As UInteger = I + 1 To UDTmanager.upbound
         UDTmanager.address(J - 1) = UDTmanager.address(J)
         UDTmanager.bytes(J - 1) = UDTmanager.bytes(J)
        Next J
        UDTmanager.upbound -= 1
        ReDim Preserve UDTmanager.address(UDTmanager.upbound)
        ReDim Preserve UDTmanager.bytes(UDTmanager.upbound)
        found = 1
        Exit For
      End If
     Next I
     If found = 0 Then
      UDTmanager.address(0) = buf
      UDTmanager.bytes(0) = 0
      UDTmanager.printLine("deallocation not matching", 0, 0)
     End If
   End Operator

   Print "Message",, "Address" & Space(SizeOf(Any Ptr)), "Size", "Total"
   Print
   Randomize
   Dim As UDTmanager Ptr pu1 = New UDTmanager[CUInt(Rnd() * 256 + 1)]
   Dim As UDTmanager Ptr pu2 = New UDTmanager[CUInt(Rnd() * 256 + 1)]
   Dim As UDTmanager Ptr pu3 = Cast(UDTmanager Ptr, 1)
   Delete[] pu2
   Delete[] pu3
   Delete[] pu2
   Delete[] pu1
   Do
     Dim As UDTmanager Ptr pu = New UDTmanager[CUInt(Rnd() * 512 + 1)]
   Loop

      Output for fbc 32-bit (maximum dynamic data < 2 GB).
      Here, program is stopped because of memory allocation failed:

   Message                     Address       Size          Total

   memory allocation           &h020E0020       +99.00 MB    0.10 GB
   memory allocation           &h083F3020        +3.00 MB    0.10 GB
   memory deallocation         &h083F3020        -3.00 MB    0.10 GB
   deallocation Not matching   &h00000001    (    0.00 MB)   0.10 GB
   deallocation Not matching   &h083F3020    (    0.00 MB)   0.10 GB
   memory deallocation         &h020E0020       -99.00 MB    0.00 GB
   memory allocation           &h020ED020      +103.00 MB    0.10 GB
   memory allocation           &h087F2020      +106.00 MB    0.20 GB
   memory allocation           &h0F20D020      +230.00 MB    0.43 GB
   memory allocation           &h1D812020      +137.00 MB    0.56 GB
   memory allocation           &h2612C020      +377.00 MB    0.93 GB
   memory allocation           &h3DA30020      +275.00 MB    1.20 GB
   memory allocation           &h4ED40020      +220.00 MB    1.41 GB
   memory allocation           &h5C958020      +229.00 MB    1.64 GB

   memory allocation failed    &h00000000    (  142.00 MB)   1.64 GB
   memory deallocation forced  &h5C958020      -229.00 MB    1.41 GB
   memory deallocation forced  &h4ED40020      -220.00 MB    1.20 GB
   memory deallocation forced  &h3DA30020      -275.00 MB    0.93 GB
   memory deallocation forced  &h2612C020      -377.00 MB    0.56 GB
   memory deallocation forced  &h1D812020      -137.00 MB    0.43 GB
   memory deallocation forced  &h0F20D020      -230.00 MB    0.20 GB
   memory deallocation forced  &h087F2020      -106.00 MB    0.10 GB
   memory deallocation forced  &h020ED020      -103.00 MB    0.00 GB
   End program forced

      Output for fbc 64-bit (maximum dynamic data < virtual memory).
      Here, program is stopped because of total allocated memory size > 3 
      GB (adjustable threshold):

   Message                     Address                     Size          Total

   memory allocation           &h0000000001EA5040            +105.00 MB    0.10 GB
   memory allocation           &h00000000087BC040             +93.00 MB    0.19 GB
   memory deallocation         &h00000000087BC040             -93.00 MB    0.10 GB
   deallocation Not matching   &h0000000000000001          (    0.00 MB)   0.10 GB
   deallocation Not matching   &h00000000087BC040          (    0.00 MB)   0.10 GB
   memory deallocation         &h0000000001EA5040            -105.00 MB    0.00 GB
   memory allocation           &h0000000001EA1040            +155.00 MB    0.15 GB
   memory allocation           &h000000000B9BF040            +165.00 MB    0.31 GB
   memory allocation           &h0000000015ED8040            +382.00 MB    0.69 GB
   memory allocation           &h000000002DCE7040            +458.00 MB    1.13 GB
   memory allocation           &h000000004A6FB040            +255.00 MB    1.38 GB
   memory allocation           &h000000005A607040             +96.00 MB    1.48 GB
   memory allocation           &h000000006061B040            +426.00 MB    1.89 GB
   memory allocation           &h000000007FFF9040            +221.00 MB    2.11 GB
   memory allocation           &h000000008DD03040            +119.00 MB    2.22 GB
   memory allocation           &h0000000095413040            +147.00 MB    2.37 GB
   memory allocation           &h000000009E727040            +217.00 MB    2.58 GB
   memory allocation           &h00000000AC03C040            +334.00 MB    2.91 GB
   memory allocation           &h00000000C0E4B040            +280.00 MB    3.18 GB

   memory allocation exceeded  &h00000000C0E4B040          (  280.00 MB)   3.18 GB
   memory deallocation forced  &h00000000C0E4B040            -280.00 MB    2.91 GB
   memory deallocation forced  &h00000000AC03C040            -334.00 MB    2.58 GB
   memory deallocation forced  &h000000009E727040            -217.00 MB    2.37 GB
   memory deallocation forced  &h0000000095413040            -147.00 MB    2.22 GB
   memory deallocation forced  &h000000008DD03040            -119.00 MB    2.11 GB
   memory deallocation forced  &h000000007FFF9040            -221.00 MB    1.89 GB
   memory deallocation forced  &h000000006061B040            -426.00 MB    1.48 GB
   memory deallocation forced  &h000000005A607040             -96.00 MB    1.38 GB
   memory deallocation forced  &h000000004A6FB040            -255.00 MB    1.13 GB
   memory deallocation forced  &h000000002DCE7040            -458.00 MB    0.69 GB
   memory deallocation forced  &h0000000015ED8040            -382.00 MB    0.31 GB
   memory deallocation forced  &h000000000B9BF040            -165.00 MB    0.15 GB
   memory deallocation forced  &h0000000001EA1040            -155.00 MB    0.00 GB
   End program forced

Dialect Differences
   * Only available in the -lang fb dialect.

Differences from QB
   * New to FreeBASIC

See also
   * New Expression
   * Delete Overload
   * Allocate



--------------------------------------------------- KeyPgOpPlacementNew ----
Operator Placement New

Operator to construct an object at a specified memory address.

Syntax
   result = New(address) datatype
      or
   result = New(address) datatype ( initializers, ... )
      or
   result = New(address) datatype[ count ]

Parameters
   address 
      the location in memory to construct. the parenthesis are not 
      optional.
   initializers
      Initial value(s) for the variable.
   datatype
      name of the data type to construct.
   count
      Number of elements to construct.

Return Value
   A pointer of type datatype to the newly constructed data.

Description
   The Placement New operator constructs a specified data type at the 
   specified memory location. 

   For simple types, like integers, an initial value can be given. For 
   types without Constructors, initial values can be specified for each 
   field (either with default initializer at data-field declaration, or 
   with initializer list as in New datatype (initializers, ..) if all type 
   data-fields are numeric primitives only and without any default 
   initializers). For types with at least one constructor, the initialize 
   list (if any) must match an existing constructor. If no initializers are 
   given, the default values for those types will be set.

   Memory is not allocated when using the Placement New operator. Instead, 
   the memory at the specified address is used (the provided memory size 
   must be large enough to contain all the placement).
   It is incorrect to call Delete Statement on the address. The proper way 
   is to only call the destructor if one exists (implicitly or explicitly), 
   with syntax as for a member method by using member access operator.
   See examples below for proper Placement New operator usage.

   Placement New[] operator is the (one-dimensional) array-version of the 
   Placement New operator and constructs the specified number of objects 
   from the specified memory location. The default constructor for the type 
   will be used to set the initial values for each item.

   Specifying an initial value of Any, as in New(address)datatype (Any) or 
   New(address)datatype[count] {Any} will not initialize the data.  This is 
   only valid on data types that do not have constructors (otherwise for 
   data types with constructors, syntax of simple pointer conversion, like 
   Cptr(datatype Ptr, address), can be substituted to the invalid use of 
   New...Any).

   Because it does not provide any dynamic memory allocation process, the 
   Placement New operator (unlike the New Expression operator) does not 
   allow any overloading by a member operator for user-defined types.

   Note: Using pointer = New(address)datatype[count] may be unsafe if 
   pointer was declared with a type different from datatype (for sub-type 
   polymorphism purpose for example), because the pointer arithmetic fails 
   to access the elements if the pointer type size is different from the 
   size of datatype (when using Operator [] (Pointer Index) or adding an 
   offset (element number) to the pointer).

Example
   '' "placement new" example

   Type Rational
      As Integer    numerator, denominator
      Declare Constructor ( ByVal n As Integer, ByVal d As Integer )
      As String ratio = "/"
   End Type

   Constructor Rational ( ByVal n As Integer, ByVal d As Integer )
      This.numerator = n
      This.denominator = d
   End Constructor

   Scope
      
      '' allocate some memory to construct as a Rational
      Dim As Any Ptr ap = CAllocate(Len(Rational))
      
      '' make the placement new call
      Dim As Rational Ptr r = New (ap) Rational( 3, 4 )
      
      '' you can see, the addresses are the same, just having different types in the compiler
      Print ap, r
      
      '' confirm all is okay
      Print r->numerator & r->ratio & r->denominator
      
      '' delete must not be used with placement new
      '' destroying must be done explicitly if a destructor exists (implicitly or explicitly)
      ''   (in this example, the var-string member induces an implicit destructor)
      r->Destructor( )
      
      '' we explicitly allocated, so we explicitly deallocate
      Deallocate( ap )
      
   End Scope

Dialect Differences
   * Only available in the -lang fb dialect.

Differences from QB
   * New to FreeBASIC

See also
   * Destructor
   * New Expression



--------------------------------------------------------- KeyPgOpDelete ----
Operator Delete Statement

Operator to destroy data and free memory allocated with the 
Operator New Expression

Usage
   Delete buf
      or
   Delete[] buf

Parameters
   buf 
      A pointer to memory that has been allocated by New Expression 
      operator or New[] Expression operator, the array-version of 
      New Expression operator (a typed pointer must be provided in 
      accordance to the data type to delete).

Description
   The Delete Statement operator is used to destroy and free the memory of 
   an object created with New Expression operator. When deleting a TYPE, 
   its destructor will be called. Delete Statement operator should only be 
   used with addresses returned from New Expression operator.

   The array version of Delete Statement operator, Delete[] Statement 
   operator, is used to destroy an array of objects previously created with 
   New[] Expression operator, the array-version of New Expression operator. 
   Destructors will be called here as well.

   Delete Statement operator must be used with addresses returned from 
   New Expression operator, and Delete[] Statement operator with New[] 
   Expression operator, the array-version of New Expression operator. You 
   cannot mix and match the different versions of the operators.

   After the memory is deleted, the buf pointer will be pointing at invalid 
   memory. Calling Delete Expression twice on the same pointer value leads 
   to undefined behavior. It may be a good idea to set the buf pointer to 
   null (0), in order to guard against later code using it accidentally, 
   since null pointer dereferences are easier to find and debug.

   Calling Delete Statement operator on a null pointer induces no action.

   The memory deallocation process part provided by the Delete Statement 
   operator can be overloaded for user-defined types as a member operator 
   Delete Overload. The previous process part for data destruction can 
   never be modified.

   Note: Any operator Delete[] (Statement or Overload) and the only 
   Overload operator Delete are not compatible with sub-type polymorphism, 
   even using Override Virtual Destructor that may in addition induce 
   crashing.
   Instead of having to call such an operator Delete([]) Statement on 
   derived-type pointer, the safest way is to simply call (on base-type 
   pointer) an overridden user Virtual member procedure that will 
   automatically launch the operator Delete([]) Statement at derived-type 
   level.

Example
   Type Rational
      As Integer numerator, denominator
   End Type

   ' Create and initialize a Rational, and store its address.
   Dim p As Rational Ptr = New Rational(3, 4)

   Print p->numerator & "/" & p->denominator

   ' Destroy the rational and give its memory back to the system. 
   Delete p

   ' Set the pointer to null to guard against future accesses
   p = 0

   ' Allocate memory for 100 integers, store the address of the first one.
   Dim p As Integer Ptr = New Integer[100]

   ' Assign some values to the integers in the array.
   For i As Integer = 0 To 99
      p[i] = i
   Next

   ' Free the entire integer array.
   Delete[] p

   ' Set the pointer to null to guard against future accesses
   p = 0

Dialect Differences
   * Only available in the -lang fb dialect.

Differences from QB
   * New to FreeBASIC

See also
   * New Expression
   * Delete Overload
   * Deallocate



------------------------------------------------- KeyPgOpDeleteOverload ----
Operator Delete Overload

Member operator to overload memory deallocation process part provided by 
Operator Delete Statement when applying to a UDT (User Defined Type).

Syntax
   Declare Operator Delete ( buf  As Any Ptr )
   Declare Operator delete[] ( buf  As Any Ptr )

Parameters
   buf 
      A pointer to memory that has been allocated by New Overload operator 
      or New[] Overload operator, the array-version of New Overload 
      operator.

Description
   The member operator Delete Overload overloads the memory deallocation 
   process part provided by the Delete Statement operator when applying to 
   a UDT (User Defined Type). So the user can define its own memory 
   deallocation process part.
   But before that, the UDT instance destruction process part provided by 
   the Delete Statement operator is not modified.

   Delete[] Overload operator is the array-version of Delete Overload 
   operator and overloads the memory deallocation process provided by the 
   Delete[] Statement operator when applying to a UDT (User Defined Type).

   Memory freed with Delete Overload operator must have be allocated by 
   also defining a New Overload operator. Memory freed with Delete[] 
   Overload operator must have been allocated by also defining a New[] 
   Overload operator, the array-version of New Overload operator. You 
   cannot mix and match the different versions of the operators.

   Member operators Delete Overload, and Delete[] Overload are always 
   static, even if not explicitly declared (Static keyword is unnecessary 
   but allowed). Thus, they do not have an implicit This instance argument 
   passed to them (because instance already been destroyed).

Example
   See the New Overload operator examples.

Dialect Differences
   * Only available in the -lang fb dialect.

Differences from QB
   * New to FreeBASIC

See also
   * Delete Statement
   * New Overload
   * Deallocate




============================================================================
    Iterating operators

------------------------------------------------------------ KeyPgOpFor ----
Operator For (Iteration)

Declares or defines operators used by a For...Next loop with user defined 
type variables

Syntax
   { Type | Class | Union } typename
      Declare Operator For ()
      Declare Operator For ( [ ByRef | ByVal ] stp As typename )
      ...
   End { Type | Class | Union }

Usage
   For iterator [ As typename ] = start_value To end_value [ Step 
   step_value ]
      [ ...statements... ]
   Next

Parameters
(including arguments)
   typename
      name of the Type, Class, or Union
   stp, step_value
      a typename object used as an incremental value
   iterator
      a typename object used as an iterator
   end_value
      a typename object used as a loop-terminating value
   start_value
      a typename object used to copy construct or assign to the iterator 
      initially

Description
   Operator For, Operator Next and Operator Step can be overloaded in 
   user-defined type definitions to allow objects of that type to be used 
   as iterators and step values in For...Next loops.
   As all non-static member procedures, they have passed a hidden This 
   parameter that allows to access by reference to the iterator object in 
   the code body of the 3 operators.

   Operator For is called once after copy constructing or assigning to the 
   iterator object, and allows the object to perform any additional 
   initialization needed in preparation for the loop.

   The first version of Operator For is used if no step value is given in 
   the For...Next statement. If a step value is given, the second version 
   is used and is passed the step value because eventual additional 
   initialization may use it.

   Advanced usage
      The above description seems to imply that the 3 arguments start_value
      , end_value, and step_value must be of the same type as the iterator 
      (this is the more obvious use), but it is not quite true:
         - The start_value, end_value, and step_value arguments can be of 
         any type (of different types among themselves and also of 
         different types from the one of the iterator).
         - The only constraint is that the iterator could be constructed 
         (in case of local iterator) or assigned (in case of global 
         iterator) from the start_value argument (because the iterator is 
         implicitly constructed or assigned under the hood).
         - Similarly the other parameters end_value, and step_value must be 
         able to be converted into objects of the same type as the iterator
         .

Example
   See the Operator Step examples.

Dialect Differences
   * Only available in the -lang fb dialect.

See also
   * Operator Next
   * Operator Step
   * For...Next

   


----------------------------------------------------------- KeyPgOpStep ----
Operator Step (Iteration)

Increments the iterator of a For...Next loop

Syntax
   { Type | Class | Union } typename
      Declare Operator Step ()
      Declare Operator Step ( [ ByRef | ByVal ] stp As typename )
      ...
   End { Type | Class | Union }

Usage
   For iterator [ As typename ] = start_value To end_value [ Step 
   step_value ]
      [ ...statements... ]
   Next

Parameters
(including arguments)
   typename
      name of the Type, Class, or Union
   stp, step_value
      a typename object used as an incremental value
   iterator
      a typename object used as an iterator
   end_value
      a typename object used as a loop-terminating value
   start_value
      a typename object used to copy construct or assign to the iterator 
      initially

Description
   Operator For, Operator Next and Operator Step can be overloaded in 
   user-defined type definitions to allow objects of that type to be used 
   as iterators and step values in For...Next loops.
   As all non-static member procedures, they have passed a hidden This 
   parameter that allows to access by reference to the iterator object in 
   the code body of the 3 operators.

   Operator Step is called to increment the iterator object immediately 
   after all statements in the For...Next body are executed, if any.

   The first version of Operator Step is used if no step value is given in 
   the For...Next statement. If a step value is given, the second version 
   is used and is passed the step value to increment the iterator object.

   Advanced usage
      The above description seems to imply that the 3 arguments start_value
      , end_value, and step_value must be of the same type as the iterator 
      (this is the more obvious use), but it is not quite true:
         - The start_value, end_value, and step_value arguments can be of 
         any type (of different types among themselves and also of 
         different types from the one of the iterator).
         - The only constraint is that the iterator could be constructed 
         (in case of local iterator) or assigned (in case of global 
         iterator) from the start_value argument (because the iterator is 
         implicitly constructed or assigned under the hood).
         - Similarly the other parameters end_value, and step_value must be 
         able to be converted into objects of the same type as the iterator
         .

Example
   '' Example Type
   Type T
     '' value is set by the constructor
     value As Double
     Declare Constructor( ByVal x As Double = 0 )

     Declare Operator For( ByRef stp As T )
     Declare Operator Step( ByRef stp As T )
     Declare Operator Next( ByRef cond As T, ByRef stp As T ) As Integer
   End Type

   Constructor T ( ByVal x As Double )
     Print "T iterator constructed with value " & x
     value = x
   End Constructor

   Operator T.for( ByRef stp As T )
   End Operator

   Operator T.step( ByRef stp As T )
     Print " incremented by " & stp.value & " in step."
     value += stp.value
   End Operator

   Operator T.next( ByRef cond As T, ByRef stp As T ) As Integer
     '' iterator's moving from a high value to a low value (step >= 0)
     If( stp.value < 0 ) Then
      Return( value >= cond.value )
     Else
     '' iterator's moving from a low value to a high value (step < 0)
      Return( value <= cond.value )
     End If
   End Operator

   '' Example Usage. It looks like we are working with numbers, but the iterators
   '' have overloaded constructors. The 10, 1, and -1 are all of type T.
   For i As T = 10 To 1 Step -1
     Print i.value;
   Next i
      

   A more practical example demonstrating file iteration based on 
   cha0s' file iteration class:
   '' a class which iterates through files
   Type FileIter
      As String pathName, fileName
      Declare Constructor( ByRef pathName As String )

      Declare Operator For()
      Declare Operator Step()
      Declare Operator Next( ByRef endCond As FileIter) As Integer
   End Type

   Constructor FileIter( ByRef pathName As String )   
      this.pathName = pathName
   End Constructor

   Operator FileIter.for( )   
      fileName = Dir(pathName & "/*.*")   
   End Operator

   Operator FileIter.step( )   
      fileName = Dir("")
   End Operator

   Operator FileIter.next( ByRef endCond As FileIter ) As Integer
      Return(fileName <> endCond.pathName)   
      '' the c'tor sets the path name and so we check against that
   End Operator

   '' example code
   '' change it to any directory
   For i As FileIter = "./" To ""
      Print i.fileName
   Next
      

   Another example working with strings:
   Type CharIterator
      '' used to build a step var
      Declare Constructor( ByVal r As ZString Ptr )
      
      '' implicit step versions
      Declare Operator For ( )
      Declare Operator Step( )
      Declare Operator Next( ByRef end_cond As CharIterator ) As Integer
      
      '' explicit step versions
      Declare Operator For ( ByRef step_var As CharIterator )
      Declare Operator Step( ByRef step_var As CharIterator )
      Declare Operator Next( ByRef end_cond As CharIterator, ByRef step_var As CharIterator ) As Integer
      
      '' give the current "value"    
      Declare Operator Cast( ) As String
      
      Private:   
         '' data
         value As String
         
         '' This member isn't necessary - we could use
         '' the step variable on each iteration - 
         '' but we choose this method, since we have
         '' to compare strings otherwise. See below.
         is_up As Integer
   End Type

   Constructor CharIterator( ByVal r As ZString Ptr )
      value = *r
   End Constructor

   Operator CharIterator.cast( ) As String
      Operator = value
   End Operator

   '' implicit step versions
   '' 
   '' In this example, we interpret implicit step
   '' to always mean 'up'
   Operator CharIterator.for( )
      Print "implicit step"
   End Operator

   Operator CharIterator.step( )
      value[0] += 1
   End Operator 

   Operator CharIterator.next( ByRef end_cond As CharIterator ) As Integer
      Return this.value <= end_cond.value
   End Operator

   '' explicit step versions
   '' 
   '' In this example, we calculate the direction
   '' at FOR, but since the step var is passed to
   '' each operator, we have the choice to also calculate
   '' it "on-the-fly". For strings such as this, repeated comparison
   '' may penalize, but if you're working with simpler types,
   '' then you may prefer to avoid the overhead of 
   '' an 'is_up' variable.
   Operator CharIterator.for( ByRef step_var As CharIterator )
      Print "explicit step"
      is_up = (step_var.value = "up")
   End Operator

   Operator CharIterator.step( ByRef step_var As CharIterator )
      If( is_up ) Then
         value[0] += 1
      Else
         value[0] -= 1
      End If
   End Operator 

   Operator CharIterator.next( ByRef end_cond As CharIterator, ByRef step_var As CharIterator ) As Integer
      If( this.is_up ) Then
         Return this.value <= end_cond.value
      Else
         Return this.value >= end_cond.value
      End If
   End Operator

   For i As CharIterator = "a" To "z"
      Print i; " ";
   Next
   Print "done"

   For i As CharIterator = "a" To "z" Step "up"
      Print i; " ";
   Next
   Print "done"

   For i As CharIterator = "z" To "a" Step "down"
      Print i; " ";
   Next
   Print "done"

   For i As CharIterator = "z" To "a" Step "up"
      Print i; " ";
   Next
   Print "done"
      

   Iterating with fractions:
   Type fraction
      '' Used to build a step var
      Declare Constructor( ByVal n As Integer, ByVal d As Integer )

      '' Implicit step versions
      Declare Operator For ( )
      Declare Operator Step( )
      Declare Operator Next( ByRef end_cond As fraction ) As Integer

      '' Explicit step versions
      Declare Operator For ( ByRef step_var As fraction )
      Declare Operator Step( ByRef step_var As fraction )
      Declare Operator Next( ByRef end_cond As fraction, ByRef step_var As fraction ) As Integer

      '' Give the current "value"    
      Declare Operator Cast( ) As Double
      Declare Operator Cast( ) As String

      Private:
         As Integer num, den
   End Type

   Constructor fraction( ByVal n As Integer, ByVal d As Integer )
      This.num = n : This.den = d
   End Constructor

   Operator fraction.Cast( ) As Double
      Operator = num / den
   End Operator

   Operator fraction.Cast( ) As String
      Operator = num & "/" & den
   End Operator

   '' Some fraction functions
   Function gcd( ByVal n As Integer, ByVal m As Integer ) As Integer
      Dim As Integer t
         While m <> 0
            t = m
            m = n Mod m
            n = t
         Wend
      Return n
   End Function

   Function lcd( ByVal n As Integer, ByVal m As Integer ) As Integer
      Return (n * m) / gcd( n, m )
   End Function

   ''
   '' Implicit step versions
   ''
   '' In this example, we interpret implicit step
   '' to mean 1
   ''
   Operator fraction.For( )
      Print "implicit step"
   End Operator

   Operator fraction.Step( )
      Dim As Integer lowest = lcd( This.den, 1 )
      Dim As Double mult_factor = This.den / lowest
      Dim As fraction step_temp = fraction( 1, 1 )
      
      This.num *= mult_factor
      This.den *= mult_factor
      
      step_temp.num *= lowest
      step_temp.den *= lowest
      
      This.num += step_temp.num
   End Operator

   Operator fraction.Next( ByRef end_cond As fraction ) As Integer
      Return This <= end_cond
   End Operator

   ''
   '' Explicit step versions
   ''
   Operator fraction.For( ByRef step_var As fraction )
      Print "explicit step"
   End Operator

   Operator fraction.Step( ByRef step_var As fraction )
      Dim As Integer lowest = lcd( This.den, step_var.den )
      Dim As Double mult_factor = This.den / lowest
      Dim As fraction step_temp = step_var

      This.num *= mult_factor
      This.den *= mult_factor

      mult_factor = step_temp.den / lowest

      step_temp.num *= mult_factor
      step_temp.den *= mult_factor

      This.num += step_temp.num
   End Operator

   Operator fraction.Next( ByRef end_cond As fraction, ByRef step_var As fraction ) As Integer
      If(( step_var.num < 0 ) Or ( step_var.den < 0 ) ) Then
         Return This >= end_cond
      Else
         Return This <= end_cond
      End If
   End Operator

   For i As fraction = fraction(1,1) To fraction(4,1)
      Print i; " ";
   Next
   Print "done"

   For i As fraction = fraction(1,4) To fraction(1,1) Step fraction(1,4)
      Print i; " ";
   Next
   Print "done"

   For i As fraction = fraction(4,4) To fraction(1,4) Step fraction(-1,4)
      Print i; " ";
   Next
   Print "done"

   For i As fraction = fraction(4,4) To fraction(1,4)
      Print i; " ";
   Next
   Print "done"
      

Dialect Differences
   * Only available in the -lang fb dialect.

See also
   * Operator For
   * Operator Next
   * For...Next



----------------------------------------------------------- KeyPgOpNext ----
Operator Next (Iteration)

Determines if a For...Next loop should be terminated

Syntax
   { Type | Class | Union } typename
      Declare Operator Next ( [ ByRef | ByVal ] cond As typename ) As 
      Integer
      Declare Operator Next ( [ ByRef | ByVal ] cond As typename, [ ByRef | 
      ByVal ] stp As typename ) As Integer
      ...
   End { Type | Class | Union }

Usage
   For iterator [ As typename ] = start_value To end_value [ Step 
   step_value ]
      [ ...statements... ]
   Next

Parameters
(including arguments)
   typename
      name of the Type, Class, or Union
   cond, end_value
      a typename object used as a loop-terminating value
   stp, step_value
      a typename object used as an incremental value
   iterator
      a typename object used as an iterator
   start_value
      a typename object used to copy construct or assign to the iterator 
      initially

Description
   Operator For, Operator Next and Operator Step can be overloaded in 
   user-defined type definitions to allow objects of that type to be used 
   as iterators and step values in For...Next loops.
   As all non-static member procedures, they have passed a hidden This 
   parameter that allows to access by reference to the iterator object in 
   the code body of the 3 operators.

   Operator Next is called every time the iterator object needs to be 
   checked against the end value. This happens immediately after the call 
   to its Operator For, and immediately after any calls to its Operator Step
   . Operator Next should return zero (0) if the loop should be terminated, 
   or non-zero if the loop should continue iterating. The first time 
   Operator Next is called, no statements in the For...Next body, if any, 
   have been executed yet.

   The first version of Operator Next is used if no step value is given in 
   the For...Next statement. If a step value is given, the second version 
   is used and is passed the step value because testing for iterating end 
   may depend on it.

   Advanced usage
      The above description seems to imply that the 3 arguments start_value
      , end_value, and step_value must be of the same type as the iterator 
      (this is the more obvious use), but it is not quite true:
         - The start_value, end_value, and step_value arguments can be of 
         any type (of different types among themselves and also of 
         different types from the one of the iterator).
         - The only constraint is that the iterator could be constructed 
         (in case of local iterator) or assigned (in case of global 
         iterator) from the start_value argument (because the iterator is 
         implicitly constructed or assigned under the hood).
         - Similarly the other parameters end_value, and step_value must be 
         able to be converted into objects of the same type as the iterator
         .

Example
   See the Operator Step examples.

Dialect Differences
   * Only available in the -lang fb dialect.

See also
   * Operator For
   * Operator Step
   * For...Next



---------------------------------------------------------- OpPrecedence ----
Operator Precedence

   When several operations occur in a single expression, each operation is 
   evaluated and resolved in a predetermined order. This is called the 
   order of operation or operator precedence. 

   If an operator in an expression has a higher precedence, it is evaluated 
   before an operator of lower precedence. 

   If operators have equal precedence, they then are evaluated in the order 
   in of their associativity.  The associativity may be Left-to-Right or 
   Right-to-Left order.

   As a rule, binary operators (such as +, ^) and unary postfix operators 
   (such as (), ->) are evaluated Left-to-Right, and unary prefix operators 
   (such as Not, @) are evaluated Right-to-Left.

   Operators that have an associativity of "N/A" indicate that there is no 
   expression in which the operator can be used where its order of 
   operation would need to be checked, either by precedence or by 
   associativity.  Function-like operators such as Cast are always the 
   first to be evaluated due to the parentheses required in their syntax.  
   And assignment operators are always the last to be evaluated.

   Parentheses can be used to override operator precedence. Operations 
   within parentheses are performed before other operations. Within the 
   parentheses normal operator precedence is used.

   The following table lists operator precedence from highest to lowest.  
   Breaks in the table mark the groups of operators having equal 
   precedence.

Highest Precedence

      +--------+-----------------------------------+-------------+
      |Operator|Description                        |Associativity|
      |        |                                   |             |
      |CAST    |Type Conversion                    |N/A          |
      |PROCPTR |Procedure pointer                  |N/A          |
      |STRPTR  |String pointer                     |N/A          |
      |VARPTR  |Variable pointer                   |N/A          |
      |        |                                   |             |
      |[]      |String index                       |Left-to-Right|
      |[]      |Pointer index                      |Left-to-Right|
      |()      |Array index                        |Left-to-Right|
      |()      |Function Call                      |Left-to-Right|
      |.       |Member access                      |Left-to-Right|
      |->      |Pointer to member access           |Left-to-Right|
      |        |                                   |             |
      |@       |Address of                         |Right-to-Left|
      |*       |Value of                           |Right-to-Left|
      |New     |Allocate Memory                    |Right-to-Left|
      |Delete  |Deallocate Memory                  |Right-to-Left|
      |        |                                   |             |
      |^       |Exponentiate                       |Left-to-Right|
      |        |                                   |             |
      |-       |Negate                             |Right-to-Left|
      |        |                                   |             |
      |*       |Multiply                           |Left-to-Right|
      |/       |Divide                             |Left-to-Right|
      |        |                                   |             |
      |\       |Integer divide                     |Left-to-Right|
      |        |                                   |             |
      |MOD     |Modulus                            |Left-to-Right|
      |        |                                   |             |
      |SHL     |Shift left                         |Left-to-Right|
      |SHR     |Shift right                        |Left-to-Right|
      |        |                                   |             |
      |+       |Add                                |Left-to-Right|
      |-       |Subtract                           |Left-to-Right|
      |        |                                   |             |
      |&       |String concatenation               |Left-to-Right|
      |        |                                   |             |
      |Is      |Run-time type information check    |N/A          |
      |        |                                   |             |
      |=       |Equal                              |Left-to-Right|
      |<>      |Not equal                          |Left-to-Right|
      |<       |Less than                          |Left-to-Right|
      |<=      |Less than or equal                 |Left-to-Right|
      |>=      |Greater than or equal              |Left-to-Right|
      |>       |Greater than                       |Left-to-Right|
      |        |                                   |             |
      |NOT     |Complement                         |Right-to-Left|
      |        |                                   |             |
      |AND     |Conjunction                        |Left-to-Right|
      |        |                                   |             |
      |OR      |Inclusive Disjunction              |Left-to-Right|
      |        |                                   |             |
      |EQV     |Equivalence                        |Left-to-Right|
      |IMP     |Implication                        |Left-to-Right|
      |XOR     |Exclusive Disjunction              |Left-to-Right|
      |        |                                   |             |
      |ANDALSO |Short Circuit Conjunction          |Left-to-Right|
      |ORELSE  |Short Circuit Inclusive Disjunction|Left-to-Right|
      |        |                                   |             |
      |=[>]    |Assignment                         |N/A          |
      |&=      |Concatenate and Assign             |N/A          |
      |+=      |Add and Assign                     |N/A          |
      |-=      |Subtract and Assign                |N/A          |
      |*=      |Multiply and Assign                |N/A          |
      |/=      |Divide and Assign                  |N/A          |
      |\=      |Integer Divide and Assign          |N/A          |
      |^=      |Exponentiate and Assign            |N/A          |
      |MOD=    |Modulus and Assign                 |N/A          |
      |AND=    |Conjunction and Assign             |N/A          |
      |EQV=    |Equivalence and Assign             |N/A          |
      |IMP=    |Implication and Assign             |N/A          |
      |OR=     |Inclusive Disjunction and Assign   |N/A          |
      |XOR=    |Exclusive Disjunction and Assign   |N/A          |
      |SHL=    |Shift Left and Assign              |N/A          |
      |SHR=    |Shift Right and Assign             |N/A          |
      |LET     |Assignment                         |N/A          |
      |        |                                   |             |
      |LET()   |Assignment                         |N/A          |
      +--------+-----------------------------------+-------------+

   In some cases, the order of precedence can cause confusing or 
   counter-intuitive results.  Here are some examples:
   '' trying to raise a negated number to a power
   -2 ^ 2
   Desired result: (-2) ^ 2 = 4
   Actual result:   -(2 ^ 2) = -4

   '' trying to test a bit in a number
   n And 1  <>  0
   Desired result: (n And 1) <> 0
   Actual result:   n And (1 <> 0)

   '' trying to shift a number by n+1 bits
   a Shl n+1
   Desired result: a Shl (n + 1)
   Actual result: (a Shl n) + 1

   For expressions where the operator precedence may be ambiguous, it is 
   recommended to wrap parts of the expression in parentheses, in order 
   both to minimise the possibility of error and to aid comprehension for 
   people reading the code.

See also
   * Operators



-------------------------------------------------------------- TblTruth ----
Bitwise Operators Truth Tables

Computed values for the bitwise logical operators.

Binary operators
   Operators that take two operands.
Unary operator
   Operator that take a single operand.

   These logical operators return a value based on the value of their 
   operand(s). For the binary operators, each bit in the left-hand side 
   value is applied logically to the corresponding bit in the right-hand 
   side value. The result of this operation is returned. For the unary 
   operator, (Operator Not), the logic is applied to its right-hand side 
   operand only.

Binary operators

   Operator And (Conjunction)
      Bits in the result are set if and only if both of the corresponding 
      bits in the left and right-hand side operands are set.

         +------+-+-+-+-+
         |Lhs   |0|0|1|1|
         |Rhs   |0|1|0|1|
         |Result|0|0|0|1|
         +------+-+-+-+-+

   Operator Eqv (Equivalence)
      Bits in the result are set if and only if both of the corresponding 
      bits in the left and right-hand side operands are both either set or 
      unset.

         +------+-+-+-+-+
         |Lhs   |0|0|1|1|
         |Rhs   |0|1|0|1|
         |Result|1|0|0|1|
         +------+-+-+-+-+

   Operator Imp (Implication)
      Bits in the result are set if and only if the corresponding bit in 
      the left-hand side operand implies the bit in the right-hand side 
      operand.

         +------+-+-+-+-+
         |Lhs   |0|0|1|1|
         |Rhs   |0|1|0|1|
         |Result|1|1|0|1|
         +------+-+-+-+-+

   Operator Or (Inclusive Disjunction)
      Bits in the result are set if either of the corresponding bits in the 
      left and right-hand side operands are set.

         +------+-+-+-+-+
         |Lhs   |0|0|1|1|
         |Rhs   |0|1|0|1|
         |Result|0|1|1|1|
         +------+-+-+-+-+

   Operator Xor (Exclusive Disjunction)
      Bits in the result are set if and only if one of the corresponding 
      bits in the left and right-hand side operands is set.

         +------+-+-+-+-+
         |Lhs   |0|0|1|1|
         |Rhs   |0|1|0|1|
         |Result|0|1|1|0|
         +------+-+-+-+-+

Unary operators

   Operator Not (Complement)
      Bits in the result are set if the corresponding bits in the 
      right-hand side operand are unset, and unset if they are set.

         +------+-+-+
         |Rhs   |0|1|
         |Result|1|0|
         +------+-+-+




============================================================================
    Statements

------------------------------------------------------ CatPgControlFlow ----
Control Flow Statements

Statements that direct the flow of program execution.

Transferring Statements
   Statements that transfer control to another part of a program.
Branching Statements
   Statements that execute one of a number of code branches.
Looping Statements
   Statements that execute code repeatedly.

Transferring Statements
   Goto
      Transfers execution to another point in code defined by a text label.
   GoSub
      Temporarily transfers execution to another point in code, defined by 
      a text label.
   On Goto
      Transfers execution to one of a number of points in code defined by 
      text labels, based on the value of an expression.
   On Gosub
      Temporarily transfers execution to one of a number of points in code 
      defined by text labels, based on the value of an expression.
   Return (From Procedure)
      Returns from a procedure returning a value.
   Return (From Gosub)
      Returns from a call using GoSub.
   Exit Sub, Exit Function, Exit Operator,
   Exit Constructor, Exit Destructor and Exit Property
      Prematurely leaves a procedure code block.

Branching Statements
   If..End If
      Executes a block of statements if a condition is met.
   ..Else If..
      Executes a block of code if a condition is met and all previous 
      conditions weren't met.
   ..Else..
      Executes a block of code if all previous conditions weren't met.
   Select..End Select
      Executes one of a number of statement blocks using a set of 
      conditions.
   ..Case..
      Executes a block of code if a condition is met.
   ..Case Else..
      Executes a block of code if all previous conditions weren't met.

   Intra-branch control
      Exit Select
         Prematurely breaks out of a Select..End Select statement.
Looping Statements
   While..Wend
      Executes a block of statements while a condition is met.
   For..Next
      Executes a block of statements while an iterator is less than or 
      greater than an expression.
   Do..Loop
      Executes a block of statements while or until a condition is met.

   Intra-loop control
      Continue While, Continue For and Continue Do
         Prematurely re-enters a loop.
      Exit While, Exit For and Exit Do
         Prematurely breaks out of a loop.



------------------------------------------------------- CatPgProcedures ----
Procedures

Keywords that work with procedures.

Description
   These keywords control the declaration and definition of both 
   module-level procedures and member procedures, how they are called, how 
   arguments are passed and how their names are seen externally to other 
   modules. Procedures can also be declared to be executed automatically 
   before any module-level code is executed.

Declaration
   Keywords that declare and define procedures.
Linkage
   Keywords that specify how procedure names are seen by external modules.
Calling conventions
   Keywords that specify how arguments are used when calling procedures.
Parameter passing conventions
   Keywords that specify how arguments are passed to procedures.
Variadic Procedures
   Macros that allow for an arbitrary number of arguments to be passed to a 
   procedure.
Automatic execution
   Keywords that specify automatic execution of procedures.
Miscellaneous
   Miscellaneous keywords.

Declaration
   Declare
      Declares a module-level or member procedure.
   Sub
      Specifies a procedure that does not return an argument.
   Function
      Specifies a procedure that returns an argument.
   Overload
      Specifies that the procedure name can be used in other procedure 
      declarations.
   Static
      Specifies static storage for all variables and objects in the 
      procedure body.
   Const (Member)
      Specifies a const member procedure in user-defined type definitions.
   Static (Member)
      Specifies a static member procedure in user-defined type definitions.

Linkage
   Public
      Specifies external linkage for a procedure.
   Private
      Specifies internal linkage for a procedure.
   Alias
      Specifies an alternate external name for a procedure.
   Export
      Specifies a procedure is to be exported from a shared library.
   Lib
      Specifies automatic loading of a library.

Calling conventions
   stdcall
      Specifies the standard calling convention for BASIC languages, 
      including FreeBASIC.
   cdecl
      Specifies the standard calling convention in the C and C++ languages.
   pascal
      Specifies the standard calling convention in the Fortran, Pascal and 
      Microsoft QuickBASIC/QBasic languages.
   Fastcall
      Specifies the fastcall calling convention for 32-bit procedures.
   Thiscall
      Specifies the thiscall calling convention for 32-bit member 
      procedures.
Parameter passing conventions
   ByRef
      Specifies passing an argument by reference.
   ByVal
      Specifies passing an argument by value.
   Any
      Disables type-checking on arguments.

Variadic Procedures
   ... (Ellipsis)
      Indicates a variadic procedure in a declaration.
    Cva_Arg
      Macro to obtain the next argument from a variadic argument list 
      object
    Cva_Copy
      Macro to copy a variadic argument list object variable
    Cva_End
      Macro to end using a variadic argument list object variable
    Cva_List
      Variadic argument list object type 
    Cva_Start
      Macro to initialize variadic argument list object variable
   va_first
      Macro to obtain the argument list in a variadic procedure.
   va_arg
      Macro to obtain the current argument in a variadic procedure.
   va_next
      Macro to move to the next argument in a variadic procedure.

Automatic execution
   Constructor (Module)
      Indicates a procedure is to be executed before module-level code.
   Destructor (Module)
      Indicates a procedure is to be executed after module-level code.

Miscellaneous
   Byref (Function Results)
      Specifies that a function returns by reference rather than by value.
   Call
      Invokes a procedure.
   Naked
      Specifies that a function body is not to be given any prolog/epilog 
      code



----------------------------------------------------- CatPgModularizing ----
Modularizing

Keywords helpful when writing modular programs.

   * Common
   * DyLibFree
   * DyLibLoad
   * DyLibSymbol
   * Export
   * Extern

   * Extern...End Extern
   * Import
   * Namespace
   * Private
   * Public
   * Using (Namespaces)




============================================================================
    Other

------------------------------------------------------- CatPgPreProcess ----
Preprocessor

Commands that control the preprocessor.

Description
   Preprocessor commands are sent to the compiler to control what gets 
   compiled and how. They can be used to choose to compile one block of 
   code rather than another for cross-platform compatibility, include 
   headers or other source files, define small inline functions called 
   macros, or alter how the compiler handles variables.

Conditional Compilation
   Commands that allow for branches in compilation based on conditions.
Text Replacement
   Commands that create text-replacement macros.
Feature-control Defines
   User-defined symbols that affect how selected compiler features are 
   parsed.
File Directives
   Commands that indicate to the compiler how other files relate to the 
   source file.
Control Directives
   Commands that set compile options, control compilation, and report 
   compile time information.
Metacommands
   Commands that are kept for backward compatibility.

Conditional Compilation
   #if
      Compiles the following code block based on a condition.
   #ifdef
      Compiles the following code block if a symbol is defined.
   #ifndef
      Compiles the following code block if a symbol is not defined.
   #elseif
      Compiles the following code block if a condition is true and the 
      previous conditions was false.
   #elseifdef
      Compiles the following code block if a symbol is defined and the 
      previous conditions was false.
   #elseifndef
      Compiles the following code block if a symbol is not defined and the 
      previous conditions was false.
   #else
      Compiles the following code block if previous conditions were false.
   #endif
      Signifies the end of a code block.
   defined
      Returns "-1" if a symbol is defined, otherwise "0".

Text Replacement
   #define
      Creates a single-line text-replacement macro.
   #macro and #endmacro
      Creates a multi-line text-replacement macro.
   #undef
      Undefines a symbol.
   # Preprocessor Stringize
      Converts text into a string literal.
   ## Preprocessor Concatenate
      Concatenates two pieces of text.
   ! Escaped String Literal
      Indicates string literal immediately following must be processed for 
      escape sequences.
   $ Non-Escaped String Literal
      Indicates string literal immediately following must not be processed 
      for escape sequences.
Feature-control Defines
   Fb_No_Gfxlib
      Allows selected graphics-library command words to be used as normal 
      identifiers.
   Fb_No_Sfxlib
      Allows selected sound-library command words to be used as normal 
      identifiers.
File Directives
   #include
      Inserts text from a file.
   #inclib
      Includes a library in the linking processes.
   #libpath
      Includes a path to search for libraries in the linking process.

Control Directives
   #pragma
      Sets compiling options.
   #Pragma Reserve
      Reserves symbol name.
   #Cmdline
      Sets compiler command options from source.
   #lang
      Sets dialect from source.
   #print
      Outputs a messages to standard output while compiling.
   #error
      Outputs a messages to standard output and stops compilation.
   #assert
      Stops compilation with an error message if a given condition is 
      false.
   #line
      Sets the current line number and file name.

Metacommands
   '$Include
      Alternate form of the #include directive.
   '$Dynamic
      Alternate form of the Option Dynamic statement.
   '$Static
      Alternate form of the Option Static statement.
   '$Lang
      Alternate form of the #lang directive.

See also
   * Intrinsic Defines



---------------------------------------------------- TblEscapeSequences ----
Escape Sequences

Escape sequences can be used in string literals by using the operator ! .

Usage
result = !"text"

Description
   The accepted escape sequences in text  are:
      +-----------+---------------------+
      |\a         |beep                 |
      |\b         |backspace            |
      |\f         |formfeed             |
      |\l or \n   |newline              |
      |\r         |carriage return      |
      |\t         |tab                  |
      |\unnnn     |unicode char in hex  |
      |\v         |vertical tab         |
      |\nnn       |ascii char in decimal|
      |\&hnn      |ascii char in hex    |
      |\&onnn     |ascii char in octal  |
      |\&bnnnnnnnn|ascii char in binary |
      |\\         |backslash            |
      |\"         |double quote         |
      |\'         |single quote         |
      +-----------+---------------------+
 

Note: The zero-character (\000 = \&h00 = \&o000 = \&b00000000) is the null 
terminator. Only characters before the first null terminator can be seen 
when the literal is used as a String. To get a zero character in a string 
use Chr(0) instead.

See also
   * Operator ! (Escaped String)
   * Operator $ (Non-Escaped String)
   * Option Escape
   * String
   * Chr
   * Literals



------------------------------------------------- CatPgCompilerSwitches ----
Compiler Switches

Statements that affect how code is compiled.

Description
   These statements affect how the compiler declares variables, arrays and 
   procedures, parses string literals, passes procedure parameters and 
   more.

Metacommands
   * '$Dynamic
   * '$Include
   * '$Static
   * '$Lang

Compiler Options
   * Option Base
   * Option ByVal
   * Option Dynamic
   * Option Escape
   * Option Explicit
   * Option Gosub
   * Option Nogosub
   * Option NoKeyword
   * Option Private
   * Option Static
Set Default Datatypes
   * DefByte
   * DefDbl
   * DefInt
   * DefLng
   * DefLongInt
   * DefShort
   * DefSng
   * DefStr
   * DefUByte
   * DefUInt
   * Defulongint
   * DefUShort

Dialect Differences
   * DefLongInt and Defulongint available only in the -lang fblite 
     dialect.
   * OPTION statements are available only in the -lang fblite and -lang qb 
     dialects only.

See also
   * Preprocessor



-------------------------------------------------------- CatPgDddefines ----
Intrinsic Defines

Preprocessor symbols defined by the compiler.

Description
   Intrinsic defines are set by the compiler and may be used as any other 
   defined symbol.  Intrinsic defines often convey information about the 
   state of the compiler, either in general or at a specific point in the 
   compilation process.  Most intrinsic defines are associated with a 
   value.

Platform Information
   Defines that provide information on the system.
Version Information
   Defines that provide information on the fbc compiler version being used.
Command-line switches
   Defines that provide information with the command-line switches used 
   with fbc.
Environment Information
   Defines that provide information about the operating system environment.
Context-specific Information
   Defines that provide context information about the compilation process.
Basic-macros
   Built-in basic-macros.
Constants
   Built-in constants.

Platform Information
   __FB_WIN32__
      Defined if compiling for Windows.
   __FB_LINUX__
      Defined if compiling for Linux.
   __FB_DOS__
      Defined if compiling for DOS.
   __FB_CYGWIN__
      Defined if compiling for Cygwin.
   __FB_FREEBSD__
      Defined if compiling for FreeBSD.
   __FB_NETBSD__
      Defined if compiling for NetBSD.
   __FB_OPENBSD__
      Defined if compiling for OpenBSD.
   __FB_DARWIN__
      Defined if compiling for Darwin.
   __FB_XBOX__
      Defined if compiling for Xbox.
   __FB_BIGENDIAN__
      Defined if compiling on a system using big-endian byte-order.
   __FB_PCOS__
      Defined if compiling for a common PC OS (e.g. DOS, Windows, OS/2).
   __FB_UNIX__
      Defined if compiling for a Unix-like OS.
   __FB_64BIT__
      Defined if compiling for a 64bit target.
   __FB_ARM__
      Defined if compiling for the ARM architecture.
   __FB_PPC__
      Defined if compiling for the PowerPC architecture.
   __Fb_Riscv64__
      Defined if compiling for the 64-bit RISC-V architecture.
   __Fb_S390X__
      Defined if compiling for the s390x architecture.
   __Fb_Loongarch64__
      Defined if compiling for the 64-bit LoongArch architecture.
   __FB_X86__
      Defined if compiling for the X86 / X86_64 architecture.
   __FB_JS__
      Defined if compiling for emscripten target.
   __FB_ANDROID__
      Defined if compiling for android target.

Version Information
   __FB_VERSION__
      Defined as a string literal of the compiler version.
   __FB_VER_MAJOR__
      Defined as an integral literal of the compiler major version number.
   __FB_VER_MINOR__
      Defined as an integral literal of the compiler minor version number.
   __FB_VER_PATCH__
      Defined as an integral literal of the compiler patch number.
   __FB_MIN_VERSION__
      Macro to check for a minimum compiler version.
   __FB_BUILD_DATE__
      Defined as a string literal of the compiler build date in 
      "mm-dd-yyyy" format.
   __FB_BUILD_DATE_ISO__
      Defined as a string literal of the compiler build date in 
      "yyyy-mm-dd" format.
   __FB_SIGNATURE__ 
      Defined as a string literal of the compiler signature.
   __FB_BUILD_SHA1__ 
      Defined as a string literal of the compiler's source revision sha-1.
   __FB_BUILD_FORK_ID__ 
      Defined as a string literal of the custom defined project fork 
      identifier name.

Command-line switches
   __FB_ASM__
      Defined to either "intel" or "att" depending on -asm.
   __FB_BACKEND__
      Defined to either "gas" or "gcc" depending on -gen.
   __FB_GCC__
      True (-1) if -gen gcc is used, false (0) otherwise.
   __FB_OPTIMIZE__
      Defined to the optimization level depending on -O.
   __FB_GUI__
      True (-1) if GUI subsystem mode is active, false (0) otherwise.
   __FB_MAIN__
      Defined if compiling a module with an entry point.
   __FB_DEBUG__
      True (-1) if the "-g" switch was used, false (0) otherwise.
   __FB_ERR__
      Zero (0) if neither the "-e", "-ex" or "-exx" switches were used.
   __FB_FPMODE__
      Defined as "fast" if compiling for fast SSE math, "precise" 
      otherwise.
   __FB_FPU__
      Defined as "sse" if compiling for SSE floating point unit, or "x87" 
      for normal x87 floating-point unit.
   __FB_LANG__
      Defined to a string literal of the "-lang" dialect used.
   __FB_MT__
      True (-1) if the "-mt" switch was used, false (0) otherwise.
   __FB_OUT_DLL__
      True (-1) in a module being compiled and linked into a shared 
      library, false (0) otherwise.
   __FB_OUT_EXE__
      True (-1) in a module being compiled and linked into an executable, 
      false (0) otherwise.
   __FB_OUT_LIB__
      True (-1) in a module being compiled and linked into a static 
      library, zero (0) otherwise.
   __FB_OUT_OBJ__
      True (-1) in a module being compiled only, zero (0) otherwise.
   __FB_PROFILE__
      Set to an integer to indicate the profiling method.
   __FB_SSE__
      Defined if compiling for SSE floating point unit.
   __FB_VECTORIZE__
      Defined as the level of automatic vectorization (0 to 2)
Environment Information
   __FB_ARGC__
      Defined as an integer literal of the number of command-line arguments 
      passed to the program.
   __FB_ARGV__
      Defined as a ZString Ptr Ptr to the command line arguments passed to 
      the program.
   __DATE__
      Defined as a string literal of the compilation date in "mm-dd-yyyy" 
      format.
   __DATE_ISO__
      Defined as a string literal of the compilation date in "yyyy-mm-dd" 
      format.
   __TIME__
      Defined as a string literal of the compilation time.
   __PATH__
      Defined as a string literal of the absolute path of the module.

Context-specific Information
   __FILE__ and __FILE_NQ__
      Defined as the name of the module.
   __FUNCTION__ and __FUNCTION_NQ__
      Defined as the name of the procedure where it's used.
   __LINE__
      Defined as an integer literal of the line of the module where it's 
      used.
   __FB_OPTION_BYVAL__
      True (-1) if parameters are declared by value by default, zero (0) 
      otherwise.
   __FB_OPTION_DYNAMIC__
      True (-1) if all arrays are variable-length, zero (0) otherwise.
   __FB_OPTION_ESCAPE__
      True (-1) if string literals are processed for escape sequences, zero 
      (0) otherwise.
   __FB_OPTION_GOSUB__
      True (-1) if gosub support is enabled, zero (0) otherwise.
   __FB_OPTION_EXPLICIT__
      True (-1) if variables and objects need to be explicitly declared, 
      zero (0) otherwise.
   __FB_OPTION_PRIVATE__
      True (-1) if all procedures are private by default, zero (0) 
      otherwise.
   __FB_OPTION_PROFILE__
      True (-1) if profiling code is generated, zero (0) otherwise.

Basic-macros
   __FB_ARG_COUNT__
      Counts the number of arguments in an argument list.
   __FB_ARG_EXTRACT__
      Returns nth argument from an argument list.
   __FB_ARG_LEFTOF__
      Returns left token based on separator.
   __Fb_Arg_Listexpand__
      Expands a macro one or more time on an argument list
   __FB_ARG_RIGHTOF__
      Returns right token based on separator.
   __FB_EVAL__
      Evaluates an argument (expression) at compile time.
   __FB_IIF__
      Returns an expression depending on the result of a comparison 
      expression evaluated at compile time.
   __FB_JOIN__
      Joins two token arguments together as one.
   __Fb_Query_Symbol__
      Queries a fbc's symbol internals.
   __FB_QUOTE__
      Converts the argument to a string.
   __FB_UNIQUEID__
      Gets the identifier at the top of a stack.
   __FB_UNIQUEID_POP__
      Pops an identifier off of a stack.
   __FB_UNIQUEID_PUSH__
      Pushes a new unique identifier on to a stack.
   __FB_UNQUOTE__
      Takes a literal string and converts it back to tokens.

Constants
   False and True
      Intrinsic constants for the Boolean data type.



---------------------------------------------------- ProPgErrorHandling ----
Error Handling

Handling runtime errors.

   FreeBASIC can handle the errors in the following ways:
   * By default the program does nothing with the errors - they are 
     silently ignored and code continues. In this case code should process 
     possible errors in the next line by using the Err function.
   * If compiled with -e, -ex or -exx options, FreeBASIC uses QB-like 
     error handling.
   * Future OOP versions of FreeBASIC may have a java-like 
     TRY..CATCH...FINALLY exception handler implemented.

   NOTE: The following information is valid unless the error produces an OS 
   General Protection Fault (for example if the program writes outside the 
   process memory area). In these cases the OS will immediately stop the 
   program and issue an error: nothing can avoid it from inside FreeBASIC.

Default error handling
   The default FreeBASIC behavior is to set the ERR variable and continue. 

   Dim As Integer e
   Open "xzxwz.zwz" For Input As #1
   e = Err
   Print e
   Sleep
      

   (The example program supposes there is no xzxwz.zwz file). The program 
   does not stop; it sets the ERR variable and continues. The error can be 
   processed in the next line.

   Some IO functions such as Open and Put #... can be used in function 
   form, returning an error number or zero if successful.

   Print Open ("xzxwz.zwz" For Input As #1)
   Sleep
      

QuickBASIC-like error handling
   If the  -e, -ex or -exx switch is used at compile time, the program is 
   expected to have a QB-like error handler enabled. If no handler 
   processes the error, the program stops with an error.

   Notice: if QB-Like error handling is used, the programmer should be 
   prepared to handle all error conditions.

   '' Compile with QB (-lang qb) dialect

   '$lang: "qb"

   On Error Goto FAILED
   Open "xzxwz.zwz" For Input As #1
   On Error Goto 0
   Sleep
   End

   FAILED:
   Dim e As Integer
   e = Err
   Print e
   Sleep
   End
      

   On Error sets an error handling routine which the program will jump to 
   when an error is found. On Error Goto 0 disables the error handling.

   If an error handling routine is not set when an error occurs, the 
   program will stop and send the console an error message.

   Aborting program due To runtime Error 2 (file Not found)
   	

   The error handler routine can be at the end of the program, as in QB. 
   The On Local Error statement allows the setting of a local error handler 
   routine at the end of the same Sub or Function in which the error 
   occurs.

   '' Compile with -e
   '' The -e command line option is needed to enable error handling.

   Declare Sub foo
     foo
   Sleep

   Sub foo
      
      Dim filename As String
      Dim errmsg As String
      filename = ""
      On Local Error Goto fail
     Open filename For Input Access Read As #1
      Print "No error"
      On Local Error Goto 0
      Exit Sub
      
     fail:
     errmsg = "Error " & Err & _
            " in function " & *Erfn & _
            " on line " & Erl
     Print errmsg
      
   End Sub
      

   If the -e switch is used (whatever the -lang dialect), the error handler 
   must terminate the program. 
   With (-ex or -exx) and -lang qb dialect only, the error routine can end 
   by using Resume (retries the statement that caused the error) or 
   Resume Next (continues at the next instruction) .

Error codes
   See Runtime Error Codes for a listing of runtime error numbers and their 
   associated meaning.

   No user error code range is defined. If Error is used to set an error 
   code it is wise to use high values to avoid collisions with the list of 
   built-in error codes. (This built-in list may be expanded later.)

'On [Local] Error Goto' statement use
   'On [Local] Error Goto label' causes a program jump to a specified label 
   as soon as an error occurs. Such errors can be triggered by built-in 
   statements such as 'Open', 'Get', 'Put', or when the Error statement is 
   used.
   The error checking for built-in statements is only enabled if the 
   program is compiled with one of the -e, -ex or -exx options. Otherwise, 
   no jump will be performed, but the command will still consume processor 
   time.
   When triggered by the only Error statement, 'On [Local] Error Goto 
   label' remains always working even when none of these compile options 
   are used.
   'On Error Goto 0' deactivates the current error handler. If an error 
   occurs, FreeBASIC will not jump.

   The optional Local keyword (authorized only inside Sub/Function) was 
   intended to be used to define an error handler only in the same 
   procedure the 'On Local Error' is in (for compatibility with PDS 7.1 and 
   VB Dos 1.0 for example). In this case, FreeBASIC should have searched 
   for the label in the current procedure only.
   But presently, the Local clause is ignored by the compiler, and the 
   error handler can be either in the scope of the same procedure the 'On 
   [Local] Error' is in, or in the main part of the module (if defined 
   before the procedure).
   Exception when -gen gcc is used (or for the fbc 64-bit): the Local 
   clause seems to be rightly taken into account, but except inside a local 
   scope!

   'On [Local] Error Goto label' is not the best way to catch errors from a 
   built-in procedure when a syntax in the form of a function is available. 
   The return error code can be directly tested (using the returned error 
   code from function inhibits the QuickBASIC-like error checking and 
   statement 'On Error Goto').

   It is advisable to try to write programs compatible with the -lang fb 
   dialect and -exx option, because to test programs with option -exx for 
   debugging purposes is a great helping:
      - Avoid to use the statement Resume or Resume Next, because it is not 
      at all supported by -lang fb (compilation error).
      - On the other hand, sometimes when it is useful (when no form of a 
      function is available), use the statement 'On [Local] Error Goto', 
      because it runs with any option among -e, -ex, -exx. Otherwise (no 
      error checking option), 'On [Local] Error Goto' is inactive (without 
      compilation error), but it consumes CPU time.

   Accordingly and if necessary, usually write QuickBasic-like error 
   handling ('On [Local] Error Goto label' ..... 'label:' .....), with 
   conditional assembly directive depending on the value of __FB_ERR__, in 
   order not to penalize the execution speed (if not error checking option 
   is used).

   The behavior of statement 'On Error Goto' (-lang fb) regarding 
   compilation options (none, -e/-ex/-exx) is enlighten with the following 
   program including several examples (4), to be compiled with or without 
   error checking option (4*2=8 tests):
   #define Config 1
   '#DEFINE Config 2
   '#DEFINE Config 3
   '#DEFINE Config 4

   #if Config = 1 '-----------------------------------------------------------

   Open "does_not_exist" For Input As #1

   Print "main end"
   Sleep
   System

   ' - with compiler option 'none' :
   '     console output :
   '       'main end'
   '
   ' - with compiler option '-e' or '-ex' or '-exx' :
   '     console output :
   '       'Aborting due to runtime error 2 (file not found) at line 10 of .....'

   #endif '-------------------------------------------------------------------

   #if Config = 2 '-----------------------------------------------------------

   Dim As Integer Result = Open("does_not_exist" For Input As #1)
   If Result <> 0 Then
      Print "error code returned: " & Result
      Print "file not found (processed by 'Result = Open(.....)')"
   End If

   Print "main end"
   Sleep
   End

   ' - with compiler option 'none' or '-e' or '-ex' or '-exx' :
   '     console output :
   '       'error code returned: 2'
   '       'file not found (processed by 'Result = Open(.....)')'
   '       'main end'

   #endif '-------------------------------------------------------------------

   #if Config = 3 '-----------------------------------------------------------

   On Error Goto Error_Handler
   Open "does_not_exist" For Input As #1

   Print "main end"
   Sleep
   End

   error_handler:
   Print "file not found (processed by 'On Error Goto')"
   On Error Goto 0
   Print "QB-like error handling end"
   Sleep
   End

   ' - with compiler option 'none' :
   '     console output :
   '       'main end'
   '
   ' - with compiler option '-e' or '-ex' or '-exx' :
   '     console output :
   '       'file not found (processed by 'On Error Goto')'
   '       'QB-like error handling end'

   #endif '-------------------------------------------------------------------

   #if Config = 4 '-----------------------------------------------------------

   On Error Goto error_handler
   Dim As Integer Result = Open("does_not_exist" For Input As #1)
   If Result <> 0 Then
      Print "error code returned: " & Result
      Print "file not found (processed by 'Result = Open(.....)')"
   End If

   Print "main end"
   Sleep
   End

   error_handler:
   Print "file not found (processed by 'On Error Goto')"
   On Error Goto 0
   Print "QB-like error handling end"
   Sleep
   End

   ' - with compiler option 'none' or '-e' or '-ex' or '-exx' :
   '     console output :
   '       'error code returned: 2'
   '       'file not found (processed by 'Result = Open(.....)')'
   '       'main end'

   #endif '-------------------------------------------------------------------
      
The Config=2 and Config=4 sections highlight that when FB function is 
called using explicitly its returned error code (-lang fb dialect), 'On 
Error Goto' is by-passed whatever the error checking level ('none', '-e', 
'-ex', '-exx').

See also
   * Error Handling Functions
   * Runtime Error Codes



-------------------------------------------------------------- KeyPgAsm ----
Asm

Code block that allows the use of architecture-specific instructions.

Syntax
   Asm
      architecture-dependent instructions
   End Asm

      Or

   Asm architecture-dependent instructions

Description
   The Asm block is used to insert specific machine-code instructions in a 
   program in order to perform operations that cannot be carried out using 
   the features of the language or to hand-optimize performance-sensitive 
   sections of code.

   The current FreeBASIC compiler currently only produces code for Intel 
   80x86-based machines; however, in the future, the compiler might be 
   ported to a platform which does not support the same instruction set.  
   Therefore, Asm blocks should only be used when necessary, and a 
   FreeBASIC-only alternative should be provided if possible.

   The return value of a function may be set by using the Function keyword 
   within brackets as shown in the example below.

   Asm block comments have the same syntax as usual FreeBASIC Comments  - 
   use FreeBASIC-like " ' " comments, not " ; " as usual in assembly code. 

   x86 Specific:

      Syntax
         The syntax of the inline assembler is a simplified form of Intel 
         syntax.  Intel syntax is used by the majority of x86 assemblers, 
         such as MASM, TASM, NASM, YASM and FASM. In general, the 
         destination of an instruction is placed first, followed by the 
         source. Variables and functions defined by a program may be 
         referenced in an Asm block.  The assembler used by FreeBASIC is 
         GAS, using the .intel_syntax noprefix directive, and Asm blocks 
         are passed through unmodified, except for the substitution of 
         local variable names for stack frame references, and commenting 
         removal.

         Instruction syntax is mostly the same as FASM uses, one important 
         difference is that GAS requires size settings to be followed by 
         the word "ptr".

   ' Assuming "n" is a FB global or local ULONG variable
   mov  eax, [n]        ' OK: size is apparent from eax
   inc  [n]             ' Not OK: size is not given
   inc  dword [n]       ' Not OK: size given, but still not accepted by GAS
   inc  dword Ptr [n]   ' OK: "ptr" is needed by GAS here

      Register Preservation
         When an Asm block is opened, the registers ebx, esi, and edi are 
         pushed to the stack, when the block is closed, these registers are 
         popped back from the stack.  This is because these registers are 
         required to be preserved by most or all OS's using the x86 CPU.  
         You can therefore use these registers without explicitly 
         preserving them yourself. You should not change esp and ebp, since 
         they are usually used to address local variables. 
         Note: Inside a Naked procedure, there is no such register 
         preservation.

      Register Names
         The names of the registers for the x86 architecture are written as 
         follows in an Asm block:
         * 4-byte integer registers: eax, ebx, ecx, edx, ebp, esp, edi, 
           esi
         * 2-byte integer registers: ax, bx, cx, dx, bp, sp, di, si (low 
           words of 4-byte e- registers)
         * 1-byte integer registers: al, ah, bl, bh, cl, ch, dl, dh (low 
           and high bytes of 2-byte -x registers)
         * Floating-point registers: st(0), st(1), st(2), st(3), st(4), 
           st(5), st(6), st(7)
         * MMX registers (aliased onto floating-point registers): mm0, mm1
           , mm2, mm3, mm4, mm5, mm6, mm7
         * SSE registers: xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7

      Instruction Set
         See these external references:
         * Original Intel 80386 manual from 1986
         * Latest Intel Pentium 4 manuals
         * NASM x86 Instruction Reference (Please note that NASM is not 
           the assembler used by FreeBASIC, but this page provides a good 
           overview of x86 instructions)

      Unsafe instructions
         Note that the FreeBASIC compiler produces 32-bit protected-mode 
         code for the x86 which usually runs in an unprivileged user level; 
         therefore, privileged and sensitive instructions will assemble 
         fine, but possibly won't work correctly or cause a runtime 
         "General Protection Fault", "Illegal instruction", or SIGILL 
         error. The following are the privileged and sensitive instructions 
         as of the Intel Pentium 4 and Xeon:
         * cli *1
         * clts
         * hlt
         * in *1
         * ins *1
         * int *1               
         * into *1               
         * invd
         * invlpg
         * lgdt
         * lidt
         * lldt
         * lmsw
         * ltr
         * mov to/from CRn, DRn, TRn
         * out *1
         * outs *1
         * rdmsr
         * rdpmc *2
         * rdtsc *2
         * sti *1
         * str
         * wbinvd
         * wrmsr
         * all SSE2 and higher instructions *2

          *1: sensitive to IOPL, fine in DOS 
          *2: sensitive to permission bits in CR4, see below

   The privileged instructions will work "correctly" in DOS when running on 
   a Ring 0 DPMI kernel, like the (non-default) Ring 0 version of CWSDPMI, 
   WDOSX or D3X, nevertheless most of them are not really useful and 
   dangerous when executed from DPMI code. RDTSC (Read Time Stamp Counter) 
   has been shown to be allowed by most, or all OS'es.

   However the usefulness of RDTSC has been diminished with the advent of 
   multi-core and hibernating CPUs. SSE2 and higher instructions are 
   disabled "by default" after CPU initialization, Windows and Linux 
   usually do enable them, in DOS it is business of the DPMI host: HDPMI32 
   will enable them, CWSDPMI won't. The INT instruction is usable in the 
   DOS version/target only, note that it works slightly differently from 
   real mode DOS, see also FaqDOS.

   The segment registers (cs, ds, es, fs, gs) should not be changed from an 
   Asm block, except in certain cases with the DOS port (note that they do 
   NOT work the same way as in real-mode DOS, see also FaqDOS). The 
   operating system or DPMI host is responsible for memory management; the 
   meaning of segments (selectors) in protected mode is very different from 
   real-mode memory addressing.

   Note that those "unsafe" instructions are not guaranteed to raise a 
   "visible" crash even when ran with insufficient privilege - the OS or 
   DPMI host can decide to "emulate" them, either functionally (reading 
   from some CRx works under HDPMI32), or "dummy" (nothing happens, 
   instruction will pass silently, like a NOP).

Example
   '' This is an example for the x86 architecture.
   Function AddFive(ByVal num As Long) As Long
      Asm
         mov eax, [num]
         Add eax, 5
         mov [Function], eax
      End Asm
   End Function

   Dim i As Long = 4

   Print "4 + 5 ="; AddFive(i)

   4 + 5 = 9

   FreeBASIC's Assembler is AS / GAS, the assembler of GCC, so an external 
   program. Some quirks apply:
      * The error lines  returned by FBC for Asm blocks are not related 
        the FB source file. As FBC simply displays the errors returned by 
        AS , the lines are related to the assembly file. To make FreeBASIC 
        preserve them, the compiler must be invoked with the -R option 
        ("don't delete ASM files").
      * The label names are case sensitive inside Asm blocks.

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Asm.

Differences from QB
   * New to FreeBASIC

See also
   * Function
   * Naked





============================================================================
  RUNTIME LIBRARY REFERENCE
  -------------------------


------------------------------------------------------------ CatPgArray ----
Array Functions

Statements and procedures for working with arrays.

Defining Arrays
   Statements that create arrays.
Clearing Array Data
   Procedures that work with array memory.
Retrieving Array Size
   Procedures that return the array's length/size and bounds for any 
   array's dimension.
Retrieving Array Descriptor
   Procedures that return a pointers to an array's descriptor.

Defining Arrays
   Option Dynamic
      Forces arrays to be defined as variable-length arrays.
   '$Dynamic
      Alternate form of the Option Dynamic statement.
   Option Static
      Reverts a previous Option Dynamic command.
   '$Static
      Alternate form of the Option Static statement.
   Dim
      Defines any type of array.
   ReDim
      Defines and resizes variable-length arrays.
   Preserve
      Preserves array contents when used with ReDim.

Clearing Array Data
   Erase
      Destroys variable-length array elements and initializes fixed-length 
      array elements.
Retrieving Array Size
   Arraylen
      Returns the total number of array elements.
   Arraysize
      Returns the total array size (in bytes).
   LBound
      Returns the lower bound of an array's dimension.
   UBound
      Returns the upper bound of an array's dimension.

Retrieving Array Descriptor
   Array[Const]Descriptorptr
      Returns a [constant] pointer to array's descriptor (FBARRAY).



------------------------------------------------------------- CatPgBits ----
Bit Manipulation

Macros that work with the bits and bytes of numbers.

Description
   The macros documented here provide access to the individual bits, bytes 
   and words of integer values.

Byte Manipulation Macros
   Gets the value of individual bytes or words of UInteger values.
Bit Manipulation Macros
   Gets the state of individual bits of numeric values.

Byte Manipulation Macros
   LoByte
      Gets the least significant byte (LSB, or lo-byte) value of an UInteger
      value.
   HiByte
      Gets the most significant byte (MSB, or hi-byte) value of the least 
      significant word (LSW, or lo-word) of an UInteger value.
   LoWord
      Gets the least significant word (LSW, or lo-word) value of an UInteger
      value.
   HiWord
      Gets the most significant word (LSW, or hi-word) value of an UInteger 
      value.
Bit Manipulation Macros
   Bit
      Gets the state of an individual bit in an integer value.
   BitReset
      Gets the value of an integer with a specified bit cleared.
   BitSet
      Gets the value of an integer with a specified bit set.



---------------------------------------------------------- CatPgConsole ----
Console Functions

Procedures that work with the console.

Description
   These procedures provide ways to output text to the console, as well as 
   control where and how text is output.

Configuring the Console
   Statements that affect how text is displayed.
Cursor Color and Positioning
   Procedures that move the cursor and change its color.
Writing Text to the Console
   Procedures that output text to the console.

Configuring the Console
   Cls
      Clears the entire screen or text viewport.
   Width
      Sets or returns the number of rows and columns of the console 
      display.
   View Print
      Sets the printable area of the console screen.

Cursor Color and Positioning
   Color
      Changes the foreground and background color of text to be written.
   CsrLin
      Returns the row position of the cursor.
   Pos
      Returns the column position of the cursor.
   Locate
      Sets the row and column position of the cursor and its visibility.
   Screen (Console)
      Gets the character or color attribute at a given location.
Writing Text to the Console
   Print
   ? (Shortcut For 'Print')
      Writes text to the console.
   Print Using
   ? Using (Shortcut For 'Print Using')
      Writes formatted text to the console.
   Write
      Writes a list of items to the console.
   Spc
      Skips a number of spaces when writing text.
   Tab
      Skips to a certain column when writing text.



------------------------------------------------------------- CatPgDate ----
Date and Time Functions

Procedures that work with dates and time.

Description
   These procedures provide ways to deal with date and time intervals in a 
   consistent way. Additional procedures are provided to set and get the 
   current system date and time, and to retrieve a time stamp for sensitive 
   timing algorithms.

VisualBasic compatible procedures
   Procedures for working with so-called date serials, similar to those 
   used in Visual Basic(r).
Date and time procedures
   Procedures for working with the system date and time.

VisualBasic compatible procedures
   Now
      Gets a date serial of the current date and time.

   Creating Date serials
      DateSerial
         Gets the date serial representation of a date.
      TimeSerial
         Gets the date serial representation of a time.
      DateValue
         Gets the date serial representation of a date expressed as a String
         .
      TimeValue
         Gets the date serial representation of a time expressed as a String
         .

   Extracting information from Date serials
      Second
         Gets the seconds of the hour from a date serial.
      Minute
         Gets the minutes of the hour from a date serial.
      Hour
         Gets the hour of the day from a date serial.
      Day
         Gets the day of the month from a date serial.
      Weekday
         Gets the day of the week from a date serial.
      Month
         Gets the month of the year from a date serial.
      Year
         Gets the year from a date serial.
      DatePart
         Gets a time interval from a date serial.

   Extracting information from Date serials
      DateAdd
         Gets the result of a time interval added to a date serial.
      DateDiff
         Gets a time interval between two date serials.

   Miscellaneous
      IsDate
         Tests if a String can be converted to a date serial.
      MonthName
         Gets the month name of its integer representation.
      WeekdayName
         Gets the weekday name of its integer representation.
Date and time procedures
   Date
      Gets the String representation of the current system date.
   Time
      Gets the String representation of the current system time.
   SetDate
      Sets the current system date.
   SetTime
      Sets the current system time.
   Timer
      Gets a counter expressed in seconds.



------------------------------------------------------------ CatPgError ----
Error Handling Functions

Statements and procedures that provide runtime error-handling capabilities.

Description
   These statements and procedures provide ways of dealing with runtime 
   errors. Specific modules, procedures and source code lines can be 
   retrieved, and error handlers can be set up.

Determining Errors
   Procedures that retrieve information about an error.
Handling Errors
   Statements that allow handling of errors.

Determining Errors
   Erl
      Gets the line in source code where the error occurred.
   Erfn
      Gets the name of the function where the error occurred.
   Ermn
      Gets the name of the source file where the error occurred.
   Err
      Gets the error number of the last error that occurred.
   Error
      Generates an error using an error number.
Handling Errors
   On Error
      Sets a global error handler using a label.
   On Local Error
      Sets a local error handler using a label.
   Resume
      Resumes execution at the line where the error occurred.
   Resume Next
      Resumes execution at the line after where the error occurred.

See also
   * Error Handling
   * Runtime Error Codes



------------------------------------------------------------- CatPgFile ----
File I/O Functions

Statements and procedures for working with files and devices.

Description
   These statements and procedures provide file and device i/o 
   capabilities. So called file numbers can be bound to files or devices, 
   which can be read or written to using formatted (text mode) or 
   unformatted (binary mode) data. In binary mode, files and devices can be 
   read from or written to in arbitrary locations. For multithreaded 
   applications, files and devices can also be locked.

Opening Files or Devices
   Procedures and other keywords that provide read or write access to a 
   file or device.
Reading from and Writing to Files or Devices
   Procedures that read and write data to an opened file or device.
File Position and other Info
   Procedures that determine where reading and writing will take place 
   within an opened file.

Opening Files or Devices
   FreeFile
      Gets an available file number that can be used to read or write from 
      files or devices.
   Open
      Binds a file number to a physical file to provide reading and writing 
      capabilities.
   Open Com
      Binds a file number to a communications port.
   Open Cons
      Binds a file number to the standard input and output streams.
   Open Err
      Binds a file number to the standard input and error streams.
   Open Lpt
      Binds a file number to a printer device.
   Open Pipe
      Binds a file number to the input and output streams of a process.
   Open Scrn
      Binds a file number directly to the console.
   Open Tcp
      Binds a file number to a TCP client connection.
   Open Tcp Server
      Binds a file number to a listening TCP server socket.
   Close
      Unbinds a file number from a file or device.
   Reset
      Unbinds all active file numbers.

   File I/O modes
      Input (File Mode)
         Text data can be read from the file.
      Output
         Text data can be written to the file.
      Append
         Text data is added to the end of a file when output.
      Binary
         Arbitrary data can be read from or written to the file.
      Random
         Blocks of data of certain size can be read from and written to the 
         file.

   File access privileges
      Access
         An overview of file access privileges.
      Read (File Access)
         Binary data can only be read from the file.
      Write (File Access)
         Binary data can only be written to the file.
      Read Write(File Access)
         Binary data can be read from and written to the file.

   Character encoding
      Encoding
         Specifies the character encoding of a file.
Reading from and Writing to Files or Devices
   Input #
      Reads a list of values from a file or device.
   Write #
      Writes a list of values to a file or device.
   Input()
      Reads a number of characters from a file or device.
   Winput()
      Reads a number of wide characters from a file or device.
   Line Input #
      Reads a line of text from a file or device.
   Print #
   ? # (Shortcut For 'Print #')
      Writes text data to a file or device.
   Put #
      Writes arbitrary data to a file or device.
   Get #
      Reads arbitrary data from a file or device.
   Tcp Accept
      Accepts a TCP client from a server file number.

File Position and other Info
   LOF
      Gets the length (in bytes) of a file.
   LOC
      Gets the file position of the last read or write operation.
   EOF
      Returns true if all of the data has been read from a file.
   Eoc
      Returns true if a TCP connection has been closed by the peer.
   Seek (Statement)
      Sets the file position of the next read or write operation.
   Seek (Function)
      Gets the file position of the next read or write operation.
   Lock
      Restricts read or write access to a file or portion of a file.
   Unlock
      Remove read or write restrictions from a previous Lock command.



------------------------------------------------------------- CatPgMath ----
Mathematical Functions

Procedures that work with numbers mathematically.

Description
   This set of procedures provide basic algebraic and trigonometric 
   function. Random numbers can also be retrieved, using a variety of 
   random number generators.

Algebraic Procedures
   Absolute values, logarithms, square roots and more.
Trigonometry Procedures
   Sine, Cosine and other trigonometry-related procedures.
Miscellaneous Procedures
   Miscellaneous procedures.

Algebraic Procedures
   Abs
      Returns the absolute value of a number.
   Exp
      Returns e raised to some power.
   Log
      Returns the natural logarithm of a number.
   Sqr
      Returns the square root of a number.
   Fix
      Returns the integer part of a number.
   Frac
      Returns the fractional part of a number.
   Int
      Returns the largest integer less than or equal to a number.
   Sgn
      Returns the sign of a number.
Trigonometric Procedures
   Sin
      Returns the sine of an angle.
   Asin
      Returns the arcsine of a number.
   Cos
      Returns the cosine of an angle.
   Acos
      Returns the arccosine of a number.
   Tan
      Returns the tangent of an angle.
   Atn
      Returns the arctangent of a number.
   Atan2
      Returns the arctangent of the ratio between two numbers.

Miscellaneous Procedures
   Randomize
      Seeds the random number generator used by Rnd.
   Rnd
      Returns a random Double in the range [0, 1).



----------------------------------------------------------- CatPgMemory ----
Memory Functions

Procedures that work with static and dynamic memory.

Description
   These procedures provide access to the free store, or heap. Memory from 
   the free store can be reserved and freed, and procedures are provided to 
   read and write directly to that memory.

Working with Dynamic Memory
   Procedures that reserve, resize or free dynamic memory.
Miscellaneous Procedures
   Procedures that read or write values to and from addresses in memory.

Working with Dynamic Memory
   Allocate
      Reserves a number of bytes of uninitialized memory and returns the 
      address.
   CAllocate
      Reserves a number of bytes of initialized (zeroed) memory and returns 
      the address.
   Reallocate
      Changes the size of reserved memory.
   Deallocate
      Returns reserved memory back to the system.
Miscellaneous Procedures
   Peek
      Reads some type of value from an address.
   Poke
      Writes some type of value to an address.
   Clear
      Clears data in an array with a specified value.
   Fb_Memcopy
      Copies a block of memory from a location to another.
      (memory areas must not overlap)
   fb_MemCopyClear
      Copies the first part of a block of memory from a location to another 
      and clears the rest.
      (memory areas must not overlap)
   Fb_Memmove
      Copies a block of memory from a location to another.
      (memory areas may overlap)
   Swap
      Exchange the contents of two variables.
   SAdd
      Returns the address for the data in a zstring/wstring variable.

See also
   * Memory Operators



------------------------------------------------------------ CatPgOpsys ----
Operating System Functions

Statements and procedures for working with files, directories and the 
system.

Description
   The statements and procedures listed here provide access to the 
   operating system environment. They transfer execution to external 
   programs, get information about files and directories, manipulate the 
   file system and send commands to the command shell.

Working with Files
   Procedures that deal with files.
Working with Directories
   Various directory management procedures.
File Properties
   Get information about files.
System Procedures
   Procedures for working with the environment.

Working with Files
   Exec and Chain
      Temporarily transfers control to another program.
   Run
      Transfers control to another program.
   Kill
      Deletes an existing file.
   Name
      Renames an existing file.

File Properties
   FileAttr
      Gets information about a file bound to a file number.
   FileCopy
      Copies a file.
   FileDateTime
      Gets the last modified date and time of a file.
   FileExists
      Tests for the existence of a file.
   FileLen
      Gets the length (in bytes) of a file.
   FileSetEof
      Sets the length of an open file bound to a file number.
   FileFlush
      Flushes application or system buffers for an open file bound to a 
      file number.
Working with Directories
   CurDir
      Gets the current working directory.
   ChDir
      Sets the current working directory.
   Dir
      Gets the names of files or directories matching certain attributes.
   ExePath
      Gets the directory of the current running program.
   MkDir
      Creates a new directory.
   RmDir
      Deletes an existing directory.

System Procedures
   Fre
      Gets the amount of free memory (in bytes) available.
   Command
      Gets the command-line parameters passed to the program.
   Environ
      Gets the value of an environment variable.
   IsRedirected
      Checks whether stdin or stdout is redirected to a file or not.
   SetEnviron
      Sets the value of an environment variable.
   Shell
      Sends a command to the system command interpreter.
   System
      Closes all open files and exits the program.



----------------------------------------------------------- CatPgString ----
String Functions

Statements and Procedures that work with strings.

Description
   These statements and procedures provide many ways to create and 
   manipulate strings and substrings. Numbers can be converted to strings 
   and vice-versa. Procedures are also provided to aid in serialization of 
   numeric data, perhaps for persistent storage.

Creating Strings
   String data types and procedures that create new strings.
Character Conversions
   Procedures that convert from character codes to strings and back.
Numeric/Boolean to String Conversions
   Procedures that convert numeric values to strings.
String to Numeric Conversions
   Procedures that convert strings to numeric values.
Numeric Serializations
   Procedures that convert raw numeric data to and from strings suitable 
   for storage.
Working with Substrings
   Procedures that return subsets of strings, or that modify subsets of 
   strings.

Creating Strings
   String
      Standard data type: 8 bit character string.
   String (Function)
      Returns a String of multiple characters.
   ZString
      Standard data type: null terminated 8 bit character string.
   WString
      Standard data type: wide character string.
   Wstring (Function)
      Returns a WString of multiple characters.
   Space
      Returns a String consisting of spaces.
   WSpace
      Returns a WString consisting of spaces.
   Len
      Returns the length of a string in characters.

Character Conversion
   Asc
      Returns an Integer representation of an character.
   Chr
      Returns a string of one or more characters from their ASCII Integer 
      representation.
   WChr
      Returns a WString of one or more characters from their Unicode Integer
      representation.

Numeric/Boolean to String Conversions
   Bin
      Returns a binary String representation of an integral value.
   WBin
      Returns a binary WString representation of an integral value.
   Hex
      Returns a hexadecimal String representation of an integral value.
   WHex
      Returns a hexadecimal WString representation of an integral value.
   Oct
      Returns an octal String representation of an integral value.
   WOct
      Returns an octal WString representation of an integral value.
   Str
      Returns the String representation of numeric value or boolean.
   WStr
      Returns the WString representation of numeric value.
   Format
      Returns a formatted String representation of a Double.

String to Numeric Conversions
   Val
      Returns the Double conversion of a numeric string.
   ValInt
      Returns the Integer conversion of a numeric string.
   ValLng
      Returns the Long conversion of a numeric string.
   ValUInt
      Returns the UInteger conversion of a numeric string.
   ValULng
      Returns the ULong conversion of a numeric string.
Numeric Serialization
   MKD
      Returns an eight character String representation of a Double.
   MKI
      Returns a four character String representation of a Integer.
   MKL
      Returns a four character String representation of a Long.
   MKLongInt
      Returns an eight character String representation of a LongInt.
   MKS
      Returns a four character String representation of a Single.
   MKShort
      Returns a two character String representation of a Short.
   CVD
      Returns a Double representation of an eight character String.
   CVI
      Returns an Integer representation of a four character String.
   CVL
      Returns a Long representation of a four character String.
   CVLongInt
      Returns a LongInt representation of an eight character String.
   CVS
      Returns a Single representation of a four character String.
   CVShort
      Returns a Short representation of a two character String.

Working with Substrings
   Left
      Returns a substring of the leftmost characters in a string.
   Mid (Function)
      Returns a substring of a string.
   Right
      Returns a substring of the rightmost characters in a string.
   LCase
      Returns a copy of a string converted to lowercase alpha characters.
   UCase
      Returns a copy of a string converted to uppercase alpha characters.
   LTrim
      Removes surrounding substrings or characters on the left side of a 
      string.
   RTrim
      Removes surrounding substrings or characters on the right side of a 
      string.
   Trim
      Removes surrounding substrings or characters on the left and right 
      side of a string.
   InStr
      Returns the first occurrence of a substring or character within a 
      string.
   InStrRev
      Returns the last occurrence of a substring or character within a 
      string.
   Mid (Statement)
      Copies a substring to a substring of a string.
   LSet
      Left-justifies a string.
   RSet
      Right-justifies a string.



-------------------------------------------------------- CatPgThreading ----
Threading Support Functions

Procedures for working with multithreaded applications.

Description
   These procedures allow for multithreaded programming. Threads and 
   conditional variables can be created and destroyed, and so-called 
   mutexes can be obtained to protect thread-sensitive data.

Threads
   Procedures that start and wait for threaded procedures.
Mutexes
   Procedures that deal with mutexes.
Conditional Varables
   Procedures that create and signal conditional variables.

Threads
   ThreadCall
      Starts a procedure with parameters in a separate thread of execution.
   ThreadCreate
      Starts a procedure in a separate thread of execution.
   ThreadWait
      Waits for a thread to finish and releases the thread handle.
   ThreadDetach
      Releases a thread handle without waiting for the thread to finish.
   ThreadSelf
      Returns the thread handle of the current thread.

Mutexes
   MutexCreate
      Creates a mutex.
   MutexLock
      Acquires a lock on a mutex.
   MutexUnlock
      Releases a lock on a mutex.
   MutexDestroy
      Destroys a mutex that is no longer needed.
Conditional Variables
   CondCreate
      Creates a conditional variable.
   CondWait
      Pauses execution of a threaded procedure.
   CondSignal
      Resumes execution of a threaded procedure waiting for a conditional.
   CondBroadcast
      Resumes all threaded procedures waiting for a conditional.
   CondDestroy
      Destroys a conditional variable that is no longer needed.

Platform Differences
   * These procedures are not supported in DOS.



------------------------------------------------------------ CatPgInput ----
User Input (Runtime Library)

Statements and procedures (from runtime library) that get input from the 
user.

Description
   These statements and procedures allow access to the keyboard buffer, and 
   provide ways of getting input from the user.

Reading keys from the keyboard buffer
   Procedures that read individual keys from the keyboard buffer.
Reading values from the keyboard buffer
   Procedures that read characters and values from the keyboard buffer.
Detecting key status by keyboard scancode
   Procedure that detects the status of a key by its scancode.

Reading values from the keyboard buffer
   Input
      Reads values from the keyboard buffer.
   Line Input
      Reads a line of text from the keyboard buffer.
   Input()
      Reads a number of characters from the keyboard buffer, file or 
      device.
   Winput()
      Reads a number of wide characters from the keyboard buffer, file or 
      device.
Reading keys from the keyboard buffer
   Inkey
      Gets the first key, if any, waiting in the keyboard buffer.
   GetKey
      Gets and waits for the first key in the keyboard buffer.

Detecting key status by keyboard scancode
   MultiKey
      Detects the status of a key by its scancode.





============================================================================
  GRAPHICS LIBRARY REFERENCE
  --------------------------


------------------------------------------------------------ CatPgGfx2D ----
2D Drawing Functions

Statements and procedures for working with 2D graphics.

Description
   The statements and procedures listed here provide ways of drawing to the 
   screen. Image buffers can be created and blitted to the screen using a 
   variety of blending methods. Palette colors can be retrieved or set in 
   graphics modes that support them.

Working with Color
   Procedures that control the color used by other drawing procedures.
Drawing to Image Buffers
   Procedures that draw shapes and text onto image buffers or to the 
   screen.
Image Buffer Creation
   Procedures that create, free and save image buffers.
Blitting Image Buffers
   Procedures that draw image buffers onto other image buffers or to the 
   screen.

Working with Color
   Color
      Sets the foreground and background color to use with the drawing 
      procedures.
   Palette
      Gets or sets color table information in paletted modes.
   RGB
      Returns a color value for hi/truecolor modes.
   RGBA
      Returns a color value including alpha (transparency) for hi/truecolor 
      modes.
   Point
      Gets a pixel value from an image buffer or screen.

Drawing to Image Buffers
   PSet and PReset
      Plots a single pixel on an image buffer or screen.
   Line (Graphics)
      Plots a line of pixels on an image buffer or screen.
   Circle
      Plots circles and ellipses on an image buffer or screen.
   Draw
      Draws in a sequence of commands on an image buffer or screen.
   Draw String
      Writes text to an image buffer or screen.
   Paint
      Fills an area with color on an image buffer or screen.

Image Buffer Creation
   Get (Graphics)
      Creates an image buffer from a portion of another image buffer or 
      screen.
   ImageCreate
      Creates an image buffer of a certain size and pixel depth.
   ImageDestroy
      Frees an image buffer resource.
   ImageConvertRow
      Converts a row of pixels in an image buffer to a different color 
      depth.
   ImageInfo
      Retrieves useful information about an image buffer
   BLoad
      Creates an image buffer from a file.
   BSave
      Saves an image buffer to a file.
Blitting Image Buffers
   Put (Graphics)
      Blits an image buffer to another image buffer or screen.

   Blending Methods
      Add
         Saturated addition of the source and target components.
      Alpha
         Blend using a uniform transparency or the image buffer's alpha 
         channel.
      And (Graphics Put)
         Combine the source and target components using a bitwise And
      Or
         Combine the source and target components using a bitwise Or
      PSet
         Directly copy pixel colors from the source to the destination.
      Trans
         Pixels matching the transparent mask color are not blitted.
      Custom
         Allows a custom blending procedure to be used.
      Xor
         Combine the source and target components using a bitwise Xor



--------------------------------------------------------- CatPgGfxInput ----
User Input Functions (Graphics Library)

Procedures (from graphics library) for working with mice, gaming devices 
and keyboards.

Description
   These procedures provide access to external devices such as keyboards, 
   mice and gamepads.

Mouse and Joystick Input
   Procedures that provide state information of the mouse or joystick.
Keyboard Input
   Procedures that provide keyboard state information.

Mouse and Joystick Input
   GetMouse
      Gets button and axis information for the mouse.
   SetMouse
      Sets position and visibility of the mouse cursor.
   GetJoystick
      Gets button and axis information for gaming devices.
   Getxpad
      Gets Xbox-style controller state for gaming devices.
   Stick
      Gets axis position for gaming devices.
   Strig
      Gets button state for gaming devices.
Keyboard Input
   MultiKey
      Gets key information for the keyboard.



-------------------------------------------------------- CatPgGfxScreen ----
Screen Functions

Statements and procedures that work with the graphics display.

Description
   These statements and procedures control the graphics capabilities of the 
   FreeBASIC graphics library. Screen modes can be set with varying 
   resolutions and color depths, window events can be handled, and specific 
   OpenGL procedures can be retrieved.

Working with screen modes
   Procedures for setting and retrieving information about screen modes.
Working with pages
   Procedures that manipulate screen pages.
Working video memory
   Procedures that provide direct access to framebuffer memory.
Screen Metrics
   Procedures that control the way coordinates are interpreted.
Screen Data Types
   Data types and data definitions for screen functions.

Working with screen modes
   ScreenList
      Gets the available fullscreen resolutions.
   Screen (Graphics) and ScreenRes
      Sets a new graphics display mode.
   ScreenInfo
      Gets information about the system desktop or current display mode.
   ScreenControl
      Gets or sets internal graphics library settings.
   ScreenEvent
      Gets system events.
   ScreenGLProc
      Returns the address of an OpenGL procedure.
   WindowTitle
      Sets the running program's window caption.

Working with pages
   Cls
      Clears the entire screen or viewport.
   ScreenSet
      Sets the current work and visible pages.
   ScreenCopy and PCopy and Flip
      Copies pixel data from one page to another.
   ScreenSync
      Waits for the vertical refresh of the monitor.
Working video memory
   ScreenPtr
      Gets the address of the working page's framebuffer.
   ScreenLock
      Locks the current working page's framebuffer for direct access.
   ScreenUnlock
      Reverts a previous ScreenLock command.

Screen Metrics
   View (Graphics)
      Sets a clipping region for all drawing and blitting procedures.
   Window
      Sets a new coordinate mapping for the current viewport.
   PMap
      Converts coordinates between physical and view mappings.
   PointCoord
      Queries Draw's pen position.

Screen Data Types
   Event
      Data type for ScreenEvent function.



---------------------------------------------------------------- GfxLib ----
GfxLib - FreeBASIC graphics library overview

The libary named GfxLib is the built-in graphics library included in FreeBAS
IC. As well as re-creating every QuickBASIC graphics command, GfxLib has 
built-in commands to handle input from the keyboard and mouse. Major 
contributors of the library are Lillo, coderJeff and DrV.

The library supports various drivers depending on the platform: 

   * All:
      * Null Does nothing, allows to use graphics functions on in-memory 
        buffers and such, without anything being displayed in a graphics 
        window.  (gfxlib2/gfx_driver_null.c)

   * Windows:
      * Direct2D the default selection of FB GfxLib. For fbc built on 
        WinXP + mingw.org (very old tool chain now), the Direct2D driver is 
        disabled in the gfxlib.
      * DirectX is fallback if Direct2D can't be initialized. May not be 
        available on old Windows installations. 
        (gfxlib2/win32/gfx_driver_ddraw.c)
      * GDI as last resort, the "safest" one, available in all Windows 
        versions. Bug note: broken in FB versions 0.20 to 0.24 (crash), and 
        minor problems 0.18.5, and 0.90.x and 1.xx ("banding effects", try 
        extra SCREENUNLOCK), (forum discussion: p=106600) 
        (gfxlib2/win32/gfx_driver_gdi.c)
      * OpenGL (gfxlib2/win32/gfx_driver_opengl.c)

   * Linux & others:
      * X11 The default on Unix systems  (gfxlib2/unix/gfx_driver_x11.c)
      * OpenGL (on top of X11) (gfxlib2/unix/gfx_driver_opengl_x11.c)
      * FBDev Linux framebuffer device -- fallback in case X11 is disabled 
        (gfxlib2/linux/gfx_driver_fbdev.c)

   * DOS:
      * BIOS (gfxlib2/dos/gfx_driver_bios.c)
      * ModeX "tuned" 320x240x8bpp VGA mode 
        (gfxlib2/dos/gfx_driver_modex.c)
      * VESA banked compatible with very old VESA 1.x implementations 
        (gfxlib2/dos/gfx_driver_vesa_bnk.c)
      * VESA linear needs VESA version at least 2.0, usually faster than 
        banked VESA (gfxlib2/dos/gfx_driver_vesa_lin.c)
      * VGA (gfxlib2/dos/gfx_driver_vga.c)
      * Bug note: Palette doesn't work well 
        (forum discussion: t=12691 2008) (forum discussion: t=19980 2012)

ScreenControl can be used (SET_DRIVER_NAME 103) to override the default 
driver preferences.

Platform Differences
   * In DOS, GfxLib will create and "manage" a mouse arrow if a mouse 
     driver is detected. There is no "official" way to disable this. Also 
     note that the arrow doesn't react to mouse movements while the screen 
     is locked.
   * In DOS, Windowing and OpenGL related commands and switches are not 
     available (they exist but do nothing, or return some values with no 
     meaning)
   * In DOS, the refresh rate setting is not available (some VESA cards do 
     support it, but FreeBASIC for now doesn't)
   * In DOS, the resolution must match one supported by the graphics card. 
     GfxLib will try to find an appropriate mode from VGA modes, ModeX or 
     VESA, preferring VESA LFB interface if available, or banked VESA 
     otherwise. Unsupported resolutions may currently crash the program (if 
     you fail to check SCREENPTR for ZERO before using it), though in 
     future GfxLib may try to find a close match instead. For optimal 
     compatibility, you should support "safe" resolutions like 640x480 and 
     800x600, and maybe 1024x768. There are various additional modes like 
     768x576 around, but they are vendor specific and lacking on many other 
     cards. Also modes 1024x768 and above are not available on older cards 
     and laptops.
   * It has been observed that SCREEN and SCREENRES may fail to clear the 
     screen in DOS, actually this is probably a BIOS bug that GfxLib 
     currently doesn't workaround.

Differences from QB
   * Graphics support was internally redesigned. QB used VGA graphics 
     modes, and wrote directly into the VGA RAM. Multiple pages were 
     available as long as the card supported them. FB uses backbuffers, one 
     per defined page, and copies them to the video RAM (VGA (DOS), VESA 
     (DOS), DirectX (Win32), ...) in the background. Graphics commands do 
     work as they used to in QB, but a few notable differences are present:
      * The background screen updating eats a considerable amount of CPU 
        performance.
      * There is a thread (Win32 and Linux) or ISR (DOS, uses the PIT) 
        active for this.
      * Mixing FB's graphics support with low-level screen accesses (VGA) 
        is not supported, even in DOS. However direct screen memory access 
        is possible using Screenptr and Screenlock and is fully portable. 
        In DOS VGA and VESA are still available, but can't be mixed with 
        FB's graphics support.

See also
   * GFX Functions Index
   * Screen (Graphics) The QB-like way to set graphics mode
   * ScreenRes More flexible alternative to Screen
   * ScreenList Check display modes available for FB GfxLib to use
   * ScreenControl Select driver and more 
   * ScreenLock
   * ScreenUnlock
   * ScreenPtr Semi-low level access
   * ScreenSet
   * ScreenCopy
   * ScreenInfo
   * ScreenGLProc
   * Internal pixel formats



---------------------------------------------------------- GfxScancodes ----
DOS Keyboard Scancodes

Listing of keyboard scancodes.

Description
Here follows a list of hardware keyboard scancodes accepted by the MultiKey 
function. These are equal to DOS scancodes, and are guaranteed to be always 
recognized on all platforms.

These constants are also defined in the fbgfx.bi include file you can use 
in your programs. If you are using the lang fb dialect then everything 
inside fbgfx.bi is enclosed in the FB Namespace. To use these constants in 
lang fb, either prepend "FB." to the constant name, or put "Using FB" after 
the #include line.
The hexadecimal code is not required and provided only for reference.

   SC_ESCAPE       &h01
   SC_1            &h02
   SC_2            &h03
   SC_3            &h04
   SC_4            &h05
   SC_5            &h06
   SC_6            &h07
   SC_7            &h08
   SC_8            &h09
   SC_9            &h0A
   SC_0            &h0B
   SC_MINUS        &h0C
   SC_EQUALS       &h0D
   SC_BACKSPACE    &h0E
   SC_TAB          &h0F
   SC_Q            &h10
   SC_W            &h11
   SC_E            &h12
   SC_R            &h13
   SC_T            &h14
   SC_Y            &h15
   SC_U            &h16
   SC_I            &h17
   SC_O            &h18
   SC_P            &h19
   SC_LEFTBRACKET  &h1A
   SC_RIGHTBRACKET &h1B
   SC_ENTER        &h1C
   SC_CONTROL      &h1D
   SC_A            &h1E
   SC_S            &h1F
   SC_D            &h20
   SC_F            &h21
   SC_G            &h22
   SC_H            &h23
   SC_J            &h24
   SC_K            &h25
   SC_L            &h26
   SC_SEMICOLON    &h27
   SC_QUOTE        &h28
   SC_TILDE        &h29
   SC_LSHIFT       &h2A
   SC_BACKSLASH    &h2B
   SC_Z            &h2C
   SC_X            &h2D
   SC_C            &h2E
   SC_V            &h2F
   SC_B            &h30
   SC_N            &h31
   SC_M            &h32
   SC_COMMA        &h33
   SC_PERIOD       &h34
   SC_SLASH        &h35
   SC_RSHIFT       &h36
   SC_MULTIPLY     &h37
   SC_ALT          &h38
   SC_SPACE        &h39
   SC_CAPSLOCK     &h3A
   SC_F1           &h3B
   SC_F2           &h3C
   SC_F3           &h3D
   SC_F4           &h3E
   SC_F5           &h3F
   SC_F6           &h40
   SC_F7           &h41
   SC_F8           &h42
   SC_F9           &h43
   SC_F10          &h44
   SC_NUMLOCK      &h45
   SC_SCROLLLOCK   &h46
   SC_HOME         &h47
   SC_UP           &h48
   SC_PAGEUP       &h49
   SC_LEFT         &h4B
   SC_CLEAR        &h4C
   SC_CENTER       &h4C
   SC_RIGHT        &h4D
   SC_PLUS         &h4E
   SC_END          &h4F
   SC_DOWN         &h50
   SC_PAGEDOWN     &h51
   SC_INSERT       &h52
   SC_DELETE       &h53
   SC_F11          &h57
   SC_F12          &h58
   '' Extra scancodes not compatible with DOS scancodes
   SC_LWIN         &h5B
   SC_RWIN         &h5C
   SC_MENU         &h5D

See also
   * MultiKey

   


-------------------------------------------------------- GfxDefPalettes ----
Default Palettes

Default color values for FreeBASIC graphics and text screen modes.

   FreeBASIC initializes the palette indexes with the colors in the tables 
   below. The colors are the same as in QB. Colors in graphics mode can be 
   changed using the Palette statement. There is no portable way of 
   changing the palette in console mode.

Screen mode 1
   4 colors: Black and white, and two others
Screen modes 2, 10 and 11
   Monochromatic: black and white.
Screen modes 7, 8, 9, 12, and Console (Screen 0)
   Two sets of 8 colors: normal and intense (bright)
Screen 13 and 8-bit modes
   Multiple color and grayscale bands

Screen mode 1

      +-----+-------+
      |Value|Name   |
      |0    |black  |
      |1    |cyan   |
      |2    |magenta|
      |3    |white  |
      +-----+-------+

Screen modes 2, 10 and 11

      +-----+-----+
      |Value|Name |
      |0    |black|
      |1    |white|
      +-----+-----+

Screen modes 7, 8, 9, 12, and Console (Screen 0)

      +------------+-----------+-------------+-------------+
      |Normal Value|Normal Name|Intense Value|Intense Name |
      |0           |black      |8            |dark grey    |
      |1           |blue       |9            |bright blue  |
      |2           |green      |10           |bright green |
      |3           |cyan       |11           |bright cyan  |
      |4           |red        |12           |bright red   |
      |5           |pink       |13           |bright pink  |
      |6           |yellow     |14           |bright yellow|
      |7           |grey       |15           |white        |
      +------------+-----------+-------------+-------------+

Screen 13 and 8-bit modes

   Screen 12 color band

      Colors 0 through 15 are the same as screen 12 mode.

   Grayscale band
      Colors 16 through 31 are grayscale from black to white.

   Brightness/saturation bands
      3 bands of decreasing brightness, each containing 3 bands of 
      decreasing saturation, each containing 24 hues of color starting and 
      ending at blue.

         +-------+-----+-----+-----+-----+-----+-----+-----+-----+-----+
         |Name   |HB/HS|HB/MS|HB/LS|MB/HS|MB/MS|MB/LS|LB/HS|LB/MS|LB/LS|
         |blue   |32   |56   |80   |104  |128  |152  |176  |200  |224  |
         |magenta|36   |60   |84   |108  |132  |156  |180  |204  |228  |
         |red    |40   |64   |88   |112  |136  |160  |184  |208  |232  |
         |yellow |44   |58   |92   |116  |140  |164  |188  |212  |236  |
         |green  |48   |72   |96   |120  |144  |168  |192  |216  |240  |
         |cyan   |52   |76   |100  |124  |148  |172  |194  |220  |244  |
         +-------+-----+-----+-----+-----+-----+-----+-----+-----+-----+

   Black band
      Colors 248 through 255 are black.





============================================================================
  TUTORIALS
  ---------



============================================================================
    Getting Started

------------------------------------------------------- ProPgHelloWorld ----
Hello World

This example is a classic in any programming language.

More as a sanity check than anything else, a good place to start with any 
programming language is to try a very simple program to test that the 
compiler is installed correctly and that a valid executable can be made.

Open up any editor capable of saving text files and type in the following 
source code:
   Print "Hello World"

Save the file with a '.bas' extension.  For example 'hello.bas'

From a command prompt or shell in the directory where 'hello.bas' was 
saved, type the following command:

   fbc hello.bas

Depending on the operating system, this should create an executable file in 
the same directory as 'hello.bas'.  It might be named 'hello.exe' or '
./hello', for example.

Run the executable, and we should have the following output:

   Hello World

See also
   * Freebasic FAQ
   * Main Features
   * Requirements
   * Installing
   * Running



---------------------------------------------------------- ProPgPrimer1 ----
FreeBASIC Primer #1

This primer is intended for beginning beginners, for those who are just 
starting to learn how to program and using FreeBASIC do to it.

Learning the language
   Learning a programming language means learning the words to write it and 
   knowing what they mean when they are written.  We don't need to learn 
   them all at once.  But learning a few important words that do something 
   will help us get started.  Here we are just going to concentrate on 
   these keywords:

   * Dim
   * Print
   * Input
   * For...Next
   * If...Then
   * Do...Loop

Hello World!
   No beginners reference is complete without this example.

   Print "Hello World!"

   The text between the pair of double quotes is a literal string.  The 
   Print statement is used to output text to the display.  If you can edit, 
   compile, and execute this example, you are on your way.

   Note: A program terminates immediately after executing the last line of 
   code. User can add a Sleep statement to induce a pause until pressing 
   any key to complete instruction (see last example for usage).

Using a Variable to Store Data
   Sometimes in a program we will want to store some information somewhere, 
   in memory, and then use it later.  To store something in memory we use a 
   variable.  All variables in FreeBASIC are of some specific type, like a 
   number or a string.  We use the Dim statement to declare a variable name 
   and specify what type of information we want to store in it.

   Dim text As String
   text = "Hello World!"
   Print text

   We are using Dim to let the compiler know that we want to use a variable 
   named text in our program and that we will be putting String data in it. 
   We then assign (copy) "Hello World!" in to the variable.  Finally, we 
   use Print to output it to the display.

Using a Variable in an Expression
   An expression is a generic term for describing a part of the source code 
   that can be evaluated.  After an expression is evaluated, we can then do 
   something with it, like assign (copy) it to a variable.

   Dim As String a, b, text
   a = "Hello"
   b = "World"
   text = a + " " + b + "!"
   Print text

   We are assigning the variables a and b with some data.  We are then 
   using the variables a and b in an expression which is then assigned to 
   text.  Finally, we output the result to the display.

Getting Input from the User
   Often, we have no idea what data is needed for a program unless the user 
   gives it to us.  We can't put it in our source code since we won't know 
   what it is until the user runs the program and tells us what it is.

   Dim answer As String
   Input "Type something and press enter:", answer
   Print "You typed: '"; answer; "'"

   Here the Input statement will first, output some information to the 
   display, and then wait for the user to give the program some data.  In 
   this example, we just output back to the display, exactly what the user 
   typed in.

Doing Some Math
   Variables and expressions are not just limited to strings.  Most early 
   languages didn't handle strings very well if at all.  Writing 
   mathematical expressions is similar to how they might be written with 
   pencil and paper.

   Dim As Integer a, b, c

   a = 5
   b = 7
   c = a + b

   Print "a = "; a
   Print "b = "; b
   Print "a + b = "; c

   We are assigning values to the variables a, b and c.  We are using 
   Integer for the variables' data type.  An integer can be positive or 
   negative, but not have any fractions.

Doing Some Math with Input
   This is similar to the previous example, except we will let the user 
   choose the numbers we are going to add together.

   Dim As Integer a, b, r
   Input "Enter a number:", a
   Input "Enter another number:", b

   r = a + b
   Print "The sum of the numbers is "; r

   Dim lets the compiler know which variable names we want to use and that 
   they are going to hold Integer data.  We are using Input to get the 
   numbers from the user, and Print to display the results.

Doing More Math with Input
   Numeric variables are not limited to just integers.  We can also use  
   Single or Double precision data types which can represent fractions.  In 
   this example we will take some input from the user to convert a weight 
   in pounds to kilograms.

   Dim As Single lb, kg
   Input "Enter a weight in pounds:", lb

   kg = lb * 0.454
   Print lb; " lb. is equal to "; kg; " kg"

Repeating Statements
   Using For...Next statement we can tell the program to do something 
   repeatedly a set number of times.  For example lets say we wanted to add 
   up all the numbers from 1 to 100.

   Dim total As Integer
   Dim number As Integer
   total = 0
   For number = 1 To 100
     total = total + number
   Next
   Print "The sum of number from 1 to 100 is "; total

Making a Decision
   A program can choose which statements to execute using a conditional 
   statement like If...Then.  We can use the value of a variable or the 
   result of an expression to decide if we should, or should not, execute 
   one or more statements.

   Dim number As Integer
   Input "Enter a number : ", number
   Print "Your number is ";
   If number < 0 Then
     Print "negative"
   ElseIf number > 0 Then
     Print "positive"
   Else
     Print "zero"
   End If

   After getting a number from the user, we are going to output a word ( 
   positive, negative, or zero ) based on which condition matches the 
   statement.

Repeating Statements (Again)
   Here we will use another looping structure Do...Loop to repeat some 
   statements.  How will the program know to stop repeating the statements? 
   We will use If...Then to make the decision when to get out of the loop.

   Dim As Single   total, count, number   ' multi variable declaration (same type)
   Dim As String   text

   Print "This program will calculate the sum and average for a"
   Print "list of numbers. Enter an empty value to see results."
   Print

   Do
     Input "Enter a number: ", text       ' get user input
     If text = "" Then Exit Do            ' if empty -> quit Do/Loop
     count += 1                           ' increment count by: 1
     total += Val(text)                   ' add and assign new value
   Loop

   Print
   Print "You entered:    "; count; "  number(s)"
   Print "The sum is:     "; total

   If count > 0 Then Print "The average is: "; total / count

   Print
   Print "Any keypress ends program. ";

   Sleep

See also
   * Dim
   * Print
   * ?
   * Input
   * For...Next
   * If...Then
   * Do...Loop




============================================================================
    Source Files

------------------------------------------------------ ProPgSourceFiles ----
Source Files (.bas)

Text files read by FreeBASIC and compiled into executable code.

A source file is a text file that contains FreeBASIC language statements.  
A program might be made from just one source file or possibly hundreds.  
Source files are read by the compiler and compiled into object code.  
Object code is then linked to create an executable or can be stored for 
later use as a library.

FreeBASIC by default, automatically takes care of compiling sources and 
linking object modules in to executables, so normally it is possible to 
make an executable program by just passing the names of the source files on 
the fbc command line.  For example, assuming we had three source files that 
together made a program, we could create an executable for the program by 
running fbc, the FreeBASIC compiler on a command line as follows:

   fbc myprog.bas tools.bas funcs.bas

Unicode support
   * Besides ASCII files with Unicode escape sequences (\u), FreeBASIC can 
     parse UTF-8, UTF-16LE, UTF-16BE, UTF-32LE and UTF-32BE source (.bas) 
     or header (.bi) files as long as they were saved with Byte Order Mark 
     (BOM), they can be freely mixed with other sources/headers in the same 
     project (also with other ASCII files).
   * Unicode files must be saved with Byte Order Mark (BOM), otherwise fbc 
     does not recognize them as Unicode.
   * Literal strings can be typed in the original non-Latin alphabet, just 
     use a text-editor that supports one of the Unicode formats listed 
     above.

   Note: The most reliable cross-platform code is obtained by encoding 
   without BOM in ASCII/UTF-8 characters.

Implicit main()
   Some languages require a special main() procedure be defined as an entry 
   point to the program which define the first statements that will be 
   executed when the program starts.  FreeBASIC allows executable 
   statements in module level code and normally the first source file 
   passed to fbc on the command line will be used as the "main" module.  
   The main module can be explicitly named by passing -m filename on the 
   command line, where filename is the name of the main module without the 
   .bas extension.
      '' sample.bas
      Declare Sub ShowHelp()

      '' This next line is the first executable statement in the program
      If Command(1) = "" Then
         ShowHelp
         End 0
      End If   

      Sub ShowHelp()
         Print "no options specified."   
      End Sub

Header Files
   A header file is a special kind of source file that typically only 
   contains declarations and has a .bi extension. See Header Files (.bi).

See also
   * fbc command-line
   * Header Files (.bi)



------------------------------------------------------ ProPgHeaderFiles ----
Header Files (.bi)

Provides an interface for a module.

A header file is a special kind of source file that typically only contains 
preprocessor statements, defines, declarations, prototypes, constants, 
enumerations, or similar types of statements, however, a header file can 
contain any valid source code if the purpose suits.  What makes them 
different from other module (.bas) source files, is instead of being 
compiled directly, they are included by another source file (module or 
header) using the #include preprocessor directive.  All compiled libraries 
typically have one or more header files that can be included in another 
source file and will introduce to the compiler all the names of the 
procedures usable in a particular library.

FreeBASIC Header Files
   Some of the keywords, constants, and procedures documented in this 
   manual are not normally available when compiling a source code unless a 
   specific header file is included in the source first.
   * inc/fbc-int/array.bi
   * inc/datetime.bi
   * inc/dir.bi
   * inc/fbgfx.bi
   * inc/fbio.bi
   * inc/fblimits.bi
   * inc/fbprng.bi
   * inc/fbthread.bi
   * inc/file.bi
   * inc/fbc-int/symbol.bi
   * inc/crt/string.bi
   * inc/vbcompat.bi

Case Sensitivity
   Although the FreeBASIC language itself is not case-sensitive, the file 
   system on which it is running might be.  If a header file can not be 
   found, check that FreeBASIC is searching for it the correct location and 
   ensure that name of both the directory and filename of the header file 
   specified in the #include statement is using the correct upper and lower 
   case letters.

Path Separators
   FreeBASIC will automatically switch backslash ( \ ) and forward slash ( 
   / ) characters as needed for a given platform.  This allows source code 
   to be easily cross compatible.

Including a header only once
   It is common that header files need to #include other header files to 
   compile correctly.  FreeBASIC offers three methods for guarding against 
   including a header file more than once.
   * #ifndef guards in the header file
   * #include Once where the file is included
   * #pragma Once in the header file itself

#ifndef guards in the header file
   The use of #ifndef and #define is a common practice in nearly any 
   language that supports preprocessing.  The first time a file is 
   included, a unique symbol is defined.  The next time the same header 
   file is included, the definition of the symbol is checked, and if it is 
   already defined, the contents of the header file are skipped.
   '' header.bi
   #ifndef __HEADER_BI__
   #define __HEADER_BI__

   #print These statements will only be included Once,
   #print even though header.bi might be included more 
   #print than Once in the same source file.

   #endif

#include once
   At the point in the source code where the header file is included, the 
   optional "once" specifier of the #include directive can tell the 
   compiler to only include the source file one time.
   '' header.bi
   #include Once "fbgfx.bi"

   '' module.bas
   #include Once "fbgfx.bi"
   #include Once "header.bi"

#pragma once
   #pragma Once can be used in a header file to indicate that the header 
   file should only be included once.  
   '' header.bi
   #pragma Once
   #print This header will only ever be included Once per module

Version
   * Since fbc 1.10.0, symbol.bi and fblimits.bi are added.
   * Before fbc 1.10.0 (for fbc 1.08.0 and fbc 1.09.0), fbprng.bi was 
     named fbmath.bi.
   * Since fbc 1.08.0, array.bi is added.
   * Before fbc 1.08.0, the standard fbmath.bi header did not exist.

See also
   * Source Files (.bas)
   * Header Files Index



------------------------------------------------ ProPgPrebuiltLibraries ----
Using Prebuilt Libraries

FreeBASIC is distributed with many headers for common or popular libraries. 
The headers allow a programmer to use functions available in these existing 
static or shared libraries (DLLs).  

The libraries themselves are not distributed with FreeBASIC, but most can 
be downloaded from the web and readily installed.  Some other libraries may 
need to be first compiled from sources to be used.  Please see the 
documentation for the specific library on how to configure, install, and 
use them.
Note that the system architecture of the library has to match the 
architecture of the application. For example, to successfully use a library 
in a x86 (32-bit) application, a x86 (32-bit) library is required.

Some static or shared libraries (DLLs) may be already present on the system 
since they might be part of FreeBASIC itself or the operating system.

Although many headers can be used on any of the platforms supported by FreeB
ASIC, some headers are platform specific and will not be usable on other 
platforms.

FreeBASIC headers
   There are a few headers that are specific to FreeBASIC and expose some 
   functions that are otherwise not available:
   * inc/fbc-int/array.bi - Declaration for 
     Fbarray (Array Descriptor Structure And Access), Arraylen, Arraysize.
   * inc/datetime.bi - Declarations for DateSerial, DateValue, IsDate, Year
     , Month, Day, Weekday, TimeSerial, TimeValue, Hour, Minute, Second, Now
     , DateAdd, DatePart, DateDiff, MonthName, WeekdayName.
   * inc/dir.bi - Constants to be used with Dir.
   * inc/fbgfx.bi - Additional constants and structures to be used with 
     graphics commands such as MultiKey,  ScreenControl, and ScreenEvent, 
     ImageCreate.
   * inc/fbio.bi - Declaration for IsRedirected.
   * inc/fblimits.bi - Constants for minimum and maximum values of 
     built-in number.
   * inc/fbprng.bi - Constants to be used with Randomize, and also 
     unfinished structures for other random number generators.
   * inc/fbthread.bi - Declaration for ThreadDetach and ThreadSelf.
   * inc/file.bi - Declarations for FileCopy, FileAttr, FileLen, FileExists
     , FileDateTime.
   * inc/fbc-int/symbol.bi - Declaration for __Fb_Query_Symbol__ and its 
     associated sub-macros.
   * inc/crt/string.bi - Declarations for Format.
   * inc/vbcompat.bi - Includes datetime.bi, dir.bi, file.bi, and 
     string.bi plus additional constants compatible with Microsoft Visual 
     Basic.

C Runtime (CRT)
   Where possible cross-platform compatible headers have been provided for 
   the C runtime (CRT).  For example,
   #include Once "crt.bi"
   printf( !"Hello World\n" )

   To include a specific CRT header, prefix the name of the header file 
   with "crt/".  For example:
   #include Once "crt/stdio.bi"
   Dim f As FILE Ptr
   f = fopen("somefile.txt", "w")
   fprintf( f, "Hello File\n")
   fclose( f )

Windows API
   Many (many) headers for the Windows API are available for inclusion in 
   FreeBASIC source code.  In most cases the only include file needed is 
   "windows.bi".  For example,
   #include Once "windows.bi"
   MessageBox( null, "Hello World", "FreeBASIC", MB_OK )

   To include a specific Windows API header, prefix the name of the header 
   with "win/" for example:
   #include Once "win/ddraw.bi"

   Browse the "inc/win/" directory where FreeBASIC was installed to see all 
   of the available Windows API headers.

Other Headers Provided
   See the External Libraries Index for an overview of the additional 
   headers shipped with FreeBASIC.  The page also describes the file(s) 
   that need to be included to use the library.  Alternatively one can 
   browse the "inc/" directory located where FreeBASIC was installed to 
   find other headers.  It is possible that headers might be available for 
   a library you need to use.  Some headers are located in "inc/" and 
   others might be located in a sub-directory.  To include headers located 
   in a subdirectory of "inc/", prefix the name of the header with the name 
   of the directory where it is located.
   For example:
   '' located at inc/curl.bi
   #include Once "curl.bi"

   '' located at inc/GL/gl.bi
   #include Once "GL/gl.bi"

Requirements for Using Prebuilt Static Libraries
   * The source code must include the appropriate headers using #include.
   * The static library must be linked at compile time by using either 
     #inclib in the source code or by using the -l option on the command 
     line to specify the name of the library.

Requirements for Using Prebuilt Shared Libraries
   * The source code must include the appropriate headers using #include.
   * The shared library (.DLL) must be present on the host computer where 
     the compiled program will run.

Version
   * Since fbc 1.10.0, symbol.bi and fblimits.bi are added.
   * Before fbc 1.10.0 (for fbc 1.08.0 and fbc 1.09.0), fbprng.bi was 
     named fbmath.bi.
   * Since fbc 1.08.0, array.bi is added.
   * Before fbc 1.08.0, the standard fbmath.bi header did not exist.

See also
   * Static Libraries
   * Shared Libraries (DLLs)



--------------------------------------------- ProPgSourceCompiledModule ----
Manage Reusable Procedures by Including Source vs Compiled Modules

How to manage FreeBASIC reusable procedures by including source modules 
versus including compiled modules.
(written with help of Josep Roca's posts)

Preamble:

   When old OSs (like DOS) were used, compiling by separate modules was 
   mandatory as soon as the program was not very short, because of the 
   small memory size available for the compiler (about 200 KB with Quick 
   Basic 4.5).
   Now, with modern PC and OS, this compilation limit is pushed back by a 
   factor of about 10000, and the compile time for a large file in one go 
   has become acceptable especially with FreeBASIC.
   This allows to use another method (than a library of compiled files) to 
   manage the reusable user procedures.

   First, the reusable user procedures source codes are grouped into 
   different source modules, for example by functionality.
   Then the process is different depending on each method used.

   To simplify the explanation that follows, it is considered that there is 
   only one source file containing the main program, which calls the 
   various user procedures contained in source modules for reuse.
   But one can easily complete these methods to take into account a main 
   program spread over several source files.

First method: The compiled modules stored in a library file are included in 
the linking process with the compiled main program
   The principle of this method is by only accessing to the compiled user 
   procedures.

   The different modules (containing the sources of the user procedures to 
   be reused) are turned in to object files and then stored into a library 
   file (using the -lib compile option).
   Finally the source file of the main program is compiled, then linked to 
   the library, to make an executable (using the -l < libname > compile 
   option, or the #Inclib "Libname" directive put at beginning of the main 
   program source code).

   For each compiled module, if at least one procedure is called, then the 
   entire module will be added in the final executable.

   Thus, the granularity of the added code to the executable is at the 
   module level (coarse granularity).

Second method: The source modules are included directly in the main source 
program to be compiled in one go
   The principle of this method is by fully accessing to the sources of 
   user procedures.

   The different modules (containing the sources of the user procedures to 
   be reused) are directly included in the source of the main program 
   (using the #Include "File" directive for each module, put at the 
   beginning of the main program source code).
   Finally, the big resulting source file is compiled in one go to make it 
   an executable.

   Since the compiler processes a single source file, all reusable user 
   procedures can be declared as Private (which is obviously impossible 
   when using library because the external links are required during the 
   linkage).
   As a result, only the Private procedures really called will be kept in 
   the executable.

   Thus, the granularity of the code added to the executable is at the 
   elementary procedure level (fine granularity).

   Note:
      The compiler removes the Private procedures that are not called, but 
      this does not currently work for Private procedures that are only 
      called by other Private procedures that are not called themselves, 
      because the first ones appear as being called.
      The problem is that the one-pass compiler only uses a simple flag to 
      track the "used" state of a procedure, which is set whenever the 
      procedure is accessed, no matter from where.

See also
   * fbc command-line
   * Source Files (.bas)
   * Header Files (.bi)
   * Using Prebuilt Libraries	




============================================================================
    Lexical Conventions

--------------------------------------------------------- ProPgComments ----
Comments

Comments are regions of text that the compiler will ignore but may contain 
information that is useful to the programmer.  One exception are 
metacommands which may appear in certain types of comments.

Single Line comments
   The single quote character (') may be used to indicate a comment and may 
   appear after other keywords on a source line.  The rest of the statement 
   will be treated as a comment.
   ' comment text

The comment statement: Rem
   A source code statement beginning with Rem indicates that the line is 
   comment and will not be compiled.  In FreeBASIC, Rem may also appear 
   after other keywords on a source line and the behavior is the same as 
   above (only the rest of the statement will be treated as a comment).
   Rem comment

Multi-line comments
   Multi-line comments are marked with the tokens /' and '/.  All text 
   between the two markers is considered comment text and is not compiled.

   Multi-line comments can span several lines, and can also be used in the 
   middle of statements.  After the end of the comment, the statement will 
   continue to be parsed as normal (even if the comment crosses line 
   breaks).
   /' Multi-line
      comment '/

   Print "Hello" /' embedded comment'/ " world"

   Note: If FreeBASIC encounters a close-comment marker while it's not in a 
   multi-line comment, it will treat it as a normal single-line comment due 
   to the single quote.

Nested Comments
   A multi-line comment can contain other multi-line comments inside it.  
   Each inner comment has its own open- and close-comment markers.

   /'
   	This is a comment.
   	/'
   	 This is a comment inside a comment
   	'/
      This Is a comment.
   '/

   A multi-line comment can contain unlimited levels of nested comments.  
   FreeBASIC will continue to parse the multi-line comment for more markers 
   until the number of close-comment markers reaches the number of 
   open-comment markers, i.e. when it has closed all the comments it has 
   opened.

Comments after line continuation
   A single-line comment may appear after the line continuation character ( 
   _ ) in a multi-line statement.  FreeBASIC does not parse the text after 
   the line continuation character, though, so you can't open multi-line 
   comments after them.

   Print _ ' line
      "This is part of the previous line's statement"

Metacommands
   Metacommands, such as $Static and $Include, can be placed in single-line 
   comments.  The $ sign and the keyword must be the first two things in 
   the statement, not including white space.

   Rem compile With -lang fblite Or qb

   #lang "fblite"

   Rem $Static
   ' $include: 'vbcompat.bi'

Single-line comment parsing
   When you make a single-line comment, FreeBASIC will parse the comment, 
   to check for a metacommand.  If it finds a multi-line comment, it will 
   treat it as usual, and continue parsing the single-line comment after 
   the close-comment marker.

   If you want to prevent FreeBASIC parsing the single-line comment, put 
   another single quote ('), at the start of the comment.  FreeBASIC will 
   treat the rest of the line, including multi-line comment markers and 
   metacommands, as ordinary text, and will ignore it.  Other words 
   encountered in a comment will also stop the parsing.
      *Note: As of version 0.21.0, this will not longer apply in the 
        -lang fb dialect, and multi-line comment markers will be completely 
        ignored inside single-line comments

   '' $static <-- will not get parsed
   '' this multiline comment marker ("/'") will be ignored
   Print "This line is not a comment."

Example
   /' this is a multi line 
   comment as a header of
   this example '/

   Rem This Is a Single Line comment

   'this is a single line comment

   Dim a As Integer   'comment following a statement

   Dim b As /' can comment in here also '/    Integer

   #if 0
      before version 0.16, This was the
      only way of commenting Out sections
      With multiple lines of code.
   #endif

See also
   * Rem



-------------------------------------------------- ProPgIdentifierRules ----
Identifier Rules

Naming conventions for FreeBASIC symbols.

Description
   An identifier is a symbolic name which uniquely identifies a variable, 
   Type, Union, Enum, Function, Sub, or Property, within its scope or 
   Namespace.

   Identifiers may contain only uppercase and lowercase Latin characters a-
   z and A-Z), digits (0-9), and the underscore character (_). The first 
   character of an identifier must be a letter or underscore, not a digit; 
   if an identifier's length exceeds 128 characters, it will be truncated.

   Identifiers are case-insensitive: FOO and foo (and all other 
   permutations of uppercase and lowercase) refer to the same symbol.

   In the -lang qb and -lang fblite dialects, identifiers may have a type 
   suffix at the end indicating one of the standard data types:

   * % for Integer
   * & for Long
   * ! for Single
   * # for Double
   * $ for String

   The use of these suffixes is generally discouraged and is not allowed in 
   the -lang fb dialect (the default).

   The alternative is to be explicit - for example, Dim As Integer foo or 
   Dim foo As Integer instead of Dim foo%.

   In the -lang qb and -lang fblite dialects, identifiers may contain one 
   or more periods (.).

Platform Differences
   * Warning:
         - For 64-bit compiler only and regarding the choice of user module 
         level procedure identifier names, an additional restriction to the 
         above normal 'Identifier Rules' should also exclude in the global 
         namespace all register names or other symbols issued from the only 
         'intel' format assembler when it is used (the one by default, no 
         problem with 'att' format), because they causes assembler errors 
         or runtime bugs (due to the 64-bit compiler not decorating module 
         level procedure names).
         - Since fbc version 1.09.0, for x86 and x86_64 only (with any 
         assembler format), the use of an inline asm symbol or a 
         global/external/backend symbol induces a warning if such a symbol 
         is used for a module level procedure or a shared variable in the 
         global namespace.

Dialect Differences
   * Periods in symbol names are only supported in the -lang qb and 
     -lang fblite dialects.

Differences from QB
   * Support for the underscore character (_) in symbol names is new to 
     FreeBASIC.

See also
   * Variables
   * Identifier Look-ups in namespaces and types



--------------------------------------------------------- ProPgLiterals ----
Literals

Non-variable compile-time string, numeric values and boolean values.

Literals are numbers, strings of characters or boolean truths specified 
directly in the source code.  Literal values may be used by assigning them 
to a variable or constant, passing them to a procedure, or using them in an 
expression.

Numeric literals come in two forms - integer and floating-point.  

Integer Literals

   Decimal
   Decimal digits ( 0 1 2 3 4 5 6 7 8 9 ).
   Note: to get negative values, a "-" sign (Operator - (Negate)) can be 
   placed before a numeric literal

   Dim x As Integer = 123456
   Dim b As Byte = -128

   Hexadecimal
   "&H", followed by hexadecimal digits ( 0 1 2 3 4 5 6 7 8 9 A B C D E F 
   ).

   Dim x As Integer = &h1E240
   Dim b As Byte = &H80

   Octal
   "&O" (or "&"), followed by octal digits ( 0 1 2 3 4 5 6 7 )

   Dim x As Integer = &O361100
   Dim b As Byte = &O200

   Binary
   "&B", followed by binary digits ( 0 1 )

   Dim x As Integer = &B11110001001000000
   Dim b As Byte = &B10000000

Integer size suffixes
   If an integer literal suffix is not given, the number field size 
   required to hold the literal is automatically calculated.  Specifying a 
   size suffix guarantees that the compiler will consider a number as a 
   specific integer size.

   Integer literals ending with:
   * "%", are considered as signed 32/64 (depending on platform) bit 
     integers. (Integer)
   * "L", "&", are considered as signed 32 bit long integers. (Long)
   * "U", are considered as unsigned 32/64 (depending on platform) bit 
     integers. (UInteger)
   * "UL", are considered as unsigned 32 bit integers. (ULong)
   * "LL", are considered as signed 64 bit integers. (LongInt)
   * "ULL", are considered as unsigned 64 bit integers. (ULongInt)

   Negative (-) and positive (+) signs that prefix a numeric literal, are 
   not part of the numeric literal.  expressions (like "-1L") are parsed as 
   the negate operator applied to the value represented by the positive 
   literal ("1L"), which may involve implicit type conversions.  Same 
   behavior when an explicit "+" sign precedes the integer literal.

   The prefixes, suffixes, and hexadecimal letter digits are all 
   case-insensitive.

   Dim a As Long = 123L
   Dim b As UInteger = &h1234u
   Dim c As LongInt = 76543LL
   Dim d As ULongInt = &b1010101ULL

Floating Point Literals
   Floating point numbers are specified in decimal digits, may be positive 
   or negative, have a fractional portion, and optionally an exponent.  The 
   format of a floating point literal is as follows (without space or 
   parenthesis added):

   number[.[fraction]][(D|E)[+|-][exponent]][suffix]
   or
   .fraction[(D|E)[+|-][exponent]][suffix]

   By default, floating point numbers that do not have either an exponent 
   or a suffix are considered as a double precision floating point value, 
   except in the -lang qb dialect, where numbers of 7 digits or fewer are 
   considered to be single precision.
   Dim a As Double = 123.456
   Dim b As Double = -123.0

   The letter "D" or "E", placed after the number/fraction part, allows the 
   number to be given an exponent.  The exponent may be specified as either 
   positive or negative with a plus ("+") or minus ("-") sign.  Exponents 
   that do not have a sign are positive.
   An exponent value is not required after the letter (or even after the 
   sign), so the letter can be used on its own just to specify the type.  "
   D" specifies a double-precision floating-point number.  "E" specifies a 
   floating-point number using the default precision. When the letter is 
   used on its own in combination with a suffix (see below) the type 
   denoted by the suffix overrules the type specified by the letter.

   Dim a As Double = -123.0d
   Dim b As Double = -123e
   Dim c As Double = 743.1e+13
   Dim d As Double = 743.1D-13
   Dim e As Double = 743.1E13
   Dim f As Single = 743D! 

   A suffix of "!" or "F" on a number specifies a single precision (32 bit 
   total) floating point value.  A suffix of "#" or "D" specifies a double 
   precision float.
   Note that the letter suffixes and exponent specifiers are all 
   case-insensitive.

   Dim a As Single = 3.1!
   Dim b As Single = -123.456e-7f
   Dim c As Double = 0#
   Dim d As Double = 3.141592653589e3#

String Literals
   String literals are a sequence of characters contained between two 
   double quotes.  The sequence of characters escaped or non-escaped.

   Double quotes can be specified in the string literal by using two double 
   quotes together.
   Print "Hello World!"
   Print "That's right!"
   Print "See the ""word"" contained in double quotes."

   String literals can contain escape sequences if the string literal is 
   prefixed by the ! Operator (Escaped String Literal).  See 
   Escape Sequences for a list of accepted escape sequences.
   Print !"Hello\nWorld!"

   By default, string literals are non-escaped unless Option Escape was 
   used in the source in which case all string literals following are by 
   default escaped.

   A string may be explicitly specified as non-escaped when prefixed by the 
   $ Operator (Non-Escaped String Literal).
   Print $"C:\temp"

   Besides ASCII files with Unicode escape sequences (\u), FreeBASIC can 
   parse UTF-8, UTF-16LE, UTF-16BE, UTF-32LE and UTF-32BE source files as 
   long as they were saved with Byte Order Mark (BOM), allowing unicode 
   characters directly in the string literal.
   Note: The most reliable cross-platform code is obtained by encoding 
   without BOM in ASCII/UTF-8 characters.

   String literals in an ASCII file are treated as ZString, while string 
   literals in a Unicode file are treated as WString (regardless of the 
   string literal's value).

Boolean Literals
   The boolean type has two values, represented by literals True and False.

   Dim a As Boolean = False
   Dim b As Boolean = True

	

See also
   * TypeOf
   * #define
   * Const 
   * Standard Data Types
   * Table with variable types overview, limits and suffixes



----------------------------------------------------------- ProPgLabels ----
Labels

Defines a location in a program.

Syntax
   symbolname :
      or
   literalnumber

Description
   A label can define a place in a program where Goto or GoSub can jump to.
   A label can also mark Data blocks, allowing Restore to change the Read 
   sequence.

   A label can be a positive integer line number or a symbolname. In both 
   cases, the label must start at the first column of line. A symbolname 
   label must end with a colon (:) character.

Example
   '' Compile with -lang fblite or qb

   #lang "fblite"

   beginning:
   3 Print "Hello World!"
   Goto beginning

   '' compile with -lang qb

   '$lang: "qb"

   '' Labels can be used to "bookmark" DATA blocks, allowing RESTORE to alter the READ sequence.
   Read a,b,c
   Restore here
   Read d,e
   Print a,b,c,d,e 

   Data 1,2,3,4,5
   here:
   Data 6,7,8

Output:

   1,2,3,6,7

Dialect Differences
   * Line numbers with decimals is available only in the -lang qb dialect.

Differences from QB
   * None if compiled in the -lang qb dialect.

See also
   * GoSub
   * Goto
   * Restore



------------------------------------------------- ProPgLineContinuation ----
Line Continuation

Line Continuation character(s) allow to spread out a single line of code 
into multiple lines.

Description
   A single '_' (underscore) character at the end of a line of code tells 
   the compiler that the line continues in the next line. This allows a 
   single statement (line of code) to be spread across multiple lines in 
   the input file, which can be a nice formatting help:
   '' This Dim statement is spread across multiple lines, using the '_' character
   Dim myvariable _
   As Integer
         

   This is often used to make very long lines of code easier to read, for 
   example procedure declarations with a lot of parameters:
   '' Here's an example:

   Declare Sub drawRectangle( ByVal x As Integer, ByVal y As Integer, ByVal w As Integer, ByVal h As Integer )

   '' which can also be written as:

   Declare Sub drawRectangle( ByVal x As Integer, ByVal y As Integer, _
                        ByVal w As Integer, ByVal h As Integer )

   '' or:

   Declare Sub drawRectangle _
      ( _
         ByVal x As Integer, _
         ByVal y As Integer, _
         ByVal w As Integer, _
         ByVal h As Integer _
      )

   '' (or any other formatting you like)
         

   The '_' line continuation character can be inserted at pretty much any 
   point in a line of code. It does not work inside comments though.

   Be careful when adding the '_' line continuation character right behind 
   an identifier or keyword. It should be separated with at least one space 
   character, otherwise it would be treated as part of the identifier or 
   keyword:
   '' Declare variable "a_"
   '' (no line continuation happening, because the '_' character is part of
   '' the "a_" identifier)
   Dim As Integer a_

   '' Declare variable "a" and initialize to value 5
   '' (line continuation happening, because the '_' character
   '' was separated from the identifier "a" with a space character)
   Dim As Integer a _
   = 5
         

   Warning: When an erroneous code line is spread over a multiple lines 
   block by using the '_' line continuation character, the error message 
   refers only to the last line of the block.

   Note for fbc version >= 1.08:
      In macro/define's use '##_' to escape line continuation character '_' 
      to allow multiple lines of macro expanded code to be combined into a 
      single statement.

See also
   * Line Separator



---------------------------------------------------- ProPgLineSeparator ----
Line Separator

Line Separator character(s) allow to place multiple statements on the same 
line.

Description
   Statements normally take up a single line with no terminator.
   But statements can even be stacked by using a colon (:) to separate 
   them.

   To place multiple statements on the same line, separate the statements 
   with a colon (:), as in the following example:
   '' These 5 statements are stacked on the same line, using the ':' character as a separator
   Dim As String text = "Hello!" : Color 14, 3 : Print text : Color 7, 0 : Sleep
         

See also
   * Line Continuation




============================================================================
    Variables and Datatypes

----------------------------------------------------- ProPgEnumerations ----
Constants and Enumerations

Enumeration, a special User-Defined Type composed of a number of named const
ants.

Syntax
   Enum [typename [ Explicit ] ]
      symbolname [= expression] [, ...]
      ...
   End Enum

Parameters
   typename
      Name of the Enum
   symbolname
      Name of the constant
   expression
      A constant expression
   Explicit
      Requires that symbols must be explicitly referred to by typename.
      symbolname

Description
   An enumeration is a User-Defined Type that consists of a set of named 
   integer constants.
   Enumerations are useful for defining sequences and states, particularly 
   when there is a natural progression through those states.

   An enumeration provides context to describe a range of values which are 
   represented as named constants through symbols.
   Unlike namespaces, enumerations can be also defined in any scope blocks, 
   and their symbols are only visible throughout the scope in which the 
   enumeration is declared.

   Enumerations lend themselves to more maintainable code because they are 
   symbolic, allowing you to work with integer values â€‹â€‹while using an 
   explicit name.
   Enumerations are value Types, which means they contain their own value, 
   can not inherit or be inherited from.

   Enum can not contain any member procedure or member data (only symbols), 
   but it can be included (named or unnamed) in a Type by having.

Usage
   Every symbol in an enumeration is implicitly assigned an integer value 
   (positive or negative) that corresponds to its place in the order of the 
   values in the enumeration.
   Every symbol is treated as a constant. 

   By default, the first value is assigned 0, the next one is assigned 1, 
   and so on.
   But you can explicitly set the value of any symbol (and the next symbol 
   will be implicitly set to the previous value plus an increment of one).

   The values given to the symbols do not have to be unique.

   When an enumeration is qualified as Explicit, access to any symbolname 
   must be always prefixed by typename.
   Prefixing can also be used to solve ambiguity with other entities.

   An Enum instance can be passed, as any User-Defined Type instance, to a 
   procedure (including for the definition of overloaded operators).
   The size of an Enum instance will be always that of an Integer (no 
   matter how many defined symbols are just declarations for the compiler 
   assignment).

   An Enum instance (or Enum symbol) can be implicitly converted to an 
   integer.
   Note:
      - In many languages, no integer variable is implicitly convertible 
      into a scoped enumeration type instance (and vice versa), the latter 
      being strongly typed (declaration equivalent to the Enum qualified as 
      Explicit with FreeBASIC), and an explicit cast is required for such a 
      conversion.
      - But FreeBASIC accepts it (even if the numeric value does not match 
      any Enum symbol defined). This is just one of FreeBASIC's many 
      shortcomings over normal Enum functionality.
      - Therefore, there is not much interest in declaring a real ENUM 
      instance (which is sized as an INTEGER), but otherwise any pre-built 
      integer variable can be declared instead.
      - If the Explicit qualifier is not used (namespace prefix not 
      imposed), there is not much point in using an ENUM structure compared 
      to a simple discrete list of constants, except for the auto-increment 
      of values.

Example
   Simple example of use:
   Enum Colors
      black
      blue
      green
      cyan
      red
      pink
      yellow
      grey
      dark_grey
      bright_blue
      bright_green
      bright_cyan
      bright_red
      bright_pink
      bright_yellow
      white
   End Enum

   Sub print_fbc (ByVal foreground As Colors, ByVal background As Colors)
      Color foreground, background
      Print " " & __FB_SIGNATURE__ & " "
   End Sub

   Dim As Colors std_foreground, std_background
   std_foreground = LoWord(Color())
   std_background = HiWord(Color())

   Dim As Colors my_foreground, my_background
   my_foreground = bright_yellow
   my_background = cyan

   print_fbc(my_foreground, my_background)

   Color std_foreground, std_background
   Print "end"

   Sleep
         

   Same result, but with a Type interfacing Enum to impose explicit casting 
   when assigning numeric values to Enum instances (see 'Note' above):
   Enum Colors Explicit
      black
      blue
      green
      cyan
      red
      pink
      yellow
      grey
      dark_grey
      bright_blue
      bright_green
      bright_cyan
      bright_red
      bright_pink
      bright_yellow
      white
   End Enum

   Type Console_Colors
      Public:
         Declare Property foreground () As Colors
         Declare Property foreground (ByVal c As Colors)
         Declare Property background () As Colors
         Declare Property background (ByVal c As Colors)
      Private:
         Dim As Colors _foreground
         Dim As Colors _background
   End Type

   Property Console_Colors.foreground () As Colors
      Return This._foreground
   End Property

   Property Console_Colors.foreground (ByVal c As Colors)
      This._foreground = c
   End Property

   Property Console_Colors.background () As Colors
      Return This._background
   End Property

   Property Console_Colors.background (ByVal c As Colors)
      This._background = c
   End Property

   Sub print_fbc (ByVal foreground As Colors, ByVal background As Colors)
      Color foreground, background
      Print " " & __FB_SIGNATURE__ & " "
   End Sub

   Dim As Console_Colors std_colors
   std_colors.foreground = Cast(Colors, LoWord(Color()))  '' explicit cast mandatory because of property declaration
   std_colors.background = Cast(Colors, HiWord(Color()))  '' explicit cast mandatory because of property declaration

   Dim As Console_Colors my_colors
   my_colors.foreground = Colors.bright_yellow
   my_colors.background = Colors.cyan

   print_fbc(my_colors.foreground, my_colors.background)

   Color std_colors.foreground, std_colors.background
   Print "end"

   Sleep
         

See also
   * Enum
   * Type
   * Constants



----------------------------------------------------- ProPgNumericTypes ----
Numeric Types

Of all built-in data-types, Numeric Types are those dedicated to the 
representation of all kinds of numbers.

FreeBASIC supplies several numeric data types for handling numbers in 
various representations.
Of these, integer types represent only integer numbers (positive, negative, 
and zero), and floating-point types represent real numbers.

Integer types
   Integer types are those that represent only integer numbers:
      * Signed integer types:
            - Byte 8-bit
            - Short 16-bit
            - Long 32-bit
            - Integer 32-bit or 64-bit (*)
            - LongInt 64-bit
            - Integer<8|16|32|64> 8|16|32|64-bit
      * Unsigned integer types:
            - UByte 8-bit
            - UShort 16-bit
            - ULong 32-bit
            - UInteger 32-bit or 64-bit (*)
            - ULongInt 64-bit
            - Uinteger<8|16|32|64> 8|16|32|64-bit

Floating-point types
   Floating-point types are those that represent real numbers:
      * Single precision:
            - Single 32-bit
      * Double precision:
            - Double 64-bits

Pseudo-integer types
   Other types that also represent but indirectly integer numbers:
      * Enumerated type:
            - Enum (32-bit or 64-bit) (*)
      * Boolean type:
            - Boolean (1-bit useful in 8-bit)

Pointer types
   Pointers are types whose values (uinteger) are addresses in memory (they 
   are said to 'point' to this memory).
   The type of data that is pointed to depends on the type of pointer (an 
   Integer Pointer points to Integer data).
   Pointers are declared like any other variable, with the suffix pointer 
   or ptr following the type name:
      * Pointer type:
            - {DataType|Any} {Pointer|Ptr} (32-bit or 64-bit) (*)

(*) INTEGER, UINTEGER, and ENUM data types vary with platform, matching the 
size of POINTER.

Example
   Size (in bits) of all types above:
   Print Using "A  BYTE     is ##"; SizeOf(Byte)     * 8; : Print "-bit"
   Print Using "A  SHORT    is ##"; SizeOf(Short)    * 8; : Print "-bit"
   Print Using "A  LONG     is ##"; SizeOf(Long)     * 8; : Print "-bit"
   Print Using "An INTEGER  is ##"; SizeOf(Integer)  * 8; : Print "-bit"
   Print Using "A  LONGINT  is ##"; SizeOf(LongInt)  * 8; : Print "-bit"
   Print Using "An UBYTE    is ##"; SizeOf(UByte)    * 8; : Print "-bit"
   Print Using "An USHORT   is ##"; SizeOf(UShort)   * 8; : Print "-bit"
   Print Using "An ULONG    is ##"; SizeOf(ULong)    * 8; : Print "-bit"
   Print Using "An UINTEGER is ##"; SizeOf(UInteger) * 8; : Print "-bit"
   Print Using "An ULONGINT is ##"; SizeOf(ULongInt) * 8; : Print "-bit"
   Print
   Print Using "A  SINGLE   is ##"; SizeOf(Single)   * 8; : Print "-bit"
   Print Using "A  DOUBLE   is ##"; SizeOf(Double)   * 8; : Print "-bit"
   Print
   Enum myENUM : option1 = 1 : option2 : End Enum
   Print Using "An ENUM     is ##"; SizeOf(myENUM)   * 8; : Print "-bit"
   Print
   Print Using "A  BOOLEAN  is ##"; SizeOf(Boolean)  * 8; : Print "-bit"
   Print
   Print Using "A  POINTER  is ##"; SizeOf(Any Ptr)  * 8; : Print "-bit"

   Sleep
         
Output example for win64:

   A  Byte     Is  8-Bit
   A  Short    Is 16-Bit
   A  Long     Is 32-Bit
   An Integer  Is 64-Bit
   A  LongInt  Is 64-Bit
   An UByte    Is  8-Bit
   An UShort   Is 16-Bit
   An ULong    Is 32-Bit
   An UInteger Is 64-Bit
   An ULongInt Is 64-Bit

   A  Single   Is 32-Bit
   A  Double   Is 64-Bit

   An Enum     Is 64-Bit

   A  Boolean  Is  8-Bit

   A  Pointer  Is 64-Bit
   		

See also
   * Standard Data Types
   * Standard Data Type Limits
   * Coercion and Conversion



----------------------------------------------------- ProPgStringsTypes ----
Strings (string, zstring, and wstring)

Of all built-in data-types, Strings types are those dedicated to the 
representation of character chains.

FreeBASIC supplies several strings data types for handling characters 
chains in various representations.
The fixed-length strings types (string, zstring and wstring) represent 
fixed-length chains of characters, while the variable-length string type 
represents a variable-length chain of characters.

Fixed-length strings
   There are 3 types of fixed-length strings:
      * Fixed-length string type for 8 bit character (QB-style 
        fixed-length string):
            - String * size
                  since fbc version 1.20.0, total length of the string: '
                  size' characters = 'size' bytes ('size' useful 
                  characters)
                  before fbc version 1.20.0, total length of the string: '
                  size+1' characters = 'size+1' bytes ('size' useful 
                  characters + '1' final null character)
      * Fixed-length zstring type for 8 bit character:
            - ZString * size
                  total length of the zstring: 'size' characters = 'size' 
                  bytes ('size-1' useful characters + '1' final null 
                  character)
               or
            - ZString Ptr
                  total length of the pointed zstring: depends on the 
                  character chain referenced by the pointer (up to and 
                  including the final null character)
      * Fixed-length wstring type for  wide character:
            - WString * size
                  total length of the wstring: 'size' characters = 'size' x 
                  k(*) bytes ('size-1' useful characters + '1' final null 
                  character)
               or
            - WString Ptr
                  total length of the pointed wstring: depends on the 
                  character chain referenced by the pointer (up to and 
                  including the final null character)

            (*) The number of bytes 'k' used by a WSTRING character depends 
            on the platform.

Variable-length string
   There is only one type of variable-length string:
      * Variable-length string type for 8 bit character:
            - String
                  total length of the string: dynamic length depending on 
                  the assigned data characters
                     (string referenced by an internal descriptor of 1 
                     pointer + 2 uinteger length)

Example
   Size (in bytes) of different strings from all types above:
   '  Result depending on fbc version (before/since 1.20.0)

   Dim As String * 20 s20 = "FreeBASIC manual"

   Dim As ZString * 20 z20 = "FreeBASIC manual"
   Dim As ZString Ptr pz = @"FreeBASIC manual"

   Dim As WString * 20 w20 = "FreeBASIC manual"
   Dim As WString Ptr pw = @WStr("FreeBASIC manual")

   Dim As String s = "FreeBASIC manual"

   Print Using "'FIXED-LENGTH STRING * 20': ## bytes in total, ## useful characters available"; SizeOf(s20); Len(s20)
   #if __FB_VERSION__ < "1.20.0"
   Print Using "    containing ## user characters of # byte(s) each"; IIf(InStr(s20, Chr(0)) > 0, InStr(s20, Chr(0)) - 1, Len(s20)); SizeOf(s20[0])
   #endif
   Print
   Print Using "'FIXED-LENGTH ZSTRING * 20': ## bytes in total, ## useful characters available"; SizeOf(z20); SizeOf(z20) \ SizeOf(z20[0]) - 1
   Print Using "    containing ## user characters of # byte(s) each"; Len(z20); SizeOf(Z20[0])
   Print "'ZSTRING PTR': dereferencing pointer -> "; """" & *pz & """"
   Print Using "    containing ## user characters of # byte(s) each"; Len(*pz); SizeOf((*pz)[0])
   Print
   Print Using "'FIXED-LENGTH WSTRING * 20': ## bytes in total, ## useful characters available"; SizeOf(w20); SizeOf(w20) \ SizeOf(w20[0]) - 1
   Print Using "    containing ## user characters of # byte(s) each"; Len(w20); SizeOf(w20[0])
   Print "'WSTRING PTR': dereferencing pointer -> "; """" & *pw & """"
   Print Using "    containing ## user characters of # byte(s) each"; Len(*pw); SizeOf((*pw)[0])
   Print
   Type descriptor : Addr As ZString Ptr : UC As UInteger : AC As UInteger : End Type
   Print Using "'STRING': ## bytes in descriptor, memory allocated for ## characters right now"; SizeOf(s); Cast(descriptor Ptr, @s)->AC
   Print Using "    containing ## user characters of # byte(s) each"; Len(s); SizeOf(s[0])

   Sleep
         
Note: For the fixed-length string type only (QB-style fixed-length string), 
the 'Len()' keyword always returns the declared constant number of 
characters, regardless of the number of characters assigned to it by user.
      (hence the formula only for fixed-length string type before fbc 
      version 1.20.0: 'user_characters_length = IIf(InStr(s, Chr(0)) > 0, 
      InStr(s, Chr(0)) - 1, Len(s))')

      Output example before fbc version 1.20.0 and for win64 (a wstring 
      character uses 2 bytes):

   'FIXED-LENGTH STRING * 20': 21 bytes in total, 20 useful characters available
   	containing 16 user characters of 1 Byte(s) each

   'FIXED-LENGTH ZSTRING * 20': 20 bytes in total, 19 useful characters available
   	containing 16 user characters of 1 Byte(s) each
   'ZSTRING PTR': dereferencing pointer -> "FreeBASIC manual"
   	containing 16 user characters of 1 Byte(s) each

   'FIXED-LENGTH WSTRING * 20': 40 bytes in total, 19 useful characters available
   	containing 16 user characters of 2 Byte(s) each
   'WSTRING PTR': dereferencing pointer -> "FreeBASIC manual"
   	containing 16 user characters of 2 Byte(s) each

   'STRING': 24 bytes in descriptor, memory allocated for 32 characters right now
   	containing 16 user characters of 1 Byte(s) each
   				

Implicit conversion from Zstring to Ubyte
   When any operand of a binary operator (as assignment, equal, +, *, ...) 
   consists in dereferencing a 'Zstring Ptr' pointer ('pz'), this can give 
   a 'Zstring' string or a 'Ubyte' variable, depending on the other 
   operand:
      - If the other operand is numeric, so the dereferenced 'Zstring Ptr' 
      pointer ('*pz') will be treated as a 'Ubyte' reference to the one 
      character pointed.
      - If in this case a 'Zstring' pointer indexing '[]' operator is used 
      as dereferencing syntax ('pz[n]'), it is basically a short-cut 
      version of the 'String' indexing '[]' operator ('(*pz)[n]').

   Since '(*pz)[i]' and 'pz[i][k]' are always numeric (each an 'Ubyte'), 
   such equalities are true:
      pz[i] = (*pz)[i]
      (*pz)[i] = pz[i]
      and even:
      pz[i+k] = pz[i][k]
      pz[i][k] = pz[i+k]

   Simple code example with a dereferenced 'Zstring Ptr' converted to an '
   Ubyte' reference (as operand of an 'assignment' operator and a '+' 
   operator):
   Dim As ZString * (14+1) z = "FreeBASIC     "
   Dim As ZString Ptr pz = @z

   Print z
   z[10] = Asc("2")
   *(pz + 11) = Asc("0")                '' *(pz + 11) is converted to an Ubyte reference
   (*pz)[12] = Asc("1")
   pz[13] = Asc("8")                    '' pz[13] is converted to an Ubyte reference
   Print z

   For I As Integer = 10 To 13
      Print Str(z[I] - Asc("0"));
   Next I
   Print
   For I As Integer = 10 To 13
      Print Str((*pz)[I] - Asc("0"));
   Next I
   Print
   For I As Integer = 10 To 13
      Print Str(pz[I] - Asc("0"));     '' pz[I] is converted to an Ubyte reference
   Next I
   Print

   Sleep
         
Output:

   FreeBASIC
   FreeBASIC 2018
   2018
   2018
   2018
   			

See also
   * String Functions
   * Standard Data Type Limits



--------------------------------------------------- ProPgDataConversion ----
Coercion and Conversion

Transfer the data of a given type variable to a variable of another type 
requires conversion.

Coercion of Numeric Data Types in Expressions and Arguments
   For the integer types, the rule depends on the following ranking:
      in 32bit:
         byte < ubyte < short < ushort < long < integer < ulong < uinteger 
         < longint < ulongint
      in 64bit:
         byte < ubyte < short < ushort < long < ulong < longint < integer < 
         ulongint < uinteger
   First,  in accordance to the above ranking, all arguments smaller than 
   Integer are converted to Integer.
   Then, if arguments have different size, the smaller argument is 
   converted to match the bigger one. Next, if arguments have different 
   signedness, the signed argument is converted to unsigned to match the 
   other one.
   Finally, the (U)Integer types replace:
      in 32bit:
         the (U)Long types
      in 64bit:
         the (U)Longint types

   On the other hand, if one of the arguments is a Single or a Double, both 
   arguments are converted and/or promoted to Double.

Conversion of Numeric Data Types
   A type conversion will occur implicitly when an expression or variable 
   is assigned, passed as a parameter to a procedure, or returned as a 
   result from a procedure. Conversions may also be explicit when using 
   CAST or one of the built-in conversion functions (among standard 
   functions).

   Integer To Integer, any combination of Signed and Unsigned
      * Any integer type to a smaller integer type: least significant bits 
        are retained
      * Any integer type to a larger integer type: sign extended to fill 
        most significant bits

   Integer to Single or Double
      * Possible loss of precision

   Double to Single
      * Possible loss of precision
      * If the value of the Double exceeds the range of a Single result is 
        +/- INF

   Double or Single to Integer
      * Possible loss of precision
      * If the value of the floating point number exceeds the range of the 
        target type are results are undefined.  A run-time error is not 
        raised.

Conversions using User Data Type constructors and operators
   For conversion between built-in types (among standard types like between 
   numeric types as above or between string types), the compiler knows what 
   to do without the need for instructions from user.
   This is called the implicit internal conversion (or coercion).

   When one of the two types is at least a UDT (User Defined Type), the 
   user has to code some UDT procedures to define how do the conversion.
   Then, the conversion execution can be explicit if the user specifies 
   what UDT procedure must be used, or implicit if the user leaves the 
   choice to compiler.

   In the world of UDTs, conversions can be controlled by means of three 
   member procedures:
      * Single-argument constructor: allow conversion from a particular 
        type to initialize an object.
      * Assignment operator: allow conversion from a particular type on 
        assignment.
      * Type-cast operator: allow conversion to a particular type.

   For a construction with implicit initialization ('Dim As UDT u = v'), 
   the compiler searches by priority:
      * Firstly a matched constructor (for u type from v type).
      * Secondly a cast operator (for v type to special type (*)) and its 
        matching conversion-constructor (for u type from special type (*)).
      * Thirdly finally a matched cast operator (for v type to u type).
      (a matched let operator (for u type from v type) is not searched by 
      compiler on a construction with implicit initialization)

   For an implicit copy-construction ('Byval As u_type') when passing a v 
   type parameter, the compiler searches by priority:
      * Firstly a matched constructor (for u type from v type).
      * Secondly a cast operator (for v type to special type (*)) and its 
        matching conversion-constructor (for u type from special type (*)).
      * Thirdly finally a matched cast operator (for v type to u type).
      (a matched let operator (for u type from v type) is not searched by 
      compiler on a construction with implicit initialization)

   For an implicit reference-passing ('Byref As u_type') when passing a v 
   type parameter, the compiler searches by priority:
      * Firstly a matched cast operator (for v type to u type).
      * Secondly a matched constructor (for u type from v type).
      * Thirdly finally a cast operator (for v type to special type (*)) 
        and its matching conversion-constructor (for u type from special 
        type (*)).
      (a matched let operator (for u type from v type) is not searched by 
      compiler on an implicit reference-passing)

   For an implicit assignment ('u = v'), or an implicit return from 
   function by assigning ('Function = v') with function returning u type, 
   the compiler searches by priority:
      * Firstly a matched let operator (for u type from v type).
      * Secondly a cast operator (for v type to special type (*)) and its 
        matching let operator (for u type from special type (*)).
      * Thirdly a matched cast operator (for v type to u type).
      * Fourthly finally a matched constructor (for u type from v type) 
        and an explicit copy-let operator (u type).

   For an implicit return from function by exiting immediately ('Return v') 
   with function returning u type, the compiler searches by priority:
      * Firstly a matched constructor (for u type from v type).
      * Secondly a cast operator (for v type to special type (*)) and its 
        matching conversion-constructor (for u type from special type (*)).
      If an explicit copy-constructor (u type) exists:
      * Thirdly a matched cast operator (for v type to u type).
      * Fourthly finally a matched let operator (for u type from v type).
      Else (an explicit copy-constructor (u type) does not exist):
      * Thirdly a matched let operator (for u type from v type).
      * Fourthly finally a matched cast operator (for v type to u type).

   special type (*) : pointer or string, or UDT if there is no explicit 
   copy-constructor / explicit copy-assignment operator for u type

   Note:
   Only the member procedures directly impacted in the conversion process 
   itself are cited above:
   - the copy-constructor (u type) and the copy-let operator (u type) are 
   not cited when only their implicit definition is sufficient and not 
   their explicit definition,
   - the default constructor (u type) is not cited whereas an implicit 
   version, otherwise explicit version if another explicit constructor (u 
   type) is defined, is always required in the 'Function = v' case, but not 
   for the conversion process itself.

Example
   Very simple syntaxic example highlighting the conversion capabilities by 
   using Cast operator (explicit and implicit), Constructor (explicit and 
   implicit) and Let operator (implicit):
   Type UDT
     Dim As Integer I
     Declare Operator Cast () As Integer
     Declare Constructor (ByVal I0 As Integer)
     Declare Operator Let (ByVal I0 As Integer)
   End Type

   Operator UDT.Cast () As Integer
     Return This.I
   End Operator

   Constructor UDT (ByVal I0 As Integer)
     This.I = I0
   End Constructor

   Operator UDT.Let (ByVal I0 As Integer)
     This.I = I0
   End Operator

   Dim As Integer J = 12
   Dim As UDT u1 = UDT(J)  '' construction with explicit initialization using the defined "Constructor(Byval As Integer)" operator
   Print u1.I
   Dim As UDT u2 = J       '' construction with implicit initialization by compiler using the defined "Constructor(Byval As Integer)" operator
   Print u2.I
   Print

   u1.I = 34
   J = Cast(Integer, u1)  '' explicit assignment using the defined "Cast() As Integer" operator
   Print J
   Dim As Integer K
   K = u1                 '' implicit assignment by compiler using the defined "Cast() As Integer" operator
   Print K
   Print

   J = 56
   u1 = J                 '' implicit assignment by compiler using the defined "Let(Byval As Integer)" operator
   Print u1.I
   Print

   Sleep

See also
   * Standard Data Types
   * Variable Types
   * Casting and Conversion Functions
   * User Defined Types



-------------------------------------------------------- ProPgConstants ----
Constants

Constants are identifiers that represent literals or constant expressions 
that can not be changed after they are defined.

For example, Const PI = 3.1415926535897932 will always mean that the 
identifier PI refers to the number 3.1415926535897932.  The identifier PI 
can be used instead of repeating the full number in source.

Global constants once defined, are available globally and the identifier 
can be used to refer to the constant anywhere in the source program. 

After an identifier is defined with the Const statement, the symbol cannot 
be altered. If code tries to alter a constant, an error message will result 
upon code compilation.

Built-in constants include the Boolean data type values True and False.

A constant definition differs from a variable definition.  Variables hold 
values that can be changed.

Example
   Declare Sub PrintConstants ()

   Const FirstNumber = 1
   Const SecondNumber = 2
   Const FirstString = "First string."
   Const FirstBoolean = False
   Const SecondBoolean = True

   Print FirstNumber, SecondNumber 'This will print 1      2
   Print FirstString 'This will print First string.
   Print FirstBoolean, SecondBoolean 'This will print false      true
   Print

   PrintConstants ()

   Sub PrintConstants ()
      Print FirstNumber, SecondNumber 'This will also print 1        2
      Print FirstString 'This will also print First string.
      Print FirstBoolean, SecondBoolean 'This will also print false      true
   End Sub

See also
   * Constant Expressions
   * Literals
   * Const
   * Enum



-------------------------------------------------------- ProPgVariables ----
Variables

Symbols representing data in memory.

Description
   Variables are name symbols which can be manipulated. They are declared 
   and referenced using names composed of letters, numbers, and character 
   "_". These reference names cannot contain most other symbols because 
   such symbols are part of the FreeBASIC programming language. They also 
   cannot contain spaces.  See Indentifier Rules.

   In FreeBASIC, variables can be defined using the Dim statement. 

   Variables are available for later access depending on where and how the 
   Dim declaration for that variable is given.  Depending on the scope of a 
   variable, a defined variable can be available within the main area of a 
   program, within a procedure, through an entire module, or through out an 
   entire program.  See Variable Scope.

   Variables are also made available when they are passed as parameters to 
   a procedure such as Function or Sub.

   After a variable is declared with the Dim statement, they can be 
   assigned, passed to procedures, and used in expressions wherever their 
   Standard Data Type is similar.  Sometimes variables are automatically 
   converted to other data types before being used in expressions, or 
   passed as parameters to procedures.  See Coercion and Conversion.

Example
   ' compile with -lang qb or fblite

   '$lang: "qb"

   Declare Sub PrintConstants()

   Dim FirstNumber As Integer
   Dim Shared SecondNumber As Integer

   FirstNumber = 1
   SecondNumber = 2

   PrintConstants ()
   Print FirstNumber, SecondNumber, ThirdNumber 'This will print 1 2 0

   Sub PrintConstants ()
      Dim ThirdNumber As Integer
      ThirdNumber = 3
      Print FirstNumber, SecondNumber, ThirdNumber 'This will print 0 2 3
   End Sub

See also
   * Coercion and Conversion
   * Dim
   * Identifier Rules
   * Variable Scope




============================================================================
    Arrays

----------------------------------------------------------- ProPgArrays ----
Arrays

Multi-dimensional container types.

Overview
   Arrays are special kinds of variables which act as containers for a 
   number of values, or elements. An array can store elements of any type, 
   and all of its elements share the same type. For example, an array can 
   store Integer elements or Single elements, but not both. These elements 
   are accessed--read from or written to--through an Integer value 
   representing their position in the array. Arrays have lengths, or sizes, 
   which are equal to the number of elements they are storing at any given 
   time. Fixed-length arrays have constant sizes throughout their 
   lifetimes, while the sizes of variable-length arrays can change 
   dynamically.

Elements and positions
   The values that an array stores are its elements. Each element of an 
   array has a corresponding position, which is an Integer value ranging 
   from the array's lower bound to its upper bound, inclusive. These 
   positions are used to access individual elements in the array using 
   Operator (), which takes a position and returns a reference to the 
   element at that position. A valid position in an array is greater than 
   or equal to its lower bound, and less than or equal to its upper bound.
   ' Create an array of 3 elements all having the value zero (0.0f).
   Dim array(1 To 3) As Single

   ' Assign a value to the first element.
   array(1) = 1.2

   ' Output the values of all the elements ("1.2 0 0").
   For position As Integer = 1 To 3
      Print array(position)
   Next
      

Sizes and bounds
   The size of an array is equal to the number of elements it stores at any 
   given time. An array can have a size of zero (0), meaning it's not 
   storing any values at the moment--it's empty. If an array's size is 
   greater than zero, that many elements are being stored. An array's size 
   is equal to one more than the difference between its upper and lower 
   bounds, or UBound(array) - LBound(array) + 1.

   The lower and upper bounds not only determine the size of an array, but 
   also the valid positions of individual elements. For example, an array 
   with a lower bound of zero (0) and an upper bound of four (4), stores 
   five (5) elements, the first element being at position 0, the last at 
   position 4. These bounds may be specified when the array is declared, 
   or, for some arrays, changed by resizing the array. An array's lower and 
   upper bounds can be retrieved using LBound and UBound, respectively.

   When creating or resizing an array, if a lower bound is not specified it 
   defaults to zero (0).
   ' Declares and initializes an array of four integer elements.
   Dim array(3) As Integer = { 10, 20, 30, 40 }

   ' Outputs all of the element values (" 10 20 30 40").
   For position As Integer = LBound(array) To UBound(array)
      Print array(position) ;
   Next
      

Fixed-length and variable-length
   There are two fundamental kinds of arrays: fixed-length and 
   variable-length. The primary difference between the two is that the 
   bounds of fixed-length arrays can never change, that is, they always 
   store the same number of elements in the same positions. Variable-length 
   array bounds can be changed, affecting the number of elements stored 
   and/or the positions of the elements.

   Since fixed-length arrays never change size, the compiler chooses to 
   make room for--or, allocate--the memory for the array elements either in 
   static storage or on the program stack, depending on the array's 
   storage class. This can be an advantage, since the cost of creating 
   these kinds of arrays doesn't include any adverse run-time penalty. 
   Fixed-length arrays are declared using Extern, Static and Dim. At least 
   an upper bound must be specified, and all bounds must be compile-time 
   constant values, such as numeric literals, Const variables or Enum 
   enumerators.

   Variable-length arrays can change in size, so the compiler chooses to 
   allocate the memory for the array elements at run-time, in the free 
   store. The advantage here of course is being able to dynamically resize 
   the arrays, however, run-time performance could vary when they are 
   created, resized or destroyed. Variable-length arrays are declared using 
   Extern, Static, Dim and ReDim. When using Extern, Static or Dim, the 
   lower and upper bounds can be left unspecified--resulting in an empty 
   array--or either one must have a variable value, such as an Integer 
   variable or Function result. ReDim can be used to resize an existing 
   variable-length array, by giving it different lower and/or upper bounds.
   ' Creates a fixed-length array that holds 5 single elements.
   Const totalSingles = 5
   Dim flarray(1 To totalSingles) As Single

   ' Creates an empty variable-length array that holds integer values.
   Dim vlarray() As Integer

   ' Resizes the array to 10 elements.
   ReDim vlarray(1 To 10)
      

Multi-dimensional arrays
   The arrays discussed so far have been one-dimensional, that is, the 
   elements are accessed through a single position. One-dimensional arrays 
   can be thought of as a simple row of elements. Arrays can also have more 
   than one dimension; an individual element of the array is accessed using 
   two or more positions. Two-dimensional arrays use two positions--a row 
   and a column position--to refer to individual elements, like a grid or 
   table. Three-dimensional arrays use three positions--a row, column and 
   perhaps depth position--to refer to individual elements, like a cube. 
   Four-dimensional arrays can be thought of as one or more 
   three-dimensional arrays, and so on. Multi-dimensional arrays are 
   declared just like one-dimensional arrays, except that more than one 
   lower and upper bound range is specified.
   The total number of elements and the total size (in bytes) of a 
   multi-dimensional array can be directly obtained using Arraylen and 
   Arraysize, respectively.
   ' Take Care while initializing multi-dimensional array
   Dim As Integer multidim(1 To 2,1 To 5) = {{0,0,0,0,0},{0,0,0,0,0}}
      

Detailed use of LBound and UBound
   LBound / UBound returns the lower / upper values of size information for 
   an array: the dimension of the array (number of usable indexes) and the 
   index bounds for each dimension. The array name is specified in the 
   first parameter, and the dimension selection in the second parameter.
   These sizing information are available both for a fixed-length array 
   (sizing fixed at compile-time) and for a variable-length array (some 
   sizing adjustable during run-time).

   - Usage:
      result = (L|U)Bound( array [, dimension ] )
         with as parameters:
            array : array name, without parentheses
            dimension : dimension number to get the bound, ordered from 
            left to right compared to index position when accessing array
               (1 = first dimension)

   - Return value:
      For the specific dimension value '0':
         LBound returns always '1', and UBound returns the number of 
         dimensions
            if the array is not fully sized (declared as 'array( )' or 
            'array( Any [, Any...] )'), UBound returns '0'

      For any valid dimension value of the array (from 1 to the last one):
         (L|U)Bound returns the lowest|highest value that can be used as an 
         index for the specified dimension
            if the array is not fully sized (declared as 'array( )' or 
            'array( Any [, Any...] )'), LBound returns '0' and UBound 
            returns '-1'

      For any other dimension value (dimension number not relevant):
         LBound returns always '0', and UBound returns always '-1'

      Summarizing table example:

   Array definition |      array( )       | array( Any , Any )  | array( 4 , 5 To 9 ) |
   Dimension nb (x) |                     |        (1)   (2)    |       (1)    (2)    |
   -----------------|---------------------|---------------------|---------------------|
   LBound(array, 0) |      1              |      1              |      1              |
   UBound(array, 0) |      0              |      0 (but Not 2!) |      2              |
   -----------------|---------------------|---------------------|---------------------|
   LBound(array, 1) |      0              |      0              |      0 (by default) |
   UBound(array, 1) |     -1              |     -1              |      4              |
   -----------------|---------------------|---------------------|---------------------|
   LBound(array, 2) |      0              |      0              |      5              |
   UBound(array, 2) |     -1              |     -1              |      9              |
   -----------------|---------------------|---------------------|---------------------|
   LBound(array, k) |      0              |      0              |      0              |
   UBound(array, k) |     -1              |     -1              |     -1              |
     For k<0 Or k>2 |                     |                     |                     |
   -----------------|---------------------|---------------------|---------------------|
   			

   - Use cases:
      So UBound( array , 0 ) value allows to easily determine if an array 
      is sized (value > 0) or not (value = 0), and if yes the number of 
      dimensions (the positive value).
         Remark:
            ( ( LBound( array ) = 0 ) AND ( UBound( array ) = -1 ) )
            OR:
            ( @array( LBound( array ) ) = 0 ) - Note: No longer supported 
            since fbc 1.20.0
            would allow to only know that the array is un-sized.

      Once the number of dimensions is determined, the information on the 
      two boundaries of each dimension is safely accessible.

      Example of a macro that displays all the sizing information for an 
      array:
   #macro PRINT_ARRAY_SIZING (array)
      If UBound( array , 0 ) = 0 Then
         Print "'" & #array & "' un-sized"
      Else
         Print "'" & #array & "' sized with " & UBound( array , 0 ) & " dimension";
         If UBound( array , 0 ) > 1 Then
            Print "s";
         End If
         Print
         For I As Integer = 1 To UBound( array , 0 )
            Print "   dimension nb: " & I
            Print "      lower bound: " & LBound( array , I )
            Print "      upper bound: " & UBound( array , I )
         Next I
      End If
   #endmacro

   Dim As Integer array1( )
   PRINT_ARRAY_SIZING( array1 )
   Print

   Dim As Single array2( Any )
   PRINT_ARRAY_SIZING( array2 )
   Print

   Dim As String array3( 4 , 5 To 9 )
   PRINT_ARRAY_SIZING( array3 )
   Print

   Type UDT
      Dim As Double array4( Any, Any, Any )
   End Type

   Dim As UDT u
   PRINT_ARRAY_SIZING( u.array4 )
   Print

   ReDim u.array4( -7 To -3, -2 To 5, 6 To 9 )
   PRINT_ARRAY_SIZING( u.array4 )
   Print

   Erase u.array4
   PRINT_ARRAY_SIZING( u.array4 )
   Print

   Sleep
            
Output:

   'array1' un-sized

   'array2' un-sized

   'array3' sized with 2 dimensions
      dimension nb: 1
   	  lower bound: 0
   	  upper bound: 4
      dimension nb: 2
   	  lower bound: 5
   	  upper bound: 9

   'u.array4' un-sized

   'u.array4' sized with 3 dimensions
      dimension nb: 1
   	  lower bound: -7
   	  upper bound: -3
      dimension nb: 2
   	  lower bound: -2
   	  upper bound: 5
      dimension nb: 3
   	  lower bound: 6
   	  upper bound: 9

   'u.array4' un-sized
   				

   - Notes:
      The maximum number of dimensions of a multidimensional array is 8.

      At the contrary to QB, FB stores the multidimensional arrays data in 
      this definite order: values differing only in the last index are 
      contiguous in memory (row-major order).

      An array declared with 'Any' instead of the bound fields is 
      considered presently to be fully un-sized from UBound ('UBound( array 
      , 0 ) = 0'), while at least its number of dimensions is already fixed 
      (and locked).
      Moreover this value of the number of dimensions is well set in the 
      array descriptor.
      In this case, UBound( array , 0 ) could return this value while 
      remaining with LBound (array , 0 ) = 0 and UBound( array , 0 ) = -1.
      A bug report (#853) has been filled in, about this behavior.

See also
   * Fixed-length Arrays
   * Variable-length Arrays
   * Array Indexing
   * Passing Arrays to Procedures
   * Variable Scope



----------------------------------------------------- ProPgFixLenArrays ----
Fixed-length Arrays

Fixed-size homogeneous data structures.

Overview
   Fixed-length arrays are arrays that have a fixed constant size 
   throughout the execution of a program. The memory used by a fixed-length 
   array to store its elements is allocated at compile-time, either on the 
   stack or in the .BSS or .DATA sections of the executable, depending on 
   whether Static (or Shared) was used to define it. This may allow for 
   quicker program execution since the memory for the array is already 
   allocated, unlike variable-length arrays, whose element memory isn't 
   allocated until runtime.

   Fixed-length arrays with automatic storage, have their elements 
   allocated on the program stack, and pointers to these elements remain 
   valid only while the array is in scope. The elements of fixed-length 
   arrays with static storage are allocated in the .DATA or .BSS sections 
   of the executable, depending on whether or not they are initialized when 
   defined, so pointers to these elements remain valid for the entire 
   execution of the program. Fixed-length arrays of any storage class 
   cannot be resized during program execution, only variable-length arrays 
   can.

   Fixed-length arrays may also be used as data members inside 
   user-defined types, in which case the array is directly allocated as 
   part of the user-defined type structure.

Declaration
   A fixed-length array is declared with either the Dim or Static keywords, 
   followed by a variable identifier, a parenthesized list of boundaries 
   and an element data type.

   '' Defines a one-dimensional fixed-length array of type INTEGER having automatic storage.
   Dim arrayOfIntegers(69) As Integer

   '' Defines a one-dimensional fixed-length array of type SHORT having static storage.
   Static arrayOfShorts(420) As Short
         

   There are various ways to specify an array's amount of elements. Each 
   array can have between 1 or 8 dimensions. Each dimension has a lower 
   bound and an upper bound.

   Dim a(1) As Integer  '' 1-dimensional, 2 elements (0 and 1)
   Dim b(0 To 1) As Integer  '' 1-dimensional, 2 elements (0 and 1)
   Dim c(5 To 10) As Integer  '' 1-dimensional, 6 elements (5, 6, 7, 8, 9 and 10)

   Dim d(1 To 2, 1 To 2) As Integer  '' 2-dimensional, 4 elements: (1,1), (1,2), (2,1), (2,2)
   Dim e(9, 9, 9, 9) As Integer '' 4-dimensional, 10 * 10 * 10 * 10 elements
         

   For an array to be declared fixed-length, the boundaries must be 
   specified using only number literals or Const values or Enum constants.

   Const myLowerBound = -5
   Const myUpperBound = 10

   '' Declares a one-dimensional fixed-length array, holding myUpperBound - myLowerBound + 1 String objects.
   Dim arrayOfStrings(myLowerBound To myUpperBound) As String

   '' Declares a one-dimensional fixed-length array of bytes,
   '' big enough to hold an INTEGER.
   Dim arrayOfBytes(0 To SizeOf(Integer) - 1) As Byte
         

Declaration with initializer
   The fixed-length arrays may be given values at the time of their 
   declaration by following the array declaration with an initializer 
   (variable-length arrays declarations can't use initializers).
   These initializing array values are given in comma-delimited values 
   enclosed by curly brackets. These methods of initializing array values 
   can be nested within one another for complex assignments, allowing for 
   arrays of any dimension to be initialized.

   '' Declare an array of 2 by 5 elements followed by an initializer
   Dim array(1 To 2, 1 To 5) As Integer => {{1, 2, 3, 4, 5}, {1, 2, 3, 4, 5}}
         

   Any upper bound can be an ellipsis "..." (3 dots). This will cause to 
   upper bound to be set automatically based on the number of elements 
   found in the initializer. When ellipsis is used in this manner, an 
   initializer must be used.

   '' Declare (with one ellipsis) an array of 2 by 5 elements followed by an initializer
   Dim array(1 To 2, 1 To ...) As Integer => {{1, 2, 3, 4, 5}, {1, 2, 3, 4, 5}}
         

   '' Declare (with two ellipsis) an array of 2 by 5 elements followed by an initializer
   Dim array(1 To ..., 1 To ...) As Integer => {{1, 2, 3, 4, 5}, {1, 2, 3, 4, 5}}
         



----------------------------------------------------- ProPgVarLenArrays ----
Variable-length Arrays

Resizable homogeneous data structures. Also known as "dynamic arrays".

Overview
   Variable-length arrays are arrays that can, during program execution, 
   either be resized to hold more or less elements, or have their 
   dimension[s] use a different subscript range. The memory used by a 
   variable-length array to store its elements is allocated at runtime in 
   the heap, as opposed to fixed-length arrays whose data is either 
   allocated on the program stack or in the .BSS or .DATA sections of the 
   executable, depending on whether they were defined with Static (or Shared
   ).

   Variable-length arrays may also be used as data members inside 
   user-defined types. As opposed to fixed-length arrays though, the array 
   is not allocated as part of the user-defined type structure, because 
   user-defined types cannot be variable-length. Instead, the user-defined 
   type only contains the array descriptor that is used to hold and access 
   the variable-length array behind the scenes, and the array is still 
   allocated on the heap, as with variable-length array variables.

   Variable-length arrays are often called "dynamic arrays" because their 
   size can change dynamically at runtime, instead of being fixed-size.

Declaration
   A variable-length array is declared with either the Dim or ReDim 
   keywords, followed by a variable identifier, a parenthesized list of 
   boundaries and an element data type. For an array to be declared 
   variable-length, it must be declared with unknown boundaries, or with 
   variable (non-constant) boundaries. ReDim always defines variable-length 
   arrays, whether the specified boundaries are constant or not.

   '' Declares a one-dimensional variable-length array of integers, with initially 2 elements (0 and 1)
   ReDim a(0 To 1) As Integer

   '' Declares a 1-dimensional variable-length array without initial bounds.
   '' It must be resized using Redim before it can be used for the first time.
   Dim b(Any) As Integer

   '' Same, but 2-dimensional
   Dim c(Any, Any) As Integer

   Dim myLowerBound As Integer = -5
   Dim myUpperBound As Integer = 10

   '' Declares a 1-dimensional variable-length array by specifying variable (non-constant) boundaries.
   '' The array will have myUpperBound - myLowerBound + 1 elements.
   Dim d(myLowerBound To myUpperBound) As Integer

   '' Declares a variable-length array whose amount of dimensions will be determined
   '' by the first Redim or array access found. The array has no initial bounds and must
   '' be resized using Redim before it can be used for the first time.
   Dim e() As Integer

Resizing
   Resizing a variable-length array refers to "redefining" the array with 
   different boundaries, allowing the array to grow or shrink. Elements 
   outside the new subscript range[s] are erased; object elements will be 
   destroyed. If the array is resized to a larger size, new elements are 
   added initialized with a zero or null value; object elements are 
   default-constructed. Variable-length arrays are resized using the ReDim 
   keyword following the same form as definition. In this case the element 
   data type may be omitted from the ReDim statement.

   '' Define an empty 1-dimensional variable-length array of SINGLE elements...
   Dim array(Any) As Single

   '' Resize the array to hold 10 SINGLE elements...
   ReDim array(0 To 9) As Single

   '' The data type may be omitted when resizing:
   ReDim array(10 To 19)

   Resizing an array cannot change its amount of dimensions, but only the 
   boundaries of each dimension.

   By default, element values of a variable-length array are lost when 
   resized. To retain the previous element values during a resize, use the 
   Preserve keyword.

See also
   * Fixed-length Arrays
   * Passing Arguments to Procedures
   * Passing Arrays to Procedures
   * ... (Ellipsis)



------------------------------------------------------- ProPgArrayIndex ----
Array Index

An array index is the number used to access an Array of Variables created 
using the Dim command.

Description
   The following examples illustrate the use of array elements.

   If we have an array myArray with elements of 1 to 10, filled with random 
   data:

   Index        Data
   1              5
   2              2
   3              6
   4              5
   5              9
   6              1
   7              0
   8              4
   9              5
   10             7

   One can access each piece of data separately by pointing to the Index of 
   the array element:
      Print myArray(5)
      

   Printing the data contained in the fifth element of myArray results in 
   an output of:

   	9
   	

   To change the contents of an array, use it like any other Variable:
      myArray(3) = 0
      

   To print the contents of myArray(3), use the command:
      Print myArray(3)
      

   Which results in an output of:

   	0
   	

   Array elements can be indexed using another Variable. In this example we 
   set all elements in our array to zero:
      Dim a As Integer
      For a = 1 To 10
        myArray(a) = 0
      Next a
      

   To change a random array element to a random value:
      Dim Index As Integer
      Dim Value As Integer
      index = Int(Rnd(1) * 10) + 1 'This line will simply return a random value between 1 and 10
      Value = Int(Rnd(1) * 10) + 1 'This line will do the same
      myArray(index) = Value
      

Example
   Declare Sub PrintArray()

   Dim Numbers(1 To 10) As Integer
   Dim Shared OtherNumbers(1 To 10) As Integer
   Dim a As Integer

   Numbers(1) = 1
   Numbers(2) = 2
   OtherNumbers(1) = 3
   OtherNumbers(2) = 4

   PrintArray ()

   For a = 1 To 10
    Print Numbers(a)
   Next a

   Print OtherNumbers(1)
   Print OtherNumbers(2)
   Print OtherNumbers(3)
   Print OtherNumbers(4)
   Print OtherNumbers(5)
   Print OtherNumbers(6)
   Print OtherNumbers(7)
   Print OtherNumbers(8)
   Print OtherNumbers(9)
   Print OtherNumbers(10)

   Sub PrintArray ()
    Dim a As Integer
    For a = 1 To 10
      Print otherNumbers(a)
    Next a
   End Sub

See also
   * Arrays Overview
   * Dim
   * Function
   * Sub
   * Variables 
   * Variable Scope
   * Standard Data Type Limits



---------------------------------------------------- ProPgPassingArrays ----
Passing Arrays to Procedures

Declaring/defining array parameters and passing array arguments to 
procedures

Syntax for array symbol name
   As parameter in procedure declaration:
      ( [ Any [, Any...] ] ) As datatype
      array_name( [ Any [, Any...] ] ) As datatype
   As parameter in procedure definition:
      array_name( [ Any [, Any...] ] ) As datatype
   As argument in procedure call:
      array_name()

   Parentheses (even empty) are mandatory to specify that the 
   parameter/argument is an array.

Usage of array symbol name
   When declaring procedure with array parameter:
      Declare { Sub | Function } proc_name ... ( ( [ Any [, Any...] ] ) As 
      datatype , ... ) [ ... ]
      Declare { Sub | Function } proc_name ... ( array_parameter_name( [ Any
      [, Any...] ] ) As datatype , ... ) [ ... ]
   When defining procedure with array parameter:
      { Sub | Function } proc_name ... ( array_parameter_name( [ Any [, Any
      ...] ] ) As datatype , ... ) [ ... ]
   When passing array argument to procedure:
      sub_name ( array_argument_name() , ... )
      sub_name array_argument_name() , ...
      funct_name ( array_argument_name() , ... )
      funct_name array_argument_name() , ...
      ... funct_name ( array_argument_name() , ... ) [ ... ]

      Note (same rules as for any parameter/argument list):
         When declaring/defining a procedure, parentheses surrounding a non 
         empty parameter list are required.
         When calling a subroutine, parentheses surrounding an argument 
         list (empty or non empty) are optional.
         When calling a function as a subroutine (without using the return 
         variable), the same rules as for subroutine apply.
         When calling a function in an expression (which uses the return 
         value), parentheses surrounding a non empty argument list are 
         required.
         But it is a common convention to always use parentheses (empty or 
         non empty) after the procedure name, to signify a procedure call.

Description
   Array parameter can not have a ByVal or ByRef keyword before them, 
   because arrays don't get passed the same way as normal parameters. While 
   variables get passed by value or by reference, arrays get passed by 
   descriptor (see below). In fact when an array is passed to a procedure, 
   it is a reference to its descriptor which is passed.
   All the elements of a passed array can be modified, and those changes 
   are reflected at the calling level. Perhaps ByRef should be allowed by 
   similarity with variable-length string (which are also passed by 
   descriptor).

   There is no direct possibility of passing an array by value. Declaring a 
   passed array parameter As Constant only forbids any modification in the 
   procedure body. A workaround would be to pass a user copy of the array.

   Note:
      A function return can not be an array type variable.
      A fixed-length String array can not be passed to a procedure.
      A ZString/WString array can not be simply passed to a procedure 
      because the zstring/wstring size is not passed (the "as 
      zstring/wstring * 1" type is taken by default by compiler in 
      procedure body). It is a bug at the moment because compiler just 
      fails silently while it badly computes in the procedure body the 
      address of each array element (except the first obviously).

   Array descriptor (for information purposes only):
      For a fixed-length array, the descriptor is only used for passing the 
      array to a procedure (otherwise the compiler does not use it because 
      knowing the fixed characteristics of the array).
      For a variable-length array, the descriptor is always used (the array 
      descriptor is the only defining the array characteristics).

      The array descriptor has the following structure (each item is coded 
      on an 'Any Ptr' or an 'Uinteger', except on an 'Integer' for lbound 
      and ubound):
         - pointer to the real or virtual element: @array(0, 0, ...)
         - pointer to the first real element: @array(lbound1, lbound2, ...)
         - "global" size in bytes: (ubound1 - lbound1 + 1) * (ubound2 - 
         lbound2 + 1) * ... * (size of 1 element in bytes)
         - size of one element in bytes
         - number of dimensions
         - flags(*): array points to fixed-length memory (1-bit) / array 
         has nb of dimensions defined at first declaration / nb of 
         dimensions allocated in descriptor (4-bit)
         then for each dimension:
         - number of elements: (ubound - lbound + 1)
         - lbound
         - ubound

         (*): Additional member field (an 'Uinteger') for fbc versions >= 
         1.08
         (see the include file ./inc/fbc-int/array.bi for fbc versions >= 
         1.07)

      For more information, see 
      Fbarray (Array Descriptor Structure And Access).

Example

   Declare Sub splitString(ByVal As String, (Any) As String, ByVal As UByte = Asc(","))

   Dim As String s = "Programmer's Guide/Variables and Datatypes/Arrays/Passing Arrays to Procedures"
   Dim As String array(Any)

   splitString(s, array(), Asc("/"))

   Print "STRING TO SPLIT:"
   Print s
   Print
   Print "RESULT ARRAY FROM SPLITTING:"
   For i As Integer = LBound(array) To UBound(array)
      Print i, array(i)
   Next i

   Sleep

   Sub splitString(ByVal source As String, destination(Any) As String, ByVal delimitor As UByte)
      Do
         Dim As Integer position = InStr(1, source, Chr(delimitor))
         ReDim Preserve destination(UBound(destination) + 1)
         If position = 0 Then
            destination(UBound(destination)) = source
            Exit Do
         End If
         destination(UBound(destination)) = Left(source, position - 1)
         source = Mid(source, position + 1)
      Loop
   End Sub

See also
   * Passing Arguments to Procedures
   * Calling Conventions
   * Returning Values




============================================================================
    Pointers

--------------------------------------------------------- ProPgPointers ----
Pointers

Data types whose values are addresses in memory.

Declaration
   Pointers are Variables whose values are addresses in memory, and they 
   are said to 'point' to this memory. The type of data that is pointed to 
   depends on the type of pointer (an Integer Pointer points to Integer 
   data). Pointers are declared like any other variable, with the suffix "
   pointer" or "ptr" following the type name.

Assigning pointer variables
   A pointer is a memory address and the value of the pointer itself is 
   that memory address.  To assign a pointer variable is to assign it a 
   memory address to something.  One way to assign a pointer a memory 
   address is to take the address of some other variable in the program 
   using Operator @ (Address of).

Accessing pointed to data
   The data pointed to by a pointer can be accessed with Operator * (Value 
   of). This operator returns a reference to the data that its operand 
   points to. The following,

   Dim myInteger As Integer = 10
   Dim myPointer As Integer Pointer = @myInteger
   *myPointer = 20
   Print myInteger

   defines an Integer variable called myInteger and an Integer pointer 
   called myPointer that points to the location in memory where myInteger 
   is stored. Operator @ (Address of) is used to retrieve the address of 
   myInteger. The value of 20 is assigned to the location at which 
   myPointer points - the address of myInteger, or @myInteger. Changes to 
   *myPointer directly affect the value of myInteger (the expression "
   *myPointer" is the same thing as "myInteger").

Pointers to user-defined types
   Pointers to user-defined types are defined and used like all other 
   pointers. Accessing a member of a Type or Class requires one of the 
   following two methods:

   Type myType
      a As Integer
      b As Double
   End Type

   Dim x As myType
   Dim p As myType Pointer = @x

   '' 1) dereference the pointer and use the member access operator:
   (*p).a = 10
   (*p).b = 12.34

   '' 2) use the shorthand form of the member access operator:
   Print p->a
   Print p->b

   The first method uses Operator . (Member Access). This operator accesses 
   members from references, so the pointer is dereferenced first. The 
   member access operator has higher priority over the dereference 
   operator, so parenthesis are needed to dereference the pointer before 
   using it with the member access operator.

   The second method uses Operator -> (Pointer To Member Access). This 
   operator accesses members from pointers, which are automatically 
   dereferenced. This can make code a little clearer, although both forms 
   produce identical results.

See also
   * Operator @ (Address Of)
   * Operator * (Value Of)
   * Operator . (Member Access)
   * Operator -> (Pointer To Member Access)
   * VarPtr
   * StrPtr
   * ProcPtr



---------------------------------------------------- ProPgPtrArithmetic ----
Pointer Arithmetic

Manipulating address values mathematically.

Overview
Adding and subtracting from pointers
Incrementing and decrementing pointers
Distance between two pointers

Overview
   It is often useful to iterate through memory, from one address to 
   another. Pointers are used to accomplish this. While the type of a 
   pointer determines the type of variable or object retrieved when the 
   pointer is dereferenced (using Operator * (Value Of)), it also 
   determines the distance, in bytes, its particular type takes up in 
   memory. For example, a Short takes up two (2) bytes in memory, while a 
   Single needs four (4) bytes.

Adding and subtracting from pointers
   Pointers can be added to and subtracted from just like a numeric type. 
   The result of this addition or subtraction is an address, and the type 
   of pointer determines the distance from the original pointer.

   For example, the following,

   Dim p As Integer Ptr = New Integer[2]

   *p = 1
   *(p + 1) = 2

   will assign the values "1" and "2" to each integer in the array pointer 
   to by p. Since p is an Integer Pointer, the expression "*(p + 1)" is 
   saying to dereference an Integer four/eight (4/8 on 32/64bit systems) 
   bytes from p; the "1" indicates a distance of "1 * the size of an Integer
   ", or four/eight (4/8 on 32/64bit systems) bytes.

   Subtraction follows the exact same principle. Remember, a - b = a + -b.

Incrementing and decrementing pointers
   Sometimes it is more convenient to modify the pointer itself, in which 
   case the combination addition and subtraction operators will work just 
   like above. For example, the following,

   Dim array(5) As Short = { 32, 43, 66, 348, 112, 0 }
   Dim p As Short Ptr = @array(0)

   While (*p <> 0)
      If (*p = 66) Then Print "found 66"
      p += 1
   Wend

   iterates through an array until it finds an element with the value of "0
   ". If it finds an element with the value "66" it displays a nice 
   message.

Distance between two pointers
   The distance between two pointers is retrieved with Operator - (Subtract)
   , and is measured in values, not bytes. For example, the following,

   Type T As Single

   Dim array(5) As T = { 32, 43, 66, 348, 112, 0 }
   Dim p As T Ptr = @array(0)

   While (*p <> 0)
      p += 1
   Wend
   Print p - @array(0)

   will output "5" regardless of what type T is. This is because there is a 
   five (5) element difference between the first element of array (32) and 
   the element pointed to by p (0).

   Specifically, if a and b are both pointers of type T, the distance 
   between them is the number of bytes between them, divided by the size, 
   in bytes, of T, or

      ( cast(byte ptr, a) - cast(byte ptr, b) ) / sizeof(T)

See also
   * Operator + (Add)
   * Operator - (Subtract)
   * Operator @ (Address Of)
   * Operator * (Value Of)
   * Pointer Operators




============================================================================
    References

----------------------------------------------------- ProPgFromPtrToRef ----
From Pointers to References

References do not fully offer the same capabilities as Pointers, but using 
them instead can simplify coding.

Preamble:

   References and pointers are closely related.
   Indeed, a variable and its different references hold the same address, 
   since they allow access to the same object.

   The reference encapsulates the manipulation of the address of the object 
   and is used as a dereferenced pointer.
   The difference lies here in the fact that one does not have to perform 
   the dereferencing.

   References are much easier to handle than pointers, so they make code 
   much safer.

Reminder on pointers
   An address is a value. User can store this value in a variable. Pointers 
   are precisely variables that contain the address of other objects, for 
   example the address of another variable.
   The value of a pointer may change. This does not usually mean that the 
   pointed variable is moved to memory, but rather that the pointer points 
   to something else.
   In order to precise what is pointed by a pointer, the pointers have a 
   type. This type is usually constructed from the type of the pointed 
   object. This allows the compiler to verify that the manipulations made 
   in memory via the pointer are valid.

   The most common use of pointers is when sent in the parameters of a 
   procedure. They make it possible to manipulate in a simple way data 
   which can be important (instead of providing to a procedure a very big 
   data block, one could for example provide a pointer to this one).
   Another use is when doing dynamic allocation in memory, with the 
   '[C]Allocate' and 'New' keywords which return the address of the memory 
   that has been allocated. This address must be stored somewhere and know 
   how to use it.
   Finally, pointers can also be used to manipulate tables, but their 
   interest is lower with FB because user has the capacity to declare 
   static and dynamic arrays and to use the dedicated '()' (Array Index) 
   operator to access their elements.

   It is also possible to create pointers to procedures, and to use these 
   pointers to parameterize an algorithm, the behavior of which will depend 
   on the procedures thus pointed out.

   It is very important to make sure that the pointers that user is 
   manipulating are all initialized (that is, they contain the address of a 
   valid object, not just anything). Indeed, to access a variable by means 
   of an uninitialized pointer amounts to read or, more seriously, to write 
   in the memory at a completely random place (according to the initial 
   value of the pointer at the time of its creation).
   In general, pointers are initialized as soon as they are created, or if 
   they are to be used later, they are initialized with the null value. 
   This will allow future tests on the validity of the pointer or at least 
   to detect errors. Indeed, using a pointer with a null value to access a 
   variable can often generate a program protection fault, but will always 
   generate an error message at run-time if the program was compiled with 
   the option '-exx'.

   With the dereferencing operators '*' and '[]', it is possible to access 
   the variables from pointers.
   The 'Any Ptr' pointers are a special type of pointer. They can point to 
   a variable of any type. You can not use the '*' and '[]' dereferencing 
   operators on an 'Any Ptr' pointer. It must first be converted into a 
   pointer of a given type.
   Similarly, a typed pointer can also be converted into a pointer of any 
   other type (if necessary converting first through an 'Any Ptr' pointer).
   For object pointers ('po'), it's more convenient to use the single '->' 
   operator rather than combining the "*" and "." to access object members 
   (use 'po->member' instead of '(*po).member').

   A pointer can also be declared with a type different but compatible with 
   the address types of objects to be pointed (as a simple example, 
   'Zstring Ptr' and 'Ubyte Ptr' are two compatible pointer types in both 
   directions). In a more evolved way in case of inheritance structure, 
   derived type objects can be referenced with pointers constructed from 
   the type of one among those of their common bases (allowing to activate 
   the polymorphism when a virtual and overridden method is called on such 
   pointers).

   Pointers have their own arithmetic. Increment/decrement is special for 
   this type. This is done by multiplying the size of the type of the 
   pointer by the value that one wants to add/remove to it. This makes it 
   possible to properly move the pointer forward or back from the number of 
   elements indicated.
   The only operation allowed between pointers is the subtraction, provided 
   the pointers are of the same type. This operation only makes sense if 
   the pointers point to the same homogeneous structure of elements (of the 
   type of the pointers), because the result corresponds to a difference in 
   number of elements.

Notion of reference
   In higher-level languages, the use of pointers tends to be suppressed, 
   in favor of references and dynamic arrays managed by the compiler. 
   References fulfill some pointer functions by removing explicit user 
   access to memory. This avoids many problems, in return some uses and 
   optimizations are no longer possible.

   In addition to the two classic ways to access data represented in 
   memory: use its name (if it is a variable or a constant) or dereference 
   a pointer containing its address, there is a third method, the use of 
   references, which is absolutely essential in some cases and provides, in 
   addition, an alternative to the use of a pointer.

   A reference is a way to associate a new name with an already existing 
   object.
   It is not a means to create a new object, even if the syntax to create a 
   reference variable leads to an expression strangely resembling the 
   definition of an initialized variable.
   This assignment of a new name does not deprive the object concerned of 
   its original name, if it had one. The new name simply becomes a synonym 
   for the old one, meaning that they both refer to the same object.

   To pass/return a variable by reference instead of doing it by value 
   avoids making a copy of the transmitted object. When the object in 
   question is very large, the copy operation can be expensive in run-time 
   and in memory.

   In the manner of a pointer, a reference has its own type, which must be 
   identical to that of the referenced object, otherwise compatible at 
   least. In this last case only (type compatible but not the same), 
   references (like pointers) can not do all same operations than with the 
   original object.

   The use of a reference to an object makes it possible to obtain the 
   advantages associated with the use of a "pointer to object" (speed and 
   memory savings) while avoiding the heaviness of writing implied by the 
   use of an object pointer (usage of the '@' operator, and '*' or '[]' 
   operators).

   Note:
      - The arrays of references are not supported yet in FB.
      - The non-static reference fields for UDT are not supported yet in 
      FB.
      - The references to procedures are not supported in FB (only 
      references to pointers to procedures).

Using references
   See the next page of this "References" section:
      - the 'Using References' page.

See also
   * Allocate, CAllocate, New (Expression)
   * Operator @ (Address Of), Operator * (Value Of), 
     Operator [] (Pointer Index)
   * Operator . (Member Access), Operator -> (Pointer To Member Access)
   * Pointer Overview
   * Pointer Arithmetic
   * Using References



------------------------------------------------------- ProPgReferences ----
Using References

The syntax for declaring the References and Using them instead of pointers.

Preamble:

   The different syntaxes used to declare a reference all use the 'Byref' 
   keyword.
   Since a pointer is a variable, it is possible to modify its contents, 
   and the same pointer can allow successive access to different variables. 
   The association between a reference and the object that it designates 
   is, however, fixed when it is declared.

   The 'Byref' keyword indicates a variable that is declared by reference. 
   It is used in three different contexts:
      - In a procedure signature, to pass an argument by reference (byref 
      parameter).
      - In a function signature, to return a variable to the caller by 
      reference (byref return).
      - In the body of the code, to define a reference variable (byref 
      variable).

   Table of Contents
1. Passing parameter by reference to procedure (byref parameter)
2. Returning variable by reference from function (byref return)
3. Defining reference variable in code (byref variable)
4. References versus pointers by comparative examples
5. Hacking on usage of references with the additional syntaxes allowed by FreeBASIC

1. Passing parameter by reference to procedure (byref parameter)
   * Syntax of declaration:
      {Sub|Function} procedure_name (ByRef parameter As [Const] datatype, 
      ...

      When used in the parameter list of a procedure, the Byref keyword 
      indicates that an argument is passed by reference, not by value. The 
      consequence is that any modification made to the argument in the 
      called procedure is reflected in the body of the call.
      If the procedure does not need or must not to modify the transmitted 
      object, the Const qualifier can be used in the declaration (before 
      the declaration of the datatype) so that the compiler checks in the 
      body of the procedure that the passed object is not modified in any 
      place (otherwise, a compiler error message is issued).

   * Full syntax example for passing a parameter by reference:
   Declare Sub passbyref (ByRef ref As Double, ByVal value As Double)  '' declaration for passing by reference

   Dim As Double X = 0
   Print X
   passbyref(X, 1.23)
   Print X

   Sleep

   Sub passbyref (ByRef ref As Double, ByVal value As Double)  '' declaration for passing by reference
      ref = value
   End Sub
         
Output:

    0
    1.23
   			

   Note: A pointer can be passed directly (without first dereferencing it) 
   to Byref procedure parameter if in argument term the Byval keyword is 
   specified in front of the pointer name.

Back to top

2. Returning variable by reference from function (byref return)
   * Syntax of declaration:
      Function function_name (...) ByRef As [Const] datatype

      When used in the return type of a function, the Byref keyword 
      indicates that the variable is returned by reference, not by value. 
      The consequence is that the caller can modify the variable returned 
      by the function and the modification is reflected in the state of the 
      variable that the function processes.
      If the caller does not need or must not to modify the transmitted 
      object, the Const qualifier can be used in the declaration (before 
      the declaration of the datatype) so that the compiler checks in the 
      body of the caller that the returned object is not modified in any 
      place (otherwise, a compiler error message is issued).

      Operators (member or global), when used as functions, have also the 
      capability to return results by reference, by using the similar 
      syntax.

   * Full syntax example for returning a variable by reference:
   Declare Function returnbyref () ByRef As Double  '' declaration for returning by reference

   Print returnbyref()
   returnbyref() = 4.56
   Print returnbyref()

   Sleep

   Function returnbyref () ByRef As Double  '' declaration for returning by reference
      Static As Double X = 0
      Return X
   End Function
         
Output:

    0
    4.56
   		
As for the arguments list, it should always be surrounded with parentheses 
even if empty.

      Specific syntax:
         On the left-hand side of an assignment expression using the '=' 
         symbol, the result of the function (returned by reference) must be 
         enclosed in parentheses when the function calls one single 
         argument, in order to solve the parsing ambiguity.
         From fbc version 0.90, '=>' can be used for assignments, in place 
         of '=', same as for initializers, allowing to avoid parsing 
         ambiguity (without parentheses):
   Declare Function transitbyref( ByRef _s As String ) ByRef As String

   Dim As String s

   s = "abcd"
   Print s

   '' the enclosing parentheses are required here.
   ( transitbyref( s ) ) = transitbyref( s ) & "efgh"
   Print s

   '' the enclosing parentheses are not required here.
   transitbyref( s ) => transitbyref( s ) & "ijkl"
   Print s

   Sleep

   Function transitbyref( ByRef _s As String ) ByRef As String
      '' This var-len string will transit by reference (input and output), no copy will be created.
      Return _s
   End Function
               
Output:

   abcd
   abcdefgh
   abcdefghijkl
   					

   Note: A pointer can be returned directly (without first dereferencing 
   it) for a Byref function return if in identifier= or Function= or Return 
   statement the Byval keyword is specified in front of the pointer name.

Back to top

3. Defining reference variable in code (byref variable)
   * Syntax of declaration:
         {Dim|Static} [Shared] ByRef As [Const] datatype ref = variable
      or
         [Static] Var [Shared] ByRef ref = variable

      Unlike pointers, the reference variable must be assigned as soon as 
      the declaration using an initializer.
      datatype must be the same type as that of the variable, or a 
      compatible type (for example one from the types of its Bases in case 
      of inheritance):
         - Only when the two types are identical (or using the second 
         syntax with Var), a reference variable can be considered as an 
         alias of the variable. One can do the same operations through such 
         a reference variable as one can do with the original variable.
         - Otherwise (types compatible but not identical), one can not do 
         all same operations than with the original variable:
            For example, a base type reference variable referring to a 
            derived type object allows to activate polymorphism when a 
            virtual method is called on it, similarly to a base type 
            pointer referring to a derived type object. One can do the same 
            operations through such a reference variable as one can do with 
            a dereferenced pointer of same type (but for both not the same 
            operations as using directly the derived type instance).

      If the code does not need or must not to modify the referred object, 
      the Const qualifier can be used in the declaration (before the 
      declaration of the data_type in the first syntax) so that the 
      compiler checks in the code that the object is not modified, through 
      the reference variable, in any place (otherwise, a compiler error 
      message is issued).

      There is no interaction between the life of a reference and the life 
      of the object who is referred (similarly to a pointer: destroy an 
      object does not destroy its pointer(s)).
      Once created, each one lives his life independently.

   * Full syntax example for defining a reference variable in code:
   Dim As Double X = 0

   Dim ByRef As Double refX = X  '' declaration for defining a reference
   Print X
   refX = 7.89
   Print X

   Sleep
         
Output:

    0
    7.89

Back to top

4. References versus pointers by comparative examples
   * Function returning the greater variable between two integer 
     variables:
      - Using pointers (by passing/returning pointer variables):
   Function maxPtr (ByVal p1 As Integer Ptr, ByVal p2 As Integer Ptr) As Integer Ptr
      If *p1 > *p2 Then
         Return p1
      Else
         Return p2
      End If
   End Function

   Dim As Integer i1 = 1, i2 = 2
   Print i1, i2
   *maxPtr(@i1, @i2) = 3
   Print i1, i2

   Sleep
            
Output:

    1             2
    1             3
   				

      - Using references (by passing/returning reference variables):
   Function maxRef (ByRef r1 As Integer, ByRef r2 As Integer) ByRef As Integer
      If r1 > r2 Then
         Return r1
      Else
         Return r2
     End If
   End Function

   Dim As Integer i1 = 1, i2 = 2
   Print i1, i2
   maxRef(i1, i2) = 3
   Print i1, i2

   Sleep
            
Output:

    1             2
    1             3
   				

               * Inheritance structure with overriding subroutine and 
                 overriding function with covariant return:
      - Using pointers to objects:
   Type myBase Extends Object
      Declare Virtual Function clone () As myBase Ptr
      Declare Virtual Sub Destroy ()
   End Type

   Function myBase.clone () As myBase Ptr
      Dim As myBase Ptr pp = New myBase(This)
      Print "myBase.clone() As myBase Ptr", pp
      Function = pp
   End Function

   Sub myBase.Destroy ()
      Print "myBase.Destroy()", , @This
      Delete @This
   End Sub

   Type myDerived Extends myBase
      Declare Function clone () As myDerived Ptr Override  '' overriding member function with covariant return
      Declare Sub Destroy () Override                      '' overriding member subroutine
   End Type

   Function myDerived.clone () As myDerived Ptr      '' overriding member function with covariant return
      Dim As myDerived Ptr pc = New myDerived(This)
      Print "myDerived.clone() As myDerived Ptr", pc
      Function = pc
   End Function

   Sub myDerived.Destroy ()                '' overriding member subroutine
      Print "myDerived.Destroy()", , @This
      Delete @This
   End Sub

   Dim As myDerived c

   Dim As myBase Ptr ppc = @c                '' base type pointer to derived object c
   Dim As myDerived Ptr pcc = @c             '' derived type pointer to derived object c

   Dim As myBase Ptr ppc1 = ppc->clone()     '' base type pointer to clone of object c
   '                                              (through its base type pointer and polymorphism)
   Dim As myDerived Ptr pcc1 = pcc->clone()  '' derived type pointer to derived object c
   '                                              (through its derived type pointer and covariance of return value)
   Print
   ppc1->Destroy()                           '' using base type pointer and polymorphism
   pcc1->Destroy()                           '' using derived type pointer

   Sleep
            
Output example:

   myDerived.clone() As myDerived Ptr        4663904
   myDerived.clone() As myDerived Ptr        4663952

   myDerived.Destroy()                       4663904
   myDerived.Destroy()                       4663952
   				

      - Using references to objects:
   Type myBase Extends Object
      Declare Virtual Function clone () ByRef As myBase
      Declare Virtual Sub Destroy ()
   End Type

   Function myBase.clone () ByRef As myBase
      Dim As myBase Ptr pp = New myBase(This)
      Print "myBase.clone() Byref As myBase", pp
      Function = *pp
   End Function

   Sub myBase.Destroy ()
      Print "myBase.Destroy()", , @This
      Delete @This
   End Sub

   Type myDerived Extends myBase
      Declare Function clone () ByRef As myDerived Override  '' overriding member function with covariant return
      Declare Sub Destroy () Override                        '' overriding member subroutine
   End Type

   Function myDerived.clone () ByRef As myDerived      '' overriding member function with covariant return
      Dim As myDerived Ptr pc = New myDerived(This)
      Print "myDerived.clone() Byref As myDerived", pc
      Function = *pc
   End Function

   Sub myDerived.Destroy ()                '' overriding member subroutine
      Print "myDerived.Destroy()", , @This
      Delete @This
   End Sub

   Dim As myDerived c

   Dim ByRef As myBase rpc = c                '' base type reference to derived object c
   Dim ByRef As myDerived rcc = c             '' derived type reference to derived object c

   Dim ByRef As myBase rpc1 = rpc.clone()     '' base type reference to clone of object c
   '                                               (through its base type reference and polymorphism)
   Dim ByRef As myDerived rcc1 = rcc.clone()  '' derived type reference to derived object c
   '                                               (through its derived type reference and covariance of return value)
   Print
   rpc1.Destroy()                             '' using base typpe reference and polymorphism
   rcc1.Destroy()                             '' using derived type reference

   Sleep
            
Output example:

   myDerived.clone() ByRef As myDerived      9775712
   myDerived.clone() ByRef As myDerived      9775760

   myDerived.Destroy()                       9775712
   myDerived.Destroy()                       9775760

Back to top

5. Hacking on usage of references with the additional syntaxes allowed by 
FreeBASIC
   In FB, a reference is implemented under the hood through an internal 
   pointer which holds the address of the variable.

   The access to this internal pointer is presently allowed for user, in 
   read, and also in write for a reference variable (unlike many other 
   languages):
      - Therefore, the address of the referred variable (the value of the 
      internal pointer) can be get by using the '@' operator applied on the 
      reference variable symbol name:
         variable_address = @ref
      - And even, a reference variable can be reassigned (by modifying the 
      value of the internal pointer) to refer to another variable (of 
      compatible type) by doing:
         @ref = @other_variable
      - The address of the internal pointer of a reference variable can 
      even be obtained:
         internal_pointer_address = @@ref
      Note:
         - A reference variable can also be re-initialized to a "null" 
         reference:
            @ref = 0
         - A reference variable can even be directly declared as a "null" 
         reference:
            Dim ByRef As datatype ref = *CPtr(datatype Ptr, 0)

   Thus, by always using the same reference symbol name, one can mix the 
   pure syntax on the reference with the syntax on its internal pointer.

   * Example of hacking on reference symbol name:
   Declare Function resizeZstring (ByRef refZstring As ZString, ByVal length As Integer) ByRef As ZString
   Declare Sub prntZstring (ByRef refZstring As ZString)

   Dim ByRef As ZString refZ = *CPtr(ZString Ptr, 0)  '' "null" reference declaration

   Const cz1 = "FB"
   @refZ = @(resizeZstring(refZ, Len(cz1)))           '' reference (re-)inititialization
   refZ = cz1
   prntZstring(refZ)

   Const cz2 = "FreeBASIC"
   @refZ = @(resizeZstring(refZ, Len(cz2)))           '' reference re-inititialization
   refZ = cz2
   prntZstring(refZ)

   Const cz3 = "FreeBASIC 1.06.0"
   @refZ = @(resizeZstring(refZ, Len(cz3)))           '' reference re-inititialization
   refZ = cz3
   prntZstring(refZ)

   Const cz4 = ""
   @refZ = @(resizeZstring(refZ, Len(cz4)))           '' reference re-inititialization to "null" reference
   refZ = cz4
   prntZstring(refZ)

   Sleep

   Function resizeZstring (ByRef refZstring As ZString, ByVal length As Integer) ByRef As ZString
      If length > 0 Then
         If @refZstring = 0 Then
            Print "Zstring memory buffer allocation"
         Else
            Print "Zstring memory buffer re-allocation"
         End If
         length += 1
      Else
         Print "Zstring memory buffer de-allocation"
      End If
   '	Return *Cptr(Zstring Ptr, Reallocate(@refZstring, length * Sizeof(Zstring)))
   '	'' Using the "Return Byval ..." syntax allows to avoid casting + dereferencing as above
      Return ByVal Reallocate(@refZstring, length * SizeOf(ZString))
   End Function

   Sub prntZstring (ByRef refZstring As ZString)
      Print "  " & @refZstring, "'" & refZstring & "'"
      Print
   End Sub
         
Output example:

   ZString memory buffer allocation
     9513600     'FB'

   ZString memory buffer re-allocation
     9513600     'FreeBASIC'

   ZString memory buffer re-allocation
     9513600     'FreeBASIC 1.06.0'

   ZString memory buffer de-allocation
     0           ''

Back to top

See also
   * Byref (Parameters), Byref (Function Results), Byref (Variables)
   * Operator @ (Address Of), Operator * (Value Of)
   * From Pointers to References




============================================================================
    Declarations

--------------------------------------------- ProPgImplicitdeclarations ----
Implicit Declarations

Lazy declaration of variables.

   The qb and fblite FreeBASIC language dialects allow variable names to be 
   used without declaring them first. This is called implicit or lazy 
   declaration since the actual declaration is inferred from how the name 
   is first used.

Variable Type
   When a variable is implicitly declared, its type depends on one of two 
   things: the most recent default implicit type directive, if any, or the 
   variable type suffix symbol used, if any.

   Default type
      In the qb dialect, implicitly declared variables default to Single 
      type, while in the fblite dialect they default to Integer type.

   Default implicit type directives
      "DEFxxx" directives dictate the new default type for any following 
      implicit variable declarations. These directives are: DefByte, 
      DefUByte, DefShort, DefUShort, DefInt, DefUInt, DefLng, DefSng, DefDbl
      and DefStr.

   Variable type suffix symbols
      Variable names suffixed with one of a certain set of symbols will be 
      implicitly declared of a certain type. These symbols are: '%' for 
      Integer, '&' for Long, '!' for Single, '#' for Double and '$' for 
      String. These symbols override previous "DEFxxx" directives, if any.

Implicit Array Declaration
   Currently, FreeBASIC does not support implicit declaration of arrays.

Debugging
   For full debugging support, all variables must be explicitly declared 
   and suffixes should not be used. The use of Option Explicit is 
   recommended to turn of support for implicit declarations, so that 
   mistyped variable names are caught at compile time by the compiler.

See also
   * Option Explicit
   * FreeBASIC Language Dialects

 

--------------------------------------------------- ProPgInitialization ----
Variable Initializers

Variable initializers are supported for initializing pre-built type 
variables, UDT objects and arrays.

Preamble:

   Pre-built type variables, user defined type (UDT) objects and arrays are 
   initialized to zero (or 'False' for 'Boolean') or null strings by 
   default when they are created.

   To avoid the overhead of default variable initialization, the 'Any' 
   initializer can be used with 'Dim' to tell the compiler to only reserve 
   the place for the variable in memory but not initialize it, so the 
   variable will contain garbage. In this case the programmer should not 
   make assumptions about the initial values.

   Pre-built type variables, UDT objects and arrays may be given a value at 
   the time of their declaration using 'Dim ...', with the syntaxes shown 
   below.
   Pre-built type variables, UDT objects and arrays are initialized as they 
   would in a normal assignment, using an '=' sign. The '=>' sign can also 
   be used, allowing to avoid the declaration resembling an expression for 
   example when declaring fixed length strings.

   Table of Contents
1. Initializer syntax and validity for pre-built type variable declaration
2. Initializer syntax and validity for UDT object declaration
3. Initializer syntax and validity for array declaration
4. Nested Initializer syntax with another

1. Initializer syntax and validity for pre-built type variable declaration
   The main pre-built types are:
      - Integer types
      - Floating-point types
      - Boolean types
      - String types

   Initializer syntaxes
      4 basic syntaxes are described below.

      Static allocations with initializer:
         (1) Dim variable_symbol [As PreBuiltType] = expression
         or:
         (2) Dim ByRef ref_variable_symbol [As PreBuiltType] = variable

      Dynamic allocations with initializer:
         (3) Dim ptr_variable_symbol As PreBuiltType Ptr = New PreBuiltType
         ( expression )
         or:
         (4) Dim ByRef ref_variable_symbol As PreBuiltType = *New 
         PreBuiltType( expression )

   Initializer validity
      - expression:
         Must produce an evaluated value of 'PreBuiltType' type or 
         compatible.
      - variable:
         'PreBuiltType' variable or compatible, when 'As PreBuiltType' is 
         specified.

   Declaration syntax for global symbol
      If using global symbols when declaring pre-built type variable with 
      initializer ('Dim Shared' or 'Static [Shared]' or 'Static Var [Shared
      ]', instead of 'Dim'), the initializer argument must at least be able 
      to be evaluated at the start of the program so that it can be placed 
      in the .data section:
         - The initializer syntaxe for variable-length string becomes no 
         longer valid because the 'variable_symbol' must refer to a dynamic 
         memory block in the heap.
         - For the other pre-built type variables, the initializer syntaxe 
         remains valid if the provided argument can be evaluated at compile 
         time.

   Example
   Dim d As Double = 1234.56789

   Print d

   Sleep
         

   Note:
      In the -lang fb only, 'Var' can be used instead of 'Dim' (removing 
      the explicit type declaration), except for an initializer value of '
      WString' type.

Back to top

2. Initializer syntax and validity for UDT object declaration
   The UDT (User Defined Type) is a type structure defined by the user, in 
   addition to the already existing pre-built types.

   All the following assumes that any statement below (1 to 7) has the 
   access rights to any constructor explicitly defined in the UDT, if any 
   exists.

   Initializer syntaxes
      7 basic syntaxes are described below.

      Static allocations with initializer:
         (1) Dim udt_symbol As UdtName = ( argument_list )
         or:
         (2) Dim udt_symbol As UdtName = udt_instance
         or:
         (3) Dim ByRef ref_udt_symbol As UdtName = udt_instance
         or:
         (4) Dim udt_symbol As UdtName = UdtName( argument_list )
         or:
         (5) Dim udt_symbol As UdtName = Type[<UdtName>]( argument_list )

      Dynamic allocations with initializer:
         (6) Dim ptr_udt_symbol As UdtName Ptr = New UdtName( argument_list 
         )
         or:
         (7) Dim ByRef ref_udt_symbol As UdtName = *New UdtName( 
         argument_list )

   Parameters
      - argument_list:
         List of any argument type (with comma delimited items).
         If there is only one argument, the '= Type[<UdtName>]( argument )' 
         initializer (if valid) can be shortened into '= ( argument )' or 
         even '= argument' (case of the conversion-constructor).
      - udt_instance:
         Instance of 'UdtName' or compatible (derived type).

   Initializer validity
      - Initializer syntax line (1):
         Valid only if exists none constructor (neither implicit nor 
         explicit).
      - Initializer syntax line (2 or 3):
         Always valid.
         Case of the copy-construction (2) and reference declaration (3).
      - Initializer syntax line (4):
         Valid only if exists an implicit or explicit constructor matching 
         the 'argument_list'.
      - Initializer syntax line (5):
         Valid only if exists none constructor (neither implicit nor 
         explicit), or otherwise if exists at least a constructor (implicit 
         or explicit) matching the 'argument_list'.
      - Initializer syntax line (6 or 7):
         Its validity follows the same rules as that of the initializer 
         syntax line (5) above.

      But the most complex are the rules determining the existence of an 
      implicit constructor depending on the type structure:
         - Apart from the default-constructor and the default 
         copy-constructor, any other type of constructor exists only if it 
         is explicitly defined.
         - For the implicit default-constructor and the implicit 
         copy-constructor, it depends on the type structure, for example 
         they both exist for (main cases):
            - type having or inheriting a member field with a 
            implicit/explicit default-constructor (including member 
            string),
            - or type having a base with an implicit/explicit 
            default-constructor (including type derived from Object),
            - .....,
            - otherwise for example, only a variable member with an 
            initializer itself induces only an implicit 
            default-constructor. but no implicit copy-constructor.

   Description
      When a UDT has an implicit constructor (due to a string member, or a 
      variable member with an initializer itself, or a data member with 
      constructor, or UDT derived from Object, or since fbc version 1.20.0 
      containing a STRING*N field plus another data type field) or an 
      explicit constructor, then a simple initializer as '= ( argument_list 
      )', the first initializer syntax in the list (1), becomes not valid.
      In that case, an advanced initialization can be applied by using a 
      constructor matching the initialization expression of the last four 
      syntaxes in the list (4 to 7).

      The simpler initializer syntax, the first in the list (1), can always 
      be replaced by one of the last four initializer syntaxes in the list 
      (4 to 7), but the contrary does not work.

      The second initializer syntax in the list (2) is the special case of 
      copy-construction. This initializer syntax always works, either by 
      default copy-construction or by the way of a copy-constructor 
      (implicit or explicit).

      The third initializer syntax in the list (3) is the special case of 
      reference declaration which must always have an initializer. This 
      initializer syntax always works if 'udt_instance' is a reference (or 
      a dereferenced pointer).

   Declaration syntax for global symbol
      If using global symbols when declaring UDT object with initializer ('
      Dim Shared' or 'Static [Shared]' or 'Static Var [Shared]', instead of 
      'Dim'), the initializer argument(s) must at least be able to be 
      evaluated at the start of the program so that it can be placed in the 
      .data section:
         - The initializer syntaxes (6) and (7) in the list become no 
         longer valid because the symbol must refer to a dynamic memory 
         block in the heap.
         - The other initializer syntaxes remain valid if the provided 
         argument(s) can be evaluated at compile time. If the initializer 
         must call an existing constructor (implicit or explicit), it is 
         the constructor code, called when the program starts, which writes 
         the "initial" values into the .data section.

   Commented example
   Type UDT1
      Dim As Integer I
      Dim As Integer J
   End Type

   Dim As UDT1 u11 = (1, 2)                  '' default-construction + initialization
   'Dim As UDT1 u12 = UDT1(1, 2)             '' not valid: no Constructor(As Integer, As Integer)
   Dim As UDT1 u13 = Type<UDT1>(1, 2)        '' default-construction + initialization
   Dim As UDT1 Ptr pu14 = New UDT1(1, 2)     '' default-construction + initialization
      Delete pu14
   Dim ByRef As UDT1 ru15 = *New UDT1(1, 2)  '' default-construction + initialization
      Delete @ru15
      
   Dim As UDT1 u16 = u13                     '' default copy-construction
   'Dim As UDT1 u17 = UDT1(u13)              '' not valid: no implicit Constructor(As UDT1)
   Dim As UDT1 u18 = Type<UDT1>(u13)         '' default-construction + initialization
   Dim As UDT1 Ptr pu19 = New UDT1(u13)      '' default-construction + initialization
      Delete pu19
   Dim ByRef As UDT1 ru110 = *New UDT1(u13)  '' default-construction + initialization
      Delete @ru110
   Print

   Type UDT2
      Dim As Integer I = Any
      Dim As Integer J
      Declare Constructor ()
      Declare Constructor (ByVal _I As Integer, ByVal _J As Integer)
   End Type
   Constructor UDT2 ()
      Print "UDT2.Constructor()"
   End Constructor
   Constructor UDT2 (ByVal _I As Integer, ByVal _J As Integer)
      Print "UDT2.Constructor(Byval As Integer, Byval As Integer)"
      This.I = _I
      This.J = _J
   End Constructor

   'Dim As UDT2 u21 = (1, 2)                  '' not valid: exist constructor (due at least to '= Any' initialiser)
   Dim As UDT2 u22 = UDT2(1, 2)               '' call Constructor(As Integer, As Integer)
   Dim As UDT2 u23 = Type<UDT2>(1, 2)         '' call Constructor(As Integer, As Integer)
   Dim As UDT2 Ptr pu24 = New UDT2(1, 2)      '' call Constructor(As Integer, As Integer)
      Delete pu24
   Dim ByRef As UDT2 ru25 = *New UDT2(1, 2)   '' call Constructor(As Integer, As Integer)
      Delete @ru25
      
   Dim As UDT2 u26 = u23                      '' default copy-construction
   'Dim As UDT2 u27 = UDT2(u23)               '' not valid: no implicit Constructor(As UDT2)
   'Dim As UDT2 u28 = Type<UDT2>(u23)         '' not valid: no implicit Constructor(As UDT2)
   'Dim As UDT2 Ptr pu29 = New UDT2(u23)      '' not valid: no implicit Constructor(As UDT2)
   'Dim Byref As UDT2 ru210 = *New UDT2(u23)  '' not valid: no implicit Constructor(As UDT2)
   Print

   Type UDT3
      Dim As Integer I
      Dim As String S
      Declare Constructor ()
      Declare Constructor (ByVal _I As Integer, ByRef _S As Const String)
   End Type
   Constructor UDT3 ()
      Print "UDT3.Constructor()"
   End Constructor
   Constructor UDT3 (ByVal _I As Integer, ByRef _S As Const String)
      Print "UDT3.Constructor(Byval As Integer, Byref As Const String)"
      This.I = _I
      This.S = _S
   End Constructor

   'Dim As UDT3 u31 = (1, "2")                 '' not valid: exist constructor (due at least to string member)
   Dim As UDT3 u32 = UDT3(1, "2")              '' call Constructor(As Integer, As String)
   Dim As UDT3 u33 = Type<UDT3>(1, "2")        '' call Constructor(As Integer, As String)
   Dim As UDT3 Ptr pu34 = New UDT3(1, "2")     '' call Constructor(As Integer, As String)
      Delete pu34
   Dim ByRef As UDT3 ru35 = *New UDT3(1, "2")  '' call Constructor(As Integer, As String)
      Delete @ru35
      
   Dim As UDT3 u36 = u33                       '' default copy-construction
   Dim As UDT3 u37 = UDT3(u33)                 '' call implicit Constructor(As UDT3)
   Dim As UDT3 u38 = Type<UDT3>(u33)           '' call implicit Constructor(As UDT3)
   Dim As UDT3 Ptr pu39 = New UDT3(u33)        '' call implicit Constructor(As UDT3)
      Delete pu39
   Dim ByRef As UDT3 ru310 = *New UDT3(u33)    '' call implicit Constructor(As UDT3)
      Delete @ru310
   Print

   Type UDT4 Extends Object
      Dim As Integer I
      Dim As Integer J
      Declare Constructor ()
      Declare Constructor (ByVal _I As Integer, ByVal _J As Integer)
   End Type
   Constructor UDT4 ()
      Print "UDT4.Constructor()"
   End Constructor
   Constructor UDT4 (ByVal _I As Integer, ByVal _J As Integer)
      Print "UDT4.Constructor(Byval As Integer, Byval As Integer)"
      This.I = _I
      This.J = _J
   End Constructor

   'Dim As UDT4 u41 = (1, 2)                 '' not valid: exist constructor (due at least to Object as base)
   Dim As UDT4 u42 = UDT4(1, 2)              '' call Constructor(As Integer, As Integer)
   Dim As UDT4 u43 = Type<UDT4>(1, 2)        '' call Constructor(As Integer, As Integer)
   Dim As UDT4 Ptr pu44 = New UDT4(1, 2)     '' call Constructor(As Integer, As Integer)
      Delete pu44
   Dim ByRef As UDT4 ru45 = *New UDT4(1, 2)  '' call Constructor(As Integer, As Integer)
      Delete @ru45
      
   Dim As UDT4 u46 = u43                     '' default copy-construction
   Dim As UDT4 u47 = UDT4(u43)               '' call implicit Constructor(As UDT4)
   Dim As UDT4 u48 = Type<UDT4>(u43)         '' call implicit Constructor(As UDT4)
   Dim As UDT4 Ptr pu49 = New UDT4(u43)      '' call implicit Constructor(As UDT4)
      Delete pu49
   Dim ByRef As UDT4 ru410 = *New UDT4(u43)  '' call implicit Constructor(As UDT4)
      Delete @ru410
   Print

   ' Note for static UDT declaration + initializer:
   '    When the initializer expression calling the constructor has only one parameter 'x', example:
   '    'Dim As UDT u = UDT(x)', in this case, 'UDT(x)' can be shortened into '(x)' or even 'x', like:
   '    'Dim As UDT u = (x)' or even 'Dim As UDT u = x', but all these statements call the constructor.
   '    (a constructor with one parameter is called a conversion-constructor)

   ' The six below declarations + initialisers all call only the conversion-constructor

   Type UDT5
      Dim As Integer I
      Declare Constructor ()
      Declare Constructor (ByVal _I As Integer)
   End Type
   Constructor UDT5 ()
      Print "UDT5.Constructor()"
   End Constructor
   Constructor UDT5 (ByVal _I As Integer)
      Print "UDT5.Constructor(Byval As Integer)"
      This.I = _I
   End Constructor

   Dim As UDT5 u51 = UDT5(1)                  '' call Constructor(As Integer)
   Dim As UDT5 u52 = Type<UDT5>(1)            '' call Constructor(As Integer)
   Dim As UDT5 u53 = (1)                      '' call Constructor(As Integer)
   Dim As UDT5 u54 = 1                        '' call Constructor(As Integer)
   Dim As UDT5 Ptr pu55 = New UDT5(1)         '' call Constructor(As Integer)
      Delete pu55
   Dim ByRef As UDT5 ru56 = *New UDT5(1)      '' call Constructor(As Integer)
      Delete @ru56
      
   Dim As UDT5 u57 = u54                      '' default copy-construction
   'Dim As UDT5 u58 = UDT5(u54)               '' not valid: no implicit Constructor(As UDT5)
   'Dim As UDT5 u59 = Type<UDT5>(u54)         '' not valid: no implicit Constructor(As UDT5)
   'Dim As UDT5 Ptr pu510 = New UDT5(u54)     '' not valid: no implicit Constructor(As UDT5)
   'Dim Byref As UDT5 ru511 = *New UDT5(u54)  '' not valid: no implicit Constructor(As UDT5)
   Print

   Sleep
         

   Note:
      In the -lang fb only, 'Var' can be used instead of 'Dim' (removing 
      the explicit type declaration), but it must not have ambiguity on the 
      type of the initializer value.
      In the previous example, only 'Var u11 = (1, 2)' does not work, but 
      'Var u13 = Type<UDT1>(1, 2)' works.

Back to top

3. Initializer syntax and validity for array declaration
   The array can be of any DataType.

   Initializer syntax
      1 basic syntax is described below.
      (arrays of references is not supported presently)

      Dim array_symbol ([lbound To] ubound) [AS DataType] = { expression [, 
      ...] }

   Parameter
      - 'lbound', 'ubound':
         Constant numeric values.
      - 'expression(s)':
         List given in comma delimited items, then enclosed by curly 
         brackets.
         Initialization list ordered from 'lbound' to 'ubound'.
         Must produce evaluated values of 'DataType' type or compatible.

   Initializer validity
      'lbound' and 'ubound' must be constant numeric values because 
      variable-length (dynamic) array declaration does not support any 
      initializer.
      Only fixed-length (static) array declaration supports an initializer.

   Declaration syntax for global symbol
      If using global symbols when declaring array variable with 
      initializer ('Dim Shared' or 'Static [Shared]', instead of 'Dim'), 
      the initializer argument(s) must at least be able to be evaluated at 
      the start of the program so that it can be placed in the .data 
      section:
         - The initializer syntaxe for fixed-length (static) array of 
         variable-length string become no longer valid because the symbol 
         must refer to a dynamic memory block in the heap.
         - For the fixed-length (static) arrays of other pre-built type 
         variables, the initializer syntaxe remains valid if the provided 
         expression(s) can be evaluated at compile time.

   Example
   Dim array(0 To 4) As String = {"array(0)", "array(1)", "array(2)", "array(3)", "array(4)"}

   For I As Integer = 0 To 4
      Print array(I),
   Next I
   Print

   Sleep
         

   Note:
      Even in the -lang fb, 'Var' can not be used instead of 'Dim', because 
      'Var' does not support the array declaration.

Back to top

4. Nested Initializer syntax with another
   These methods of initializing variables can be nested within one another 
   for complex assignments.
   For instance, to initialize a multidimensional array:
   Dim array(1 To 3, 1 To 5) As Integer = _
      { _
         {11, 12, 13, 14, 15}, _
         {21, 22, 23, 24, 25}, _
         {31, 32, 33, 34, 35} _
      }

   For I As Integer = 1 To 3
      For J As Integer = 1 To 5
         Print array(I, J),
      Next J
      Print
   Next I

   Sleep
         
In this declaration, the values for the left-most dimension are given as 
5-index arrays.
      Nesting allows for arrays of any dimension to be initialized.

   UDTs and arrays can be nested within each other as well.
   For instance, the following code declares and initializes an array of 
   UDTs:
   Type mytype
      var1 As Double
      var2 As Integer
      var3 As ZString Ptr
   End Type

   Dim MyVar(0 To 1) As mytype = _
      { _
         (1.1, 1, @"Hello"), _
         (2.2, 2, @"GoodBye") _
      }

   For I As Integer = 0 To 1
      Print MyVar(I).var1, MyVar(I).var2, *MyVar(I).var3
   Next I

   Sleep
         

   Note:
      Even in the -lang fb, 'Var' can not be used instead of 'Dim', because 
      'Var' does not support the array declaration.

Back to top

Dialect Differences
   * In the -lang qb dialect, variables cannot be initialised.
   * In the -lang fblite dialect, the explicit type declaration can be 
     omitted in 'Dim ... = ...', but only for the Integer type (initializer 
     value must match the Integer type).

Differences from QB
   * Variable Initializers are new to FreeBASIC.
   * The alternate syntax 'Dim [Byref] As DataType symbolname = ...' is 
     new to FreeBASIC.

See also
   * Implicit declarations
   * Constant Expressions
   * Dim
   * Shared
   * Static
   * Var



--------------------------------------------------- ProPgStorageClasses ----
Storage Classes

Visibility and lifetime of variables, objects and arrays

A variable, object or array's storage class determines when and where 
memory is allocated for it and when that memory is destroyed. There are 2 
storage classes in FreeBASIC: automatic and static.

Automatic

   Automatic variable, object and array lifetimes begin at the point of 
   declaration and end when leaving the scope they are declared in.

   Automatic entities are guaranteed to have unique storage for each 
   instance of the block in which they are declared. For example, the 
   automatic variables declared within a procedure will be allocated at 
   different addresses and have unique state (value) for each call to the 
   procedure.

   Automatic variables, objects and arrays are defined using the Dim, ReDim 
   and Var keywords without the Shared specifier.

   The memory for automatic variables, objects and arrays is allocated on 
   the program stack.

   Automatic variables, objects and arrays have no linkage.

Static

   Static variable, object and array lifetimes begin at program creation 
   and end with program termination.

   Static entities are guaranteed to have the same storage for each 
   instance of the block in which they are declared. For example, the 
   static variables declared within a procedure will be allocated at the 
   same address, and retain their state (value) across each call to the 
   procedure.

   Static variables, objects and arrays are declared using the Static 
   keyword. Entities declared using the Shared specifier are implicitly 
   static. All entities declared within a procedure that is declared using 
   the Static specifier are also implicitly static.

   The memory for static variables, objects and arrays is allocated in the 
   .BSS section of the executable, or in the .DATA section if they are 
   initialized when defined. Static variable-length arrays must be declared 
   empty, with an empty subscript range list; their element data is still 
   allocated in the free store (when they are resized), but the internal 
   array data is allocated in the .DATA section of the executable to allow 
   the element data to persist throughout program execution.

   Static variables, objects and arrays have internal linkage by default, 
   unless previously declared using the Extern or Common keywords.

Platform Differences
   *  In DOS and Windows platforms, the size of the program stack can be 
     adjusted at compile-time using the -t command-line switch. In Linux 
     platforms, the size of the program stack can be adjusted at load-time 
     by modifying /etc/security/limits.conf, or on a per-thread basis using 
     the shell builtin ulimit.

Differences from QB
   * QuickBASIC allows static entities to be declared within procedures 
     and DEF FN routines only.

See also
   * Extern, Common
   * Dim, ReDim, Var, Shared, Byref (Variables)
   * Static
   * Linkage



---------------------------------------------------- ProPgVariableScope ----
Variable Scope

Visibility and access rules for variables and objects

A variable's scope refers to its visibility in a program. A variable is not 
visible (cannot be accessed) outside the scope in which it was declared. 
Where and how a variable is declared determines its scope.

   In FreeBASIC, there are 4 categories of scope: local, shared, common and 
   common shared. Each of these scopes has different visibility rules, 
   which are detailed below.

Local Scope
   Variables declared in the local scope are visible only in the most local 
   instance of the IF, SELECT, WITH, FOR, WHILE, DO, SCOPE, procedure, or 
   module block in which they are declared.

   * Sub, Function, the main body, and each compound statement implicitly 
     define a new local scope block. 
   * Explicitly declared variables using Dim or ReDim or Static take the 
     scope of the local most block in which they are declared. 
   * Implicit variables take the scope of the the local most 
     Scope...End Scope block in which they are first used, otherwise take 
     the scope of the Sub, Function, or main body in which they are used. 

   In the local scope, there is no visibility between module-level code and 
   procedure level code. Furthermore, variables dimensioned within a block 
   decision or loop statement will only be visible within the block in 
   which they are dimensioned. Variables declared in the local scope of a 
   module are not visible in any of the procedures within that module. 
   Similarly, local variables declared inside procedures are not visible in 
   the module-level code, nor any other procedure within the module.

   Variables declared inside Scope blocks may only be declared of local 
   scope, and are not visible outside the block. Scope blocks, however, 
   inherit the surrounding scope, so local variables declared outside the 
   Scope block will be visible inside (see example program).

   You can declare a variable to be of local scope explicitly by using the 
   Dim statement, or implicitly (for only -lang qb and -lang fblite 
   dialects) by simply introducing the variable (see Implicit Declarations
   ). The example program local.bas demonstrates visibility rules for the 
   local scope.

local.bas
   '' visible only in this module
   Dim As Integer local_moduleLevel1

   '' OK.
   Print local_moduleLevel1

   Scope
     '' OK; SCOPE Blocks inherit outer scope
     Print local_moduleLevel1
     
     '' visible only in this SCOPE Block
     Dim As Integer local_moduleLevel2

     '' OK.
     Print local_moduleLevel2
   End Scope

   '' Error; can't see inner-SCOPE vars
   '' print local_moduleLevel2

   Function some_function( ) As Integer
     '' visible only in this function
     Dim As Integer local_functionLevel

     '' OK.
     Print local_functionLevel

     '' Error; can't see local module-level vars  
     '' print local_moduleLevel1

     '' Error; can't see local module-level vars
     '' print local_moduleLevel2

     Function = 0

   End Function

   '' print local_functionLevel                    '' Error; can't see function_level vars
   End 0

Shared Scope
   Variables declared in the shared scope of a module are visible to both 
   the module and all procedures of that module.

   Unlike the local scope, the shared scope makes module-level variables 
   visible to procedures of that module. In other words, the module shares 
   its declarations with its procedures.

   Variables can only be declared to be of shared scope at the 
   module-level. Ie., only modules can share variables. Neither procedures 
   nor Scope blocks can declare variables in the shared scope, thus 
   variables declared there can only be local to that procedure or block.

   You can declare a variable to be of shared scope by using the DIM (or 
   REDIM or STATIC) statement with the Shared keyword. The example program 
   shared_scope.bas demonstrates visibility rules for the shared scope.

shared.bas
   '' visible throughout this module
   Dim Shared As Integer shared_moduleLevel1

   '' OK.
   Print shared_moduleLevel1

   Scope
     '' OK; can see outer-scope vars
     Print shared_moduleLevel1
     
     '' Error; SCOPE-level vars cannot be shared
     '' dim shared as integer shared_ModuleLevel2
   End Scope

   End 0

   Function some_function( ) As Integer
     '' OK; can see shared module-level vars
     Print shared_moduleLevel1

     '' Error; function-level vars cannot be shared  
     '' dim shared as integer sharedFunctionLevel

     Function = 0
   End Function

Common Scope
   Variables declared in the common scope are visible to all modules.

   Variables declared with Common are visible to other modules with a 
   matching Common variable declaration.  The variable name declared must 
   match from between modules.

module1.bas
   '' compile with:
   ''    fbc -lang qb module1.bas module2.bas

   '$lang: "qb"

   Declare Sub Print_Values()
   Common m1 As Integer
   Common m2 As Integer
                    ' This is executed after all other modules
   m1 = 1

   Print "Module1"       
   Print "m1 = "; m1     ' m1 = 1 as set in this module
   Print "m2 = "; m2     ' m2 = 2 as set in module2

   Print_Values

module2.bas
   Common m1 As Integer
   Common m2 As Integer

   m2 = 2

   Print "Module2"       ' This is executed first
   Print "m1 = "; m1     ' m1 = 0 (by default)
   Print "m2 = "; m2     ' m2 = 2

   Sub Print_Values()
     Print "Module2.Print_Values"
     Print "m1 = "; m1   ' Implicit variable = 0, because '-lang qb' use
     Print "m2 = "; m2   ' Implicit variable = 0, because '-lang qb' use
   End Sub

Output:

     Module2
     m1 = 0
     m2 = 2
     Module1
     m1 = 1
     m2 = 2
     Module2.Print_Values
     m1 = 0
     m2 = 0

Common Shared Scope
   Variables declared in the common shared scope are visible to all modules 
   and all procedures of those modules.

   Variables declared with Common are visible to other modules with a 
   matching Common variable declaration.  The variable name declared must 
   match from between modules.  Within a module the Shared declaration 
   modifier gives the variable module scope and makes the variable visible 
   to all subs and functions.

module3.bas
   '' compile with:
   ''    fbc module3.bas module4.bas

   Declare Sub Print_Values()
   Common m1 As Integer
   Common m2 As Integer

   '' This is executed after all other modules
   m1 = 1

   Print "Module3"       
   Print "m1 = "; m1     '' m1 = 1 as set in this module
   Print "m2 = "; m2     '' m2 = 2 as set in module2

   Print_Values

module4.bas
   Common Shared m1 As Integer
   Common Shared m2 As Integer

   m2 = 2

   Print "Module4"       '' This is executed first
   Print "m1 = "; m1     '' m1 = 0 (by default)
   Print "m2 = "; m2     '' m2 = 2

   Sub Print_Values()
     Print "Module4.Print_Values"
     Print "m1 = "; m1   '' m1 = 1    
     Print "m2 = "; m2   '' m2 = 2
   End Sub

Output:

     Module4
     m1 = 0
     m2 = 2
     Module3
     m1 = 1
     m2 = 2
     Module4.Print_Values
     m1 = 1
     m2 = 2

Example
   See examples above.

See also
   * Scope
   * Dim
   * Common
   * Shared
   * Variables
   * Implicit Declarations
   * Simple Variable Lifetime vs Scope
   * Dynamic Object and Data Lifetime



------------------------------------------------- ProPgVariableLifetime ----
Simple Variable Lifetime vs Scope

Lifetime of Simple Variable, created from declaration keyword for static 
memory allocation, relative to its Scopes.

Preamble:

   * The Lifetime of a variable is the time period in which the variable 
     has valid memory (the Scope referring to the program part where its 
     name is visible). The value of a variable may change during its 
     lifetime, but it retains some consistent value.
   * The simple variables considered are the predefined variables 
     including the raw pointers, and the fixed-length strings/arrays, but 
     excluding the variable-length strings/arrays. Instances of simple UDT 
     (without any dynamic data allocated) are also considered.
   * The declaration keywords for static memory allocation are: 'Dim', 
     'Static', 'Var'.

   For such variables allocated in static way as defined above, the 
   lifetime generally matches the surrounding scope, otherwise it can be 
   greater than this one.

Declaration syntax for a lifetime matching the surrounding scope
   For such variables declared anywhere, as follows (or similar syntax):
            (1)	Dim Shared As datatype [Ptr] variablename ...
         or
            (2)	Var Shared variablename = expression
                  (equivalent to: 'Dim Shared As TypeOf((expression)) = 
                  expression')
      or
            (3)	{Dim|Static} Shared As datatype [Ptr] variablename ...
         or
            (4)	[Static] Var Shared variablename = expression
                  (equivalent to: '{Dim|Static} Shared As TypeOf((
                  expression)) = expression')
         or
            (5)	Common [Shared] As datatype [Ptr] variablename
   they always have a lifetime matching their surrounding scope (global 
   scope, or scope block, or compound statement block, or procedure scope).

   With (1) or (2) syntax, the local variable is always allocated on the 
   program stack at the time of its declarations, and is automatically 
   deallocated when going out its scope.
   With (3) or (4) or (5) syntax, the global variable is always allocated 
   in the .BSS or .DATA section of the executable (its scopes and lifetimes 
   begins at program creation and ends with program termination).

Declaration syntax for a lifetime that may be greater than the surrounding 
scope
   For such variables declared anywhere, as follows (or similar syntax):
         Static Shared As datatype [Ptr] variablename ...
         Static Var Shared variablename = expression
   they always have a lifetime equal to the program duration, so greater 
   than their surrounding scope if there are declared in any local scope 
   block (matching their surrounding scope if there are declared in the 
   global scope).

   The static variable is always allocated in the .BSS or .DATA section of 
   the executable (its lifetimes begins at program creation and ends with 
   program termination).

   Interest of declaring such static variables in a compound instruction 
   block or in a procedure scope:
      - As for 'Dim', the 'Static' keyword is used in a compound statement 
      block or in a procedure scope to declare variables whose scope stops 
      at the end of the compound statement block or the procedure.
      - However, unlike 'Dim', the lifetime differs because the variables 
      declared with the 'Static' keyword retain their value between the 
      successive loops of the compound instruction block or the successive 
      calls to the procedure.
      - In summary, a declared static variable has a local scope, but its 
      lifetime is comparable to that of a global scope variable.
      - So, static variables with the same name can be declared in several 
      different compound statement blocks and in different procedure 
      scopes. Each of these variables therefore remains independent and 
      retains its own value in its own local scope.

Example
   Lifetime's comparison between different variables declared in a local 
   scope:
   local variable vs static variable, both declared in a procedure scope
   Dim Shared As ZString Ptr pzl ' global variable to memorize the local Zstring address
   Dim Shared As ZString Ptr pzs ' global variable to memorize the static Zstring address

   Declare Sub prntSubString (ByVal p As ZString Ptr, ByVal size As Integer)

   Sub s ()                                          ' beginning of procedure scope
      Dim As ZString * 15 zl = "local variable"     ' declare/initialize a local Zstring
      pzl = @zl                                     ' memorize the local Zstring address
       
      Static As ZString * 16 zs = "static variable" ' declare/initialize a static Zstring
      pzs = @zs                                     ' memorize the static Zstring address
       
      Print "     From inside the procedure scope:"
      prntSubString(pzl, 14)                        ' display address/content of the local zstring
      prntSubString(pzs, 15)                        ' display address/content of the static zstring
   End Sub                                           ' end of procedure scope

   Print "Lifetimes comparison between local/static variables declared in a local scope:"
   s() ' call the procedure

   Print "     From outside the procedure scope:"
   prntSubString(pzl, 14) ' display address/content of the local zstring after going out its scope
   prntSubString(pzs, 15) ' display address/content of the static zstring after going out its scope

   Sleep

   Sub prntSubString (ByVal p As ZString Ptr, ByVal size As Integer)
      Print , "&h" & Hex(p, SizeOf(Any Ptr) * 2),
      Print """";
      For I As Integer = 0 To size - 1
         Dim As UByte u = (*p)[I]
         If u < Asc(" ") Then
            Print " ";
         Else
            Print Chr(u);
         End If
      Next I
      Print """"
   End Sub
            
Output example:

   Lifetimes comparison between Local/Static variables declared in a Local Scope:
   	 From inside the procedure Scope:
   			  &h0019FE74    "local variable"
   			  &h00407004    "static variable"
   	 From outside the procedure Scope:
   			  &h0019FE74    " p@ Ã‡p@ Â¿â–   Y "
   			  &h00407004    "static variable"

 
See also
   * Dim, Static, Var
   * Storage Classes
   * Variable Scope
   * Dynamic Object and Data Lifetime



--------------------------------------------------- ProPgObjectLifetime ----
Dynamic Object and Data Lifetime

Lifetime of Dynamic Object and its Data, created from declaration keyword 
for dynamic memory allocation.

Preamble:

   * The Lifetime of an object (and of its data) is the time period in 
     which its identifier variable exists (and refers to valid data). But 
     in absolute terms, the identifier variable of the object and its 
     associated data can have two independent lifetimes (the Scope 
     referring to the program part where the identifier variable is 
     visible).
   * The dynamic objects considered are the predefined pseudo-objects such 
     as the variable-length strings/arrays, and the instances of complex 
     UDT (with its own dynamic data allocated).
   * Simple variables but allocated in a dynamic way are also considered, 
     and finally the dynamic objects which are allocated as well in a 
     dynamic way.
   * The declaration keywords for dynamic memory allocation are: 
     'Allocate'/'Callocate'/'Reallocate', 'New', 'ImageCreate' (for 
     deallocation: 'Deallocate', 'Delete', 'ImageDestroy').

   For such objects and data dynamically allocated as defined above, the 
   lifetime of the identifier variable of the object generally matches the 
   surrounding scope (otherwise it can be greater than this one), but the 
   lifetime of associated data may mismatch this one because the 
   allocation/deallocation of associated data is triggered by the user 
   himself.

Case of predefined pseudo-objects allocated in a static way by user
   Even though these predefined type variables (variable-length strings (1)
   , or variable-length arrays (2)) are allocated in a static way as 
   follows (or similar syntax):
         (1)	Dim [Shared] As String stringname ...
      or
         (2)	Dim [Shared] As datatype arrayname() ...
   these variables can be considered as dynamic pseudo-objects because they 
   are assemblies of two entities:
      - a descriptor associated to the identifier variable (stringname (1), 
      or arrayname() (2)), the first entity
      - referencing a dynamic allocation in memory (the string data (1), or 
      the array data (2)), the second entity (unnamed).

   The descriptor is allocated in the .BSS or .DATA section, if 'Shared' is 
   used, otherwise on the program stack.
   The string data are allocated/reallocated/deallocated in the heap by 
   string assigning, also updating the descriptor accordingly (assigning an 
   empty string does not destroy the descriptor but just resets it).
   The array data are allocated/reallocated in the heap by 'Redim' and 
   deallocated by 'Erase', also updating the descriptor accordingly 
   ('Erase' does not destroy the descriptor but just re-initializes it).
   So whatever such a user command applied, the identifier variable remains 
   always defined in its scope, at cons the memory allocation can be 
   dynamically modified/freed in this same scope (accordingly to the user 
   command).

Case of dynamic objects allocated in a static way by user
   The user can also define a dynamic object through a complex UDT with 
   member procedures to allocate/reallocate/deallocate dynamic data 
   associated to it.
   The member procedures normally used to perform this are the constructors 
   (for allocation), the assignment operators (for reallocation) and the 
   destructor (for deallocation).

   Even if the object identifier variable is allocated in a static way 
   (similarly to above):
      Dim [Shared] As complexUDT instancename ...
   inducing automatic allocation and deallocation of object data following 
   the identifier variable scope (by means of implicit call to UDT 
   constructor then destructor), between the two, the dynamic data 
   allocation can be deeply impacted by user commands (such as explicit 
   calls to operators overloaded for the UDT).

Case of simple variables but allocated in a dynamic way by user
   The keywords ('Allocate', 'Reallocate', 'New', 'ImageCreate'), used to 
   declare a dynamic allocation, create an unnamed entity whose the 
   lifetime depends on other user commands ('Deallocate', 'Delete', 
   'ImageDestroy').
   Generally, these allocation keywords are included in expressions used to 
   initialize (1|3), or assign (2|4), a simple variable (a pointer (1|2), 
   or a reference (3|4)), as for example:
            (1)	Dim As datatype Ptr DATApointername = New datatype ...
         or
            (2)	Dim [Shared] As datatype Ptr DATApointername
            (2)	.....
            (2)	DATApointername = New datatype ...
      or
            (3)	Dim ByRef As datatype DATAreferencename = *New datatype ...
         or
            (4)	Dim [Shared] ByRef As datatype DATAreferencename = *CPtr(
            datatype Ptr, 0)
            (4)	.....
            (4)	@DATAreferencename = New datatype ...

   Therefore, in this case, there are two distinct entities:
      - a named pointer (1|2) or a reference (3|4), the first entity,
      - pointing (1|2) or referring (3|4) to an allocated memory, the 
      second entity (unnamed).

   Do not confuse the two entities, each has its own lifetime.
   'Deallocate', 'Delete', 'ImageDestroy', deallocating only the second 
   entity (not the first), as for example using:
         (1|2)	Delete DATApointername
      or
         (3|4)	Delete @DATAreferencename

Case of dynamic objects allocated as well in a dynamic way by user
   The dynamic object (complex UDT) can also be allocated as well in a 
   dynamic way (similarly to above), by initializing (1|3), or assigning 
   (2|4), a simple variable (a pointer (1|2), or a reference (3|4)), as for 
   example:
            (1)	Dim As complexUDT Ptr UDTpointername = New complexUDT ...
         or
            (2)	Dim [Shared] As complexUDT Ptr UDTpointername
            (2)	.....
            (2)	UDTpointername = New complexUDT ...
      or
            (3)	Dim ByRef As complexUDT UDTreferencename = *New complexUDT 
            ...
         or
            (4)	Dim [Shared] ByRef As complexUDT UDTreferencename = *CPtr(
            complexUDT Ptr, 0)
            (4)	.....
            (4)	@UDTreferencename = New complexUDT ...

   Therefore, in this last case, three entities can be considered:
      - a named pointer (1|2) or a reference (3|4), the first entity,
      - pointing (1|2) or referring (3|4) to the allocated fields of the 
      object, the second entity (unnamed),
      - and addressing the dynamic allocated associated data, the third 
      entity (unnamed).

   Do not confuse the three entities, each has its own lifetime.
   'Delete' deallocates the second entity (not the first), which begins to 
   deallocate the third at first (by calling its destructor), as for 
   example using:
         (1|2)	Delete UDTpointername
      or
         (3|4)	Delete @UDTreferencename

Example
   Dynamic object (complex UDT) allocated as well in a dynamic way by user:
      - first entity: the UDT reference, statically allocated on the 
      program stack,
      - second entity: the UDT instance with its zstring pointer field 
      (referred by the UDT reference), dynamically allocated in the heap by 
      the user,
      - third entity: the zstring data (referred by the zstring pointer 
      field), dynamically reallocated in the heap by the UDT procedure 
      members (constructors, let operator, destructor).
   Type complexUDT
      Public:
         Declare Constructor ()
         Declare Constructor (ByVal p As ZString Ptr)
         Declare Operator Let (ByVal p As ZString Ptr)
         Declare Operator Cast () As String
         Declare Property info () As String ' allocation address, allocation size, string length
         Declare Destructor ()
      Private:
         Dim As ZString Ptr pz
   End Type

   Declare Sub prntInfo_printString (ByRef u As complexUDT)
     
     
   Print "'Dim Byref As complexUDT ref = *New complexUDT(""Beginning"")':"
   Dim ByRef As complexUDT ref = *New complexUDT("Beginning")
   prntInfo_printString(ref)

   Print "'ref = """"':"
   ref = ""
   prntInfo_printString(ref)

   Print "'ref = ""FreeBASIC""':"
   ref = "FreeBASIC"
   prntInfo_printString(ref)

   Print "'ref = ""Programmer's Guide / Declarations / Dynamic Object and Data Lifetime""':"
   ref = "Programmer's Guide / Declarations / Dynamic Object and Data Lifetime"
   prntInfo_printString(ref)

   Print "'ref.Destructor()':"
   ref.Destructor()
   prntInfo_printString(ref)

   Print "'ref.Constructor()':"
   ref.Constructor()
   prntInfo_printString(ref)

   Print "'ref.Constructor(""End"")':"
   ref.Constructor("End")
   prntInfo_printString(ref)

   Print "'Delete @ref':"
   Delete @ref
   @ref = 0 ' systematic safety to avoid double-delete on same allocation

   Sleep

   Constructor complexUDT ()
      Print "    complexUDT.Constructor()"
      This.pz = Reallocate(This.pz, 1)
      (*This.pz)[0] = 0
   End Constructor

   Constructor complexUDT (ByVal p As ZString Ptr)
      Print "    complexUDT.Constructor(Byval As Zstring Ptr)"
      This.pz = Reallocate(This.pz, Len(*p) + 1)
      *This.pz = *p
   End Constructor

   Operator complexUDT.Let (ByVal p As ZString Ptr)
      Print "    complexUDT.Let(Byval As Zstring Ptr)"
      This.pz = Reallocate(This.pz, Len(*p) + 1)
      *This.pz = *p
   End Operator

   Operator complexUDT.Cast () As String
      Return """" & *This.pz & """"
   End Operator

   Property complexUDT.info () As String
      Return "&h" & Hex(This.pz, SizeOf(Any Ptr) * 2) & ", " & _     ' allocation address
            Len(*This.pz) + Sgn(Cast(Integer, This.pz)) & ", " & _ ' allocation size
            Len(*This.pz)                                          ' string length
   End Property

   Destructor complexUDT ()
      Print "    complexUDT.Destructor()"
      This.pz = Reallocate(This.pz, 0)
   End Destructor

   Sub prntInfo_printString (ByRef u As complexUDT)
      Print "        " & u.info
      Print "        " & u
      Print
   End Sub
            
Output:

   'Dim Byref As complexUDT ref = *New complexUDT("Beginning")':
   	complexUDT.Constructor(ByVal As ZString Ptr)
   		&h001F2AD0, 10, 9
   		"Beginning"

   'ref = ""':
   	complexUDT.Let(ByVal As ZString Ptr)
   		&h001F2AD0, 1, 0
   		""

   'ref = "FreeBASIC"':
   	complexUDT.Let(ByVal As ZString Ptr)
   		&h001F2AD0, 10, 9
   		"FreeBASIC"

   'ref = "Programmer's Guide / Declarations / Dynamic Object and Data Lifetime"':
   	complexUDT.Let(ByVal As ZString Ptr)
   		&h001F2AD0, 69, 68
   		"Programmer's Guide / Declarations / Dynamic Object and Data Lifetime"

   'ref.Destructor()':
   	complexUDT.Destructor()
   		&h00000000, 0, 0
   		""

   'ref.Constructor()':
   	complexUDT.Constructor()
   		&h001F2AD0, 1, 0
   		""

   'ref.Constructor("End")':
   	complexUDT.Constructor(ByVal As ZString Ptr)
   		&h001F2AE0, 4, 3
   		"End"

   'Delete @ref':
   	complexUDT.Destructor()

See also
   * Allocate, CAllocate, Reallocate, Deallocate
   * New (Expression), Delete (Statement)
   * ImageCreate, ImageDestroy
   * ReDim, Erase
   * Storage Classes
   * Variable Scope
   * Simple Variable Lifetime vs Scope



------------------------------------------------------- ProPgNamespaces ----
Namespaces

Namespace, a container for identifiers so that they don't conflict with 
those in other Namespaces or the global scope.

Syntax
   Namespace identifier [ Alias "aliasname" ]
      statements
   End Namespace

Parameters
   identifier
      The name of the Namespace (including nested names specifier).
   aliasname
      An alternate external name for the Namespace.

Description
   Namespaces are declaration fields that allow to delimit the search for 
   the names of identifiers by the compiler. Their purpose is essentially 
   to group the identifiers logically and to avoid name conflicts between 
   several parts of the same project.
   This type of conflict stems from the fact that only one global scope is 
   provided by default, in which there should be no name conflict. With 
   Namespaces, this type of problem can be more easily avoided, because 
   defining global objects in the global scope can be avoid.

   Namespaces are not allowed to contain code directly, only inside 
   procedures declared in that Namespace. That is because a Namespace is 
   not a scope, it is not something that is executed, it is just something 
   that can be used to hold declarations.

   Any variable declared in Namespace is implicitly static and visible 
   throughout the entire program (Static and Shared keywords are useless). 
   Therefore only an initializer with a constant is authorized.

Usage
   Unlike another declarative region such as a Type, a Namespace can be 
   split into several pieces. The first piece serves as declaration, and 
   the following ones as extensions. The syntax for a Namespace extension 
   is exactly the same as that for the declaration part.
   Identifiers declared or defined within the same Namespace must not 
   conflict. They may have the same names, but only as part of the 
   overloading. A Namespace therefore behaves exactly like the declaration 
   fields of Types and the global scope.

   Access to Namespace identifiers is through the resolution operator 
   ("."), by prefixing the name of the identifier to use from the name of 
   its Namespace. However, this prefixing is useless inside the Namespace 
   itself, just like members inside their Type.
   Namespace member procedures can be defined inside this space. They can 
   also be set outside this space, if the resolution operator is used 
   (prefixing from the name of its Namespace). The procedures thus defined 
   must appear after their declarations in the Namespace.

   It is possible to define a Namespace within another Namespace. However, 
   this declaration must occur at the outermost declarative level of the 
   Namespace that will contain the Namespace. Namespace declarations can 
   not be put inside a procedure body or inside a Type block.

   When a Namespace has a very complicated name, it may be advantageous to 
   define an alias for that name. The alias will then have a simpler name.
   Names given to Namespace aliases  must not conflict with the names of 
   other identifiers in the same Namespace, whether this is the global 
   scope or not.

   Note: The parser allows to define anonymous Namespaces (without 
   identifier term), but this is the only similarity with the actual C++ 
   capability: The FB compiler automatically generates multiple separate 
   anonymous Namespaces instead of one only per module in such a case.
   The FB anonymous Namespaces are almost unusable because all their 
   declarations are inaccessible, even from the body of the module that 
   contains them. Apart from encapsulating module constructors/destructors 
   also inside, nothing else can be done with them.

   'Using (Namespaces)' command
      Using (Namespaces) allows to use a identifier from a Namespace in a 
      simplified way, without having to specify its full name (that is, the 
      Namespace name followed by the "." operator then the identifier 
      name).
      Each Using command allows to directly use all the identifiers of the 
      referred Namespace.

      - Syntax:
         Using identifier [, identifier [, ...] ]

      - Parameters:
         identifier: The name of the Namespace to use.

      - Usage:
         After a Using command, it is still possible to use the full names 
         of the identifiers from a Namespace, but this is no longer 
         necessary. The Using commands are valid from the line where they 
         are declared until the end of the current scope block.
         If a Namespace is extended after a Using directive, the 
         identifiers defined in the Namespace extension can be then used 
         exactly as the identifiers defined before the using directive 
         (that is, without the full expression of their Namespace names).

         When entering Using command(s) for several Namespace names, name 
         conflicts may occur. In this case, no error is reported from the 
         Using command(s), but an error occurs if one of the identifiers 
         for which there is a conflict is used (using full name of the 
         expected identifier solves the conflict).

Example
   Namespace extension:
   Namespace A  ' Declaration of Namespace A
      Dim As Integer i
   End Namespace

   Namespace B  ' Declaration of Namespace B
      Dim As Integer i
   End Namespace

   Namespace A  ' Extension of Namespace A
      Dim As Integer j
   End Namespace

   Access to Namespace members:
   Dim As Integer i  ' Declare i in the global scope

   Namespace A
      Dim As Integer i = 2  ' Declare i in Namespace A
      Dim As Integer j = 3  ' Declare j in Namespace A
   End Namespace

   i = 1    ' Use i from global scope (.i)
   A.i = 4  ' Use i from Namespace A (A.i)

   External definition of a function declared in a Namespace:
   Namespace A
      Declare Function f () As Integer  ' Declaration of f() in Namespace A (A.f())
   End Namespace

   Function A.f () As Integer  ' Definition of f() from Namespace A (A.f())
      Return 0
   End Function

   Definition of nested Namespace:
   Namespace A
      Dim As Integer i  ' (A.i)
      Namespace B
         Dim As Integer j  ' (A.B.j)
      End Namespace
   End Namespace

   Access with 'Using (Namespaces)' command:
   Namespace A
      Dim As Integer i  ' Declaration of A.i
      Dim As Integer j  ' Declaration of A.j
   End Namespace

   Using A  ' Namespace A identifiers are also used
   i = 1  ' Equivalent to A.i
   j = 1  ' Equivalent to A.j

   Extension of Namespace after 'Using (Namespace)' command:
   Namespace A
      Dim As Integer i
   End Namespace

   Using A

   Namespace A
      Dim As Integer j
   End Namespace

   i = 0  ' Initialize A.i
   j = 0  ' Initialize A.j

   Conflict between local identifiers with 'Using (Namespaces)' command:
   Namespace A
      Dim As Integer i  ' Declare A.i
      Dim As Integer j  ' Declare A.j
   End Namespace

   Namespace B
      Dim As Integer i  ' Declare B.i
      Dim As Integer j  ' Declare B.j
      Using A           ' A.i/j and B.i/j are in conflict, but no error is given
   End Namespace

   Dim As Integer j  ' Declare also j the global scope

   Using B
   'i = 1   ' error: Ambiguous symbol access, explicit scope resolution required (between B.i and A.i)
   B.i = 1  ' ambiguity resolution solved by using full name
   j = 2    ' ambiguity (between .j, B.j, A.j) solved by compiler, by choosing override .j in the global scope

See also
   * Namespace
   * Using (Namespaces)
   * Scope...End Scope



--------------------------------------------------- ProPgVarProcLinkage ----
Variable and Procedure Linkage

Name visibility within and between modules
   Linkage refers to the visibility of the name of a variable, object or 
   procedure between one or more modules of a program. In other words, a 
   linkage dictates how a name is shared between modules. There are two 
   main types of linkage a name can have: internal and external.

Internal linkage
   Names with internal linkage only refer to variables, objects or 
   procedures defined within their own module; they are not outwardly 
   visible to other modules. This means that two or more modules can refer 
   to different things using the same name. Note that linkage only refers 
   to visibility of a name, and depending on storage class and lifetime, a 
   variable, object or procedure with internal linkage may be shared 
   between modules using its address.

   Module-scope declarations

      Variable and object names declared at module-scope have internal 
      linkage unless otherwise declared with Extern or Common. For example, 
      variable names first introduced with Dim or Static have internal 
      linkage, and those variables can only be referred to by name within 
      the module in which they are defined. Note that using Shared only 
      allows name visibility within the module's procedures, and does not 
      contribute to the name's linkage.

      Procedure names declared with Private have internal linkage.

   Local-scope declarations

      All variable and object names declared at local-scope (in a Do loop, 
      or procedure body, for instance) have internal linkage.

External linkage
   Names with external linkage may refer to variables, objects or 
   procedures defined within their module or in another module. Having 
   external linkage means that a name is outwardly visible to other 
   modules, and all modules that use that same external name all refer to 
   the same variable, object or procedure. Thus, only one module may define 
   an external name (the compiler will complain about a duplicated 
   definition if it finds an additional definition of a name with external 
   linkage).

   Module-scope declarations

      Variable and object names declared at module-scope are declared to 
      have external linkage with Extern or Common. 

      Extern declares the variable having external linkage, but does not 
      define it.  This external declaration must come before any definition 
      of the same name (a declaration without Extern specifies internal 
      linkage, and currently, any further external declarations of that 
      name signify a duplicated definition).  Variable and object names 
      with external linkage declared using Extern are always in the shared 
      scope, and so can be referred to within procedure bodies.

      Common declares the variable having external linkage as well as 
      defining the variable.  But, it is different from Extern in that the 
      Common definition of the variable may appear in more than one module. 
      When used with arrays, only variable-length arrays without subscripts 
      may be declared, and the array must be sized at run-time using Dim or 
      ReDim before it can be used.  Variable and object names with external 
      linkage declared using Common are only in the shared scope if the 
      Shared scope specifier is also given.  Shared variables can be 
      referred to within procedure bodies.

      When both Extern and Common are both used to declare and define a 
      variable, the effect is that the meaning of Common statement is 
      altered to behave as though it were a Dim declaration.  So it is 
      generally, not recommended to mix Extern and Common on the same 
      variable in the same module.  However, variables may be declared and 
      defined with Common in one module and then referenced with Extern in 
      another module without confusion.

      Procedure names are declared to have external linkage by default. 
      Declarations using Public explicitly specify external linkage.

   Local-scope declarations

      Currently, names declared at local-scope cannot have external 
      linkage.




============================================================================
    User Defined Types

------------------------------------------------------------- ProPgUDTs ----
User Defined Types

Custom types.

Overview
   User-Defined Types are special kinds of variables which can be created 
   by the programmer.  A User-Defined Type (UDT) is really just a container 
   that contains a bunch of other variables, like an array, but unlike 
   arrays, UDTs can hold different variable types (whereas arrays always 
   hold many variables of the same type).  In fact, UDTs can even have 
   procedures inside of them!

Members
   The different variables and/or procedures stored inside a UDT are called 
   "members", or more generally, items.  Members can be variables of just 
   about any type, including numerical types, strings, pointers, Enums, and 
   even arrays.  Variables are created in UDTs much the same way variables 
   are created 	normally, except that the Dim keyword is optional.  UDT 
   members are accessed via the . Operator, so for example if you created a 
   variable called someVar in a UDT you would access it with the name of 
   the UDT variable followed by ".someVar".  Here is an example:

   'Define a UDT called myType, with an Integer member named someVar
   Type myType
     As Integer someVar
   End Type

   'Create a variable of that type
   Dim myUDT As myType

   'Set the member someVar to 23, then display its contents on the screen
   myUDT.someVar = 23
   Print myUDT.someVar

   Notice that the Type...End Type does not actually create a variable of 
   that type, it only defines what variables of that type contain.  You 
   must create a variable of that type to actually use it!

UDT Pointers
   UDT Pointers are, as the name implies, pointers to UDTs.  They are 
   created like regular pointers, but there is a special way to use them.  
   To access the member of a UDT pointed to by a pointer, you use the 
   -> Operator.  For example, if myUDTPtr is a pointer to a UDT which has a 
   member someVar, you would access the member as myUDTPtr->someVar, which 
   is a much cleaner shorthand for the equally valid (*myUDTPtr).someVar.

   Type rect
      x As Integer
      y As Integer
   End Type

   Dim r As rect
   Dim rp As rect Pointer = @r

   rp->x = 4
   rp->y = 2

   Print "x = " & rp->x & ", y = " & rp->y
   Sleep

UDT Instantiation
   When creating an object of a UDT:
      - only non-static data members induce a specific memory allocation to 
      each object instance,
      - static data members are allocated only once for the UDT and are 
      therefore common to all object instances,
      - procedure members are also defined only once for the UDT and their 
      code is not duplicated for each object instance (and this, even for 
      the non-static procedure members).

   That is why a static variable declared inside any procedure member is 
   allocated only once for the UDT.
   Therefore this static variable is indeed permanent but shared by all UDT 
   instances executing the code (it is not an instance-specific variable).

See also
   * Type Aliases
   * Temporary Types
   * Constructors and Destructors (basics)
   * Member Procedures
   * Member Access Rights and Encapsulation
   * Operator Overloading



------------------------------------------------------ ProPgTypeAliases ----
Type Aliases

Additional names for variable or object types

Overview
Declaration
Overload resolution
Pointers to procedure pointers
Type forwarding
Incomplete types

Overview
   Type aliases are alternative names for a type. They can be used to 
   facilitate a mass change from one type to another, save typing, or make 
   circular dependency possible.

Declaration
   Type aliases are declared using the Type keyword much like declaring 
   variables or objects with Extern or Dim.

   The following example declares a type alias to Single called "float", a 
   procedure, and defines and initializes two variables of that type:

   Type float As Single

   Declare Function Add (a As float, b As float) As float

   Dim foo As float = 1.23
   Dim bar As float = -4.56
         

   Procedure pointer type aliases are declared in the same fashion, as 
   shown in the following example:

   Declare Function f (ByRef As String) As Integer

   Type func_t As Function (ByRef As String) As Integer

   Dim func As func_t = @f
         
   Function f (ByRef arg As String) As Integer
      Function = CInt(arg)
   End Function

Overload resolution
   Type aliases are just that - aliases. For all intents and purposes, a 
   type alias is the type it aliases. So as far as procedure overload 
   resolution is concerned, a procedure declared with a parameter of type "
   alias_to_T" is the same as a procedure declared with a parameter of type 
   "T" (the same applies to overloading member procedures as well).

   In other words, it is an error - duplicated definition - to declare a 
   procedure where parameters differ only in a type and its alias, as the 
   following example shows:

   Type float As Single

   Declare Sub f Overload (a As Single)

   '' If following line is uncommented, this will generate a duplicated definition error
   '' Declare Sub f (a As float)

Pointers to procedure pointers
   Pointers to procedure pointers are just like any other pointer type, 
   except they point to procedure pointers. Because the syntax for 
   declaring procedure pointers doesn't allow directly creating a pointer 
   to procedure pointer when the procedure is a function (because ptr 
   applies on return type and not on procedure), a type alias is used.

   The following example declares a pointer to a procedure returning an 
   integer pointer, and then a pointer to a pointer to a procedure 
   returning an integer:

   Dim pf As Function() As Integer Ptr

   Type pf_t As Function() As Integer
   Dim ppf As pf_t Ptr
      

Type forwarding
   Type aliases can be forward referencing: an alias can refer to some 
   other type not yet fully defined.

   Type foo As bar

   Type sometype
     f   As foo Ptr
   End Type

   Type bar
     st  As sometype
     a   As Integer
   End Type
      

   Using a type alias and forward referencing allows circular dependencies 
   between types.

   Type list As list_

   Type listnode
     parent As list Ptr
     text As String
   End Type

   Type list_
     first As listnode Ptr
     count As Integer
   End Type
      

Incomplete types
    A type is considered incomplete until the size of it, that is the 
   number of bytes it would need to occupy in memory is known, and the 
   offsets of all of its fields are known.  It is not possible to allocate 
   space for an incomplete type.  It is not possible to declare a variable 
   having the data type of an incomplete type, pass an incomplete type as a 
   parameter, or access the members of an incomplete type.

   However, pointers to incomplete types may be allocated, declared as 
   members in other types, or passed as parameters to a procedures since 
   the size of a pointer is known.

   Type sometype As sometype_

   '' Not allowed since size of sometype is unknown
   '' TYPE incomplete
   ''   a AS sometype
   '' END TYPE

   '' Allowed since size of a pointer is known
   Type complete
     a As sometype Ptr
   End Type
   Dim x As complete

   '' Not allowed since size of sometype is still unknown
   '' DIM size_sometype AS INTEGER = SIZEOF( sometype )

   '' Complete the type
   Type sometype_
     value As Integer
   End Type

   '' Allowed since the types are now completed
   Dim size_sometype As Integer = SizeOf( sometype )

   Type completed
     a As sometype
   End Type

   Dim size_completed As Integer = SizeOf( completed )
      

   


--------------------------------------------------------- KeyPgTypeTemp ----
Type (Temporary)

Creates a temporary copy of a user defined type

Syntax
   result = Type( initializers, ... )
      or
   result = Type<typename>( initializers, ... )

Parameters
   initializers
      Initial values for the type (or only the firsts)
   typename
      The name of the Type or Union

Return Value
   A temporary copy of the type.

Description
   Used to create a temporary type.  If typename is not explicitly given, 
   it will be inferred from its usage if possible.  Usage of the temporary 
   copy may include assigning it to a variable, passing it as a parameter 
   to a procedure, or returning it as a value from a procedure.

   For a type without own or inherited constructor (excluding also any type 
   that is directly or indirectly derived from Object), the temporary type 
   syntax is allowed if all type data-fields (including those inherited) 
   are numeric primitives only and without any default initializers.
   If at same time the type is without destructor, the compiler does a 
   direct assignment instead of using a temporary copy.

   The Constructor for the type, if there is one with parameters matching 
   with the initializers provided, will be called when the temporary copy 
   is created, and the Destructor for the type, if there is one, will be 
   called immediately after its use. But when there is a matching 
   constructor, the temporary type expression may be simply replaced by 
   typename( initializers, ... ).
   If there is a constructor at least but none which matches with the 
   initializers, the temporary type syntax is obviously disallowed.

   It can create not only a temporary copy of an user defined type, but 
   also a temporary copy of predefined data-type as a variable-length 
   string or any numeric data-type (all standard data-types excluding 
   fixed-length strings).

   It can also be used as an even shorter shortcut than With (see below) if 
   you are changing all the data-fields (or the n firsts only).

   A temporary object is destroyed at the end of execution of the statement 
   (where it's defined), but its corresponding allocated memory is not 
   released and remains available (unused) until going out the scope where 
   statement is.
   In the particular case where a temporary type is used in a With 
   expression, the destruction of the temporary type is deferred to the end 
   of the With scope.

   Note: Static qualifier used at procedure definition level does not apply 
   to temporary types.

Example
   Type Example
      As Integer field1
      As Integer field2
   End Type

   Dim myexample As Example

   '' Filling the type by setting each field
   myexample.field1 = 1
   myexample.field2 = 2

   '' Filling the type by setting each field using WITH
   With myexample
      .field1 = 1
      .field2 = 2
   End With

   '' Fill the variable's fields with a  temporary type
   myexample = Type( 1, 2 )

   '' Passing a user-defined types to a procedure using a temporary type
   '' where the type can be inferred.

   Type S
     As Single x, y
   End Type

   Sub test ( v As S )
     Print "S", v.x, v.y
   End Sub

   test( Type( 1, 2 ) )

   '' Passing a user-defined type to a procedure using temporary types
   '' where the type is ambiguous and the name of the type must be specified.

   Type S
     As Single x, y
   End Type

   Type T
     As Integer x, y
   End Type

   Union U
     As Integer x, y
   End Union

   '' Overloaded procedure test()
   Sub test Overload ( v As S )
     Print "S", v.x, v.y
   End Sub

   Sub test ( v As T )
     Print "T", v.x, v.y
   End Sub

   Sub test ( v As U )
     Print "U", v.x, v.y
   End Sub

   '' Won't work: ambiguous
   '' test( type( 1, 2 ) )

   '' Specify name of type instead
   test( Type<S>( 1, 2 ) )
   test( Type<T>( 1, 2 ) )
   test( Type<U>( 1 ) )

Differences from QB
   * New to FreeBASIC

See also
   * Type...End Type
   * Type (Alias)



-------------------------------------------------------- ProPgTypeUnion ----
Type (UDT/Alias/Temporary) and Union

The different keywords Type (UDT), Type (Alias), Type (Temporary), and Union
.

Definition
   There may be confusion in the user mind between the different keywords 
   Type and Union (despite the documentation that distinguishes them from 
   each other through some different pages):
      * Type (Udt):
            Declares/Defines a user structure of non overlapping data with 
            possibly member procedures:
               - Named Type: Type that has a name that can be referenced to 
               declare the data type.
               - Anonymous Type: Type that does not have a name and so 
               cannot be referenced by a name.
      * Type(Alias):
            Declares a user defined type name from other user defined or 
            standard data types.
      * Type (Temporary):
            Creates a temporary instance of a user defined type.
      * Union:
            Declares/Defines a user structure of overlapping data with 
            possibly member procedures but no object fields (or bases) with 
            constructors or destructors (directly on indirectly):
               - Named Union: Union that has a name that can be referenced 
               to declare the data type.
               - Anonymous Union: Union that does not have a name and so 
               cannot be referenced by a name.

   Complexity level for a Type/Union structure:
      - Trivial structure: Named or Anonymous structure that has no member 
      procedures (directly on indirectly).
      - Complex structure: Named Structure that has member procedure(s) 
      (directly or indirectly).
      - Extended structure: Named structure that inherits from another 
      named structure.

   Type/Union structure can be also nested inside another Type/Union 
   structure:
      - Nested Named Type: Named Type that is nested inside another Named 
      Type/Union structure.
      - Nested Anonymous Type: Anonymous Type that is nested inside another 
      Named or Anonymous Union structure.
      - Nested Named Union: Named Union that is nested inside another Named 
      Type/Union structure.
      - Nested Anonymous Union: Anonymous Union that is nested inside 
      another Named or Anonymous Type structure.

   Type (Alias) declaration can be also nested inside a Type/Union 
   structure:
      - Nested Type (Alias) declaration allows declaration of an inner 
      alias inside a Type/Union and according to the access right of the 
      place.

Description
   The main purpose of Nested Named Types/Unions is:
      - To allow relationships between Types and Unions to be expressed in 
      an understandable way.
      - Such a Type or Union has its own namespace in which to organize 
      related symbols - and provide visibility access (Public/Protected/
      Private) for Types only - to give finer-grained control over access 
      to members.
      - When there are circular dependencies between Types/Unions, Nested 
      Named Type/Union usage can avoid using Type (Alias) and forward 
      referencing.
   Without Nested Named Types/Unions:
      - Relationships can still be expressed between Types/Unions but have 
      the disadvantage that all Types/Unions must be publicly accessible.
      - Namespace use can help organize scope of visibility but the problem 
      remains that *all* Types/Unions must be visible.
      - In some situations this allows a user (or the author himself) to 
      inadvertently use a Type/Union in a way that it was never intended, 
      potentially creating valid but error-prone code.
      - This problem can be reduced by hiding Types/Unions through of 
      forward declarations (via Type (Alias)) and putting private symbols 
      in a separate module, but creates new problems by fragmenting the 
      code.

   Anonymous Type (or Union):
      - Does not have a name and cannot be referenced by name.
      - May only appear nested within a Named Union (or Type) or another 
      Anonymous Union (or Type) .
      - Declares fields within the structure that nests it, either at 
      separate memory locations (Nested Type) or overlapping memory 
      locations (Nested Union).
      - Fields can be referenced.
      - Cannot contain any static members or procedures declarations 
      (directly or indirectly) => Trivial structure.

   Named Type (or Union):
      - Has a name that can be referenced to declare the data type for 
      fields, variables, parameters, arrays, etc.
      - Can appear on its own or nested inside another Named Type (or 
      Union).
      - Declaration of the Type (or Union) only.
      - Does not declare any fields within the structure that nests it, so 
      it does not add any size to it.
      - Can contain static member(s) or procedure declaration(s) (directly 
      or indirectly) => Trivial/Complex structure.

   Complexity level for Type/Union structure versus scope location:
      - Trivial structure: Named or Anonymous Type/Union that can be 
      declared at global / namespace / nested scopes or inside local scopes 
      (like Scope or Sub).
      - Complex structure: Named Type/Union that must be declared at the 
      global / namespace / nested scope with definitions at the global / 
      namespace scope.
      - Extended structure: Named Type/Union declared in a scope that has 
      visibility to its Base's scope (currently in same scope than its 
      Base).	

   The main structure (Type/Union) must be always Named, the other (Nested) 
   structures can be Anonymous or Named.
   Mostly everything it can be done in a Named Type/Union can also be done 
   in a Nested Named Type/Union, including the inheritance capability (as 
   base or as derived).
   Nested Anonymous Type/Union can not have procedure members or static 
   data members (same restriction than for a Named Type/Union inside a 
   local scope).

Example
   Example: 'Named Type' <- 'Nested Anonymous Union' <- 'Nested Anonymous 
   Type':
   Type T  '' named
      Union  '' anonymous
         Dim a As Short
         Type  '' anonymous
            Dim b1 As Byte
            Dim b2 As Byte
         End Type
      End Union
      Declare Sub proc()
   End Type

   Sub T.proc()
      b1 = 1
      b2 = 2
      Print b1, b2, a
   End Sub

   Dim x As T
   x.proc()

   Sleep

   Example of circular dependencies between two main types solved by Nested 
   Named Type usage (to avoid using type aliases and forward referencing):
   '' example of two dependent types, with a type alias and a forward referencing:
   '
   'Type list As list_
   '
   'Type listnode
   '    text As String
   '    parent As list Ptr
   'End Type
   '
   'Type list_
   '    first As listnode Ptr
   '    count As Integer
   'End Type

   '' same example of two dependent types, but with simply one of them a Nested Named Type: 

   Type list
      count As Integer
      Type listnode
         text As String
         parent As list Ptr
      End Type
      first As listnode Ptr
   End Type

   Example to check access syntaxes and access rights:
   Type UDT1
      Private:
         Dim As Integer I1 = 123
         Type UDT2
            Private:
               Dim As Integer I2 = 456
            Public:
               Declare Function returnI2() As Integer
         End Type
      Public:
         Type UDT3
            Private:
               Dim As Integer I3 = 789
            Public:
               Declare Function returnI3() As Integer
         End Type
         Declare Function returnI1() As Integer
         Dim As UDT2 t2
         Dim As UDT3 t3
   End Type

   Function UDT1.returnI1() As Integer
      Return This.I1
   End Function

   Function UDT1.UDT2.returnI2() As Integer
      Return This.I2
   End Function

   Function UDT1.UDT3.returnI3() As Integer
      Return This.I3
   End Function

   Dim As UDT1 t11

   'Print t11.I1            '' error 202: Illegal member access
                      ''    I1 is in the private section of UDT1

   Print t11.returnI1()     '' OK, returnI1() is in the public section of UDT1

   'Print t11.t2.I2         '' error 202: Illegal member access
                      ''    t2 is in the public section of UDT1, but I2 is in the private section of UDT2

   Print t11.t2.returnI2()  '' OK, t2 is in the public section of UDT1, and returnI2() is in the public section of UDT2

   'Print t11.t3.I3         '' error 202: Illegal member access
                      ''    t3 is in the public section of UDT1, but I3 is in the private section of UDT3

   Print t11.t3.returnI3()  '' OK, t3 is in the public section of UDT1, and returnI3() is in the public section of UDT3
   Print

   'Dim As UDT1.UDT2 t21    '' error 202: Illegal member access
                      ''    UDT2 is in the private section of UDT1

   Dim As UDT1.UDT3 t31     '' OK, UDT3 is in the public section of UDT1

   'Print t31.I3            '' error 202: Illegal member access
                      ''    I3 is in the private section of UDT3

   Print t31.returnI3()     '' OK, returnI3() is in the public section of UDT3

   Sleep

   Example of what we can do with nested named types.
   This is just the declaration part, but gives a few things worth pointing 
   out:
   Type MemoryTable
      Private:
         '' private members visible within MemoryTable only
         Const default_alignment = 16
         m_bytes_per_node As UInteger = 0
         m_nodes_per_chunk As UInteger = 0
         Type Chunk
            m_owner As MemoryTable Ptr
            m_nodes As UInteger
            m_prevChunk As Chunk Ptr
            m_data As Any Ptr
         End Type
         Declare Sub allocChunk()
         m_headChunk As Chunk Ptr = 0
      Protected:
         '' protected members visible within MemoryTable and derived types
         Declare Constructor()
         Type Iterator
            Private:
               m_chunk As Chunk Ptr
               m_index As Integer
            Protected:
               Declare Constructor()
               Declare Constructor(ByVal table As MemoryTable Ptr)
               Declare Property item() As Any Ptr
            Public:
               Declare Property hasItem() As Boolean
               Declare Sub nextItem()
         End Type
         Declare Function newNode() As Any Ptr
      Public:
         '' public member visible from outside the type
         Declare Constructor(ByVal bytes As UInteger, nodes As UInteger)
         Declare Destructor()
   End Type

	
See also
   * Overview (User Defined Types)
   * Type Aliases
   * Temporary Types
   * Constructors and Destructors (basics)
   * Member Access Rights and Encapsulation



------------------------------------------------------- ProPgCtorsDtors ----
Constructors and Destructors (basics)

In charge of the creation and destruction of objects.

Overview
Declaration
Default constructors
Copy constructors
Calling constructors
Compiler-provided constructors and destructors

Overview
   Constructors and destructors are responsible for creating and destroying 
   objects, respectively. In general, constructors give objects their 
   initial state, that is, they give meaningful values to their objects' 
   member data. Destructors perform the opposite function; they make sure 
   any resources owned by their objects are properly freed.

   Simply, constructors are special member procedures that are called when 
   an object is created, and destructors are special member procedures 
   called when an object is destroyed. Both constructors and destructors 
   are called automatically by the compiler whenever an object is created 
   or destroyed, whether explicitly with the use of the Dim or 
   New Expression/Delete Statement keywords, or implicitly by passing an 
   object to a procedure by value or through an object going out of scope.

Declaration
   Constructors and destructors are declared like member procedures but 
   with the Constructor keyword instead of Sub or Function, and without a 
   name. Similarly, they are defined with only the name of the Type or Class
   they are declared in.

   A Type or Class can have multiple constructors, but only one destructor.

Default constructors
   Default constructors are constructors that either have no parameters, or 
   all of their parameters have a default value. They are called when an 
   object is defined but not initialized, or is created as part of an 
   array, with the Dim, ReDim or New[] expression keywords. The first 
   constructor declared in the example below is a default constructor.

Copy constructors
   Copy constructors are constructors called when an object is created, or 
   cloned, from another object of the same type (or an object that can be 
   converted to that type). This happens explicitly when initializing an 
   object with another object, or implicitly by passing an object to a 
   procedure by value. Copy constructors are declared having one parameter: 
   an object of the same type passed by reference.

   Copy constructors are only called when creating and initializing object 
   instances. Assignment to objects is handled by the Member Operator Let.

Calling constructors
   Unlike other member procedures, constructors are generally not called 
   directly from an object instance. Instead, a constructor is specified in 
   a Dim statement either with an initializer or without one, or in a 
   New Expression statement with or without arguments.

   When specifying an initializer for an object, the name of the type 
   followed by any arguments it requires is used.

   Type foo
      '' Declare a default ctor, copy ctor and normal ctor
      Declare Constructor
      Declare Constructor (ByRef As foo)
      Declare Constructor (As Integer)

      '' Declare a destructor
      Declare Destructor

      ints As Integer Ptr
      numints As Integer
   End Type

   '' Define a constructor that creates 100 integers
   Constructor foo
      ints = New Integer(100)
      numints = 100
   End Constructor

   '' Define a constructor that copies the integers from another object
   Constructor foo (ByRef x As foo)
      ints = New Integer(x.numints)
      numints = x.numints
   End Constructor

   '' Define a constructor that creates some integers based on a parameter
   Constructor foo (n As Integer)
      ints = New Integer(n)
      numints = n
   End Constructor

   '' Define a destructor that destroys those integers
   Destructor foo
      Delete[] ints
   End Destructor

   Scope
      '' calls foo's default ctor
      Dim a As foo
      Dim x As foo Ptr = New foo

      '' calls foo's copy ctor
      Dim b As foo = a
      Dim y As foo Ptr = New foo(*x)

      '' calls foo's normal ctor
      Dim c As foo = foo(20)
      Dim z As foo Ptr = New foo(20)

      '' calls foo's dtor
      Delete x
      Delete y
      Delete z
   End Scope '' <- a, b and c are destroyed here as well

Compiler-provided constructors and destructors
   If no copy constructor is declared for a Type or Class, the compiler 
   provides one. If no constructor has been declared, the compiler also 
   provides a default constructor.

   The compiler-provided default constructor initializes member data to 
   default values, that is, numeric and pointer members are set to zero 
   (0), and object members are default-constructed. The copy constructor 
   that the compiler declares shallow-copies all member data from one type 
   to another: numeric and pointer types are initialized with the 
   corresponding data members in the object that is copied, and object 
   members are copy-constructed from their corresponding object members. 
   This means that dynamic resources, such as memory pointed to by a 
   pointer data member, is not copied; only the address is copied. So if an 
   object owns a resource, meaning it is responsible for its creation and 
   destruction, then the compiler-generated copy constructor will not be 
   sufficient.

   If a destructor is not declared, the compiler generates one. This 
   destructor calls object members' destructors and does nothing for 
   numeric and pointer types. Again, if an object owns a dynamic resource, 
   then the compiler-generated destructor will not be sufficient, as the 
   resource will not be freed when the object is destroyed.

   This is commonly referred to as the "Rule of 3": If an object needs a 
   custom copy constructor, assignment operator or destructor, chances are 
   it needs all three.

See also
   * Constructor, Destructor
   * Constructors, '=' Assignment-Operators, and Destructors (advanced, part #1)
   * Constructors, '=' Assignment-Operators, and Destructors (advanced, part #2)



------------------------------------------------- ProPgMemberProcedures ----
Member Procedures

Procedures with full access to members of a Type or Class

Declaration and definition
   Declaring and defining member procedures.
Usage
   Calling member procedures.
The hidden parameter, This
   Implicit access to the instance with which non-static member procedures 
   are called.
Access rights
   Referring to other members in member procedures.
Overloading
   Declaring two or more member procedures with the same name.
Static member procedures
   Differences from non-static member procedures.

   The term 'member procedure' refers to both static and non-static member 
   procedures, unless otherwise noted.

Declaration and definition
   Member procedures are declared much like normal module-level procedures 
   except that they are declared within, and defined outside, a Type or 
   Class definition [1].

   When defining member procedures, the procedure name is prefixed with the 
   name of the Type or Class and the member access operator (
   Operator . (Member Access)). It is an error to define a member procedure 
   without a matching declaration in the Type or Class definition.

   The following example declares and defines a Sub and Function member 
   procedure:

   '' foo1.bi

   Type foo
      Declare Sub f (As Integer)
      Declare Function g As Integer

      i As Integer
   End Type

   Sub foo.f (n As Integer)
      Print n
   End Sub

   Function foo.g As Integer
      Return 420
   End Function

Usage
   Member procedures are referred to just like member data, that is, their 
   name is prefixed with the name of an object instance and the member 
   access operator (Operator . (Member Access)) [2].

   The following example, using the code from the last example, calls Sub 
   and Function member procedures:

   '' ... foo with non-static members as before ...
   #include Once "foo1.bi"

   Dim bar As foo
   bar.f(bar.g())

The hidden parameter, This
   Member procedures actually have an additional parameter than what they 
   are declared with [3]. When they are called, using the name of an 
instance and Operator . (Member Access), a reference to that instance is 
passed along with any other arguments in the call, allowing the member 
procedure direct access to the instance.

   The additional parameter added by the compiler is called This, and since 
   it's a reference, any modifications to This are actually modifications 
   to the instance that was passed to the member procedure when it was 
   called. You can use This just like any other variable, ie., pass it to 
   procedures taking a object of the same type, call other member 
   procedures and access member data using Operator . (Member Access), etc.

   Most of the time, however, using This explicitly is unnecessary; member 
   procedures can refer to other members of the instance which they are 
   passed directly by name, without having to qualify it with This and 
   Operator . (Member Access). The only times when you need to qualify 
   member names with This is when the member name is hidden, for example, 
   by a parameter or local variable. In these situations, qualifying the 
   member name is the only way to refer to these hidden member names.

   Note:
   To access duplicated symbols defined as global outside the Type, add one 
   or preferably two dot(s) as prefix: .SomeSymbol or preferably ..
   SomeSymbol (or only ..SomeSymbol if inside a With..End With block).

   The following example uses the This keyword to refer to member data 
   whose name is hidden by a parameter and local variable:

   Type foo
      Declare Sub f (i As Integer)
      Declare Sub g ()

      i As Integer = 420
   End Type

   Sub foo.f (i As Integer)
      '' A parameter hides T.i, so it needs to be qualified to be used:
      Print this.i
   End Sub

   Sub foo.g ()
      '' A local variable hides T.i, so it needs to be qualified to be used:
      Dim i As Integer
      Print this.i
   End Sub

Access rights
   Unlike normal module-level procedures, member procedures have full 
   access rights to the members of the Type or Class they are declared in; 
   they can refer to the public, protected and private members of a Type or 
   Class.

Overloading
   A member procedure can be declared to have the same name as another 
   member procedure, provided the parameters are different, either in 
   number or in type. This is referred to as overloading.

   Only the parameters are used to determine if a procedure declaration is 
   a valid overload. For example, a Type or Class could have static and 
   non-static member procedures with the same name, or Sub and Function 
   member procedures with the same name

   Unlike a module-level procedure, which needs to specify the Overload 
   clause in the declaration to allow overloading it, a member procedure is 
   overloadable by default, and does not need the Overload clause.

   Type T
      Declare Sub f
      
      '' Different number of parameters:
      Declare Sub f (As Integer)
      
      '' Different type of parameters:
      Declare Sub f (ByRef As String)
      
      '' Again, parameters are different:
      Declare Function f (As UByte) As Integer
      
      '' following three members would cause an error,
      '' number of parameters and/or types do not differ:

      '' Declare Function f As Integer
      '' Declare Function f (As UByte) As String
      '' Declare Static Function f (As UByte) As Integer

      '' ...
      somedata As Any Ptr
   End Type

Static member procedures
   Static member procedures are declared and defined much in the same way 
   as non-static member procedures, with the Static keyword preceding the 
   declaration and definition.

   Member procedures defined using the Static keyword must be declared with 
   the Static keyword in the Type or Class definition, or a compiler error 
   will occur. Like non-static member procedures, it is an error to define 
   a static member procedure without a matching declaration in the Type or 
   Class definition.

   Do not confuse this with procedure definitions that specify static 
   storage for their variables and objects by appending the Static keyword 
   to the procedure header. The Static keyword can be used in both 
   contexts, however; static member procedures can be defined with static 
   variable and object storage.

   The following example declares two static member procedures, the first 
   of which also has static variable and object storage. Note that the 
   Static keyword is optional in the member procedure definition:

   '' foo2.bi

   Type foo
      Declare Static Sub f (As Integer)
      Declare Static Function g As Integer

      i As Integer
   End Type

   Static Sub foo.f (n As Integer) Static
      Print n
   End Sub
      
   Function foo.g As Integer
      Return 420
   End Function

   Static member procedures can be called like non-static member 
   procedures, qualifying the name of the procedure with the name of an 
   instance and the member access operator (Operator . (Member Access)).

   They can also be called by qualifying the procedure name with the name 
   of the Type or Class they were declared in and the member access 
   operator (Operator . (Member Access)). In other words, an instance is 
   not required in order to call static-member procedures.

   The following example, using the code from the last example, uses both 
   ways to call static member procedures:

   '' ... foo with static members as before ...
   #include Once "foo2.bi"

   Dim bar As foo
   bar.f(foo.g())

   Unlike non-static member procedures, which are declared with an extra 
   This parameter, static member procedures do not get passed an instance 
   when called. Because of this, static member procedures can only refer to 
   constants, enumerations, other static members (data or procedures), 
   etc., without qualifying their names. Static member procedures can still 
   refer to non-static members when qualified with an instance, for 
   example: a parameter or local variable.

   The following example refers to a non-static member from a static 
   procedure:

   Type foo
      Declare Static Sub f (ByRef As foo)

      i As Integer
   End Type

   Sub foo.f (ByRef self As foo)
      '' Ok, self is an instance of foo:
      Print self.i

      '' would cause error
      '' cannot access non-static members, no foo instance:
      '' Print i
   End Sub

[1] In the future, member procedures may be able to be defined within the 
Type or Class definition.
[2] Static member procedures do not require an object instance in order to 
be called.
[3] Static member procedures do not have this extra parameter added by the 
compiler, and so cannot access the object instance from which it was called 
with.



------------------------------------------------------- ProPgProperties ----
Properties

Properties are a special mix of member variable and member procedure. 

They provide a way to set or retrieve values of an object, through normal 
looking assignments or member accesses, but also let the object perform 
actions if it needs to update itself.

Basic properties
   Declaring and using setter and getter properties.
Indexed properties
   Properties with an additional parameter.

Basic properties

   A property is declared similar to a member procedure, except that the 
   Property keyword is used instead of Sub or Function. For example, let's 
   consider a window class for a windowing system or GUI library.

   Type Window
   Private:
      As String title_
   End Type

   Dim As Window w

   In order to set the window's title, a setter property can be added:

   Type Window
      Declare Property title(ByRef s As String)
   Private:
      As String title_
   End Type

   Property Window.title(ByRef s As String)
      this.title_ = s
   End Property

   Dim As Window w
   w.title = "My Window"

   It is very similar to a member Sub, as it takes a parameter and updates 
   the object to the new state based on the parameter. However, the syntax 
   for sending this parameter is a basic assignment, not a function call. 
   By assigning the new value to the title property, the property procedure 
   will automatically be called with the given new value, and can update 
   the window to reflect the change. It is up to the object how to 
   represent the property state internally.

   By design, properties can only be assigned one value at a time, and as a 
   result the property procedure can not have more than one parameter.

   After setting the window title, it should also be possible to retrieve 
   it. Here is how to add a getter property:

   Type Window
      '' setter
      Declare Property title(ByRef s As String)
      '' getter
      Declare Property title() As String
   Private:
      As String title_
   End Type

   '' setter
   Property Window.title(ByRef s As String)
      this.title_ = s
   End Property

   '' getter
   Property Window.title() As String
      Return this.title_
   End Property

   Dim As Window w
   w.title = "My Window"
   Print w.title

   The getter is very similar to a Function. It is supposed to return the 
   current value of the property, and it allows the current value to be 
   calculated from other internal values, if needed. Note that both setter 
   and getter use the same identifier, indicating they handle the same 
   property.

   Just like method overloading, it is possible to specify multiple 
   setters, provided they have different parameter types:

   Type Window
      Declare Property title(ByRef s As String)
      Declare Property title(ByVal i As Integer)
      Declare Property title() As String
   Private:
      As String title_
   End Type

   Property Window.title(ByRef s As String)
      this.title_ = s
   End Property

   Property Window.title(ByVal i As Integer)
      this.title_ = "Number: " & i
   End Property

   Property Window.title() As String
      Return this.title_
   End Property

   Dim As Window w
   w.title = "My Window"
   Print w.title
   w.title = 5
   Print w.title

   In comparison to this example of properties, here is similar code that 
   does not use properties:

   Type Window
      Declare Sub set_title(ByRef s As String)
      Declare Sub set_title(ByVal i As Integer)
      Declare Function get_title() As String
   Private:
      As String title
   End Type

   Sub Window.set_title(ByRef s As String)
      this.title = s
   End Sub

   Sub Window.set_title(ByVal i As Integer)
      this.title = "Number: " & i
   End Sub

   Function Window.get_title() As String
      Return this.title
   End Function

   Dim As Window w
   w.set_title("My Window")
   Print w.get_title()
   w.set_title(5)
   Print w.get_title()

   The code is basically the same, only the syntax is different. Properties 
   are specifically designed to combine the setter/getter concept and the 
   language's normal way of literally assigning and accessing values to a 
   class' member variables. It is up to the programmers to decide which way 
   they prefer.

   Here is an example demonstrating a text user interface window class 
   allowing to set position and title using properties:

   Namespace tui
      Type Point
         Dim As Integer x, y
      End Type

      Type char
         Dim As UByte value
         Dim As UByte Color
      End Type

      Type Window
         '' public
         Declare Constructor _
            ( _
               x As Integer = 1, y As Integer = 1, _
               w As Integer = 20, h As Integer = 5, _
               title As ZString Ptr = 0 _
            )
         
         Declare Destructor

         Declare Sub show

         '' title property
         Declare Property title As String
         Declare Property title( new_title As String )

         '' position properties
         Declare Property x As Integer
         Declare Property x( new_x As Integer )

         Declare Property y As Integer
         Declare Property y( new_y As Integer )

      Private:
         Declare Sub redraw
         Declare Sub remove
         Declare Sub drawtitle

         Dim As String p_title
         Dim As Point Pos
         Dim As Point siz
      End Type

      Constructor Window _
         ( _
            x_ As Integer, y_ As Integer, _
            w_ As Integer, h_ As Integer, _
            title_ As ZString Ptr _
         )

         pos.x = x_
         pos.y = y_
         siz.x = w_
         siz.y = h_

         If( title_ = 0 ) Then
            title_ = @"untitled"
         End If

         p_title = *title_
      End Constructor

      Destructor Window
         Color 7, 0
         Cls
      End Destructor

      Property window.title As String
         title = p_title
      End Property

      Property window.title( new_title As String )
         p_title = new_title
         drawtitle
      End Property

      Property window.x As Integer
         Return pos.x
      End Property

      Property window.x( new_x As Integer )
         remove
         pos.x = new_x
         redraw
      End Property

      Property window.y As Integer
         Property = pos.y
      End Property

      Property window.y( new_y As Integer )
         remove
         pos.y = new_y
         redraw
      End Property

      Sub window.show
         redraw
      End Sub

      Sub window.drawtitle
         Locate pos.y, pos.x
         Color 15, 1
         Print Space( siz.x );
         Locate pos.y, pos.x + (siz.x \ 2) - (Len( p_title ) \ 2)
         Print p_title;
      End Sub

      Sub window.remove
         Color 0, 0
         Var sp = Space( siz.x )
         For i As Integer = pos.y To pos.y + siz.y - 1
            Locate i, pos.x
            Print sp;
         Next
      End Sub

      Sub window.redraw
         drawtitle
         Color 8, 7
         Var sp = Space( siz.x )
         For i As Integer = pos.y + 1 To pos.y + siz.y - 1
            Locate i, pos.x
            Print sp;
         Next
      End Sub
   End Namespace

   Dim win As tui.window = tui.window( 3, 5, 50, 15 )

   win.show
   Sleep 500

   win.title = "Window 1"
   Sleep 250
   win.x = win.x + 10
   Sleep 250

   win.title = "Window 2"
   Sleep 250
   win.y = win.y - 2
   Sleep 250

   Locate 25, 1
   Color 7, 0
   Print "Press any key...";

   Sleep

   Note how updating the window's position or title automatically causes 
   the window to be redrawn.

Indexed properties

   Properties can have an additional parameter that is called an index 
   (currently only one additional parameter is allowed). The index is 
   specified in parentheses behind the property's name, as if the property 
   was an array (with only one dimension). For example:

   Type IntArray
      '' setters
      Declare Property value(index As Integer, v As Integer)
      Declare Property value(index As String, v As Integer)
      Declare Property value(index As Integer, v As String)
      Declare Property value(index As String, v As String)

      '' getters
      Declare Property value(index As Integer) As Integer
      Declare Property value(index As String) As Integer

   Private:
      Dim As Integer data_(0 To 9)
   End Type

   Property IntArray.value(index As Integer) As Integer
      Return This.data_(index)
   End Property

   Property IntArray.value(index As String) As Integer
      Return This.data_(CInt(index))
   End Property

   Property IntArray.value(index As Integer, v As Integer)
      This.data_(index) = v
   End Property

   Property IntArray.value(index As String, v As Integer)
      This.data_(CInt(index)) = v
   End Property

   Property IntArray.value(index As Integer, v As String)
      This.data_(index) = CInt(v)
   End Property

   Property IntArray.value(index As String, v As String)
      This.data_(CInt(index)) = CInt(v)
   End Property

   Dim a As IntArray

   a.value(0) = 1234
   a.value("1") = 5678
   a.value(2) = "-1234"
   a.value("3") = "-5678"

   Print a.value(0)
   Print a.value("1")
   Print a.value(2)
   Print a.value("3")

   Sleep

   This simulates an integer array that can be assigned strings, and even 
   be indexed with strings. See KeyPgProperty for another example.



----------------------------------------------- ProPgVariableLengthData ----
Variable-length member data

Management of variable-length strings/arrays as members of a Type.

Preamble:

   In FreeBASIC, Type data structures must ultimately be fixed-size, such 
   that the compiler knows how much memory to allocate for objects of that 
   Type.
   Nevertheless, Types may contain variable-length string or array data 
   members.

   However, the string's/array's data will not be embedded in the Type 
   directly. Instead, the Type will only contain a string/array descriptor 
   structure, which FreeBASIC uses behind the scenes to manage the 
   variable-length string/array data.
   For sizing the structure of the array descriptor in the Type, a 
   variable-length array data member must be always declared by using 
   Any(S) in place of the array bounds, in order to fix the amount of 
   dimensions based on the number of Anys specified. A variable-length 
   array data member can also be pre-sized in its declaration by using 
   syntax with ReDim.

   Variable-length array fields are considered as pseudo-objects when they 
   are declared in a Type (variable-length strings are real objects).
   So the implicit copy constructor and the implicit let operator of the 
   Type themselves support [re]sizing and copying such strings/arrays, or 
   their erasing.

Implicit string/array sizing and copying by the compiler code
   When the compiler build a default copy-constructor and a default 
   copy-assignment operator for such a Type (having string/array members), 
   it also includes all code for sizing the destination string/array and 
   copying the data from the source string/array, if needed.

   Example:
   Type UDT
      Dim As String s
      Dim As Integer array(Any)
   End Type

   Dim As UDT u1, u2

   u1.s = "FreeBASIC"
   ReDim u1.array(1 To 9)
   For I As Integer = LBound(u1.array) To UBound(u1.array)
      u1.array(I) = I
   Next I
    
   u2 = u1
   Print u2.s
   For I As Integer = LBound(u2.array) To UBound(u2.array)
      Print u2.array(I);
   Next I
   Print
   Print

   Dim As UDT u3 = u1
   Print u3.s
   For I As Integer = LBound(u3.array) To UBound(u3.array)
      Print u3.array(I);
   Next I
   Print

   Sleep
         
Output:

   FreeBASIC
    1 2 3 4 5 6 7 8 9

   FreeBASIC
    1 2 3 4 5 6 7 8 9
   			

Implicit string/array sizing and copying by the compiler code broken by an 
explicit copy-constructor and copy-assignment operator
   If the user want to specify his own copy-constructor and copy-assignment 
   operator (to initialize additional complex field members for example), 
   the above automatic string/array sizing and copying by compiler code is 
   broken.

   Example:
   Type UDT
      Dim As String s
      Dim As Integer array(Any)
      Declare Constructor ()
      Declare Constructor (ByRef u As UDT)
      Declare Operator Let (ByRef u As UDT)
      'user fields
   End Type

   Constructor UDT ()
      'code for user fields in constructor
   End Constructor

   Constructor UDT (ByRef u As UDT)
      'code for user fields in copy-constructor
   End Constructor

   Operator UDT.Let (ByRef u As UDT)
      'code for user fields in copy-assignement operator
   End Operator

   Dim As UDT u1, u2

   u1.s = "FreeBASIC"
   ReDim u1.array(1 To 9)
   For I As Integer = LBound(u1.array) To UBound(u1.array)
      u1.array(I) = I
   Next I
    
   u2 = u1
   Print u2.s
   For I As Integer = LBound(u2.array) To UBound(u2.array)
      Print u2.array(I);
   Next I
   Print
   Print

   Dim As UDT u3 = u1
   Print u3.s
   For I As Integer = LBound(u3.array) To UBound(u3.array)
      Print u3.array(I);
   Next I
   Print

   Sleep
         
Output (blank):

   			

String/Array sizing and copying explicitly set in the user copy-constructor 
and copy-assignment operator
   The variable-length array cannot be processed as a true object like a 
   variable-length string, because for example there is no implicit 
   assignment.
   Referring to the above example, This.array() = u.array() is disallowed, 
   while This.s = u.s is allowed.
   The user must code explicitly the sizing and the copying of the array 
   member (for the array data copy, a C run-time function memcpy() is used 
   to optimize the execution time).

   Example:
   #include "crt/string.bi"  '' C run-time header for 'memcpy()'

   Type UDT
      Dim As String s
      Dim As Integer array(Any)
      Declare Constructor ()
      Declare Constructor (ByRef u As UDT)
      Declare Operator Let (ByRef u As UDT)
      'user fields
   End Type

   Constructor UDT ()
      'code for user fields in constructor
   End Constructor

   Constructor UDT (ByRef u As UDT)
      This.s = u.s
      If UBound(u.array) >= LBound(u.array) Then  '' explicit array sizing and copying
         ReDim This.array(LBound(u.array) To UBound(u.array))
         memcpy(@This.array(LBound(This.array)), @u.array(LBound(u.array)), (UBound(u.array) - LBound(u.array) + 1) * SizeOf(@u.array(LBound(u.array))))
      End If
      'code for user fields in copy-constructor
   End Constructor

   Operator UDT.Let (ByRef u As UDT)
      If @This <> @u Then  '' not self-assignment
         This.s = u.s
         If UBound(u.array) >= LBound(u.array) Then  '' explicit array sizing and copying
            ReDim This.array(LBound(u.array) To UBound(u.array))
            memcpy(@This.array(LBound(This.array)), @u.array(LBound(u.array)), (UBound(u.array) - LBound(u.array) + 1) * SizeOf(@u.array(LBound(u.array))))
         End If
         'code for user fields in copy-assignement operator
      End If
   End Operator

   Dim As UDT u1, u2

   u1.s = "FreeBASIC"
   ReDim u1.array(1 To 9)
   For I As Integer = LBound(u1.array) To UBound(u1.array)
      u1.array(I) = I
   Next I
    
   u2 = u1
   Print u2.s
   For I As Integer = LBound(u2.array) To UBound(u2.array)
      Print u2.array(I);
   Next I
   Print
   Print

   Dim As UDT u3 = u1
   Print u3.s
   For I As Integer = LBound(u3.array) To UBound(u3.array)
      Print u3.array(I);
   Next I
   Print

   Sleep
         
Output:

   FreeBASIC
    1 2 3 4 5 6 7 8 9

   FreeBASIC
    1 2 3 4 5 6 7 8 9
   			

Using an extra base Type containing the variable-length string and array
   Another elegant possibility is to keep this sizing/copying, 
   automatically coded by the compiler, but by simply calling it 
   explicitly.
   For this, an elegant solution for the member array is to no longer put 
   it at the level of the Type itself, but rather in another specific Type 
   which is inherited (seen from the outside, it is exactly the same). This 
   is not necessary for the member string, but including also allows to 
   save one code line each time.

   Example:
   Type UDT0
      Dim As String s
      Dim As Integer array(Any)
   End Type

   Type UDT Extends UDT0
      Declare Constructor ()
      Declare Constructor (ByRef u As UDT)
      Declare Operator Let (ByRef u As UDT)
      'user fields
   End Type

   Constructor UDT ()
      'code for user fields in constructor
   End Constructor

   Constructor UDT (ByRef u As UDT)
      Base(u)  '' inherited string copying plus array sizing and copying from Base implicit copy-constructor call
      'code for user fields in copy-constructor
   End Constructor

   Operator UDT.Let (ByRef u As UDT)
      Cast(UDT0, This) = u  '' inherited string copying plus array sizing and copying from Base implicit copy-assignement operator call
      'code for user fields in copy-assignement operator
   End Operator

   Dim As UDT u1, u2

   u1.s = "FreeBASIC"
   ReDim u1.array(1 To 9)
   For I As Integer = LBound(u1.array) To UBound(u1.array)
      u1.array(I) = I
   Next I
    
   u2 = u1
   Print u2.s
   For I As Integer = LBound(u2.array) To UBound(u2.array)
      Print u2.array(I);
   Next I
   Print
   Print

   Dim As UDT u3 = u1
   Print u3.s
   For I As Integer = LBound(u3.array) To UBound(u3.array)
      Print u3.array(I);
   Next I
   Print

   Sleep
         
Output:

   FreeBASIC
    1 2 3 4 5 6 7 8 9

   FreeBASIC
    1 2 3 4 5 6 7 8 9
   			

See also
   * Constructors, '=' Assignment-Operators, and Destructors (advanced, part #1)
   * Constructors, '=' Assignment-Operators, and Destructors (advanced, part #2)



----------------------------------------------- ProPgMemberAccessRights ----
Member Access Rights and Encapsulation

Restricting member access to certain parts of code.

Member Access Rights
   Overview
      All members of a Type - including member data, procedures, constants, 
      etc. - belong in one of three different classifications, each with 
      its own rules dictating where in code they may be accessed, or 
      referred to.
      These rules are called access rights.
      There are public, protected and private members, and they are 
      declared in a Type definition following a Public, Protected or Private
      label, respectively.

      By default, that is, without an access classification label, members 
      of a Type are public.

   Public members
      Public members can be referred to from anywhere; they are accessible 
      from, for example, member procedures or module-level code or 
      procedures.

   Protected members
      Protected members can only be accessed from member procedures of the 
      Type they are declared in, or member procedures of a derived Type. 
      They are not accessible to outside code.

   Private members
      Private members can only be accessed from member procedures of the 
      Type they are declared in. They are not accessible to outside code or 
      member procedures from a derived Type.

   Constructors and destructors
      Constructors and destructors follow the same rules as any other 
      member:
         - When public, objects can be instantiated and destroyed from 
         anywhere in code.
         - When protected, objects can be instantiated and destroyed only 
         from member procedures of their Type or a derived Type.
         - Private constructors and destructors restrict object 
         instantiation solely to member procedures of their Type.

Encapsulation
   Overview
      Encapsulation is the process of keeping the details about how an 
      object is implemented hidden away from users of the object.
      Instead, users of the object access the object through a public 
      interface.
      In this way, users are able to use the object without having to 
      understand how it is implemented.

      Encapsulation is implemented via access specifiers (Private, 
      Protected or Public).
      Typically, all member variables of the Type are made private (hiding 
      the implementation details), and most member procedures are made 
      public (exposing an interface for the user).
      Although requiring users of the Type to use the public interface may 
      seem more burdensome than providing public access to the member 
      variables directly, doing so actually provides a large number of 
      useful benefits that help encourage Type re-usability and 
      maintainability.

   Benefit of encapsulated Types
      Protection:
         Global access to variables is dangerous because you donâ€™t have 
         strict control over who has access to the global variable, or how 
         they use it.
         Only the public members of a Type suffers from the same problem, 
         but just on a smaller scale.

         Encapsulation allows the programmer of a Type to:
            - Actively control the access to its internals (pointers, 
            variables, ...), by: none / read only / write only / read & 
            write.
            - Secure operations, by denying certain destructive user 
            actions (like pointer overwriting, deallocating, ...)

      Abstraction:
         With a fully encapsulated Type, you only need to know what member 
         procedures are publicly available to use the Type, what arguments 
         they take, and what values they return. It doesnâ€™t matter how 
         the Type was implemented internally.

         For example, a Type holding a list of names could have been 
         implemented using different data structures.
         In order to use the Type, you donâ€™t need to know (or care) 
         which.
         This dramatically reduces the complexity of your programs, and 
         also reduces mistakes.

         Hiding the internal implementation details:
            - internal members declared as Private/Protected and user 
            interface using methods and properties as getter/setter,
            - in addition to define constructors, copy-constructor, 
            destructor, assignment operators, ... ,
         provides some abstraction.
         More than any other reason, this is the key advantage of 
         encapsulation.

Examples
   * In the example below, the data member hour, minute, and second are 
     private while the member procedures set_Time(), get_Time() and 
     increment_Time() are public:
      - As all data is declared as private, the data is only accessible 
      through the public procedures provided by the Type.
      - This also allows programmers to validate changes to data members 
      before making such a change. In this example, the set_Time() 
      procedure would be written to check to valid values for time (hour 
      between 0 and 23, minute and second between 0 and 59).
   Type my_Time
      Public:
         Declare Sub set_Time (ByVal new_Hour As UByte, ByVal new_Minute As UByte, ByVal new_Second As UByte)
         Declare Sub get_Time (ByRef curr_Hour As UByte, ByRef curr_Minute As UByte, ByRef curr_Second As UByte)
         Declare Function get_Time () As String
         Declare Sub increment_Time ()
      Private:
         Dim As UByte Hour
         Dim As UByte Minute
         Dim As UByte Second
   End Type
            

      Example of use:
   Type my_Time
      Public:
         Declare Sub set_Time (ByVal new_Hour As UByte, ByVal new_Minute As UByte, ByVal new_Second As UByte)
         Declare Sub get_Time (ByRef curr_Hour As UByte, ByRef curr_Minute As UByte, ByRef curr_Second As UByte)
         Declare Function get_Time () As String
         Declare Sub increment_Time ()
      Private:
         Dim As UByte Hour
         Dim As UByte Minute
         Dim As UByte Second
   End Type

   Sub my_Time.set_Time (ByVal new_Hour As UByte, ByVal new_Minute As UByte, ByVal new_Second As UByte)
      If new_Hour <= 23 And new_Minute <= 59 And New_Second <= 59 Then
         This.Hour = new_Hour
         This.Minute = new_Minute
         This.Second = new_Second
      End If
   End Sub

   Sub my_Time.get_Time (ByRef curr_Hour As UByte, ByRef curr_Minute As UByte, ByRef curr_Second As UByte)
      curr_Hour = This.Hour
      curr_Minute = This.Minute
      curr_Second = This.Second
   End Sub

   Function my_Time.get_Time () As String
      Return Right("0" & Str(This.Hour), 2) & ":" & Right("0" & Str(This.Minute), 2) & ":" & Right("0" & Str(This.second), 2)
   End Function

   Sub my_Time.increment_Time ()
      This.Second += 1
      If This.Second = 60 Then
         This.Second = 0
         This.Minute += 1
         If This.Minute = 60 Then
            This.Minute = 0
            This.Hour += 1
            If This.Hour = 24 Then
               This.Hour = 0
            End If
         End If
      End If
   End Sub

   Dim As my_Time my_T
   Dim As UByte h, m, s
   Input "Hour? ", h
   Input "Minute? ", m
   Input "Second? ", s
   my_T.set_Time(h, m, s)

   Print
   Dim As Double Tr = Int(Timer)
   Do
      If Tr <> Int(Timer) Then
         Tr = Int(Timer)
         my_T.increment_Time()
         Locate  , 1, 0
         Print my_T.get_Time;
      End If
      Sleep 100, 1
   Loop Until Inkey <> ""
   Print
            

   * For a more advanced example using OOP (with encapsulation + 
     abstraction + inheritance + polymorphism), see the example (Graph type 
     collection) in 'Inheritance Polymorphism'.

See also
   * Properties



---------------------------------------------- ProPgOperatorOverloading ----
Operator Overloading

Changing the way user defined types work with built-in operators.

Overview
Global Operators
Member Operators
Special Cases of Operators: '.' (Member access), '@' (Address of), '->' (Pointer to member access), and '*' (Value of)

Overview
   Simply, operators are procedures, and their arguments are called 
   operands. Operators that take one operand (Operator Not) are called 
   unary operators, operators that take two operands (Operator +) are 
   called binary operators and operators taking three operands (Operator Iif
   ) are called ternary operators.

   Most operators are not called like procedures. Instead, their operator 
   symbol is placed next to their operands. For unary operators, their sole 
   operand is placed to the right of the symbol. For binary operators, 
   their operands - referred to as the left and right-hand side operands - 
   are placed to the left and right of the operator symbol. FreeBASIC has 
   one ternary operator, Operator Iif, and it is called like a procedure, 
   with its operands comma-separated surrounded by parenthesis.
   For example, the following code calls Operator Iif to determine if a 
   pointer is valid. If it is, Operator * (Value Of) is called to 
   dereference the pointer, and if not, Operator / (Divide) is called to 
   find the value of twenty divided by four:
   Dim i As Integer = 420
   Dim p As Integer Ptr = @i

   Dim result As Integer = IIf( p, *p, CInt( 20 / 4 ) )
         

      Notice the call to Operator Iif is similar to a procedure call, while 
      the calls to Operator * (Value Of) and Operator / (Divide) are not. 
      In the example, p is the operand to Operator * (Value Of), and 20 and 
      4 are the left and right-hand side operands of Operator / (Divide), 
      respectively.

   All operators in FreeBASIC are predefined to take operands of standard 
   data types, like Integer and Single, but they may also be overloaded for 
   user-defined types; that is, they can be defined to accept operands that 
   are objects as well. There are two types of operators that can be 
   overloaded, global operators and member operators.

Global Operators
   Global operators are those that are declared in module-level scope 
   (globally). These are the operators - (Negate), Not (Bitwise Not), 
   -> (Pointer To Member Access), * (Value Of), + (Add), - (Subtract), 
   * (Multiply), / (Divide), \ (Integer Divide), & (Concatenate), 
   Mod (Modulus), Shl (Shift Left), Shr (Shift Right), And (Bitwise And), 
   Or (Bitwise Or), Xor (Bitwise Xor), Imp (Bitwise Imp), Eqv (Bitwise Eqv)
   , ^ (Exponentiate), = (Equal), <> (Not Equal), < (Less Than), 
   > (Greater Than), <= (Less Than Or Equal), >= (Greater Than Or Equal), 
   Abs, Sgn, Fix, Frac, Int, Exp, Log, Sin, Asin, Cos, Acos, Tan, Atan, Len
   , and Sqr.

   Declaring a custom global operator is similar to declaring a procedure. 
   The Declare keyword is used with the Operator keyword. The operator 
   symbol is placed next followed by the comma-separated list of parameters 
   surrounded in parenthesis that will represent the operands passed to the 
   operator. Unlike procedures, operators can be overloaded by default, so 
   the Overload keyword is not necessary when declaring custom operators. 
   At least one of the operator's parameters must be of user-defined type 
   (after all, operators with built-in type parameters are already 
   defined).

   The following example declares the global operators - (Negate) and 
   + (Multiply) to accept operands of a user-defined type:
   Type Rational
      As Integer numerator, denominator
   End Type

   Operator - (ByRef rhs As Rational) As Rational
      Return Type(-rhs.numerator, rhs.denominator)
   End Operator

   Operator * (ByRef lhs As Rational, ByRef rhs As Rational) As Rational
      Return Type(lhs.numerator * rhs.numerator, _
         lhs.denominator * rhs.denominator)
   End Operator

   Dim As Rational r1 = (2, 3), r2 = (3, 4)
   Dim As Rational r3 = -(r1 * r2)
   Print r3.numerator & "/" & r3.denominator
         

      Here the global operators are defined for type Rational, and are used 
      in the initialization expression for r3. The output is -6/12.

Member Operators
   Member operators are declared inside a Type or Class definition, like 
   member procedures, and they are the cast and assignment operators 
   Operator Cast (Cast), Operator @ (Address Of),  
   Operator [] (Pointer Index), Operator New Overload, 
   Operator Delete Overload, Operator For (Iteration), 
   Operator Step (Iteration), Operator Next (Iteration), Let (Assign), 
   += (Add And Assign), -= (Subtract And Assign), *= (Multiply And Assign), 
   /= (Divide And Assign), \= (Integer Divide And Assign), 
   ^= (Exponentiate And Assign), &= (Concat And Assign), 
   Mod= (Modulus And Assign), Shl= (Shift Left And Assign), 
   Shr= (Shift Right And Assign), And= (Conjunction And Assign), 
   Or= (Inclusive Disjunction And Assign), 
   Xor= (Exclusive Disjunction And Assign), Imp= (Implication And Assign) 
   and Eqv= (Equivalence And Assign).

   When declaring member operators, the Declare and Operator keywords are 
   used followed by the operator symbol and its parameter list. Like member 
   procedures, member operators are defined outside the Type or Class 
   definition, and the symbol name is prefixed with the name of the Type or 
   Class name.

   The following example overloads the member operators Operator Cast (Cast)
   and *= (Multiply And Assign) for objects of a user-defined type:
   Type Rational
      As Integer numerator, denominator
      
      Declare Operator Cast () As Double
      Declare Operator Cast () As String
      Declare Operator *= (ByRef rhs As Rational)
   End Type

   Operator Rational.cast () As Double
      Return numerator / denominator
   End Operator

   Operator Rational.cast () As String
      Return numerator & "/" & denominator
   End Operator

   Operator Rational.*= (ByRef rhs As Rational)
      numerator *= rhs.numerator
      denominator *= rhs.denominator
   End Operator

   Dim As Rational r1 = (2, 3), r2 = (3, 4)
   r1 *= r2
   Dim As Double d = r1
   Print r1, d
         

      Notice that the member operator Cast (Cast) is declared twice, once 
      for the conversion to Double and once for the conversion to String. 
      This is the only operator (or procedure) that can be declared 
      multiple times when only the return type differs. The compiler 
      decides which cast overload to call based on how the object is used 
      (in the initialization of the Double d, Rational.Cast as double is 
      called, and in the Print statement, Rational.Cast as string is used 
      instead).

Special Cases of Operators: '.' (Member access), '@' (Address of), '->' 
(Pointer to member access), and '*' (Value of)
   - Overloading Operator . (Member access)
      The operator '.' (member access) cannot be overloaded.

   - Overloading Operator @ (Address of)
      The operator @ (Adress of) is used to access the address of a 
      variable.
      There is no many interest to overload this operator for an object, 
      and moreover if we did, we could no longer access its address.

   - Overloading Operator -> (Pointer to member access) and Operator * 
   (Value of)
      The operator -> (Pointer to member access) is used to access any 
      member of an object (instance) via a pointer to this instance.
      The operator * (Value of) is used to access to variable via a pointer 
      to this variable.
      Under normal circumstances, the operand of these operators must be a 
      pointer:
         Declare Operator -> ( ByRef lhs As T Ptr ) ByRef As U
         Declare Operator * ( ByRef rhs As T Ptr ) ByRef As T

      Overloading of these operators allows you to create a pointer wrapper 
      class and let it behave like the pointer itself:
         Declare Operator -> ( ByRef lhs As wrapperClass ) ByRef As U
         Declare Operator * ( ByRef rhs As wrapperClass ) ByRef As U

      The wrapper can be then used (to access a member) like:
         wrapper->member
         instead of:
         wrapper.realPointer->member
         and:
         (*wrapper).member
         instead of:
         (*wrapper.realPointer).member

      Clarifying the particular case of overloading the operator -> 
      (pointer to member access):
            The operator -> (pointer to member access) exhibits a different 
            behavior from the other operators with respect to overloading:
               - It doesn't return only the user datatype as indicated in 
               the overloaded procedure header,
               - but it returns this user datatype implicitly followed by 
               the operator . (member access).

      The operator -> (pointer to member access) is mainly used often in 
      conjunction with the operator * (Value of) to implement "smart 
      pointers".

   - Using smart pointer
      The use of smart pointers allows automatic management of dynamic 
      references created by New (each reference is destroyed automatically 
      when its smart pointer goes out of scope), without even making any 
      copy of these references.

      Reminder of what a smart pointer:
         - A smart pointer is an object which behaves like a pointer but 
         does more than a pointer.
         - This object is flexible as a pointer and has the advantage of 
         being an object (like constructor and destructor called 
         automatically).
         - Therefore, the destructor of the smart pointer will be 
         automatically called when this object goes out of scope, and it 
         will delete the user pointer.

      As the smart pointer must behave like a pointer, it must support the 
      same interface as a pointer does.
      So it must support the following operations:
         - Dereferencing (operator * (Value of))
         - Indirection (operator -> (pointer to member access))

      The operator * (Value of) and the operator -> (pointer to member 
      access) must return references (by means of using Byref As ..... in 
      the declaration of there return type).

      Example of a smart pointer (to UDT) with an interface:
         - public default-constructor
         - public copy-constructor
         - public destructor
         - private UDT pointer and public operator cast (Cast) to access it 
         in read only mode
         - private operator let to disallow assignment not implemented here 
         (to avoid copying the pointers values only)
         - operator * (Value of) and operator -> (pointer to member access)
   Type UDT
      Declare Constructor ()
      Declare Destructor ()
      Dim As String s = "object #0"
   End Type

   Constructor UDT ()
      Print "  UDT construction "; @This
   End Constructor

   Destructor UDT ()
      Print "  UDT destruction "; @This
   End Destructor

   Type SmartPointer
      Public:
         Declare Constructor ()                            '' to construct smart pointer (and UDT object)
         Declare Constructor (ByRef rhs As SmartPointer)   '' to copy construct smart pointer
         Declare Operator Cast () As UDT Ptr               '' to cast private UDT pointer (for read only)
         Declare Destructor ()                             '' to destroy smart pointer (and UDT object)
      Private:
         Dim As UDT Ptr p                                  '' private UDT pointer
         Declare Operator Let (ByRef rhs As SmartPointer)  '' to disallow assignment (to avoid copy of real pointers)
   End Type

   Constructor SmartPointer ()
      Print "SmartPointer construction "; @This
      This.p = New UDT
   End Constructor

   Constructor SmartPointer (ByRef rhs As SmartPointer)
      Print "SmartPointer copy-construction "; @This; " from "; @rhs
      This.p = New UDT
      *This.p = *rhs.p
   End Constructor

   Operator SmartPointer.Cast () As UDT Ptr
      Return This.p
   End Operator

   Destructor SmartPointer ()
      Print "SmartPointer destruction "; @This
      Delete This.p
   End Destructor

   Operator * (ByRef sp As SmartPointer) ByRef As UDT   '' overloaded operator '*'
      Print "SmartPointer operator '*'"
      Return *Cast(UDT Ptr, sp)                        ''    (returning byref)
   End Operator                                         ''    to behave as pointer
    
   Operator -> (ByRef sp As SmartPointer) ByRef As UDT  '' overloaded operator '->'
      Print "SmartPointer operator '->'"
      Return *Cast(UDT Ptr, sp)                        ''    (returning byref)
   End Operator                                         ''    to behave as pointer
    

   Scope
      Dim sp1 As SmartPointer
      Print "'" & sp1->s & "'"
      sp1->s = "object #1"
      Print "'" & sp1->s & "'"
      Print
    
      Dim sp2 As SmartPointer = sp1
      Print "'" & (*sp2).s & "'"
      (*sp2).s = "object #2"
      Print "'" & (*sp2).s & "'"
      Print
    
      Dim sp3 As SmartPointer = sp1
      Print "'" & sp3->s & "'"
      *sp3 = *sp2
      Print "'" & sp3->s & "'"
      sp3->s = "object #3"
      Print "'" & sp3->s & "'"
      Print
   End Scope

   Sleep
            
Example of output:

   SmartPointer construction 1703576
     UDT construction 10693312
   SmartPointer Operator '->'
   'object #0'
   SmartPointer Operator '->'
   SmartPointer Operator '->'
   'object #1'

   SmartPointer copy-construction 1703524 from 1703576
     UDT construction 10693384
   SmartPointer Operator '*'
   'object #1'
   SmartPointer Operator '*'
   SmartPointer Operator '*'
   'object #2'

   SmartPointer copy-construction 1703472 from 1703576
     UDT construction 10693456
   SmartPointer Operator '->'
   'object #1'
   SmartPointer Operator '*'
   SmartPointer Operator '*'
   SmartPointer Operator '->'
   'object #2'
   SmartPointer Operator '->'
   SmartPointer Operator '->'
   'object #3'

   SmartPointer destruction 1703472
     UDT destruction 10693456
   SmartPointer destruction 1703524
     UDT destruction 10693384
   SmartPointer destruction 1703576
     UDT destruction 10693312
   				

      Example of an extended smart pointer type macro for any UDT (or any 
      predefined type), with an extended interface:
         - public constructor
         - public reference counter in read only mode
         - public destructor
         - private UDT pointer and 2 public operators cast to access it in 
         read only mode (numeric value and string value)
         - private default-constructor to disallow self construction
         - private copy-constructor to disallow cloning
         - private operator let to disallow assignment
         - operator * (Value of) and operator -> (pointer to member access)
   #macro Define_SmartPointer (_UDTname_)

      Type SmartPointer_##_UDTname_
         Public:
            Declare Constructor (ByVal rhs As _UDTname_ Ptr)              '' to construct smart pointer
            '                                                                '' from _UDTname_ pointer,
            '                                                                '' with reference counter increment
            Declare Static Function returnCount () As Integer             '' to return reference counter value
            Declare Operator Cast () As _UDTname_ Ptr                     '' to cast private _UDTname_ pointer
            '                                                                '' to _UDTname_ pointer (read only)
            Declare Operator Cast () As String                            '' to cast private _UDTname_ pointer
            '                                                                '' to string (read only)
            Declare Destructor ()                                         '' to destroy smart pointer
            '                                                                '' and _UDTname_ object
            '                                                                '' with reference counter decrement
         Private:
            Dim As _UDTname_ Ptr p                                        '' private _UDTname_ pointer
            Static As Integer Count                                       '' private reference counter
            Declare Constructor ()                                        '' to disallow default-construction
            Declare Constructor (ByRef rhs As SmartPointer_##_UDTname_)   '' to disallow copy-construction
            Declare Operator Let (ByRef rhs As SmartPointer_##_UDTname_)  '' to disallow copy-assignment
      End Type
      Dim As Integer SmartPointer_##_UDTname_.Count = 0

      Constructor SmartPointer_##_UDTname_ (ByVal rhs As _UDTname_ Ptr)
         If rhs <> 0 Then
            This.p = rhs
            SmartPointer_##_UDTname_.count += 1
         End If
      End Constructor

      Static Function SmartPointer_##_UDTname_.returnCount () As Integer
         Return SmartPointer_##_UDTname_.count
      End Function

      Operator SmartPointer_##_UDTname_.Cast () As _UDTname_ Ptr
         Return This.p
      End Operator

      Operator SmartPointer_##_UDTname_.Cast () As String
         Return Str(This.p)
      End Operator

      Destructor SmartPointer_##_UDTname_ ()
         If This.p <> 0 Then
            Delete This.p
            SmartPointer_##_UDTname_.count -= 1
            This.p = 0
         End If
      End Destructor

      Operator * (ByRef sp As SmartPointer_##_UDTname_) ByRef As _UDTname_  '' operator '*' (return byref)
         '                                                                    '' to behave as pointer
         Return ByVal sp                                                   '' 'Return *sp' would induce an infinite loop
      End Operator

      Operator -> (ByRef sp As SmartPointer_##_UDTname_) ByRef As _UDTname_  '' operator '->' (return byref)
         '                                                                     '' to behave as pointer
         Return ByVal sp
      End Operator

   #endmacro

   '--------------------------------------------------------------------------------------------------------

   ' Example using all eight keywords of inheritance:
   '   'Extends', 'Base.', 'Base()', 'Object', 'Is' operator, 'Virtual', 'Abstract', 'Override'

   Type root Extends Object ' 'Extends' to activate RTTI by inheritance of predefined Object type
      Public:
         Declare Function ObjectHierarchy () As String
         Declare Function ObjectName () As String
         Declare Abstract Function ObjectRealType () As String  '' 'Abstract' declares function without local body
         '                                                         '' which must be overridden
         Declare Virtual Destructor ()                          '' 'Virtual' declares destructor
      Protected:
         Declare Constructor ()                                 '' to avoid default-construction from outside Types
         Declare Constructor (ByRef _name As String = "")       '' to avoid construction from outside Types
         Declare Constructor (ByRef rhs As root)                '' to avoid copy-construction from outside Types
         Declare Operator Let (ByRef rhs As root)               '' to avoid copy-assignment from outside Types
      Private:
         Dim Name As String
   End Type                                                   '' derived type may be member data empty

   Constructor root ()  '' only to avoid compile error (due to inheritance)
   End Constructor

   Constructor root (ByRef _name As String = "")              '' only to avoid compile error (due to inheritance)
      This.name = _name
      Print "root constructor:", This.name
   End Constructor

   Function root.ObjectHierarchy () As String
      Return "Object(forRTTI) <- root"
   End Function

   Function root.ObjectName () As String
      Return This.name
   End Function

   Virtual Destructor root ()
      Print "root destructor:", This.name
   End Destructor

   Operator root.Let (ByRef rhs As root)                      '' only to avoid compile error (due to onheritance)
   End Operator

   Type animal Extends root                                           '' 'Extends' to inherit of root
      Declare Constructor (ByRef _name As String = "")
      Declare Function ObjectHierarchy () As String
      Declare Virtual Function ObjectRealType () As String Override  '' 'Virtual' declares function with local
      '                                                              ''    body which can be overridden
      '                                                              '' 'Override' to check if the function is
      '                                                              ''    well an override
      Declare Virtual Destructor () Override                         '' 'Virtual' declares destructor with local body
      '                                                              '' 'Override' to check if the destructor is well an override
   End Type

   Constructor animal (ByRef _name As String = "")
      Base(_name)                                                    '' 'Base()' allows to call parent constructor
      Print "  animal constructor:", This.ObjectName()
   End Constructor

   Function animal.ObjectHierarchy () As String
      Return Base.ObjectHierarchy & " <- animal"                     '' 'Base.' allows to access to parent member function
   End Function

   Virtual Function animal.ObjectRealType () As String
      Return "animal"
   End Function

   Virtual Destructor animal ()
      Print "  animal destructor:", This.ObjectName()
   End Destructor

   Type dog Extends animal                                    '' 'Extends' to inherit of animal
      Declare Constructor (ByRef _name As String = "")
      Declare Function ObjectHierarchy () As String
      Declare Function ObjectRealType () As String Override  '' 'Override' to check if the function is well an
      '                                                      ''    override
      Declare Destructor () Override                         '' 'Override' to check if the destructor is well an override
   End Type                                                   '' derived type may be member data empty

   Constructor dog (ByRef _name As String = "")
      Base(_name)                                            '' 'Base()' allows to call parent constructor
      Print "    dog constructor:", This.ObjectName()
   End Constructor

   Function dog.ObjectHierarchy () As String
      Return Base.ObjectHierarchy & " <- dog"                '' 'Base.' allows to access to parent member function
   End Function

   Function dog.ObjectRealType () As String
      Return "dog"
   End Function

   Destructor dog ()
      Print "    dog destructor:", This.ObjectName()
   End Destructor

   Type cat Extends animal                                  '' 'Extends' to inherit of animal
      Declare Constructor (ByRef _name As String = "")
      Declare Function ObjectHierarchy () As String
      Declare Function ObjectRealType () As String Override  '' 'Override' to check if the function is well an
      '                                                      ''    override
      Declare Destructor () Override                         '' 'Override' to check if the destructor is well an override
   End Type                                                   '' derived type may be member data empty

   Constructor cat (ByRef _name As String = "")
      Base(_name)                                            '' 'Base()' allows to call parent constructor
      Print "    cat constructor:", This.ObjectName()
   End Constructor

   Function cat.ObjectHierarchy () As String
      Return Base.ObjectHierarchy & " <- cat"                '' 'Base.' allows to access to parent member function
   End Function

   Function cat.ObjectRealType () As String
      Return "cat"
   End Function

   Destructor cat ()
      Print "    cat destructor:", This.ObjectName()
   End Destructor

   Sub PrintInfo (ByVal p As root Ptr)                                       '' parameter is a 'root Ptr' or compatible (smart pointer)
      Print "  " & p->ObjectName, "  " & p->ObjectRealType, "           ";
      If *p Is dog Then                                                     '' 'Is' allows to check compatibility with type symbol
         Print  Cast(dog Ptr, p)->ObjectHierarchy
      ElseIf *p Is cat Then                                                 '' 'Is' allows to check compatibility with type symbol
         Print Cast(cat Ptr, p)->ObjectHierarchy
      ElseIf *p Is animal Then                                              '' 'Is' allows to check compatibility with type symbol
         Print Cast(animal Ptr, p)->ObjectHierarchy
      End If
   End Sub

   Define_SmartPointer(root)  '' smart pointer definition

   Scope
      Print "reference counter value:"; SmartPointer_root.returnCount()
      Print
      Dim As SmartPointer_root sp(2) = {New animal("Mouse"), New dog("Buddy"), New cat("Tiger")}
      Print
      Print "reference counter value:"; SmartPointer_root.returnCount()
      For I As Integer = 0 To 2
         Print "  " & sp(I), sp(I)->ObjectName()
      Next I
      Print
      Print "Name:", "Object (real):         Hierarchy:"
      For I As Integer = 0 To 2
         #if __FB_VERSION__ = "1.10.0" Or __FB_VERSION__ = "1.10.1"
            PrintInfo(Cast(root Ptr, sp(I)))  '' bug workaround
         #else
            PrintInfo(sp(I))
         #endif
      Next I
      Print
   End Scope
   Print
   Print "reference counter value:"; SmartPointer_root.returnCount()
   Print

   Sleep
            
Example of output:

   reference counter value: 0

   root Constructor:           Mouse
     animal Constructor:       Mouse
   root Constructor:           Buddy
     animal Constructor:       Buddy
   	dog Constructor:        Buddy
   root Constructor:           Tiger
     animal Constructor:       Tiger
   	cat Constructor:        Tiger

   reference counter value: 3
     11145960    Mouse
     11151496    Buddy
     11151616    Tiger

   Name:         Object (real):         Hierarchy:
     Mouse         animal                 Object(forRTTI) <- root <- animal
     Buddy         dog                    Object(forRTTI) <- root <- animal <- dog
     Tiger         cat                    Object(forRTTI) <- root <- animal <- cat

   	cat Destructor:         Tiger
     animal Destructor:        Tiger
   root Destructor:            Tiger
   	dog Destructor:         Buddy
     animal Destructor:        Buddy
   root Destructor:            Buddy
     animal Destructor:        Mouse
   root Destructor:            Mouse

   reference counter value: 0
   				



---------------------------------------------------- ProPgTypeIterators ----
Iterators

The overload Operators For, Next, and Step, allowing to construct 
User-Defined Types Iterators (instead of only intrinsic scalar types 
iterators) for a For...Next loop

Syntax (declaration)
   { Type | Class | Union } typename
      ' For...Next' statement with implicit step (1st version of operators)
         Declare Operator For ( )
         Declare Operator Next ( [ ByRef | ByVal ] cond As typename ) As 
         Integer
         Declare Operator Step ( )
      ' For...Next' statement with explicit step (2nd version of operators)
         Declare Operator For ( [ ByRef | ByVal ] stp As typename )
         Declare Operator Next ( [ ByRef | ByVal ] cond As typename, [ ByRef
         | ByVal ] stp As typename ) As Integer
         Declare Operator Step ( [ ByRef | ByVal ] stp As typename )
   End { Type | Class | Union }

Usage
   For iterator [ As typename ] = start_value To end_value [ Step 
   step_value ]
      [ ...statements... ]
   Next

   The first version of operators is used if no step_value is given in the 
   For...Next statement.
   If a step_value is given, the second version is used and a step object 
   (initialized with step-value) is passed through the stp parameter:
      - to Operator For because eventual additional initialization may use 
      it,
      - to Operator Next because testing for iterating end may depend on 
      it,
      - to Operator Step to increment the iterator object.
   Both versions of the operators can coexist (thanks to member 
   overloading) in the same user-defined type (to be able to both use and 
   not use the explicit increment in For...Next statements of the user 
   code).

Parameters
(including arguments)
   typename
      name of the Type, Class, or Union
   stp, step_value
      a typename object used as an incremental value
   iterator
      a typename object used as an iterator
   cond, end_value
      a typename object used as a loop-terminating value
   start_value
      a typename object used to copy construct or assign to the iterator 
      initially

Description
   Operator For, Operator Next and Operator Step can be overloaded in 
   user-defined type definitions to allow objects of that type to be used 
   as iterators and step values in For...Next loops (instead of the 
   pre-defined for intrinsic scalar types).

   As all non-static member procedures, the 3 operators have passed a 
   hidden This parameter that allows to access by reference to the iterator 
   object (initialized to the start_value argument value from the For...Next
   statement).
   The cond parameter of the Operator Next allows to access the end_value 
   argument value from the For...Next statement.
   If a step_value is given (as argument) in the For...Next statement, the 
   stp parameter allows to access this value in the 3 operators.

   Note: If no step_value is given in the For...Next statement (implicit 
   step), the user-defined type must have a default constructor (implicit 
   or explicit) or a conversion constructor. It is a bug at the moment 
   because if the user defines a default constructor, the compiler does not 
   even use it when initializing the For...Next loop!

   Operator For
      Operator For is called once immediately after copy constructing or 
      assigning to the iterator object (with the start_value), constructing 
      the end object (with the end_value), and constructing the step object 
      (with step_value if defined in the For...Next statement).
      Operator For allows to perform any additional initialization needed 
      in preparation for the loop.

   Operator Next
      Operator Next is called every time the iterator object needs to be 
      checked against the end value. This happens immediately after the 
      call to the Operator For, and then immediately after any calls to the 
      Operator Step.
      Operator Next should return zero (0) if the loop should be 
      terminated, or non-zero if the loop should continue iterating.
      The first time Operator Next is called, no statements in the 
      For...Next body have been executed yet.
      Operator Next also allows to perform some processing before the 
      execution of all statements in the For...Next body.

   Operator Step
      Operator Step is called to increment the iterator object immediately 
      after all statements in the For...Next body are executed.

   Advanced usage
      The above description seems to imply that the 3 arguments start_value
      , end_value, and step_value must be of the same type as the iterator 
      (this is the more obvious use), but it is not quite true:
         - The start_value, end_value, and step_value arguments can be of 
         any type (of different types among themselves and also of 
         different types from the one of the iterator).
         - The only constraint is that the iterator could be constructed 
         (in case of local iterator) or assigned (in case of global 
         iterator) from the start_value argument (because the iterator is 
         implicitly constructed or assigned under the hood).
         - Similarly the other arguments end_value, and step_value must be 
         able to be converted into objects of the same type as the iterator
         .

Algorithm
   For...Next loop algorithm around the 3 overload operators:

   '                       FOR...NEXT loop
   '                              V
   '                              |
   '            constructing/assigning iterator object
   '       (This = start_value from For...Next statement)
   '                              |
   '                   constructing end object
   '       (cond = end_value from For...Next statement)
   '                              |
   '                   if step_value is defined >---------------------.
   '                            else                                  :
   '                              v                                   v
   '                              :                        constructing step object
   '                              :               (stp = step_value from For...Next statement)
   '                              :                                   :
   '                              :<----------------------------------'
   '                              |
   '                    calling Operator For
   '                              |
   '     .----------------------->|
   '     |                        |
   '     |              calling Operator Next
   '     |     (if end-condition verified: =0 returned) >-------------.
   '     |               (else: <>0 returned)                         |
   '     |                        v                                   |
   '     |                        |                                   |
   '     |            executing For...Next body                       |
   '     |                        |                                   |
   '     |              calling Operator Step                         |
   '     |                        |                                   |
   '     '------------------------'                                   |
   '                                                                  |
   '                                                                  V

Example
   Type for iterating through screen resolutions, with implicit step-value:
   Type screenResolution
      ' user interface
         Declare Constructor (ByVal colorBit As Long)
         Declare Property colorDepth () As Long
         Declare Property screenWidth () As Long
         Declare Property screenHeigth () As Long
      ' overload iteration operators when Step is not defined in For...Next statement
         Declare Operator For ()
         Declare Operator Next (ByRef iterateCondition As screenResolution) As Integer
         Declare Operator Step ()
      ' internal variables
         Dim As Long colorBit, resolutionWH
   End Type

   Constructor screenResolution (ByVal colorBit As Long)
      This.colorBit = colorBit
   End Constructor

   Property screenResolution.colorDepth () As Long
      Return This.colorBit
   End Property

   Property screenResolution.screenWidth () As Long
      Return HiWord(This.resolutionWH)
   End Property

   Property screenResolution.screenHeigth () As Long
      Return LoWord(This.resolutionWH)
   End Property

   Operator screenResolution.For ()
      This.resolutionWH = ScreenList(This.colorBit)
   End Operator

   Operator screenResolution.Next (ByRef iterateCondition As screenResolution) As Integer
      While This.resolutionWH = 0
         If This.colorBit < iterateCondition.colorBit Then
            This.colorBit += 1
            This.resolutionWH = ScreenList(This.colorBit)
         Else
            Exit While
         End If
      Wend
      Return (This.resolutionWH <> iterateCondition.resolutionWH)
   End Operator

   Operator screenResolution.Step ()
      This.resolutionWH = ScreenList()
   End Operator

   Print "Screen resolutions supported within [1 bpp , 64 bpp]:"
   For iterator As screenResolution = screenResolution(1) To screenResolution(64)
      Print "    " & iterator.colorDepth & " bpp ",
      Print ":" & iterator.screenWidth & "x" & iterator.screenHeigth
   Next iterator
   Print "End of supported screen resolutions"

   Sleep
         
Output example:

   Screen resolutions supported within [1 bpp , 64 bpp]:
   	24 bpp    :320x200
   	24 bpp    :320x240
   	24 bpp    :400x300
   	24 bpp    :512x384
   	24 bpp    :640x400
   	24 bpp    :640x480
   	24 bpp    :800x600
   	24 bpp    :1024x768
   	24 bpp    :1152x864
   	24 bpp    :1280x600
   	24 bpp    :1280x720
   	24 bpp    :1280x768
   	24 bpp    :1280x800
   	24 bpp    :1280x960
   	24 bpp    :1280x1024
   	24 bpp    :1360x768
   	24 bpp    :1366x768
   	24 bpp    :1400x1050
   	24 bpp    :1440x900
   	24 bpp    :1600x900
   	24 bpp    :1680x1050
   	24 bpp    :1920x1080
   	32 bpp    :320x200
   	32 bpp    :320x240
   	32 bpp    :400x300
   	32 bpp    :512x384
   	32 bpp    :640x400
   	32 bpp    :640x480
   	32 bpp    :800x600
   	32 bpp    :1024x768
   	32 bpp    :1152x864
   	32 bpp    :1280x600
   	32 bpp    :1280x720
   	32 bpp    :1280x768
   	32 bpp    :1280x800
   	32 bpp    :1280x960
   	32 bpp    :1280x1024
   	32 bpp    :1360x768
   	32 bpp    :1366x768
   	32 bpp    :1400x1050
   	32 bpp    :1440x900
   	32 bpp    :1600x900
   	32 bpp    :1680x1050
   	32 bpp    :1920x1080
   End of supported Screen resolutions

   Type for iterating through fractions, with explicit step-value used in 
   the 3 operators:
   (improved example compared to the one of Operator Step page)
   Type fraction
      ' user interface
         Declare Constructor (ByVal n As Integer, ByVal d As Integer)
         Declare Operator Cast () As String
      ' overload iteration operators when Step is defined in For...Next statement
         Declare Operator For (ByRef iterateStep As fraction)
         Declare Operator Next (ByRef iterateCondition As fraction, ByRef iterateStep As fraction) As Integer
         Declare Operator Step (ByRef step_var As fraction)
      ' internal variables and cast operator
         As Integer num, den
         Declare Operator Cast () As Double
   End Type

   Constructor fraction (ByVal n As Integer, ByVal d As Integer)
      this.num = n
      this.den = d
   End Constructor

   Operator fraction.Cast () As String
      ' search for the highest common factor (a) between numerator and denominator
         Dim As Integer a = Abs(This.num), b = Abs(This.den)
         If a <> 0 Then
            While a <> b 
               If a > b Then
                  a -= b
               Else
                  b -= a
               End If
            Wend
         Else
            a = 1
         End If
      ' reduce the fraction
         Return num \ a & "/" & den \ a
   End Operator

   Operator fraction.Cast () As Double
      Return This.num / This.den
   End Operator

   Operator fraction.For (ByRef iterateStep As fraction)
      ' search for the least common multiple (a) between the two denominators
         Dim As Integer a = Abs(This.den), b = Abs(iterateStep.den), c = a, d = b
         While a <> b
            If a > b Then
               b += d
            Else
               a += c
            End If
         Wend
      ' align at the same denominator the 2 fractions
         This.num *= a \ This.den
         This.den = a
         iterateStep.num *= a \ iterateStep.den
         iterateStep.den = a
   End Operator

   Operator fraction.Next (ByRef iterateCondition As fraction, ByRef iterateStep As fraction) As Integer
      If iterateStep.num < 0 Or iterateStep.den < 0 Then
         Return This >= iterateCondition
      Else
         Return This <= iterateCondition
      End If
   End Operator

   Operator fraction.Step (ByRef iterateStep As fraction)
      This.num += iterateStep.num
   End Operator 

   Print "iteration from 1/8 to 1/2 by step of 1/12:"
   For iterator As fraction = fraction(1, 8) To fraction(1, 2) Step fraction(1, 12)
      Print "    " & iterator;
   Next
   Print
   Print
   Print "iteration from 7/10 to -8/5 by step of -8/15:"
   For iterator As fraction = fraction(7, 10) To fraction(-8, 5) Step fraction(-8, 15)
      Print "    " & iterator;
   Next
   Print

   Sleep
         
Output:

   iteration from 1/8 To 1/2 by Step of 1/12:
   	1/8    5/24    7/24    3/8    11/24
   	
   iteration from 7/10 To -8/5 by Step of -8/15:
   	7/10    1/6    -11/30    -9/10    -43/30

See also
   * For...Next
   * Operator



-------------------------------------------------------- ProPgNewDelete ----
New and Delete

The different operators New (Implicit/Overload/Expression/Placement) and Del
ete (Implicit/Overload/Statement), and all their array-versions New[] and De
lete[]

Definition
   There may be confusion in the user mind between the different operators 
   New and Delete (despite the documentation that distinguishes them from 
   each other through some different pages):
      * 'Operator New Implicit' (inaccessible by user):
            - It is a static function that only allocates memory (it is not 
            very different from Allocate).
      * Operator New Overload:
            - It is a member operator (static function) that can overload 
            the 'Operator New Implicit' only for user-defined types.
            - So the user can define its own dynamic memory allocation 
            process part (the following process part for implicit data 
            construction can not be modified).
      * 'Operator Delete Implicit' (inaccessible by user):
            - It is a static sub that only frees the memory (it is not very 
            different from Deallocate).
      * Operator Delete Overload:
            - It is a member operator (static sub) that can overload the 
            'Operator Delete Implicit' only for user-defined types.
            - So the user can define its own memory deallocation process 
            part (the previous process part for implicit data destruction 
            can not be modified).
      * Operator New Expression:
            - It starts by using the 'Operator New Implicit/Overload' (the 
            implicit, or the overload if exists) to allocate memory.
            - Then it invokes the constructor for the right type of object. 
            If that object contains any other objects (either embedded or 
            as base types) those constructors as invoked as well.
            - So the final result is memory allocated and object 
            constructed.
            - This operator applies to pre-defined types (except 
            fixed-length strings) as well as user-defined types.
      * Operator Delete Statement:
            - It starts by invoking the destructor for the right type of 
            object. If that object contains any other objects (either 
            embedded or as base types) those destructors as invoked as 
            well.
            - Then it uses the 'Operator Delete Implicit/Overload' (the 
            implicit, or the overload if exists) to deallocate memory.
            - So the final result is object destroyed and memory freed.
            - This operator applies to pre-defined types (except 
            fixed-length strings) as well as user-defined types.
      * Operator Placement New:
            - It only constructs object at a specified memory address 
            (already allocated). This operator applies to pre-defined types 
            (except fixed-length strings) as well as user-defined types.

   Similar definition for 'Operator New[] Implicit/Overload/Expression', 
   'Operator Delete[] Implicit/Overload/Statement' and 'Operator Placement 
   New[]', which are only the (one-dimensional) array-versions of the 
   previous operators (there is construction/destruction loop on the array 
   elements).

   Instances created with 'Operator New Overload/Expression' must be freed 
   with 'Operator Delete Overload/Statement'.
   Instance array created with 'Operator New[] Overload/Expression' must be 
   freed with 'Operator Delete[] Overload/Statement', the array-version of 
   'Operator Delete Overload/Statement'.
   User can not mix and match the different versions of the operators.

   Instances constructed at a specified memory address with 'Operator 
   Placement New' must never induce a symmetric freeing with any 'Operator 
   Delete' on the address (because the memory has been allocated in another 
   way than by the 'Operator Placement New').
   Instance array constructed at a specified memory address with 'Operator 
   Placement New[]' must never induce a symmetric freeing with any 
   'Operator Delete[]' on the address (because the memory has been 
   allocated in another way than by the 'Operator Placement New[]').
   For such UDT instances, the proper way to just destroy each instance if 
   necessary, is to call only the destructor if one exists (implicitly or 
   explicitly), with syntax as for a member method by using member access 
   operator.

   Note: Any operators 'New[]' or 'Delete[]' (the array versions for  
   statement/expression/overload operators) and even the overload operator 
   'Delete' are not directly compatible with inheritance polymorphism 
   (sub-type polymorphism), because the use of a sub-type pointer (instead 
   of the real type) mainly fails for accessing the other elements (except 
   the first).

Algorithm (applied to user-defined types)
   Operator New/New[] Expression:

   '       OPERATOR NEW/NEW[] EXPRESSION
   '                     V
   '                     |
   '              call if there is >----------------------------.
   '                   else                                     :
   '                     v                                      v
   '       (Operator New/New[] Implicit)          (Operator New/New[] Overload)
   '                     :                                      :
   '          BASIC MEMORY ALLOCATION            USER BODY for memory allocation
   '                     :                                      :
   '                     :<-------------------------------------'
   '                     |
   '                     |<-------------------------------------.
   '                     |                                      :
   '        DATA FIELDS INITIALIZATION                          :
   '        OBJECT FIELDS CONSTRUCTION                          :
   '           (VPTR INITIALIZATION)                            :
   '                     |                                      :
   '              call if there is >-----------.                :
   '                   else                    :                :
   '                     v                     v                :
   '                     :            (User Constructor)        :
   '                     :                     :                :
   '                     :                 USER BODY            :
   '                     :                     :                :
   '                     :<--------------------'                :
   '                     |                                      :
   '        loop if array-version NEW[] >-----------------------'
   '                   else
   '                     v
   '                     |
   '                     V

   Operator Delete/Delete[] Statement:

   '     OPERATOR DELETE/DELETE[] STATEMENT
   '                     V
   '                     |
   '                     |<-------------------------------------.
   '                     |                                      :
   '          (VPTR REINITIALIZATION)                           :
   '                     |                                      :
   '              call if there is >-----------.                :
   '                   else                    :                :
   '                     v                     v                :
   '                     :             (User Destructor)        :
   '                     :                     :                :
   '                     :                 USER BODY            :
   '                     :                     :                :
   '                     :<--------------------'                :
   '                     |                                      :
   '         OBJECT FIELDS DESTRUCTION                          :
   '                     |                                      :
   '       loop if array-version DELETE[] >---------------------'
   '                   else
   '                     v
   '                     |
   '              call if there is >----------------------------.
   '                   else                                     :
   '                     v                                      v
   '    (Operator Delete/Delete[] Implicit)    (Operator Delete/Delete[] Overload)
   '                     :                                      :
   '         BASIC MEMORY DEALLOCATION          USER BODY for memory deallocation
   '                     :                                      :
   '                     :<-------------------------------------'
   '                     |
   '                     V

   Operator Placement New/New[]:

   '        OPERATOR PLACEMENT NEW/NEW[]
   '                     V
   '                     |
   '                     |<-------------------------------------.
   '                     |                                      :
   '        DATA FIELDS INITIALIZATION                          :
   '        OBJECT FIELDS CONSTRUCTION                          :
   '           (VPTR INITIALIZATION)                            :
   '                     |                                      :
   '              call if there is >-----------.                :
   '                   else                    :                :
   '                     v                     v                :
   '                     :             (User Constructor)       :
   '                     :                     :                :
   '                     :                 USER BODY            :
   '                     :                     :                :
   '                     :<--------------------'                :
   '                     |                                      :
   '        loop if array-version NEW[] >-----------------------'
   '                   else
   '                     v
   '                     |
   '                     V

Example
   Example that uses the operators New (Overload/Expression/Placement) and 
   Delete (Overload/Statement), and all their array-versions New[] and 
   Delete[]:
   (all the 10 operators New and Delete accessible by the user):
   Declare Sub printArray (ByRef label As String = "", array() As String)

   Type UDT
      Declare Constructor ()
      Declare Destructor ()
      Declare Operator New (ByVal size As UInteger) As Any Ptr    ' Operator New Overload
      Declare Operator New[] (ByVal size As UInteger) As Any Ptr  ' Operator New[] Overload
      Declare Operator Delete (ByVal buf As Any Ptr)              ' Operator Delete Overload
      Declare Operator Delete[] (ByVal buf As Any Ptr)            ' Operator Delete[] Overload
      Dim As String array (1 To 4)
   End Type

   Constructor UDT ()
      Static As Integer n
      Print "    Constructor"
      printArray("        init: @" & @This & " (descriptors) -> ", This.array())
      For i As Integer = LBound(This.array) To UBound(This.array)
         This.array(i) = Chr(Asc("a") + n + i - LBound(This.array))
      Next i
      printArray(" => ", This.array())
      Print
      n += UBound(This.array)- LBound(This.array) + 1
   End Constructor

   Destructor UDT ()
      Print "    Destructor"
      printArray("        erase: @" & @This & " (descriptors) -> ", This.array())
      Erase This.array
      printArray(" => ", This.array())
      Print
   End Destructor

   Operator UDT.New (ByVal size As UInteger) As Any Ptr
      Print "    Operator New Overload"
      Dim As Any Ptr p = Allocate(size)                   ' Memory allocation (with passed size)
      Print "        memory allocation: ";
      Print size & " Bytes from @" & p
      Return p                                            ' Returning memory pointer
   End Operator

   Operator UDT.New[] (ByVal size As UInteger) As Any Ptr
      Print "    Operator New[] Overload"
      Dim As Any Ptr p = Allocate(size)                   ' Memory allocation (with passed size)
      Print "        memory allocation: ";
      Print size & " Bytes from @" & p
      Return p                                            ' Returning memory pointer
   End Operator

   Operator UDT.Delete (ByVal buf As Any Ptr)
      Print "    Operator Delete Overload"
      Deallocate(buf)                                     ' Memory deallocation (with passed pointer)
      Print "        memory deallocation: ";
      Print "for @" & buf
   End Operator

   Operator UDT.Delete[] (ByVal buf As Any Ptr)
      Print "    Operator Delete[] Overload"
      Deallocate(buf)                                     ' Memory deallocation (with passed pointer)
      Print "        memory deallocation: ";
      Print "for @" & buf
   End Operator

   Print "Operator New Expression"
   Dim As UDT Ptr pu1 = New UDT         ' Operator New Expression
   Print "Operator Delete Statement"
   Delete pu1                           ' Operator Delete Statement
   Sleep

   Print
   Print "Operator New[] Expression"      
   Dim As UDT Ptr pu2 = New UDT[2]      ' Operator New[] Expression
   Print "Operator Delete[] Statement"
   Delete[] pu2                         ' Operator Delete[] Statement
   Sleep

   Dim As Byte buffer(1 To 256)
   Dim As Any Ptr p = @buffer(1)

   Print
   Print "Operator Placement New"
   Dim As UDT Ptr pu3 = New(p) UDT      ' Operator Placement New
   Print "User call of Destructor"
   pu3->Destructor()                    ' User Call of Destructor
   Sleep

   Print
   Print "Operator Placement New[]"
   Dim As UDT Ptr pu4 = New(p) UDT[2]   ' Operator Placement New[]
   For i As Integer = 0 To 1
      Print "User Call of Destructor"
      pu4[i].Destructor()              ' User Call of Destructor
   Next i
   Sleep

   Sub printArray (ByRef label As String = "", array() As String)
      Print label & "{";
      For i As Integer = LBound(array) To UBound(array)
         Print """" & array(i) & """";
         If i < UBound(array) Then
            Print ",";
         End If
      Next I
      Print "}";
   End Sub

Output example (for a 64-bit system):

   Operator New Expression
   	Operator New Overload
   		memory allocation: 96 Bytes from @1728352
   	Constructor
   		init: @1728352 (descriptors) -> {"","","",""} => {"a","b","c","d"}
   Operator Delete Statement
   	Destructor
   		Erase: @1728352 (descriptors) -> {"a","b","c","d"} => {"","","",""}
   	Operator Delete Overload
   		memory deallocation: For @1728352


   Operator New[] Expression
   	Operator New[] Overload
   		memory allocation: 200 Bytes from @1728352
   	Constructor
   		init: @1728360 (descriptors) -> {"","","",""} => {"e","f","g","h"}
   	Constructor
   		init: @1728456 (descriptors) -> {"","","",""} => {"i","j","k","l"}
   Operator Delete[] Statement
   	Destructor
   		Erase: @1728456 (descriptors) -> {"i","j","k","l"} => {"","","",""}
   	Destructor
   		Erase: @1728360 (descriptors) -> {"e","f","g","h"} => {"","","",""}
   	Operator Delete[] Overload
   		memory deallocation: For @1728352


   Operator Placement New
   	Constructor
   		init: @1375248 (descriptors) -> {"","","",""} => {"m","n","o","p"}
   User Call of Destructor
   	Destructor
   		Erase: @1375248 (descriptors) -> {"m","n","o","p"} => {"","","",""}


   Operator Placement New[]
   	Constructor
   		init: @1375248 (descriptors) -> {"","","",""} => {"q","r","s","t"}
   	Constructor
   		init: @1375344 (descriptors) -> {"","","",""} => {"u","v","w","x"}
   User Call of Destructor
   	Destructor
   		Erase: @1375248 (descriptors) -> {"q","r","s","t"} => {"","","",""}
   User Call of Destructor
   	Destructor
   		Erase: @1375344 (descriptors) -> {"u","v","w","x"} => {"","","",""}

See also
   * Operator
   * Constructor
   * Destructor
   * Use Implicit / Overload New([]) and Delete([]) Operators with Inheritance Polymorphism



------------------------------------------------------ ProPgTypeObjects ----
Types as Objects

An example of the overloadable operators and member procedures

Description
   When a Type structure is used to define a user object, many procedure 
   kinds can also be added to the data field skeleton to simplify its use 
   by any user:
      - Sub, Function and Properties members.
      - Constructors and Destructor.
      - Overload Operators (inside and outside Type definition).

   The following example is just a syntactic template for their 
   declarations and definitions:
   '' Sample Type showing available methods and operators
   '' Practically this is a pointless example, as the only
   '' data member is an Integer.  It serves only as a
   '' guide to syntax.
   ''
   '' There are many other combinations that can be
   '' used in passed parameters.  For simplicity
   '' This example only uses byref and type T
   '' where ever possible.

   '' The type 'DataType' is included to show where
   '' any data type might be used
   Type DataType As Integer

   '' The type 'UDT' is included to show where only 
   '' a UDT data type can be used
   Type UDT
     value As DataType
   End Type

   '' Our main type
   Type T
     value As DataType
     value_array( 0 ) As DataType

     '' let, cast, combined assignment operators,
     '' constructors, and the destructor, must be
     '' declared inside the type.
     ''
     '' Parameters can be passed Byval or Byref
     '' in most (All? - verify this).
     ''
     '' All procs can be overloaded with different
     '' types as parameters.  In many cases this is not
     '' necessary as the TYPE can be coerced and
     '' converted depending on the CAST methods
     '' it exposes.  The compiler will to its best
     '' to evaluate statements and expressions if
     '' there is enough information to complete
     '' the operation.
     ''
     '' For example,
     '' Even though operator += may not be overloaded
     '' but operator let and operator + are, the
     '' compiler will convert the T += datatype
     '' to T = T + datatype.

     '' Nonstatic members must be declared inside the
     '' type.
     ''
     '' All Nonstatic members are implicitly
     '' passed a hidden **this** parameter having
     '' the same type as the TYPE in which they are
     '' declared.
     ''
     '' Nonstatic member overloaded operators do not
     '' return a type.  All operations are done on the
     '' hidden this parameter.
     ''
     '' Properties: Can be value properties or single
     '' indexed value properties
     '' GET/SET methods must be each delcared if used.

     '' Nonstatic Member Declarations:

     '' Memory Allocation/Deallocation
     
     Declare Operator New ( ByVal size As UInteger ) As Any Ptr
     Declare Operator New[] ( ByVal size As UInteger ) As Any Ptr
     Declare Operator Delete ( ByVal buf As Any Ptr )
     Declare Operator Delete[] ( ByVal buf As Any Ptr )

     '' Assignment

     Declare Operator Let ( ByRef rhs As T )
     Declare Operator Let ( ByRef rhs As DataType )

     '' Cast can be overloaded to return multiple types

     Declare Operator Cast () As String
     Declare Operator Cast () As DataType

     '' Combined assignment

     Declare Operator += ( ByRef rhs As T )
     Declare Operator += ( ByRef rhs As DataType )
     Declare Operator -= ( ByRef rhs As DataType )
     Declare Operator *= ( ByRef rhs As DataType )
     Declare Operator /= ( ByRef rhs As DataType )
     Declare Operator \= ( ByRef rhs As DataType )
     Declare Operator Mod= ( ByRef rhs As DataType )
     Declare Operator Shl= ( ByRef rhs As DataType )
     Declare Operator Shr= ( ByRef rhs As DataType )
     Declare Operator And= ( ByRef rhs As DataType )
     Declare Operator Or= ( ByRef rhs As DataType )
     Declare Operator Xor= ( ByRef rhs As DataType )
     Declare Operator Imp= ( ByRef rhs As DataType )
     Declare Operator Eqv= ( ByRef rhs As DataType )
     Declare Operator ^= ( ByRef rhs As DataType )
     Declare Operator &= ( ByRef rhs As DataType )
     
     '' Address of

     Declare Operator @ () As DataType Ptr

     '' Constructors can be overloaded

     Declare Constructor ()
     Declare Constructor ( ByRef rhs As T )
     Declare Constructor ( ByRef rhs As DataType )

     '' There can be only one destructor

     Declare Destructor ()

     '' Nonstatic member functions and subs
     '' overloaded procs must have different parameters

     Declare Function f ( ) As DataType
     Declare Function f ( ByRef arg1 As DataType ) As DataType

     Declare Sub s ( )
     Declare Sub s ( ByRef arg1 As T )
     Declare Sub s ( ByRef arg1 As DataType )

     '' Properties

     Declare Property p () As DataType
     Declare Property p ( ByRef new_value As DataType )

     Declare Property pidx ( ByVal index As DataType ) As DataType
     Declare Property pidx ( ByVal index As DataType, ByRef new_value As DataType )

     '' Iterator
     
     Declare Operator For ()
     Declare Operator Step ()
     Declare Operator Next ( ByRef cond As T ) As Integer

     Declare Operator For ( ByRef stp As T )
     Declare Operator Step ( ByRef stp As T )
     Declare Operator Next ( ByRef cond As T, ByRef stp As T ) As Integer

   End Type

   '' These must be global procedures
   '' Globals are not prefixed with the the TYPE name

   '' At least one parameter must be of Type 'T'
   '' For simplicity, type 'T' is always given first for binary ops
   '' in this example

   Declare Operator - ( ByRef rhs As T ) As DataType
   Declare Operator Not ( ByRef rhs As T ) As DataType

   Declare Operator -> ( ByRef rhs As T ) As UDT
   Declare Operator * ( ByRef rhs As T ) As DataType

   Declare Operator + ( ByRef lhs As T, ByRef rhs As DataType ) As DataType
   Declare Operator - ( ByRef lhs As T, ByRef rhs As DataType ) As DataType 
   Declare Operator * ( ByRef lhs As T, ByRef rhs As DataType ) As DataType
   Declare Operator / ( ByRef lhs As T, ByRef rhs As DataType ) As DataType
   Declare Operator \ ( ByRef lhs As T, ByRef rhs As DataType ) As DataType
   Declare Operator Mod ( ByRef lhs As T, ByRef rhs As DataType ) As DataType
   Declare Operator Shl ( ByRef lhs As T, ByRef rhs As DataType ) As DataType
   Declare Operator Shr ( ByRef lhs As T, ByRef rhs As DataType ) As DataType
   Declare Operator And ( ByRef lhs As T, ByRef rhs As DataType ) As DataType
   Declare Operator Or ( ByRef lhs As T, ByRef rhs As DataType ) As DataType
   Declare Operator Xor ( ByRef lhs As T, ByRef rhs As DataType ) As DataType
   Declare Operator Imp ( ByRef lhs As T, ByRef rhs As DataType ) As DataType
   Declare Operator Eqv ( ByRef lhs As T, ByRef rhs As DataType ) As DataType
   Declare Operator ^ ( ByRef lhs As T, ByRef rhs As DataType ) As DataType
   Declare Operator = ( ByRef lhs As T, ByRef rhs As DataType ) As DataType
   Declare Operator <> ( ByRef lhs As T, ByRef rhs As DataType ) As DataType
   Declare Operator < ( ByRef lhs As T, ByRef rhs As DataType ) As DataType
   Declare Operator > ( ByRef lhs As T, ByRef rhs As DataType ) As DataType
   Declare Operator <= ( ByRef lhs As T, ByRef rhs As DataType ) As DataType
   Declare Operator >= ( ByRef lhs As T, ByRef rhs As DataType ) As DataType
   Declare Operator & ( ByRef lhs As T, ByRef rhs As DataType ) As DataType

   Declare Operator Abs ( ByRef arg As UDT ) As Double
   Declare Operator Fix ( ByRef arg As UDT ) As Double
   Declare Operator Frac ( ByRef arg As UDT ) As Double
   Declare Operator Int ( ByRef arg As UDT ) As Double
   Declare Operator Sgn ( ByRef arg As UDT ) As Double

   '' Global procedures (subs and funcs) can also accept the TYPE
   '' as a parameter or return it as a value, as could be done
   '' in previous versions of FreeBASIC.
   '' No example given. See function or sub in the manual.

   '' All TYPE members are defined outside the TYPE

   '' Nonstatic members must be prefixed with type name
   '' in this case 'T'

   '' Name resolution in a NAMESPACE is same as other
   '' subs/funcs.  Use USING or prefix the namespace name

   Operator T.new ( ByVal size As UInteger ) As Any Ptr
      Operator = Allocate( size )
   End Operator
    
   Operator T.new[] ( ByVal size As UInteger ) As Any Ptr
      Operator = Allocate( size )
   End Operator

   Operator T.delete ( ByVal buf As Any Ptr )
      Deallocate buf
   End Operator

   Operator T.delete[] ( ByVal buf As Any Ptr )
      Deallocate buf
   End Operator

   Operator T.let ( ByRef rhs As T )
     value = rhs.value  
   End Operator

   Operator T.let ( ByRef rhs As DataType )
     value = rhs  
   End Operator

   Operator T.cast ( ) As String
     Return Str( value )
   End Operator

   Operator T.cast ( ) As DataType
     Return value
   End Operator

   Operator T.+= ( ByRef rhs As T )
     value += rhs.value
   End Operator

   Operator T.+= ( ByRef rhs As DataType )
     value += rhs
   End Operator

   Operator T.-= ( ByRef rhs As DataType )
     value -= rhs
   End Operator

   Operator T.*= ( ByRef rhs As DataType )
     value *= rhs
   End Operator

   Operator T./= ( ByRef rhs As DataType )
     value /= rhs
   End Operator

   Operator T.\= ( ByRef rhs As DataType )
     value \= rhs
   End Operator

   Operator T.mod= ( ByRef rhs As DataType )
     value Mod= rhs
   End Operator

   Operator T.shl= ( ByRef rhs As DataType )
     value Shl= rhs
   End Operator

   Operator T.shr= ( ByRef rhs As DataType )
     value Shr= rhs
   End Operator

   Operator T.and= ( ByRef rhs As DataType )
     value And= rhs
   End Operator

   Operator T.or= ( ByRef rhs As DataType )
     value Or= rhs
   End Operator

   Operator T.xor= ( ByRef rhs As DataType )
     value Xor= rhs
   End Operator

   Operator T.imp= ( ByRef rhs As DataType )
     value Imp= rhs
   End Operator

   Operator T.eqv= ( ByRef rhs As DataType )
     value Eqv= rhs
   End Operator

   Operator T.^= ( ByRef rhs As DataType )
     value ^= rhs
   End Operator

   Operator T.&= ( ByRef rhs As DataType )
     Dim tmp As String
     tmp &= Str( rhs )
   End Operator

   Operator T.@ () As DataType Ptr
     Return( Cast( DataType Ptr, @This ))
   End Operator

   '' Constructors:

   Constructor T ()
     '' default constructor
     value = 0
   End Constructor

   Constructor T ( ByRef rhs As T )
     '' copy constructor
     value = rhs.value
   End Constructor

   Constructor T ( ByRef rhs As DataType )
     '' custom constructor
     value = rhs
   End Constructor

   '' There can be only one destructor

   Destructor T ()
     '' clean-up, none in this example
   End Destructor

   '' Globals must specify all arguments and return type

   Operator - ( ByRef rhs As T ) As DataType
     Return (-rhs.value)
   End Operator

   Operator Not ( ByRef rhs As T ) As DataType
     Return (Not rhs.value)
   End Operator

   Operator -> ( ByRef rhs As T ) As UDT
     Return Type(4)
   End Operator

   Operator * ( ByRef rhs As T ) As DataType
     Return 5
   End Operator

   Operator + ( ByRef lhs As T, ByRef rhs As DataType ) As DataType
     Return (lhs.value + rhs)
   End Operator

   Operator - ( ByRef lhs As T, ByRef rhs As DataType ) As DataType
     Return (lhs.value - rhs)
   End Operator

   Operator * ( ByRef lhs As T, ByRef rhs As DataType ) As DataType
     Return (lhs.value * rhs)
   End Operator

   Operator / ( ByRef lhs As T, ByRef rhs As DataType ) As DataType
     Return (lhs.value / rhs)
   End Operator

   Operator \ ( ByRef lhs As T, ByRef rhs As DataType ) As DataType
     Return (lhs.value \ rhs)
   End Operator

   Operator Mod ( ByRef lhs As T, ByRef rhs As DataType ) As DataType
     Return (lhs.value Mod rhs)
   End Operator

   Operator Shl ( ByRef lhs As T, ByRef rhs As DataType ) As DataType
     Return (lhs.value Shl rhs)
   End Operator

   Operator Shr ( ByRef lhs As T, ByRef rhs As DataType ) As DataType
     Return (lhs.value Shr rhs)
   End Operator

   Operator And ( ByRef lhs As T, ByRef rhs As DataType ) As DataType
     Return (lhs.value And rhs)
   End Operator

   Operator Or ( ByRef lhs As T, ByRef rhs As DataType ) As DataType
     Return (lhs.value Or rhs)
   End Operator

   Operator Xor ( ByRef lhs As T, ByRef rhs As DataType ) As DataType
     Return (lhs.value Xor rhs)
   End Operator

   Operator Imp ( ByRef lhs As T, ByRef rhs As DataType ) As DataType
     Return (lhs.value Imp rhs)
   End Operator

   Operator Eqv ( ByRef lhs As T, ByRef rhs As DataType ) As DataType
     Return (lhs.value Eqv rhs)
   End Operator

   Operator ^ ( ByRef lhs As T, ByRef rhs As DataType ) As DataType
     Return (lhs.value ^ rhs)
   End Operator

   Operator = ( ByRef lhs As T, ByRef rhs As DataType ) As DataType
     Return (lhs.value = rhs)
   End Operator

   Operator <> ( ByRef lhs As T, ByRef rhs As DataType ) As DataType
     Return (lhs.value <> rhs)
   End Operator

   Operator < ( ByRef lhs As T, ByRef rhs As DataType ) As DataType
     Return (lhs.value < rhs)
   End Operator

   Operator > ( ByRef lhs As T, ByRef rhs As DataType ) As DataType
     Return (lhs.value > rhs)
   End Operator

   Operator <= ( ByRef lhs As T, ByRef rhs As DataType ) As DataType
     Return (lhs.value <= rhs)
   End Operator

   Operator >= ( ByRef lhs As T, ByRef rhs As DataType ) As DataType
     Return (lhs.value >= rhs)
   End Operator

   Operator & ( ByRef lhs As T, ByRef rhs As DataType ) As DataType
     Return Val(lhs.value & rhs)
   End Operator

   Operator Abs ( ByRef arg As UDT ) As Double
      Return Abs(arg.value)
   End Operator

   Operator Fix ( ByRef arg As UDT ) As Double
      Return Fix(arg.value)
   End Operator

   Operator Frac ( ByRef arg As UDT ) As Double
      Return Frac(arg.value)
   End Operator

   Operator Int ( ByRef arg As UDT ) As Double
      Return Int(arg.value)
   End Operator

   Operator Sgn ( ByRef arg As UDT ) As Double
      Return Sgn(arg.value)
   End Operator

   '' Nonstatic member methods

   Function T.f ( ) As DataType
     Dim x As DataType
     Return x
   End Function

   Function T.f ( ByRef arg1 As DataType ) As DataType
     arg1 = this.value
     Return value
   End Function

   Sub T.s ( )
     '' refer to the type using
     
     '' with block
     With This
      .value = 1
     End With
     
     '' field access
     this.value = 2
     
     '' directly
     value = 3

   End Sub

   Sub T.s ( ByRef arg1 As T )
     value = arg1.value
   End Sub

   Sub T.s ( ByRef arg1 As DataType )
     value = arg1
   End Sub

   Property T.p () As DataType
     '' GET property
     Return value
   End Property

   Property T.p ( ByRef new_value As DataType )
     '' SET property
     value = new_value
   End Property

   Property T.pidx ( ByVal index As DataType ) As DataType
     '' GET indexed property
     Return value_array( index )
   End Property

   Property T.pidx ( ByVal index As DataType, ByRef new_value As DataType )
     '' SET indexed property
     value_array( index ) = new_value
   End Property

   Operator T.for ()
   End Operator

   Operator T.step ()
   End Operator

   Operator T.next ( ByRef cond As T ) As Integer
     Return 0
   End Operator

   Operator T.for ( ByRef stp As T )
   End Operator 

   Operator T.step ( ByRef stp As T )
   End Operator

   Operator T.next ( ByRef cond As T, ByRef stp As T ) As Integer
     Return 0
   End Operator

   '' new, delete, delete[]

   '' Allocate object
   Dim X As T Ptr = New T

   '' Deallocate object
   Delete X

   '' Allocate object vector
   Dim Xlist As T Ptr = New T[10]

   '' Deallocate object vector
   Delete[] Xlist
         

See also
   * Type



----------------------------------------------- ProPgCompoAggregInherit ----
Composition, Aggregation, Inheritance

Properly choice between Composition, Aggregation, and Inheritance, for User 
Defined Types.

Preamble:

   Complex type structures can be built through composition, aggregation, 
   and inheritance.
   Composition or aggregation (specialized form of association) is the 
   process of creating more complex types from simple ones, while 
   inheritance is the process of creating more complex type by acquiring 
   the attributes and behaviors of existing ones.

   There is a very famous design principle which says â€œFavor composition 
   over inheritanceâ€œ, or also "Donâ€™t use inheritance just to get code 
   reuse".
   One other reason to favor composition with FreeBASIC (as with many other 
   languages) is it does not support multiple inheritance.

Definition of composition, aggregation, inheritance
   The right question to ask himself for choosing the type of relationship 
   to use is to determine if this relationship is rather "HAS-A" or 
   "USES-A" or "IS-A" throughout the lifetime of the application (see 
   example below).

   When user needs to use property and behavior of a type without modifying 
   it inside its type, then association is a better option.
   Whereas if needed to use and modify property and behavior of a type 
   inside the user type, it is best to use inheritance.

   Definition of each relationship
      Composition (strong association) establishes a "HAS-A" relationship 
      between objects:
         - In composition, the component object exists solely for the use 
         of its composite object.
         - If the composite object is destroyed, the component object is 
         destroyed as well:
               > because the type contains the object itself.
         - Syntax of the member field to add in the type for object's 
         composition (or similar syntax):
               objectname As objecttypename [= initializer]

      Aggregation (weak association) establishes a â€œUSES-Aâ€� 
      relationship between objects:
         - In aggregation, the component object can have an existence 
         independent of its use in the aggregate object.
         - Destroying the aggregate does not destroy the component:
               > because the type contains only a pointer to the object.
         - Syntax of the member field to add in the type for object's 
         aggregation (or similar syntax):
               objectptrname As objecttypename Ptr [= initializer]

      Inheritance establishes an â€œIS-Aâ€� relationship between 
      instantiable types:
         - The derived-type has the same features and functionality as its 
         base-type, with some extensions.
         - Syntax of the type's declaration header for object's 
         inheritance:
               Type typename [Alias alternatename] Extends objecttypename [
               Field = alignment]

Advantages of object association (composition/aggregation) over inheritance
   In most cases "HAS-A" or "USES-A" relationship is more semantically 
   correct than "IS-A" relationship.

   Aggregation is more flexible than inheritance.
   Implementation of type can be changed at run-time by changing the 
   component object, but this cannot be do with inheritance (behavior of 
   base type cannot be changed at run-time).

   A design based on object association usually will have less types.

   It is possible to implement a pseudo "multiple inheritance" (in 
   languages which do not support it) by composing multiple objects into 
   one.
   There is no conflict between procedures/properties names, which might 
   occur with inheritance.

Downsides of object association (composition/aggregation) compared to 
inheritance
   When using aggregation, the behavior of the system may be harder to 
   understand just by looking at the source code, since it's more dynamic 
   and more interaction between types happens in run-time, rather than 
   compile time.

   Association approach might require more code and time effort.
   A design based on object association usually will have more objects.

Example
   Simple illustrative example that mixes composition, aggregation, and 
   inheritance:
   ' Between the different types "Driver", "Person", "Driver_license" and "Vehicle", the respective relationships are:
   '    - A driver â€œIS-Aâ€� person (driver is a person): => "INHERITANCE".
   '    - A driver â€œHAS-Aâ€� driver's license (driver license only existing for the driver): => "COMPOSITION".
   '    - A driver â€œUSES-Aâ€� vehicle (vehicle lifetime independent of the driver life): => "AGGREGATION".

   Type Person
      Public:
         Dim As String full_name
         Declare Constructor (ByRef _full_name As String)
      Protected:  '' to forbid at compile time the default-construction attempt of a Person instance
         Declare Constructor ()
   End Type
   Constructor Person (ByRef _full_name As String)
      This.full_name = _full_name
   End Constructor

   Type Driver_license
      Public:
         Dim As Integer number
   End Type

   Type Vehicle
      Public:
         Dim As String registration
         Declare Constructor (ByRef _registration As String)
   End Type
   Constructor Vehicle (ByRef _registration As String)
      This.registration = _registration
   End Constructor

   Type Driver Extends Person        '' inheritance
      Public:
         Dim As Driver_license dl  '' composition
         Dim As Vehicle Ptr pv     '' aggregation
         Declare Constructor (ByRef _full_name As String, ByRef _dl As Driver_license)
   End Type
   Constructor Driver (ByRef _full_name As String, ByRef _dl As Driver_license)
      Base(_full_name)
      This.dl = _dl
   End Constructor

   Dim As Driver d1 = Driver("User fxm", Type<Driver_license>(123456789))

   Dim As Vehicle Ptr pv1 = New Vehicle("ABCDEFGHI")
   d1.pv = pv1

   Print "Person full name      : " & d1.full_name
   Print "Driver license number : " & d1.dl.number
   Print "Vehicle registration  : " & d1.pv->registration

   Delete pv1
   d1.pv = 0

   Sleep
         
Output:

   Person full Name      : User fxm
   Driver license number : 123456789
   Vehicle registration  : ABCDEFGHI

See also
   * Type (Udt)
   * Extends
   * Inheritance Polymorphism
   * OBJECT built-in and RTTI info



----------------------------------------------------- ProPgPolymorphism ----
Inheritance Polymorphism

The Inheritance Polymorphism is the ability of calling from the base-type 
the member procedures of derived-types without worrying about the real type 
of the processed objects.

Preamble:

   Inheritance polymorphism (sub-type polymorphism) is the concept of 
   providing a single interface to entities that can have different types.
   More precisely, a same interface is implemented by member procedures 
   having the same identifier in each type belonging to the same 
   inheritance hierarchy.

   Thanks to the 'abstract'/'virtual' procedures, one can write a code 
   using only the base-type that will automatically call the derived-type 
   procedures.
   It is then possible to call the procedure of an object without worrying 
   about its intrinsic type.

   By using the same procedure name for several different types, the 
   polymorphism allows a much more generic programming (abstraction).
   The coder does not have to know, when calling a base procedure, the 
   precise type of object on which the procedure will apply. He just needs 
   to know that this type will implement the procedure.

   For example a procedure 'moving()' will perform the appropriate movement 
   according to the real derived-type of the instance referenced at the 
   time of the call. This will allow the program to say 'instance.moving()' 
   without having to worry about the real derived-type of 'instance'.

Inheritance polymorphism operating
   The ability to redefine a procedure in a derived-type inheriting from a 
   base-type is called specialization.
   It is then possible to call the procedure of an object without worrying 
   about its intrinsic type: it is the inheritance polymorphism.

   This makes it possible to abstract the details of the specialized types 
   of an object family, by masking them by a common interface which is the 
   base-type.

   Designation of objects using pointers or references of base-type
      Considering a collection of objects whose instantiate types are 
      derived-types from a base-type, then all these objects can be 
      manipulated in an uniform way by considering them as objects of the 
      base-type.
      Better, certain behaviors can be specialized according to the 
      instantiate type of each object. In other words, the use of distinct 
      objects of the same inheritance hierarchy is homogeneous even if the 
      behavior of these objects remains specific.

      Thus, a base-type pointer or reference, pointing to an instance of a 
      derived-type, can be used to manipulate such an object.	

   Overriding the abstract/virtual procedures in the base-type by 
   specialized procedures in derived-types
      To can declare abstract/virtual procedures in a type, this type must 
      'Extends' (directly or indirectly) the built-in 'Object' type.

      A derived-type can override an abstract/virtual procedure declared in 
      its base-type, by declaring a procedure with the same identifier and 
      signature, meaning same number and type of parameters, same calling 
      convention, and if any, same return type (or a return of a 
      derived-type for return by reference or by pointer):
         - Normally a base-type reference/pointer can access only a 
         procedure in the same type or in a type upper in hierarchy (static 
         binding at compile-time), even if this reference/pointer refers to 
         an object of instantiate type derived from the base-type.
         - But when the base-type procedure is abstract/virtual, this tells 
         the running program to resolve the override procedure the most 
         derived relating to the real object type (dynamic binding at 
         run-time).

      Restriction:
         Polymorphism is not directly compatible with:
            - any operators 'New[]' or 'Delete[]' (the array versions for  
            statement/expression/overload operators) because the use of a 
            sub-type pointer (instead of the real type) fails for accessing 
            the other elements (except the first),
            - even the overload operator 'Delete' is not directly 
            compatible because it can not be declared virtual (being 
            static).

         Instead of having to call such an operator 'Delete([])' statement 
         on derived-type pointer, the safest way is to simply call (on 
         base-type pointer) an overridden user virtual member procedure 
         that will automatically launch the operator 'Delete([])' statement 
         at derived-type level.

Inheritance polymorphism learning, through example: 'Graph type collection'
   In the below proposed example, the polymorphic part is broken down to 
   better bring out all the elements necessary for the mechanics of 
   polymorphism.

   The generic base-type chosen is any 'Graphic Form' defined by two 
   graphic points and a color (abstraction).
   The specialized derived-types are a  'Graphic Line', a 'Graphic Box', 
   and a 'Graphic Circle' (all defined by two graphic points and a color):
      - The 'Graphic Line' connects the point 1 and the point 2.
      - The 'Graphic Box' has as opposite vertices the point 1 (at the top 
      and on the left) and the point 2 (in bottom and on the right).
      - The 'Graphic Circle' has as center the point 1 and go through point 
      2.

      The abstract procedure declared in the generic base-type, and which 
      must be defined in each specialized derived-type, is the graphic 
      drawing of the specialized form in a graphic window.
      The two graphic points and the color being generic data, they so 
      induce three generic data fields in the generic base-type, included 
      by composition.
      A 'graphic point' type is also defined with encapsulation of the x/y 
      coordinate values (declared private), in order to control their 
      validity (depending on the defined graphic screen size) by means of 
      properties (but public these ones).

      Notations:
         - Generic base-type name: 'GraphicForm2P'
         - Specialized derived-type names: 'GraphicLine2P', 'GraphicBox2P', 
         'GraphicCircle2P'
         - Virtual procedure name: 'drawGraphicForm2P()'
         - Additional type name (include by composition within the generic 
         type): 'GraphicPoint'

   * 'GraphicPoint' type declaration (additional type for composition 
     within generic base-type):
         - The two coordinates ('_x' and '_y') are private as well as the 
         two static internal functions ('xValid' and 'yValid') to return 
         the validity of each coordinate passed as argument, compared to 
         the graphic window size.
         - For each coordinate, there are two public properties ('x' or 'y')
         as user interface: a getter, and a setter which tests the validity 
         of the given value.
         - The public non default constructor calls also the setters to 
         initialize the two coordinates.

   Type GraphicPoint
   	Public:  '' user interface
   		Declare Constructor ()
   		Declare Constructor (ByVal x0 As Integer = 0, ByVal y0 As Integer = 0)
   		Declare Property x () As Integer          '' x-coordinate getter
   		Declare Property x (ByVal x0 As Integer)  '' x-coordinate setter (control if inside open graphic window)
   		Declare Property y () As Integer          '' y-coordinate getter
   		Declare Property y (ByVal y0 As Integer)  '' y-coordinate setter (control if inside open graphic window)
   	Private:  '' hidden members
   		Dim As Integer _x, _y
   		Declare Static Function xValid (ByVal x0 As Integer) As Integer  '' x-coordinate inside open graphic window?
   		Declare Static Function yValid (ByVal y0 As Integer) As Integer  '' y-coordinate inside open graphic window?
   End Type

   * 'GraphicForm2P' type declaration (generic base-type):
         - Two public graphic point variables ('pt1' and 'pt2') and a 
         public color variable ('col') are included within the base type by 
         composition.
         - A public abstract procedure ('drawGraphicForm2P()') is declared 
         (but without any body defining it).
         - Although the base type is non-instantiable, a protected 
         constructor is still defined to initialize the data fields, but 
         called from each derived type constructor only.
         - A virtual destructor (with an empty body) is declared, for 
         getting compatibility with a derived type declaring its own 
         destructor (not the case here). This base type destructor is 
         public to be able to be called on a base type pointer or 
         reference.

   Type GraphicForm2P Extends Object  '' abstract graphic form defined by two points
   	Public:  '' user interface
   		Dim As GraphicPoint pt1, pt2
   		Dim As Integer col
   		Declare Abstract Sub drawGraphicForm2P ()  '' request procedure implementation for instantiable derived type
   		Declare Virtual Destructor ()              '' for polymorphic compatibility with any derived type
   	Protected:  '' hidden members
   		Declare Constructor ()
   		Declare Constructor (ByRef p1 As GraphicPoint = Type(0, 0), ByRef p2 As GraphicPoint = Type(0, 0), ByVal col0 As Integer = 0)
   End Type

   * 'GraphicLine2P', 'GraphicBox2P', 'GraphicCircle2P' type declarations 
     (specialized derived-types):
         - For each derived type, the same public procedure (
         'drawGraphicForm2P()') is declared, but its body is specialized 
         for each derived type.
         - For each derived type, a public constructor is declared and 
         defined to initialize the base data fields (by calling the base 
         constructor). No destructor because nothing specific to destroy 
         from this derived type.

   Type GraphicLine2P Extends GraphicForm2P  '' graphic line from point 1 to point 2
   	Public:  '' user interface
   		Declare Constructor (ByRef p1 As GraphicPoint = Type(0, 0), ByRef p2 As GraphicPoint = Type(0, 0), ByVal col0 As Integer = 0)
   		Declare Sub drawGraphicForm2P () Override  '' overridden procedure
   End Type


   Type GraphicBox2P Extends GraphicForm2P  '' graphic box from point 1 to point 2
   	Public:  '' user interface
   		Declare Constructor (ByRef p1 As GraphicPoint = Type(0, 0), ByRef p2 As GraphicPoint = Type(0, 0), ByVal col0 As Integer = 0)
   		Declare Sub drawGraphicForm2P () Override  '' overridden procedure
   End Type


   Type GraphicCircle2P Extends GraphicForm2P  '' graph circle centered on point1 and passing by point 2
   	Public:  '' user interface
   		Declare Constructor (ByRef p1 As GraphicPoint = Type(0, 0), ByRef p2 As GraphicPoint = Type(0, 0), ByVal col0 As Integer = 0)
   		Declare Sub drawGraphicForm2P () Override  '' overridden procedure
   End Type

   * Full code of example:
         - Three graphic points (used by the six forms) are constructed.
         - To be able to trigger polymorphism, a base type-pointer array (
         'pgf') is declared then initialized with instances of different 
         derived types, in order to constitute a collection of objects from 
         different types (but all having a common base type).
         - So, the same compiled code line, put in a loop, processes all 
         instances from different types ('pgf(I)->drawGraphicForm2P()' or 
         'Delete pgf(I)'), because the polymorphism mechanic allows to call 
         each specialized procedure at run-time. 
   Type GraphicPoint
      Public:  '' user interface
         Declare Constructor ()
         Declare Constructor (ByVal x0 As Integer = 0, ByVal y0 As Integer = 0)
         Declare Property x () As Integer          '' x-coordinate getter
         Declare Property x (ByVal x0 As Integer)  '' x-coordinate setter (control if inside open graphic window)
         Declare Property y () As Integer          '' y-coordinate getter
         Declare Property y (ByVal y0 As Integer)  '' y-coordinate setter (control if inside open graphic window)
      Private:  '' hidden members
         Dim As Integer _x, _y
         Declare Static Function xValid (ByVal x0 As Integer) As Integer  '' x-coordinate inside open graphic window?
         Declare Static Function yValid (ByVal y0 As Integer) As Integer  '' y-coordinate inside open graphic window?
   End Type

   Constructor GraphicPoint ()
   End Constructor

   Constructor GraphicPoint (ByVal x0 As Integer = 0, ByVal y0 As Integer = 0)
      This.x = x0
      This.y = y0
   End Constructor

   Property GraphicPoint.x () As Integer
      Return This._x
   End Property

   Property GraphicPoint.x (ByVal x0 As Integer)
      If GraphicPoint.xValid(x0) Then This._x = x0
   End Property

   Property GraphicPoint.y () As Integer
      Return This._y
   End Property

   Property GraphicPoint.y (ByVal y0 As Integer)
      If GraphicPoint.yValid(y0) Then This._y = y0
   End Property

   Static Function GraphicPoint.xValid (ByVal x0 As Integer) As Integer
      If ScreenPtr = 0 Then Return 0  '' no open graphic window
      Dim As Long w
      ScreenInfo(w)
      If x0 >= 0 And x0 <= w - 1 Then Return -1 Else Return 0
   End Function

   Static Function GraphicPoint.yValid (ByVal y0 As Integer) As Integer
      If ScreenPtr = 0 Then Return 0  '' no open graphic window
      Dim As Long h
      ScreenInfo( , h)
      If y0 >= 0 And y0 <= h - 1 Then Return -1 Else Return 0
   End Function

   Type GraphicForm2P Extends Object  '' abstract graphic form defined by two points
      Public:  '' user interface
         Dim As GraphicPoint pt1, pt2
         Dim As Integer col
         Declare Abstract Sub drawGraphicForm2P ()  '' request procedure implementation for instantiable derived type
         Declare Virtual Destructor ()              '' for polymorphic compatibility with any derived type
      Protected:  '' hidden members
         Declare Constructor ()
         Declare Constructor (ByRef p1 As GraphicPoint = Type(0, 0), ByRef p2 As GraphicPoint = Type(0, 0), ByVal col0 As Integer = 0)
   End Type

   Virtual Destructor GraphicForm2P ()
   End Destructor

   Constructor GraphicForm2P ()  '' implementation not absolutely necessary
   End Constructor

   Constructor GraphicForm2P (ByRef p1 As GraphicPoint = Type(0, 0), ByRef p2 As GraphicPoint = Type(0, 0), ByVal col0 As Integer = 0)
      This.pt1 = p1
      This.pt2 = p2
      This.col = col0
   End Constructor

   Type GraphicLine2P Extends GraphicForm2P  '' graphic line from point 1 to point 2
      Public:  '' user interface
         Declare Constructor (ByRef p1 As GraphicPoint = Type(0, 0), ByRef p2 As GraphicPoint = Type(0, 0), ByVal col0 As Integer = 0)
         Declare Sub drawGraphicForm2P () Override  '' overridden procedure
   End Type

   Constructor GraphicLine2P (ByRef p1 As GraphicPoint = Type(0, 0), ByRef p2 As GraphicPoint = Type(0, 0), ByVal col0 As Integer = 0)
      Base(p1, p2, col0)  '' call the base type constructor
   End Constructor

   Sub GraphicLine2P.drawGraphicForm2P ()
      If ScreenPtr <> 0 Then  '' open graphic window
         Line (This.pt1.x, This.pt1.y)-(This.pt2.x, This.pt2.y), This.col
      End If
   End Sub

   Type GraphicBox2P Extends GraphicForm2P  '' graphic box from point 1 to point 2
      Public:  '' user interface
         Declare Constructor (ByRef p1 As GraphicPoint = Type(0, 0), ByRef p2 As GraphicPoint = Type(0, 0), ByVal col0 As Integer = 0)
         Declare Sub drawGraphicForm2P () Override  '' overridden procedure
   End Type

   Constructor GraphicBox2P (ByRef p1 As GraphicPoint = Type(0, 0), ByRef p2 As GraphicPoint = Type(0, 0), ByVal col0 As Integer = 0)
      Base(p1, p2, col0)  '' call the base type constructor
   End Constructor

   Sub GraphicBox2P.drawGraphicForm2P ()
      If ScreenPtr <> 0 Then  '' open graphic window
         Line (This.pt1.x, This.pt1.y)-(This.pt2.x, This.pt2.y), This.col, B
      End If
   End Sub

   Type GraphicCircle2P Extends GraphicForm2P  '' graph circle centered on point1 and passing by point 2
      Public:  '' user interface
         Declare Constructor (ByRef p1 As GraphicPoint = Type(0, 0), ByRef p2 As GraphicPoint = Type(0, 0), ByVal col0 As Integer = 0)
         Declare Sub drawGraphicForm2P () Override  '' overridden procedure
   End Type

   Constructor GraphicCircle2P (ByRef p1 As GraphicPoint = Type(0, 0), ByRef p2 As GraphicPoint = Type(0, 0), ByVal col0 As Integer = 0)
      Base(p1, p2, col0)  '' call the base type constructor
   End Constructor

   Sub GraphicCircle2P.drawGraphicForm2P ()
      If ScreenPtr <> 0 Then  '' open graphic window
         Dim As Integer r = Sqr((This.pt2.x - This.pt1.x) * (This.pt2.x - This.pt1.x) + (This.pt2.y - This.pt1.y) * (This.pt2.y - This.pt1.y))
         Circle (This.pt1.x, This.pt1.y), r, This.col
      End If
   End Sub

   Screen 12  '' open graphic window

   Dim As GraphicPoint p1 = GraphicPoint(320, 240)  '' to construct graphic point 1
   Dim As GraphicPoint p2 = GraphicPoint(500, 350)  '' to construct graphic point 2
   Dim As GraphicPoint p3 = GraphicPoint(280, 170)  '' to construct graphic point 2

   '' array of base type pointer referring to instances of different derived types
   Dim As GraphicForm2P Ptr pgf (...) = {New GraphicLine2P(p1, p2, 14), New GraphicBox2P(p1, p2, 13), New GraphicCircle2P(p1, p2, 12), _
                                New GraphicLine2P(p1, p3, 11), New GraphicBox2P(p1, p3, 10), New GraphicCircle2P(p1, p3, 09)}

   For I As Integer = LBound(pgf) To UBound(pgf)
      pgf(I)->drawGraphicForm2P()  '' accessing dedicated overridden procedure by polymorphism
   Next I

   For I As Integer = LBound(pgf) To UBound(pgf)
      Delete pgf(I)  '' accessing dedicated overridden destructor (if necessary) by polymorphism
   Next I

   Sleep
            
See the graphics output by running this code.

See also
   * Type (Udt), Extends, Object, Operator Is (Rtti)
   * Virtual, Abstract, Override
   * Pointer, Reference
   * Composition, Aggregation, Inheritance
   * OBJECT built-in and RTTI info
   * Use Implicit / Overload New([]) and Delete([]) Operators with Inheritance Polymorphism



------------------------------------------------- ProPgCtorsAssignDtors ----
Constructors, '=' Assignment-Operators, and Destructors (advanced, part #1)

Proper use of Constructors, '=' Assignment-Operators, and Destructors, 
which are the special member procedures for constructing/initializing, 
assigning, and destroying objects (part #1).

Preamble:

   Some member procedures, which have a predefined name in the Type, have a 
   specific role that is constructing, assigning, and destroying objects. 
   These are the constructors, the '=' assignment-operators, and the 
   destructor.
   Of these, some are special because a version will be automatically built 
   by the compiler if they are needed and not explicitly defined by the 
   user. These are the default-constructor, the copy-constructor, the 
   copy-assignment operator, and the destructor.

   It is therefore often necessary that user defines its own explicit 
   versions in order to execute actions that must take place during all 
   lifetime of an object:
      - For example, if the object contains dynamically allocated 
      variables, it is necessary to reserve them memory when the object is 
      created.
      - For object assignment, the memory must often be reallocated.
      - At the destruction of the object, it is necessary to free the 
      allocated memory.

   Once the user defines any explicit constructor or explicit destructor, 
   the compiler no longer automatically defines the implicit default 
   constructor or the implicit destructor.
   In particular, if the user only defines an explicit constructor taking 
   parameters, it will no longer be possible to simply construct an object, 
   without providing the parameters to this constructor, unless, of course, 
   the user defines also an explicit default constructor (the one which 
   does not take parameters).

   Type inheritance and virtuality must also be taken into account for 
   defining these special member procedures.

   As any member, these special member procedures may have any 
   accessibility, public, protected or private (but a private access does 
   not have much interest, and even can totally prevent any direct or 
   derived object construction).

   Table of Contents
1. Constructors and destructors
2. '=' Assignment-operators
3. Processing variable-length arrays as members of Type

1. Constructors and destructors
   A constructor is called automatically when instantiating the object. The 
   destructor is called automatically when it is destroyed.
   This destruction occurs when outputting the current scope block for auto 
   storage kind objects.

   For dynamically allocated objects, the constructor and destructor are 
   automatically called by expressions that use the 'New', 'New[]', and 
   'Delete', 'Delete[]' operators. That is why it is recommended to use 
   them instead of the '[C|Re]]Allocate' and 'Deallocate' functions to 
   dynamically create objects.
   Also, do not use 'Delete' or 'Delete[]' on 'Any Ptr' pointers, because 
   the compiler must determine which destructor to call with the type of 
   pointer.

   Definition of constructors and destructors
      The constructor is called after the memory allocation of the object 
      and the destructor is called before this memory is freed. The 
      management of the dynamic allocation of memory with the Types is thus 
      simplified.
      In the case of member object fields, the order of construction is 
      that of their declarations, and the order of destruction is the 
      reverse. It is in this order that the constructors and destructors of 
      each member object field are called.

      The explicit constructors may have parameters. They can be 
      overloaded, but not the explicit destructors. This is because in 
      general one knows the context in which an object is created, but one 
      cannot know the context in which it is destroyed: there can only be 
      one destructor.
      Constructors that do not take a parameter or with all parameters 
      having a default value, automatically replace the default 
      constructors defined by the compiler if there were no explicitly 
      defined constructors in the Types. This means that these constructors 
      will be called automatically by the default constructors of the 
      derived Types.

      Example - Constructors and destructor ('ZstringChain' Type):
   Type ZstringChain                                '' implement a zstring chain
      Dim As ZString Ptr pz                        '' define a pointer to the chain
      Declare Constructor ()                       '' declare the explicit default constructor
      Declare Constructor (ByVal size As Integer)  '' declare the explicit constructor with as parameter the chain size
      Declare Destructor ()                        '' declare the explicit destructor
   End Type

   Constructor ZstringChain ()
      This.pz = 0  '' reset the chain pointer
   End Constructor

   Constructor ZstringChain (ByVal size As Integer)
      This.pz = CAllocate(size + 1, SizeOf(ZString))  '' allocate memory for the chain
   End Constructor

   Destructor ZstringChain ()
      If This.pz <> 0 Then
         Deallocate This.pz  '' free the allocated memory if necessary
      This.pz = 0         '' reset the chain pointer
      End If
   End Destructor

   Dim As ZstringChain zc1  '' instantiate a non initialized chain : useless

   Dim As ZstringChain zc2 = ZstringChain(9)  '' instantiate a szstring chain of 9 useful characters
   '                                          '' shortcut: Dim As ZstringChain zc2 = 9
   *zc2.pz = "FreeBASIC"                      '' fill up the chain with 9 characters
   Print "zc2 chain:"
   Print "'" & *zc2.pz & "'"                  '' print the chain

   Sleep
            
Output:

   zc2 Chain:
   'FreeBASIC'
   				

      The constructors will sometimes have to perform more complicated 
      tasks than those given in this example. In general, they can do all 
      the feasible operations in a normal member procedure, except using 
      uninitialized data of course.
      In particular, the data of inherited objects are not initialized as 
      long as the constructors of the base-Types are not called. For this 
      reason, the constructors of the base-Types must always be called 
      before running the constructor of the Type being instantiated.
      If the constructors of the base-Types are not explicitly called, the 
      compiler will call, by default, the constructors of the base-Types 
      that do not take a parameter or whose parameters have a default value 
      (and, if no such a constructor is explicitly defined in the 
      base-Types, it will call the implicit default constructors of these 
      Types).

   Constructors
      A constructor is a kind of member procedure that initializes an 
      instance of its Type. A constructor has the same name as the Type and 
      no return value. A constructor can have any number of parameters and 
      a Type may have any number of overloaded constructors.

      If not any constructor is explicitly defined, the compiler will 
      generate (if needed) a default-constructor that takes no parameters. 
      The user can cancel this behavior by declaring and defining 
      explicitly its own default-constructor.
      If the user defines his own constructor(s), implicit 
      default-initialization operations are always done prior to the user's 
      constructor(s) code execution.

      Order of Construction:
         - The Type constructor is called.
         - The base Types and their member constructors are called in the 
         order of declaration.
         - If the Type has virtual member procedures (including these 
         inherited from its Base), the virtual-pointer (vptr) is set to 
         point to the virtual-table (vtbl) of the Type.
         - The body of the Type constructor procedure is executed.

      Default-constructor:
         The default-constructor has no parameters.
         It follows slightly different rules:
            - The default-constructor is one of the special member 
            functions.
            - If no constructors are explicitly declared in a Type, the 
            compiler provides a default-constructor.
            - If any non default-constructors are declared, the compiler 
            does not provide a default-constructor and the user is forced 
            to declare one if necessary.

      Conversion-constructors:
         If a Type has a constructor with a single parameter, or if at 
         least all other parameters have a default value, the type of the 
         first argument can be implicitly converted to the type of the Type 
         by the compiler.
         In such expressions, the term 'variable' may be considered as a 
         short-cut of 'typename(variable)'.

         Such conversions can be useful in some cases, but more often they 
         can lead to poor readability (in these cases, it is better to 
         explicitly call the matching constructor).

         Example - Implicit conversion:
   Type UDT Extends Object
      Declare Constructor ()
      Declare Constructor (ByVal i0 As Integer)
      Declare Destructor ()
      Dim As Integer i
   End Type

   Constructor UDT ()
      Print "   => UDT.default-constructor", @This
   End Constructor

   Constructor UDT (ByVal i0 As Integer)
      Print "   => UDT.conversion-constructor", @This
      This.i = i0
   End Constructor

   Function RtnI (ByRef u As UDT) As Integer
      Return u.i
   End Function
    
   Destructor UDT ()
      Print "   => UDT.destructor", , @This
   End Destructor

   Scope
      Print "Construction: 'Dim As UDT u'"
      Dim As UDT u
      Print
      Print "Assignment: 'u = 123'"
      Print "      " & RtnI(123)            ''  RtnI(123): implicite conversion using the conversion-constructor,
      '                                     ''             short_cut of RtnI(UDT(123))
      Print
      Print "Going out scope: 'End Scope'"
   End Scope

   Sleep
               
Output example:

   Construction: 'Dim As UDT u'
      => UDT.default-Constructor             1703588

   Assignment: 'u = 123'
      => UDT.conversion-Constructor          1703580
   	  123
      => UDT.destructor                      1703580

   Going Out Scope: 'End Scope'
      => UDT.destructor                      1703588
   					

         But such conversions can even lead to subtle but serious errors in 
         the code.

         Example - Subtle/Serious errors in the code:
   Type point2D
      Declare Constructor (ByVal x0 As Integer = 0, ByVal y0 As Integer = 0)
      Declare Operator Cast () As String
      Dim As Integer x, y
   End Type

   Constructor point2D (ByVal x0 As Integer = 0, ByVal y0 As Integer = 0)
      This.x = x0
      This.y = y0
   End Constructor

   Operator point2D.cast () As String
      Return "(" & This.x & ", " & This.y & ")"
   End Operator

   Operator + (ByRef v0 As point2D, ByRef v1 As point2D) As point2D
      Return Type(v0.x + v1.x, v0.y + v1.y)
   End Operator

   Operator * (ByRef v0 As point2D, ByRef v1 As point2D) As Integer
      Return v0.x * v1.x + v0.y * v1.y
   End Operator

   Print "Construction of v1: 'Dim As point2D v1 = point2D(2, 3)'"
   Dim As point2D v1 = point2D(2, 3)
   Print "  => " & v1
   Print
   Print "Addition to v1: 'v1 + 4'"
   Print "  => " & v1 + 4                  ''  4: implicite conversion using the conversion-constructor,
   '                                       ''             short_cut of point2D(4, ) or point2D(4)
   Print
   Print "Multiplication of v1: 'v1 * 5'"
   Print "  => " & v1 * 5                  ''  5: implicite conversion using the conversion-constructor,
   '                                       ''             short_cut of point2D(5, ) or point2D(5)
   Sleep
               
Output example:

   Construction of v1: 'Dim As point2D v1 = point2D(2, 3)'
     => (2, 3)

   Addition To v1: 'v1 + 4'
     => (6, 3)

   Multiplication of v1: 'v1 * 5'
     => 10
   					
In this case, it is dangerous to declare a multi-parameter constructor with 
optional parameters, because the compiler can interpret one of its forms as 
a conversion-constructor.

         A workaround: define a default constructor, and the 
         multi-parameter constructor but without optional parameters (or at 
         least one non-optional parameter without considering the first 
         one).

      Copy-constructor:
         The copy-constructor is a special member procedure that takes as 
         input a reference to an object of the same type, and constructs a 
         new object by copying it.
         If the user does not declare a copy-constructor, the compiler 
         generates (if needed) a copy-constructor for him. The declaration 
         of a copy-assignment operator (see above) does not remove the 
         generation by the compiler of a copy-constructor.

         It will sometimes be necessary to create a copy constructor. The 
         purpose of this kind of constructor is to initialize an object 
         when instantiating it from another object.
         Any Type has if needed an implicit copy constructor automatically 
         generated by the compiler, whose sole purpose is to copy the 
         fields of the object to be copied one by one into the fields of 
         the object to be instantiated.
         However, this implicit copy constructor will not always be enough, 
         and the user will sometimes have to provide one explicitly.

         This will be particularly the case when some data objects have 
         been allocated dynamically (only member pointers in the Type for 
         object aggregation). A shallow copy of the fields of one object in 
         another would only copy the pointers, not the data pointed. Thus, 
         changing this data for one object would result in the modification 
         of the other object's data, which would probably not be the 
         desired effect.

         If the user implements a copy-constructor, it is recommend to also 
         implement a copy-assignment operator so that the meaning of the 
         code is clear.

         In addition to the explicit syntax for calling the 
         copy-constructor, this one is also called when an object is passed 
         by value to a procedure, and when a function returns an object by 
         value by using the 'Return' keyword.

         A copy constructor can not take into account its argument (the 
         object to clone) by value,  because "byval arg" itself generally 
         calls the copy-constructor, and this would induce an infinite 
         loop.

         For the 'ZstringChain' Type defined above, the user needs a copy 
         constructor:
   Type ZstringChain                                   '' implement a zstring chain
      Dim As ZString Ptr pz                           '' define a pointer to the chain
      Declare Constructor ()                          '' declare the explicit default constructor
      Declare Constructor (ByVal size As Integer)     '' declare the explicit constructor with as parameter the chain size
      Declare Constructor (ByRef zc As ZstringChain)  '' declare the explicit copy constructor
      Declare Destructor ()                           '' declare the explicit destructor
   End Type

   Constructor ZstringChain ()
      This.pz = 0  '' reset the chain pointer
   End Constructor

   Constructor ZstringChain (ByVal size As Integer)
      This.pz = CAllocate(size + 1, SizeOf(ZString))  '' allocate memory for the chain
   End Constructor

   Constructor ZstringChain (ByRef zc As ZstringChain)
      This.pz = CAllocate(Len(*zc.pz) + 1, SizeOf(ZString))  '' allocate memory for the new chain
      *This.pz = *zc.pz                                      '' initialize the new chain
   End Constructor

   Destructor ZstringChain ()
      If This.pz <> 0 Then
         Deallocate This.pz  '' free the allocated memory if necessary
         This.pz = 0         '' reset the chain pointer
      End If
   End Destructor

   Dim As ZstringChain zc1  '' instantiate a non initialized chain : useless

   Dim As ZstringChain zc2 = ZstringChain(9)           '' instantiate a szstring chain of 9 useful characters
   '                                                   '' shortcut: Dim As ZstringChain zc2 = 9
   *zc2.pz = "FreeBASIC"                               '' fill up the chain with 9 characters
   Print "zc2 chain:"
   Print "'" & *zc2.pz & "'"                           '' print the chain
   Print
   Dim As ZstringChain zc3 = zc2                       '' instantiate a new szstring chain by copy construction
   Print "zc3 chain (zc3 copy constructed from zc2):"
   Print "'" & *zc3.pz & "'"                           '' print the chain
   Print
   *zc3.pz = "modified"                                '' modify the new chain
   Print "zc3 chain (modified):"
   Print "'" & *zc3.pz & "'"                           '' print the new chain
   Print
   Print "zc2 chain:"
   Print "'" & *zc2.pz & "'"                           '' print the copied chain (not modified)

   Sleep
               
Output:

   zc2 Chain:
   'FreeBASIC'

   zc3 Chain (zc3 copy constructed from zc2):
   'FreeBASIC'

   zc3 Chain (modified):
   'modified'

   zc2 Chain:
   'FreeBASIC'
   					

   Destructor
      The destructor function is the inverse of constructor function. It is 
      called when an objects is destroyed.
      The destructor is commonly used to "clean up" when an object is no 
      longer necessary. The destructor cannot have parameters.

      If none destructor is explicitly defined, the compiler will generate 
      (if needed) a destructor. The user can override this behavior by 
      declaring and defining explicitly its own destructor.
      If the user defines his own destructor, implicit destruction 
      operations are always done posterior to the user's destruction code 
      execution.

      The destructor is called when one of the following events occurs:
         - An object created using the New operator is explicitly destroyed 
         using the Delete operator.
         - A local object with block scope goes out of scope.
         - A program terminates and global or static objects exist.

      If a base Type or data member has an accessible destructor, and if 
      the Type does not declare a destructor, the compiler generates one.

      Order of destruction:
         - The Type destructor is called
         - If the Type has virtual member procedures (including these 
         inherited from its Base), the virtual-pointer (vptr) is set to 
         point to the virtual-table (vtbl) of the Type.
         - The body of the Type destructor procedure is executed.
         - Destructors for base Types are called in the reverse order of 
         declaration.

   Constructors and destructors when inheritance
      How to call constructors and destructors of base Types when 
      instantiating and destroying a derived Type instance?
      The compiler cannot know which constructor to call among the 
      different overloaded constructors potentially present. To call 
      another constructor of a base Type than the constructor taking no 
      parameter, use the keyword 'Base ()' specifying the parameters to 
      pass, and this, only authorized on the first code line of the calling 
      constructor.

      On the other hand, it is useless to specify the destructor to call, 
      since this one is unique. The user must not call the destructors of 
      the base Types themselves, the compiler does it on its own by 
      chaining the destructors.

      Example - Explicit call of the base Type constructor ('Child' Type 
      extends 'Parent' Type):
   Type Parent  '' declare the parent type
      Dim As Integer I
      Declare Constructor ()
      Declare Constructor (ByVal i0 As Integer)
      Declare Destructor ()
   End Type

   Constructor Parent ()  '' define parent Type constructor
      Print "Parent.Constructor()"
   End Constructor

   Constructor Parent (ByVal i0 As Integer)  '' define parent Type constructor
      This.I = i0
      Print "Parent.Constructor(Byval As Integer)"
   End Constructor

   Destructor Parent ()  '' define parent Type destructor
      Print "Parent.Destructor()"
   End Destructor

   Type Child Extends Parent  '' declare the child Type
      Declare Constructor ()
      Declare Destructor ()
   End Type

   Constructor Child ()  '' define child Type default constructor
      Base(123)         '' authorize only on the first code line of the constructor body
      Print "  Child.Constructor()"
   End Constructor

   Destructor Child ()  '' define child Type destructor
      Print "  Child.Destructor()"
   End Destructor

   Scope
      Dim As Child c
      Print
   End Scope

   Sleep
            
Output:

   Parent.Constructor(ByVal As Integer)
     Child.Constructor()

     Child.Destructor()
   Parent.Destructor()
   				
If it was not specified that the constructor to be called for the base Type 
was the constructor taking an Integer parameter, the compiler would have 
called the default constructor of the base Type (in the above example, one 
can put in comment the line 'Base(123)' and execute again to see this 
different behavior).

      If the Type derives from several base Types (multiple-level 
      inheritance), each derived Type constructor can explicitly call only 
      one constructor, the one of its direct base Type, thus the all 
      constituting a chaining of the base constructors.

      When using inheritance polymorphism (sub-type polymorphism), the 
      object are manipulated through base Type pointers or references:
         - If at least one derived Type has an explicit destructor defined, 
         all its base destructors must be virtual so that the destruction 
         can start at this most derived Type and works its way down to the 
         last base Type.
         - To do this, it may be necessary to add virtual destructors with 
         an empty body anywhere an explicit destruction was not yet 
         required, in order to supersede each non-virtual implicit 
         destructor built by the compiler.

      Note:
         - When a derived Type has a base Type where a default constructor 
         or copy constructor or destructor is defined (implicitly or 
         explicitly), the compiler defines a default constructor or copy 
         constructor or destructor for that derived Type.
         - The built-in 'Object' Type having a default-constructor and a 
         copy-constructor both defined implicitly, so all Types deriving 
         (directly or indirectly) from 'Object' have at least implicitly a 
         default constructor and copy constructor.

   Virtual procedures calls in constructors and destructors
      It is usually safe to call any member procedure from within a 
      constructor or destructor because the object is completely set up 
      (virtual tables are initialized and so on) prior to the execution of 
      the first line of user code. However, it is potentially unsafe for a 
      member procedure to call a virtual member procedure for an abstract 
      base Type during construction or destruction.

      Be careful when calling virtual procedures in constructors or 
      destructor, because the procedures that are called in the base 
      constructors or destructor is the base Type versions, not the derived 
      Type versions. When such a virtual procedure is called, the procedure 
      invoked is the procedure defined for the constructor's or 
      destructor's own Type (or inherited from its Bases).

Back to top

2. '=' Assignment-operators
   Among all '=' assignment-operators, there is a specific one that takes 
   as input a reference to an object of the same type, and makes a copy of 
   it (without creating a new object).
   It is the copy-assignment operator.

   Copy-assignment operator
      If the user does not declare a copy-assignment operator, the compiler 
      generates (if needed) a copy-assignment operator for him. The 
      declaration of a copy-constructor (see above) does not remove the 
      generation by the compiler of a copy-assignment operator.

      A copy-assignment operator must be defined if the implicit copy is 
      not sufficient.
      This happens in cases when the object manages dynamically allocated 
      memory or other resources which need to be specially copied (for 
      example if a member pointer points to dynamically allocated memory, 
      the implicit '=' assignment operator will simply copy the pointer 
      value instead of allocate memory and then perform the copy of data).

      If the user implements a copy-assignment operator, it is recommend to 
      also implement a copy-constructor so that the meaning of the code is 
      clear.

      In addition to the explicit syntax for calling the copy-assignment 
      operator, this one is also called when a function returns an object 
      by value by using the 'Function =' keyword.

      A copy-assignment operator can not take into account its argument 
      (the object to clone) by value, because there are cases where "byval 
      arg" is coded as default-construction + copy-assignment (when for 
      example the UDT has no copy-constructor but has an object field with 
      a default-constructor or a Base with default-constructor), and this 
      would induce an infinite loop.

      For the 'ZstringChain' Type defined above, the user needs also a 
      copy-assignment operator (see the 'rule of three' in 'advanced #2' 
      page):
   Type ZstringChain                                    '' implement a zstring chain
      Dim As ZString Ptr pz                            '' define a pointer to the chain
      Declare Constructor ()                           '' declare the explicit default constructor
      Declare Constructor (ByVal size As Integer)      '' declare the explicit constructor with as parameter the chain size
      Declare Constructor (ByRef zc As ZstringChain)   '' declare the explicit copy constructor
      Declare Operator Let (ByRef zc As ZstringChain)  '' declare the explicit copy assignment operator
      Declare Destructor ()                            '' declare the explicit destructor
   End Type

   Constructor ZstringChain ()
      This.pz = 0  '' reset the chain pointer
   End Constructor

   Constructor ZstringChain (ByVal size As Integer)
      This.pz = CAllocate(size + 1, SizeOf(ZString))  '' allocate memory for the chain
   End Constructor

   Constructor ZstringChain (ByRef zc As ZstringChain)
      This.pz = CAllocate(Len(*zc.pz) + 1, SizeOf(ZString))  '' allocate memory for the new chain
      *This.pz = *zc.pz                                      '' initialize the new chain
   End Constructor

   Operator ZstringChain.Let (ByRef zc As ZstringChain)
      If @zc <> @This Then                                       '' avoid self assignment destroying the chain
         If This.pz <> 0 Then
            Deallocate This.pz                                 '' free the allocated memory if necessary
         End If
         This.pz = CAllocate(Len(*zc.pz) + 1, SizeOf(ZString))  '' allocate memory for the new chain
         *This.pz = *zc.pz                                      '' initialize the new chain
      End If
   End Operator

   Destructor ZstringChain ()
      If This.pz <> 0 Then
         Deallocate This.pz  '' free the allocated memory if necessary
         This.pz = 0         '' reset the chain pointer
      End If
   End Destructor

   Dim As ZstringChain zc1  '' instantiate a non initialized chain : useless

   Dim As ZstringChain zc2 = ZstringChain(9)           '' instantiate a szstring chain of 9 useful characters
   '                                                   '' shortcut: Dim As ZstringChain zc2 = 9
   *zc2.pz = "FreeBASIC"                               '' fill up the chain with 9 characters
   Print "zc2 chain:"
   Print "'" & *zc2.pz & "'"                           '' print the chain
   Print
   Dim As ZstringChain zc3 = zc2                       '' instantiate a new szstring chain by copy construction
   Print "zc3 chain (zc3 copy constructed from zc2):"
   Print "'" & *zc3.pz & "'"                           '' print the chain
   Print
   *zc3.pz = "modified"                                '' modify the new chain
   Print "zc3 chain (modified):"
   Print "'" & *zc3.pz & "'"                           '' print the new chain
   Print
   Print "zc2 chain:"
   Print "'" & *zc2.pz & "'"                           '' print the copied chain (not modified)
   Print
   zc3 = zc2
   Print "zc3 chain (zc3 copy assigned from zc2):"
   Print "'" & *zc3.pz & "'"                           '' print the new chain
   Print
   *zc3.pz = "changed"                                 '' modify the new chain
   Print "zc3 chain (changed):"
   Print "'" & *zc3.pz & "'"                           '' print the new chain
   Print
   Print "zc2 chain:"
   Print "'" & *zc2.pz & "'"                           '' print the copied chain (not modified)

   Sleep
            
Output:

   zc2 Chain:
   'FreeBASIC'

   zc3 Chain (zc3 copy constructed from zc2):
   'FreeBASIC'

   zc3 Chain (modified):
   'modified'

   zc2 Chain:
   'FreeBASIC'

   zc3 Chain (zc3 copy assigned from zc2):
   'FreeBASIC'

   zc3 Chain (changed):
   'changed'

   zc2 Chain:
   'FreeBASIC'
   				

Back to top

3. Processing variable-length arrays as members of Type
   A variable-length array is not a pseudo-object like a variable-length 
   string, because there is no default copy-constructor and copy-assignment 
   operators as for a variable-length string.

   But when a variable-length array is declared in a Type, the compiler 
   build a default copy-constructor and a default copy-assignment operator 
   for the Type. It includes all code for sizing the destination array and 
   copying the data from the source array, if needed:
      Example for automatic array sizing and copying by the compiler:
   Type UDT
      Dim As Integer array(Any)
   End Type

   Dim As UDT u1, u2

   ReDim u1.array(1 To 9)
   For I As Integer = LBound(u1.array) To UBound(u1.array)
      u1.array(I) = I
   Next I
    
   u2 = u1
   For I As Integer = LBound(u2.array) To UBound(u2.array)
      Print u2.array(I);
   Next I
   Print

   Dim As UDT u3 = u1
   For I As Integer = LBound(u3.array) To UBound(u3.array)
      Print u3.array(I);
   Next I
   Print

   Sleep
            
Output:

    1 2 3 4 5 6 7 8 9
    1 2 3 4 5 6 7 8 9
   				

   If the user want to specify his own copy-constructor and copy-assignment 
   operator (to process additional complex field members for example), the 
   above automatic array sizing and copying by the compiler is broken:
      Example for automatic array sizing and copying by the compiler broken 
      by an explicit copy-constructor and copy-assignment operator:
   Type UDT
     Dim As Integer array(Any)
     'user fields
     Declare Constructor ()
     Declare Constructor (ByRef u As UDT)
     Declare Operator Let (ByRef u As UDT)
   End Type

   Constructor UDT ()
     'code for user fields in constructor
   End Constructor

   Constructor UDT (ByRef u As UDT)
     'code for user fields in copy-constructor
   End Constructor

   Operator UDT.Let (ByRef u As UDT)
     'code for user fields in copy-assignement operator
   End Operator

   Dim As UDT u1, u2

   ReDim u1.array(1 To 9)
   For I As Integer = LBound(u1.array) To UBound(u1.array)
     u1.array(I) = I
   Next I
    
   u2 = u1
   For I As Integer = LBound(u2.array) To UBound(u2.array)
     Print u2.array(I);
   Next I
   Print

   Dim As UDT u3 = u1
   For I As Integer = LBound(u3.array) To UBound(u3.array)
     Print u3.array(I);
   Next I
   Print

   Sleep
            
Output (none):

   				

   The elementary variable-length array member cannot be copied as a 
   pseudo-object like a variable-length string member, because there is not 
   implicit assignment (referring to the above example, 'This.array = 
   u.array' is disallowed).
   The user must code explicitly the sizing and the copying of the array 
   member:
      Example for array sizing and copying explicitly set in the user 
      copy-constructor and copy-assignment operator:
   #include "crt/string.bi"

   Type UDT
      Dim As Integer array(Any)
      'user fields
      Declare Constructor ()
      Declare Constructor (ByRef u As UDT)
      Declare Operator Let (ByRef u As UDT)
   End Type

   Constructor UDT ()
      'code for user fields in constructor
   End Constructor

   Constructor UDT (ByRef u As UDT)
      'code for user fields in copy-constructor
      If UBound(u.array) >= LBound(u.array) Then  '' explicit array sizing and copying
         ReDim This.array(LBound(u.array) To UBound(u.array))
         memcpy(@This.array(LBound(This.array)), @u.array(LBound(u.array)), (UBound(u.array) - LBound(u.array) + 1) * SizeOf(@u.array(LBound(u.array))))
      End If
   End Constructor

   Operator UDT.Let (ByRef u As UDT)
      'code for user fields in copy-assignement operator
      If @This <> @u And UBound(u.array) >= LBound(u.array) Then  '' explicit array sizing and copying
         ReDim This.array(LBound(u.array) To UBound(u.array))
         memcpy(@This.array(LBound(This.array)), @u.array(LBound(u.array)), (UBound(u.array) - LBound(u.array) + 1) * SizeOf(@u.array(LBound(u.array))))
      End If
   End Operator

   Dim As UDT u1, u2

   ReDim u1.array(1 To 9)
   For I As Integer = LBound(u1.array) To UBound(u1.array)
      u1.array(I) = I
   Next I
    
   u2 = u1
   For I As Integer = LBound(u2.array) To UBound(u2.array)
      Print u2.array(I);
   Next I
   Print

   Dim As UDT u3 = u1
   For I As Integer = LBound(u3.array) To UBound(u3.array)
      Print u3.array(I);
   Next I
   Print

   Sleep
            
Output:

    1 2 3 4 5 6 7 8 9
    1 2 3 4 5 6 7 8 9
   				

   Another elegant possibility is to keep this sizing/copying automatically 
   coded by the compiler, but by simply calling it explicitly. For this, an 
   obvious solution for the member array is to no longer put it at the 
   level of the Type itself, but rather in another specific Type, but 
   inherited (seen from the outside, it is exactly the same):
      Example for using a base Type including the dynamic array member:
   Type UDT0
      Dim As Integer array(Any)
   End Type

   Type UDT Extends UDT0
      'user fields
      Declare Constructor ()
      Declare Constructor (ByRef u As UDT)
      Declare Operator Let (ByRef u As UDT)
   End Type

   Constructor UDT ()
      'code for user fields in constructor
   End Constructor

   Constructor UDT (ByRef u As UDT)
      'code for user fields in copy-constructor
      Base(u)  '' inherited array sizing and copying from Base copy-constructor
   End Constructor

   Operator UDT.Let (ByRef u As UDT)
      'code for user fields in copy-assignement operator
      Cast(UDT0, This) = u  '' inherited array sizing and copying from Base copy-assignement operator
   End Operator

   Dim As UDT u1, u2

   ReDim u1.array(1 To 9)
   For I As Integer = LBound(u1.array) To UBound(u1.array)
      u1.array(I) = I
   Next I
    
   u2 = u1
   For I As Integer = LBound(u2.array) To UBound(u2.array)
      Print u2.array(I);
   Next I
   Print

   Dim As UDT u3 = u1
   For I As Integer = LBound(u3.array) To UBound(u3.array)
      Print u3.array(I);
   Next I
   Print

   Sleep
            
Output:

    1 2 3 4 5 6 7 8 9
    1 2 3 4 5 6 7 8 9
   				

Back to top

See also
   * Constructor, Destructor
   * Operator =[>] (Assignment), Operator Let (Assignment)
   * Constructors and Destructors (basics)
   * Constructors, '=' Assignment-Operators, and Destructors (advanced, part #2)



------------------------------------------------ ProPgCtorsAssignDtors2 ----
Constructors, '=' Assignment-Operators, and Destructors (advanced, part #2)

Proper use of Constructors, '=' Assignment-Operators, and Destructors, 
which are the special member procedures for constructing/initializing, 
assigning, and destroying objects (part #2).

   Table of Contents
1. Compiler interaction (with default-constructor, copy-constructor, and copy-assignment operator)
2. Rules of good manners (for constructors, copy-constructors, copy-assignment operators, and destructors)
3. Member access rights impact (on declaration of constructors, copy-constructors, copy-assignment operators, and destructors)

1. Compiler interaction (with default-constructor, copy-constructor, and 
copy-assignment operator)
   During assignments or copy-constructions, the compiler interacts with 
   the different calls of copy-assignment operators, default-constructors 
   and copy-constructors, in order to optimize the copy for resulting 
   objects, making the best use of the member procedures provided by the 
   user (maybe non-exhaustively).

   * For an assignment ('object2 = object1')
      Algorithm:

   '   If (Type has a copy-assignment operator) Then
   '   |  => the copy-assignment operator of Type is called
   '   Else
   '   |  If (Type has a Base with default-constructor) AND (Type has a Base with copy-assignment operator) Then
   '   |  |  => the copy-assignment operator of Base is called (for Base fields)
   '   |  |  => a shallow-copy is done on only Type fields
   '   |  Else
   '   |  |  => a full shallow-copy is done on all fields
   '   |  End If
   '   End If
   			

   * For a copy-construction ('Dim As typename object2 = object1')
      Algorithm:

   '   If (Type has a Base with default-constructor) Then
   '   |  => the default-constructor of Base is called
   '   End If
   '   If (Type has a copy-constructor) Then
   '   |  => the copy-constructor of Type is called
   '   Else
   '   |  => the Type object is implicitly default-constructed (even if exists an explicit Type default-constructor)
   '   |  If (Type has a copy-assignment operator) Then
   '   |  |  If (Type has an object field with a default-constructor) OR (Type has a Base with default-constructor) Then
   '   |  |  |  => the copy-assignment operator of Type is called
   '   |  |  Else
   '   |  |  |  => a full shallow-copy is done on all fields
   '   |  |  End If
   '   |  Else
   '   |  |  If (Type has a Base with default-constructor) AND (Type has a Base with copy-assignment operator) Then
   '   |  |  |  => the copy-assignment operator of Base is called (for Base fields)
   '   |  |  |  => a shallow-copy is done on only Type fields
   '   |  |  Else
   '   |  |  |  => a full shallow-copy is done on all fields
   '   |  |  End If
   '   |  End If
   '   End If
   			

   Notes:
      A Type has a default-constructor if one among the following 
      propositions is verified:
         - It has an explicit default-constructor
         - One at least of its field has an initializer.
         - One at least of its members is an object having a 
         default-constructor itself.
         - Its Base (if exists) has a default-constructor (the built-in 
         'Object' has a default-constructor).

      Under certain conditions, the explicit copy-assignment operator may 
      be called for a copy-construction (if there is not an explicit 
      copy-constructor).
      But inversely, the explicit copy-constructor will never be called for 
      an assignment (if there is not an explicit copy-assignment operator) 
      regardless of the conditions.

   * Example to highlight/validate this interaction with 
     default-constructor, copy-constructor, and copy-assignment operator, 
     during assignments or copy-constructions
      By commenting or not, as you want, independently each of the first 7 
      code lines ('#define UDT...'), you can test all conditions of the 
      above algorithms:
   #define UDTbase_copy_assignment_operator
   #define UDTbase_default_constructor
   #define UDTbase_copy_constructor

   #define UDTderived_copy_assignment_operator
   #define UDTderived_default_constructor
   #define UDTderived_copy_constructor
   #define UDTderived_object_field_with_constructor

   Type UDTbase
      #ifdef UDTbase_copy_assignment_operator
      Declare Operator Let (ByRef u1 As UDTbase)
      #endif
      #ifdef UDTbase_copy_constructor
      Declare Constructor ()
      Declare Constructor (ByRef u1 As UDTbase)
      #endif
      #ifdef UDTbase_default_constructor
      #ifndef UDTbase_copy_constructor
      Declare Constructor ()
      #endif
      #endif
      Declare Destructor ()
      Dim As Integer i1
   End Type

   #ifdef UDTbase_copy_assignment_operator
   Operator UDTbase.Let (ByRef u1 As UDTbase)
      Print "   => UDTbase.copy-assignment", @This & " from " & @u1
      This.i1 = u1.i1
   End Operator
   #endif
   #ifdef UDTbase_copy_constructor
   Constructor UDTbase ()
      Print "   => UDTbase.default-constructor", @This
   End Constructor
   Constructor UDTbase (ByRef u1 As UDTbase)
      Print "   => UDTbase.copy-constructor", @This & " from " & @u1
      This.i1 = u1.i1
   End Constructor
   #endif
   #ifdef UDTbase_default_constructor
   #ifndef UDTbase_copy_constructor
   Constructor UDTbase ()
      Print "   => UDTbase.default-constructor", @This
   End Constructor
   #endif
   #endif
   Destructor UDTbase ()
      Print "   => UDTbase.destructor", , @This
   End Destructor

   Type UDTderived Extends UDTbase
      #ifdef UDTderived_copy_assignment_operator
      Declare Operator Let (ByRef u2 As UDTderived)
      #endif
      #ifdef UDTderived_copy_constructor
      Declare Constructor ()
      Declare Constructor (ByRef u2 As UDTderived)
      #endif
      #ifdef UDTderived_default_constructor
      #ifndef UDTderived_copy_constructor
      Declare Constructor ()
      #endif
      #endif
      Declare Destructor ()
      Dim As Integer i2
      #ifdef UDTderived_object_field_with_constructor
      Dim As String s2
      #endif
   End Type

   #ifdef UDTderived_copy_assignment_operator
   Operator UDTderived.Let (ByRef u2 As UDTderived)
      Print "   => UDTderived.copy-assignment", @This & " from " & @u2
      This.i2 = u2.i2
      This.i1 = u2.i1
   End Operator
   #endif
   #ifdef UDTderived_copy_constructor
   Constructor UDTderived ()
      Print "   => UDTderived.default-constructor", @This
   End Constructor
   Constructor UDTderived (ByRef u2 As UDTderived)
      Print "   => UDTderived.copy-constructor", @This & " from " & @u2
      This.i2 = u2.i2
      This.i1 = u2.i1
   End Constructor
   #endif
   #ifdef UDTderived_default_constructor
   #ifndef UDTderived_copy_constructor
   Constructor UDTderived ()
      Print "   => UDTderived.default-constructor", @This
   End Constructor
   #endif
   #endif
   Destructor UDTderived ()
      Print "   => UDTderived.destructor", , @This
   End Destructor

   Scope
      Print "Construction: 'Dim As UDTderived a, b : a.i1 = 1 : a.i2 = 2'"
      Dim As UDTderived a, b : a.i1 = 1 : a.i2 = 2
      Print "      " & a.i1
      Print "      " & a.i2
      Print
      Print "Assignment: 'b = a'"
      b = a
      Print "      " & b.i1
      Print "      " & b.i2
      Print
      Print "Copy-construction: 'Dim As UDTderived c = a'"
      Dim As UDTderived c = a
      Print "      " & c.i1
      Print "      " & c.i2
      Print
      Print "Going out scope: 'End Scope'"
   End Scope

   Sleep
            
Output example:

   Construction: 'Dim As UDTderived a, b : a.i1 = 1 : a.i2 = 2'
      => UDTbase.default-Constructor         1703576
      => UDTderived.default-Constructor      1703576
      => UDTbase.default-Constructor         1703556
      => UDTderived.default-Constructor      1703556
   	  1
   	  2

   Assignment: 'b = a'
      => UDTderived.copy-assignment          1703556 from 1703576
   	  1
   	  2

   Copy-construction: 'Dim As UDTderived c = a'
      => UDTbase.default-Constructor         1703488
      => UDTderived.copy-Constructor         1703488 from 1703576
   	  1
   	  2

   Going Out Scope: 'End Scope'
      => UDTderived.destructor               1703488
      => UDTbase.destructor                  1703488
      => UDTderived.destructor               1703556
      => UDTbase.destructor                  1703556
      => UDTderived.destructor               1703576
      => UDTbase.destructor                  1703576
   				

Back to top

2. Rules of good manners (for constructors, copy-constructors, 
copy-assignment operators, and destructors)
   Reminder of behaviors impacting constructors, copy-constructors, 
   copy-assignment operators, and destructors:
      - Defining an explicit default-constructor replaces the implicit 
      default-constructor built by the compiler.
      - Defining an explicit constructor other than the one default 
      suppresses the implicit default-constructor built by the compiler. In 
      this precise case, there is no default-constructor at all!
      - The implicit copy-constructor (or copy-assignment operator, or 
      destructor) built by the compiler can be replaced by an explicit 
      copy-constructor (or copy-assignment operator, or destructor) defined 
      by the user.
      - But (as opposed to the default-constructor), there is always a 
      copy-constructor (or a copy-assignment operator or a destructor), 
      either an implicit built by the compiler or an explicit defined by 
      the user.
      - When there is object composition, the composed object Type must 
      have an implicit or explicit constructor matching with the 
      declaration of the compound object.
      - When there is Type inheritance, the inherited Type must have a 
      default implicit or explicit constructor (unless the inheriting Type 
      has a constant copy-constructor, explicitly defined by user), and all 
      this even if no object is constructed (compiler test on the only 
      inheritance structure). This behavior appears to be specific to 
      FreeBASIC.

   From all the above, one can deduce 'golden rules' that avoid most of 
   compilation errors and run-time bugs.

      Golden rules for a code safer (at compile-time and run-time):
         - If the user explicitly defines any constructor, he is very 
         strongly advised to also define explicitly the default-constructor 
         as well.
         - If the user needs to explicitly define (with a non empty body) a 
         copy-constructor or a copy-assignment operator or a destructor, it 
         is better to define the 3 simultaneously (the known 'rule of 
         three'), plus the default-constructor (rule above also applied).

   From all the above and more specific cases (with inheritance), one can 
   propose one 'maximizing rule' that allows a very safer operating.

      Maximizing rule for a very safer code (at compile-time and run-time), 
      but sometimes maximizing the real constraints:
         - If the user needs to explicitly define any form of constructor 
         procedure (including any form of copy-constructor) or any form of 
         let-operator procedure or a destructor procedure, it is strongly 
         recommended to define together the default-constructor and the 
         standard copy-constructor and the standard let-operator and the 
         destructor.
         (these 4 explicit procedures are explicitly defined to always 
         overload correctly the corresponding implicit operations from 
         compiler)

   * Example of applying rules of good manners
      UDT with a string member, to compare to UDT with a string pointer 
      member where the 4 explicit procedures above must be defined 
      (otherwise program hangs):
   '=== UDT with a string member =====================

   Type UDTstr
      Dim As String s
   End Type

   '--------------------------------------------------

   Dim As UDTstr us1
   us1.s = "UDTstr"
   Dim As UDTstr us2
   us2 = us1
   Dim As UDTstr us3 = us2
   Print us1.s,
   us1.s = ""
   Print us2.s,
   us2.s = ""
   Print us3.s

   '=== UDT with a string ptr member =================

   Type UDTptr2str
      Dim As String Ptr ps
      Declare Constructor ()
      Declare Destructor ()
      Declare Operator Let (ByRef ups As UDTptr2str)
      Declare Constructor (ByRef ups As UDTptr2str)
   End Type

   Constructor UDTptr2str ()
      This.ps = New String
   End Constructor

   Destructor UDTptr2str ()
      Delete This.ps
   End Destructor

   Operator UDTptr2str.Let (ByRef ups As UDTptr2str)
      *This.ps = *ups.ps
   End Operator

   Constructor UDTptr2str (ByRef ups As UDTptr2str)
      Constructor()  '' calling the default constructor
      This = ups     '' calling the assignment operator
   End Constructor

   '--------------------------------------------------

   Dim As UDTptr2str up1
   *up1.ps = "UDTptr2str"
   Dim As UDTptr2str up2
   up2 = up1
   Dim As UDTptr2str up3 = up2
   Print *up1.ps,
   *up1.ps = ""
   Print *up2.ps,
   *up2.ps = ""
   Print *up3.ps

   '==================================================

   Sleep
            
Output example:

   UDTstr        UDTstr        UDTstr
   UDTptr2str    UDTptr2str    UDTptr2str
   				

Back to top

3. Member access rights impact (on declaration of constructors, 
copy-constructors, copy-assignment operators, and destructors)
   Access rights can be applied when declaring such member procedures, to 
   prohibit the user from performing certain specific commands (from the 
   outside of Type).

   The default constructor, copy-constructor, copy-assignment operator, and 
   destructor are the only member procedures which can have an implicit 
   version built by the compiler.
   So if one want to forbid their accesses by the user from the outside of 
   the Type, it is necessary to overload these by explicit versions with 
   restricted access rights (not Public) when declaring. In addition, such 
   member procedures may have no implementation (no body defining) if they 
   are never actually called in the program.

   * Example - Inheritance structure where any base object construction 
     must be forbidden:
      - In order to forbid any construction of base object from the outside 
      of Types, the default-constructor and the copy-constructor of base 
      Type must be explicitly declared (to overload their implicit 
      versions) with restricted access rights.
      - The base Type default-constructor cannot be declared as Private, 
      because it must be accessible from the derived Type (to construct a 
      derived object), thus it is declared as Protected. It must have an 
      implementation
      - The base Type copy-constructor can be declared as Private because 
      it is never called in this example. So it may have no implementation.
   Type Parent
      Public:
         Dim As Integer I
      Protected:
         Declare Constructor ()
      Private:
         Declare Constructor (ByRef p As Parent)
   End Type

   Constructor Parent
   End Constructor

   Type Child Extends Parent
      Public:
         Dim As Integer J
   End Type

   Dim As Child c1
   Dim As Child C2 = c1
   c2 = c1

   'Dim As Parent p1                        '' forbidden
   'Dim As Parent p2 = c1                   '' forbidden
   'Dim As Parent Ptr pp1 = New Parent      '' forbidden
   'Dim As Parent Ptr pp2 = New Parent(c1)  '' forbidden

   Sleep
            

   * Example - Singleton structure (at most one object can exist at any 
     time):
      - The singleton construction must only be done by calling the static 
      procedure 'Singleton.create()'.
      - So, the default-constructor and the copy-constructor must be 
      explicitly declared (to overload their implicit versions) with 
      restricted access rights as Private, in order to forbid any object 
      user creation by 'Dim' or 'New'. Only the copy-constructor may have 
      no implementation because it will never be called (the 
      default-constructor is called from inside the Type by 'New').
      - The singleton destruction must only be done by calling the static 
      procedure 'Singleton.suppress()'.
      - So, the destructor must be explicitly declared (to overload its 
      implicit version) with restricted access rights as Private, in order 
      to forbid any object user destruction by 'Delete' (the destructor 
      must have implementation because it is called from inside the Type by 
      'Delete').
   Type Singleton
      Public:
         Declare Static Function create () As Singleton Ptr
         Declare Static Sub suppress ()
         Dim i As Integer
      Private:
         Static As Singleton Ptr ref
         Declare Constructor ()
         Declare Constructor (ByRef rhs As Singleton)
         Declare Destructor ()
   End Type

   Dim As Singleton Ptr Singleton.ref = 0

   Static Function Singleton.create () As Singleton Ptr
      If Singleton.ref = 0 Then
         Singleton.ref = New Singleton
         Return Singleton.ref
      Else
         Return 0
      End If
   End Function

   Static Sub Singleton.suppress ()
      If Singleton.ref > 0 Then
         Delete Singleton.ref
         Singleton.ref = 0
      End If
   End Sub

   Constructor Singleton ()
   End Constructor

   Destructor Singleton ()
   End Destructor

   Dim As Singleton Ptr ps1 = Singleton.create()
   ps1->i = 1234
   Print ps1, ps1->i

   Dim As Singleton Ptr ps2 = Singleton.create()
   Print ps2

   Singleton.suppress()

   Dim As Singleton Ptr ps3 = Singleton.create()
   Print ps3, ps3->i

   Singleton.suppress()

   'Delete ps3                                      '' forbidden
   'Dim As Singleton s1                             '' forbidden
   'Dim As Singleton s2 = *ps3                      '' forbidden
   'Dim As Singleton Ptr ps4 = New Singleton        '' forbiden
   'Dim As Singleton Ptr ps5 = New Singleton(*ps3)  '' forbidden

   Sleep
            
Output example:

   5122656        1234
   0
   5122656        0
   				

Back to top

See also
   * Constructor, Destructor
   * Operator =[>] (Assignment), Operator Let (Assignment)
   * Constructors and Destructors (basics)
   * Constructors, '=' Assignment-Operators, and Destructors (advanced, part #1)




============================================================================
    Statements and Expressions

-------------------------------------------- ProPgExpressionsStatements ----
Differences between Expressions and Statements

To introduce the expressions and statements (syntactic entities) in FreeBASI
C.

Preamble:

   Simply put, an expression represents a value and a statement represents 
   an operation.
   However, in fact, some special expressions may be composed and represent 
   multiple values, and some statements may be composed of several sub 
   operations/statements.
   By context, some statements can also be considered expressions.

   Statements can contain other constructs such as expressions, keywords, 
   operators, and other elements.
   Expressions are parts of statements that return values. Thus, 
   expressions can be used whenever a value is expected.

   The following description does not make very precise definitions for 
   expressions and statements. It is difficult to achieve this.
   Not all types of expressions and statements are covered here, but only 
   simple examples are highlighted.

Expressions
   An expression is a collection of one or more terms that can perform a 
   mathematical or logical operation. To be precise, an expression must 
   have at least one operand but may not have any operator.
   The terms are usually either literals or variables or functions that are 
   combined with operators to evaluate for example to a string or numeric 
   result or boolean or user defined type.
   A value in itself is a simple expression, just like a variable. 
   Evaluating a variable gives the value to which the variable refers.

   Expressions can be used to perform calculations, manipulate variables, 
   or concatenate strings.
   Expressions are evaluated according to precedence order. Use parentheses 
   to override the default precedence order.

Statements
   A statement is a basic unit of execution of a program. A statement is a 
   complete instruction in FreeBASIC programs.
   It may contain keywords, operators, variables, literal values, constants 
   and expressions.

   Statements could be categorized as:
      - Declaration statements: these are the statements where the user 
      names a variable, constant, or procedure, and can also initialize it.
      - Executable statements: these are the statements which initiate 
      actions. These statements can call a procedure, loop or branch 
      through blocks of code or assign values or expression to a variable 
      or constant. In the last case, it is called an expression statement. 
      The most common expression statements are assignments and function 
      calls.

   A statements normally takes up one line with no terminator character, 
   but:
      - several statements can also be stacked on a same line by using the 
      separator character, a colon (:) to delimit them,
      - or a statement may also be continued to the next line using the 
      continuation character, an underscore (_) to extend the statement 
      from one line to the next.

Basic examples of expressions / statements
   Some basic examples just to illustrate the definitions above.

   Basic examples of expressions
      - Arithmetic expression:
         10
            this is an expression that is evaluated to the numeric value 
            10.
         10 + 13
            this is another expression that is evaluated to produce the 
            numeric value 23.

      - String expression:
         "hello"
            evaluates to the string "hello".
         "hello" & " " & "world"
            evaluates to the string "hello world".

      - Combined expression:
         Len("hello" & " " & "world")
            Len function evaluating the length of the string expression.

      - Logical expression:
         10 > 9
            evaluates to boolean value true (more precisely produces the 
            integer value -1 here).
         10 < 20
            evaluates to boolean value false (more precisely produces the 
            integer value 0 here).
         true
            evaluates to boolean value true.
         a=20 And b=30
            evaluates to true (-1) or false (0) based on the values of a 
            and b.

   Basic examples of statements
      - Statement:
         Print 10 + 13
         Print "hello" & " " & "world"
            where the arguments of the two Print statements are expressions 
            listed above.

      - Assignment statement:
         average = 55 + 33
            where the right-hand-side is an expression.

      - Declaration statement with initializer:
         Dim As Integer I = J + 3
            where the right-hand-side of the initializer is an expression.

      - Conditional statement:
         If (expression) Then
            statement 1
         Else
            statement 2
         End If
            if the expression following the If statement evaluates to a 
            truth value, statement 1 is executed else statement 2 is 
            executed.

See also
   * Constant Expressions
   * Assignments
   * Operator list
   * Operator Precedence
   * Control Flow Statements



---------------------------------------------- ProPgConstantExpressions ----
Constant Expressions

Constant term defines an expression that can be evaluated at compile time.

Preamble:

   A constant expression is an expression that contains only constants 
   (this means that it does not contain any variables at the evaluation 
   time) with some operators/functions allowed,  and possibly parentheses 
   to override the operator precedence order.
   A constant expression can be evaluated during compilation rather than at 
   run time, and can be used in any place that a constant can occur.

   Constant expressions are mainly required:
      - as arguments for the preprocessor directives and intrinsic defines 
      macros,
      - as initializers for the Enum/Type structures and global/static 
      variables,
      - as data constants for the Data Statements.

List of operators/functions allowed in constant expressions
   fbc is not a scripting language and does not have a full feature macro 
   processor on the front end.
   Constant folding is an optimization in fbc that takes constant 
   expressions, evaluates the constant expression at compile time and 
   produces a single constant result.
   For constant folding to work, a compile time implementation of the 
   operators/functions must be written.

   Only the following operators/functions with constant arguments can be 
   used to constitute constant expressions:
      Bit, BitReset, BitSet, HiByte, HiWord, LoByte, LoWord
      +, -, *, /, \, ^, Mod, Shl, Shr
      =, <>, <=, >=, <, >
      And, Eqv, Imp, Or, Not, Xor
      Abs, Acos, Asin, Atan2, Atn, Cos, Exp, Fix, Frac, Int, Log, Sgn, Sin, 
      Sqr, Tan
      Asc, Chr, CVD, CVI, CVL, CVLongInt, CVS, CVShort, Len, SizeOf
      Cast, CBool, CByte, CDbl, CInt, CLng, CLngInt, CShort, CSign, CSng, 
      CUByte, CUInt, CULng, CULngInt, CUnsg, CUShort
      more obviously all predefined symbols

Basic example of using constant expressions
   Example illustrating three different use-cases:
   #define pi 4 * Atn(1)

   Dim Shared As Double d = Sqr(2)

   Type pt
      Dim As Integer x = 300 * Cos(pi / 6)
      Dim As Integer y = 300 * Sin(pi / 6)
   End Type

   Dim As pt p

   Print pi        ''  3.14159...
   Print d         ''  1.41421...
   Print p.x, p.y  ''  260           150

   Sleep
         

See also
   * Differences between Expressions and Statements
   * Variable Initializers



------------------------------------------------------ ProPgAssignments ----
Assignments

Assignments typically allow a variable to hold different values at 
different times during its life-span and scope.

Single assignment statement
   An assignment statement consists of a variable (simple or with indices, 
   or even a byref function result) and an expression (constructed from 
   variables, constants, operators, and parentheses):
      variable = expression
   Executing an assignment statement evaluates the expression on the 
   right-hand side and assigns it to the variable on the left-hand side.

   For an assignment operation, it is necessary that the value of the 
   expression is well-defined (it is a valid 'rvalue') and that the 
   variable represents a modifiable entity (it is a valid modifiable 
   (non-const) 'lvalue').
   For an assignment to be well formed, the type of the expression on the 
   right-hand side should be compatible with the type of the variable on 
   the left-hand side (in other words, it must be possible to cast the 
   expression to the type of the variable).

   An example of a simple assignment is as follows:
      x = 0
   For the above example, the variable 'x' must be declared as being of 
   numeric type.
   After the assignment statement executes, the variable 'x' will have the 
   value zero (either as an integer or a floating-point value, depending on 
   its type).

   In an assignment statement:
      - The expression is evaluated in the current state of the program.
      - The variable is assigned the computed value, replacing the prior 
      value of that variable.
   Because the right-hand side is evaluated first, it is possible to 
   increment a variable by writing:
      x = x + 1

Compound assignment statement
   Arithmetic operators may be used in compound arithmetic and assignment 
   operations.

   For example, consider the following example of compound addition and 
   assignment:
      x += 7
   The compound arithmetic and assignment statement above is equivalent to 
   the following long form:
      x = x + 7

   More generally, the compound form (with operator op):
      x op= y
   is equivalent to:
      x = x op y

   The compound statement is legal whenever the long form is legal. This 
   requires that the operation 'x op y' must itself be well formed and that 
   the result of the operation be assignable to 'x'.

Assignment versus equality
   The use of the equals sign '=' as an assignment operator has been 
   frequently criticized, due to the conflict with equal as comparison for 
   equality. This results both in confusion by novices in writing code, and 
   confusion even by experienced programmers in reading code.
   Beginning programmers sometimes confuse assignment with the relational 
   operator for equality, as '=' means equality in mathematics, and is used 
   for assignment in many languages. But assignment alters the value of a 
   variable, while equality testing tests whether two expressions have the 
   same value.

   In FreeBASIC, a single equals sign '=' is generally used for both the 
   assignment operator and the equality relational operator, with context 
   determining which is meant.
   For this purpose (and for solving some cases of ambiguity of the 
   parser), the alternative symbol '=>' can be used for assignments in 
   place of '=' (same as already used commonly for the initializers inside 
   declarations).
   Note: the '=>' symbol has been chosen against '<=' (already the operator 
   'Less Than Or Equal') and ':=' (':' used as statement separator).

   Statements can even mix assignment and equality operators.
   For example:
      x = a = b
   is parsed as:
      x = ( a = b )
   The equality expression 'a = b' above returns '-1' or '0', or 'true' or 
   'false', depending on the types of the variables 'a' and 'b', but the 
   values of these variables are not modified. Only the equality expression 
   result is assigned to 'x'.
   In the above assignment statement, using parentheses around the equality 
   expression allows to highlight the global behavior.
   The alternative symbol '=>' can also be used:
      x => a = b
      ('=>' can not be also used as symbol for equality operator)

Example
   Example illustrating the different cases:
   Dim As Integer x, y, z

   x = 5          ''        (or 'x => 5')
   Print x        ''  5     (assignment expression is a constant)

   y = x + 4      ''        (or 'y => x + 4')
   Print y        ''  9     (assignment expression is the sum of a variable and a constant)

   y = y + 3      ''        (or 'y => y + 3')
   Print y        ''  12    (value of x is incremented by 3)

   z = 3          ''        (or 'z => 3')
   z *= x         ''        (or 'z *=> x')
   Print z        ''  15    (value of z is multiplied by value of x)

   If x = y Then  ''        (value of x is not modified)
     Print x
   Else
     Print x, y   ''  5     12
   End If

   x = y = z      ''        (or 'x => y = z')    (value of y is not modified)
   Print x, y, z  ''  0     12    15
         

See also
   * Operator =[>] (Assignment)
   * Operator = (Equal)
   * Operator List
   * Operator Precedence



---------------------------------------------------------- OpPrecedence ----
Operator Precedence

   When several operations occur in a single expression, each operation is 
   evaluated and resolved in a predetermined order. This is called the 
   order of operation or operator precedence. 

   If an operator in an expression has a higher precedence, it is evaluated 
   before an operator of lower precedence. 

   If operators have equal precedence, they then are evaluated in the order 
   in of their associativity.  The associativity may be Left-to-Right or 
   Right-to-Left order.

   As a rule, binary operators (such as +, ^) and unary postfix operators 
   (such as (), ->) are evaluated Left-to-Right, and unary prefix operators 
   (such as Not, @) are evaluated Right-to-Left.

   Operators that have an associativity of "N/A" indicate that there is no 
   expression in which the operator can be used where its order of 
   operation would need to be checked, either by precedence or by 
   associativity.  Function-like operators such as Cast are always the 
   first to be evaluated due to the parentheses required in their syntax.  
   And assignment operators are always the last to be evaluated.

   Parentheses can be used to override operator precedence. Operations 
   within parentheses are performed before other operations. Within the 
   parentheses normal operator precedence is used.

   The following table lists operator precedence from highest to lowest.  
   Breaks in the table mark the groups of operators having equal 
   precedence.

Highest Precedence

      +--------+-----------------------------------+-------------+
      |Operator|Description                        |Associativity|
      |        |                                   |             |
      |CAST    |Type Conversion                    |N/A          |
      |PROCPTR |Procedure pointer                  |N/A          |
      |STRPTR  |String pointer                     |N/A          |
      |VARPTR  |Variable pointer                   |N/A          |
      |        |                                   |             |
      |[]      |String index                       |Left-to-Right|
      |[]      |Pointer index                      |Left-to-Right|
      |()      |Array index                        |Left-to-Right|
      |()      |Function Call                      |Left-to-Right|
      |.       |Member access                      |Left-to-Right|
      |->      |Pointer to member access           |Left-to-Right|
      |        |                                   |             |
      |@       |Address of                         |Right-to-Left|
      |*       |Value of                           |Right-to-Left|
      |New     |Allocate Memory                    |Right-to-Left|
      |Delete  |Deallocate Memory                  |Right-to-Left|
      |        |                                   |             |
      |^       |Exponentiate                       |Left-to-Right|
      |        |                                   |             |
      |-       |Negate                             |Right-to-Left|
      |        |                                   |             |
      |*       |Multiply                           |Left-to-Right|
      |/       |Divide                             |Left-to-Right|
      |        |                                   |             |
      |\       |Integer divide                     |Left-to-Right|
      |        |                                   |             |
      |MOD     |Modulus                            |Left-to-Right|
      |        |                                   |             |
      |SHL     |Shift left                         |Left-to-Right|
      |SHR     |Shift right                        |Left-to-Right|
      |        |                                   |             |
      |+       |Add                                |Left-to-Right|
      |-       |Subtract                           |Left-to-Right|
      |        |                                   |             |
      |&       |String concatenation               |Left-to-Right|
      |        |                                   |             |
      |Is      |Run-time type information check    |N/A          |
      |        |                                   |             |
      |=       |Equal                              |Left-to-Right|
      |<>      |Not equal                          |Left-to-Right|
      |<       |Less than                          |Left-to-Right|
      |<=      |Less than or equal                 |Left-to-Right|
      |>=      |Greater than or equal              |Left-to-Right|
      |>       |Greater than                       |Left-to-Right|
      |        |                                   |             |
      |NOT     |Complement                         |Right-to-Left|
      |        |                                   |             |
      |AND     |Conjunction                        |Left-to-Right|
      |        |                                   |             |
      |OR      |Inclusive Disjunction              |Left-to-Right|
      |        |                                   |             |
      |EQV     |Equivalence                        |Left-to-Right|
      |IMP     |Implication                        |Left-to-Right|
      |XOR     |Exclusive Disjunction              |Left-to-Right|
      |        |                                   |             |
      |ANDALSO |Short Circuit Conjunction          |Left-to-Right|
      |ORELSE  |Short Circuit Inclusive Disjunction|Left-to-Right|
      |        |                                   |             |
      |=[>]    |Assignment                         |N/A          |
      |&=      |Concatenate and Assign             |N/A          |
      |+=      |Add and Assign                     |N/A          |
      |-=      |Subtract and Assign                |N/A          |
      |*=      |Multiply and Assign                |N/A          |
      |/=      |Divide and Assign                  |N/A          |
      |\=      |Integer Divide and Assign          |N/A          |
      |^=      |Exponentiate and Assign            |N/A          |
      |MOD=    |Modulus and Assign                 |N/A          |
      |AND=    |Conjunction and Assign             |N/A          |
      |EQV=    |Equivalence and Assign             |N/A          |
      |IMP=    |Implication and Assign             |N/A          |
      |OR=     |Inclusive Disjunction and Assign   |N/A          |
      |XOR=    |Exclusive Disjunction and Assign   |N/A          |
      |SHL=    |Shift Left and Assign              |N/A          |
      |SHR=    |Shift Right and Assign             |N/A          |
      |LET     |Assignment                         |N/A          |
      |        |                                   |             |
      |LET()   |Assignment                         |N/A          |
      +--------+-----------------------------------+-------------+

   In some cases, the order of precedence can cause confusing or 
   counter-intuitive results.  Here are some examples:
   '' trying to raise a negated number to a power
   -2 ^ 2
   Desired result: (-2) ^ 2 = 4
   Actual result:   -(2 ^ 2) = -4

   '' trying to test a bit in a number
   n And 1  <>  0
   Desired result: (n And 1) <> 0
   Actual result:   n And (1 <> 0)

   '' trying to shift a number by n+1 bits
   a Shl n+1
   Desired result: a Shl (n + 1)
   Actual result: (a Shl n) + 1

   For expressions where the operator precedence may be ambiguous, it is 
   recommended to wrap parts of the expression in parentheses, in order 
   both to minimise the possibility of error and to aid comprehension for 
   people reading the code.

See also
   * Operators



------------------------------------------------------ ProPgControlFlow ----
Control Flow Statements

Statements that direct the flow of execution.

Description
   Control flow statements control program execution from one statement to 
   the next; they determine what statements get executed and when, based on 
   some kind of condition. The condition is always some expression that 
   evaluates to true or false. Most control flow statements check for some 
   kind of condition, and direct code flow accordingly, that is, they do or 
   do not execute a block of code (except for the transferring control flow 
   statements and Do..Loop, which has an optional condition). Additionally, 
   all control flow statements can be nested, that is, they can have other 
   control flow statements within the statement block.

   Control flow statements come in three flavors: transferring, branching 
   and looping. Transferring control flow statements transfer execution to 
   different parts of code. Branching control flow statements execute 
   certain statements blocks based on a condition, while looping control 
   flow statements execute code repeatedly while or until a condition is 
   met.

Transferring Statements
   These statements are used for either unconditional or conditional, 
   temporary or permanent transfer of execution. The "ON" variants 
   conditionally select a point of transfer from a list of text labels.  
   Execution may be transferred between different scopes provided that the 
   branching does not cross any local array, variable length string or 
   object definition.

   Goto
      Unconditionally transfers execution to another point in code defined 
      by a text label. Execution resumes with the first statement after the 
      label.

   GoSub
      Unconditionally and temporarily transfers execution to another point 
      in code, defined by a text label. Execution resumes with the first 
      statement after the label. Execution is then brought back to its 
      original location with the Return keyword. Yes, GoSub statements can 
      be nested, that is, multiple GoSub statements can be executed before 
      the first corresponding Return, but there must always be a 
      corresponding Return throughout the course of an application.

   On Goto
      Transfers execution to one of a number of points in code defined by 
      text labels, based on the value of an expression.

   On Gosub
      Temporarily transfers execution to one of a number of points in code 
      defined by text labels, based on the value of an expression.

Branching Statements
   These statements are used for executing one of a number of statement 
   blocks.

   If..End If
      Executes a block of statements if an expression evaluates to true 
      (the condition). If and only if the expression evaluates to false, 
      another statement block can be executed if yet another expression 
      evaluates to true using the ElseIf keyword. If and only if all of 
      those expressions evaluate to false, a statement block can be execute 
      using the Else keyword.

   Select..End Select
      Executes one of a number of statement blocks. This branching 
      statement tries to meet a condition of an expression and one of a 
      number of case expressions. The case expressions are checked in the 
      order in which they are given, and the first case expression that is 
      met has its associated statement block executed. Like If..End If, a 
      default case can be defined when no other case expression meets the 
      condition, and, as with the looping control flow statements, a case's 
      statement block can be prematurely broken out of with the Exit 
      keyword.

Looping Statements
   These statements are used for executing a block of statements 
   repeatedly. Within a statement block, the loop can be prematurely 
   re-executed using the Continue keyword, or broken out of using the Exit 
   keyword. Whether the loop is terminated by the condition or with the Exit
   keyword, execution always begins at the first statement after the block.

   While..Wend
      Executes a block of statements while some expression evaluates to 
      true (the condition). The expression is evaluated and checked before 
      the block of statements is executed.

   For..Next
      Like While..Wend, but more suited to loop a certain number of times. 
      This loop initializes a so-called iterator with an initial value that 
      is checked against a test expression. If the iterator compares less 
      than or equal to the test expression (the condition), the block of 
      statements is executed and the iterator gets incremented. The loop 
      can also be setup so that the iterator gets decremented after every 
      loop, in which case it is compared greater than or equal to the test 
      expression. Iterators can be numeric data types like Integer or Double
      , or user-defined types. User-defined types must implement 
      Operator For.

   Do..Loop
      The most versatile of the looping control flow statements, this loop 
      can execute a block of statements while or until an expression 
      evaluates to true (the condition). It can also delay the checking of 
      the expression until after the block has executed the first time, 
      useful when a block of statements needs to be executed at least once. 
      Finally, this loop can have no condition at all, and merely loop 
      indefinitely.




============================================================================
    Procedures

------------------------------------------------------- ProPgProcedures ----
Procedures Overview

Overview of the different FB procedure types.

   Procedures are blocks of code that can be executed, or called, from 
   anywhere in a program, any number of times. The code that is executed is 
   called the procedure body. There are two types of procedures in 
   FreeBASIC: procedures that don't return a value and procedures that do.

Subs
   Subs are procedures that don't return values. They are declared using 
   the Declare keyword, and defined using the Sub keyword. Declaring a 
   procedure introduces its name so that it can be called, and a procedure 
   definition lists the statements of code that will be executed when 
   called. A sub is called simply by using its name somewhere in the 
   program.

   ' introduces the sub 'MyProcedure'
   Declare Sub MyProcedure

   ' calls the procedure 'MyProcedure'
   MyProcedure

   ' defines the procedure body for 'MyProcedure'
   Sub MyProcedure
      Print "the body of MyProcedure"
   End Sub

   will produce the output:


   the body of MyProcedure

   Notice that only the declaration is needed to call the procedure. The 
   procedure can be defined later in code, or even in a different source 
   file altogether.

Functions
   Functions are procedures that return a value back to the point in code 
   in which they are called. You can think of a function call as evaluating 
   to some expression, just like a variable or object. They are declared 
   using the Declare keyword, and defined using the Function keyword. The 
   type of value that functions return is specified at the end of the 
   declaration.

   ' introduces and defines a procedure that returns an integer value
   Function MyProcedure As Integer
      Return 10
   End Function

   ' calls the procedure, and stores its return value in a variable
   Dim i As Integer = MyProcedure
   Print i

   will produce the output:


   10

   Since a definition is a declaration, a procedure can be called after it 
   has been defined, as well.

   It is a common convention when calling a procedure to place parenthesis 
   '()' after the procedure name, to signify a procedure call. FreeBASIC 
   does not require this, however.

See also
   * Passing Arguments to Procedures
   * Returning Values
   * Declare
   * Sub
   * Function



------------------------------------------------- ProPgPassingArguments ----
Passing Arguments to Procedures

Passing information to procedures.

Declaring parameters
   Procedures can get passed information in the form of variables and 
   objects when they are called. In the context of a procedure call, these 
   variables and objects are called arguments. These arguments are then 
   represented as so-called parameters inside the procedure body. 
   Parameters can be used just like any other variable or object.

   To specify that a procedure should get passed arguments when called, 
   declare the procedure with a parameter list. A parameter list is a list 
   of one or more names and types that the procedure will use when 
   referring to the arguments that are passed to it. Parameter lists are 
   surrounded by parenthesis.

   Sub Procedure (s As String, n As Integer)
      Print "The parameters have the values: " & s & " and " & n
   End Sub

   Procedure "abc", 123

   will produce the following output:


   The parameters have the values: abc And 123

   There are two ways to pass arguments to procedures: by value and by 
   reference. By default, arguments are passed by value unless otherwise 
   specified.

Passing arguments by value
   Arguments that are passed by value are not actually passed to 
   procedures; a copy of the argument is made and passed instead. This 
   allows the procedure to modify the copy, and the original variable or 
   object remains unchanged.

   When passing objects to procedures by value, the copy is made by calling 
   the copy constructor of the Type or Class.

   To specify that an argument should be passed by value, precede the 
   parameter name in the procedure declaration with the ByVal keyword:

   Sub Procedure (ByVal param As Integer)
      param *= 2
      Print "The parameter 'param' = " & param
   End Sub

   Dim arg As Integer = 10
   Print "The variable 'arg' before the call = " & arg
   Procedure(arg)
   Print "The variable 'arg' after the call = " & arg

   will produce the following output:


   The variable 'arg' before the call = 10
   The parameter 'param' = 20
   The variable 'arg' after the call = 10

   Notice how parenthesis surround the arguments - in this case only one, 
   arg - in the procedure call. These parenthesis are optional, but are a 
   common convention to signify a procedure call.

Passing arguments by reference
   Unlike arguments that are passed by value, arguments that are passed to 
   procedures by reference really do get passed; no copy is made. This 
   allows the procedure to modify the original variable or object that was 
   passed to it.

   A reference is like an alias for a variable or object. Whenever you 
   refer to a reference, you're referring to the actual variable or object 
   that it aliases. In other words, you can think of a reference parameter 
   of a procedure as the argument that is passed to it; any changes made to 
   the reference parameter are actually changes to the argument it 
   represents.

   To specify that an argument should be passed by reference, precede the 
   parameter name in the procedure declaration with the ByRef keyword:

   Sub Procedure (ByRef param As Integer)
      param *= 2
      Print "The parameter 'param' = " & param
   End Sub

   Dim arg As Integer = 10
   Print "The variable 'arg' before the call = " & arg
   Procedure(arg)
   Print "The variable 'arg' after the call = " & arg

   will produce the following output:


   The variable 'arg' before the call = 10
   The parameter 'param' = 20
   The variable 'arg' after the call = 20

Manually passing pointers to by-reference parameters
   By specifying the Byval keyword in front of an argument to a ByRef 
   parameter, an address (usually stored in a pointer) can be passed 
   directly as-is, forcing the Byref parameter to reference the same memory 
   location which the address pointed to.

   Sub f( ByRef i As Integer )
      i = 456
   End Sub

   Dim i As Integer = 123
   Dim pi As Integer Ptr = @i

   Print i
   f( ByVal pi )
   Print i

See also
   * Procedures Overview
   * Returning Values
   * Declare
   * Sub
   * Function
   * ByVal
   * ByRef
   * ... (Ellipsis)



------------------------------------------------------ ProPgReturnValue ----
Returning Values

Returning Values
   Refers to the ability of a Function procedure to have a value when the 
   function finishes such that the value can be used in an expression or 
   assigned to a variable.

   The value of a function can be returned in three ways:
      - Return keyword followed by a value exits the function immediately, 
      and returns that value to the caller.
      - Functions can also return values by assigning the Function keyword 
      or the function_identifier to the desired return value (but Function 
      keyword or function_identifier does not allow to evaluate the current 
      assigned value). The latter two methods do not cause the function to 
      exit, however.

   '' Using the name of the function to set the return value and continue executing the function:
   Function myfunc1() As Integer
      myfunc1 = 1
   End Function

   '' Using the keyword 'Function' to set the return value and continue executing the function:
   Function myfunc2() As Integer
      Function = 2
   End Function

   '' Using the keyword 'Return' to set the return value and immediately exit the function:
   Function myfunc3() As Integer
      Return 3
   End Function

   '' This program demonstrates a function returning a value.

   Declare Function myFunction () As Integer

   Dim a As Integer

   'Here we take what myFunction returns and add 10.
   a = myFunction() + 10

   'knowing that myFunction returns 10, we get 10+10=20 and will print 20.
   Print a 

   Function myFunction () As Integer
     'Here we tell myFunction to return 10.
     Function = 10 
   End Function

   Return keyword mixed with Function= keyword or function_identifier= or 
   Exit Function keyword in a same function is unsupported when returning 
   objects with constructors.

   Note:
      When returning by value a UDT instance, Return on the one hand, and 
      Function= or function_identifier= on the other hand, do not treat the 
      instance in the same way (in order to optimize execution time):
         - When using Return, the only executed 'Return u' directly calls 
         the copy-constructor.
         - When using Function= or function_identifier=, the constructor is 
         always called once at the beginning of the function body, and then 
         each executed 'Function= u' or 'function_identifier= u' only calls 
         the let-operator.

Returning References
   Function results can also be returned by reference, rather than by 
   value. The semantics are quite different.

   When assigning a Byref function result through a Function = variable or 
   Return variable statement, the function does not copy and return the 
   variable's value. Instead, it returns a reference to that variable. The 
   caller of the function can modify the variable through the reference 
   returned from the function, without having to use pointers manually. 
   This is very much like ByRef parameters.

   For more information, refer to: Byref (Function Results)

Manually returning pointers as-is from Byref functions
   By specifying the Byval keyword in front of the result variable in the 
   Function = variable or Return variable statements, an address (usually 
   stored in a pointer) can be passed directly as-is, forcing the Byref 
   function result to reference the same memory location which the address 
   pointed to. For example:

   Dim Shared i As Integer = 123

   Function f( ) ByRef As Integer
      Dim pi As Integer Ptr = @i

      Function = ByVal pi

      '' or, with RETURN it would look like this:
      Return ByVal pi
   End Function

   Print i, f( )

See also
   * Function
   * Byref (Function Results)



-------------------------------------------------- ProPgProcedureScopes ----
Procedure Scopes

The Scope (visibility) of a Procedure through the different modules of a 
program.

Preamble:

   A procedure is a "subroutine" (sub) or a "function" that can be called 
   by code outside the procedure (or internal code in the case of a 
   recursion).
   A procedure consists of a sequence of instructions that form the body of 
   the procedure.
   It is possible to pass values or variables to a procedure, and a 
   function may return a value or a reference.

Description
   Scopes of procedures in modules follows simple rules:
      * Private scope:
            procedure visible only in its own module (where it is defined).
      * Public scope:
            procedure visible from all modules constituting a compiled 
            program (including static libraries).
      * Export scope:
            when defined in a DLL (dynamically linked library), procedure 
            visible from an external program that has loaded it (statically 
            or dynamically).

Syntax
      [ Public | Private ] { Sub | Function } proc_name ( argumentlist ) [ 
      [ ByRef ] As datatype ] Export
   or
      [ Public ] { Sub | Function } proc_name ( argumentlist ) [ [ ByRef ] 
      As datatype ] Export

Usage
   Private, Public and Export access controls are used in procedure 
   definitions only (forbidden at declaration line level).

   By default, a procedure is Public except if the Option Private statement 
   (in the module) modifies the default state.
   That is why both Private and Public access controls are useful, 
   depending on the default state.
   Export access control is incompatible with Private procedures 
   (implicitly or explicitly defined like this).

   Among the compiled modules, two procedures with the same identifier, but 
   defined inside different modules, may exist if both are Private.

   The compiler removes the Private procedures that are not called, but 
   this does not currently work for Private procedures that are only called 
   by other Private procedures that are not called themselves, because the 
   first one appears as being called.

See also
   * Modularizing
   * Procedures
   * Variable and Procedure Linkage



----------------------------------------------- ProPgCallingConventions ----
Calling Conventions

Specifying how procedures are called.

Calling conventions determine how calling code interacts with procedures 
when called. They specify rules about how parameters are pushed onto the 
call stack, how values are returned and when the call stack is cleaned up. 
This information is useful when interacting with code written in other 
languages, particularly assembly language. In some cases, calling 
conventions also apply some kind of name decoration to procedure names.

FreeBASIC supports 3 calling conventions: stdcall, cdecl and pascal, 
specified with stdcall, cdecl and pascal, respectively. Calling convention 
can be specified in either a procedure declaration or definition 
immediately following the procedure name. The declaration of a procedure 
must have the same calling convention as the definition.

In all calling conventions, integral procedure return values are returned 
in the EAX(, EDX) register(s), and floating-point return values are stored 
in the ST(0) register (the top of the floating-point stack). User-defined 
type (UDT) values are returned in the EAX(, EDX) register(s) if eight (8) 
bytes or smaller, otherwise they are returned in memory by having their 
address pushed onto the call stack after any parameters.

stdcall	
   In the stdcall convention, procedure parameters are pushed onto the call 
   stack prior to the procedure call (which will push the return address 
   just above parameters) in the reverse order they are declared, that is, 
   from right to left. The procedure is in charge of popping any parameters 
   from the call stack (commonly by appending a constant to the RET 
   instruction, signifying the number of bytes to release).

   stdcall is the default calling convention on Windows, and for procedures 
   within Extern "Windows" and Extern "Windows-Ms" blocks. It is also the 
   default convention used in the Windows API.

   Platform Differences
   * In DOS and Windows platforms, the procedure name is decorated with an 
     "@N" suffix, where N is the total size, in bytes, of any parameters 
     passed.

cdecl
   In the cdecl convention, procedure parameters are pushed onto the call 
   stack prior to the procedure call, in the reverse order they are 
   declared, that is, from right to left. The calling code is in charge of 
   popping parameters from the call stack.

   cdecl is the default calling convention on Linux, the *BSDs, and DOS, 
   and for procedures within Extern "C" and Extern "C++" blocks. It is also 
   the default convention used by most C and C++ compilers.

pascal
   In the pascal convention, procedure parameters are pushed onto the call 
   stack, in the order they are declared, that is, from left to right. The 
   procedure is in charge of popping any parameters from the call stack.

   pascal is the default convention used by Pascal and the Microsoft 
   QuickBASIC series of compilers.

The following table summarizes the differences between the various calling 
conventions:

      +-------------------+------------------------------------------------+---------------------------------------------+
      |Calling convention | Parameters are pushed onto the call stack from | Parameters are popped off the call stack by |
      | stdcall           | right to left                                  | the procedure                               |
      | cdecl             | right to left                                  | the calling code                            |
      | pascal            | left to right                                  | the procedure                               |
      +-------------------+------------------------------------------------+---------------------------------------------+

Platform Differences
   * In DOS and Windows platforms, all calling conventions decorate 
     procedure names with an underscore ("_") prefix.
   * The default calling convention changes depending on the platform.  
     For Windows it is stdcall; while on Linux, the *BSDs, and DOS, it is 
     cdecl.

See also
   * Declare, Sub, Function
   * stdcall, cdecl, pascal
   * Extern..End Extern



-------------------------------------------------------- ProPgRecursion ----
Recursion

Recursive procedures (subroutines or functions)

Preamble:

   Iteration and recursion are two very useful ways to program, especially 
   to perform a certain number of times a certain script, and thus allow 
   optimization of the code. If iteration is relatively easy to understand, 
   recursion is a concept not necessarily obvious at the beginning.
   When speaking of a recursive procedure (subroutine or function), we 
   refer to a syntactic characteristic: the procedure, in its own 
   definition, refers to itself (it calls itself).
   But when talking about recursive process, linear or tree, we are 
   interested in the process flow, not in the syntax of the procedure's 
   writing.
   Thus, a procedure can have a recursive definition but correspond to an 
   iterative process.

   Some treatments are naturally implemented as a recursive algorithm 
   (although this is not always the most optimal solution).
   The main problem of the recursive approach is that it consumes 
   potentially a lot of space on the execution stack: from a certain level 
   of "depth" of recursion, the space allocated for the execution stack of 
   the thread is exhausted, and causes an error of type "stack overflow".
   Repeatedly calling the same procedure can also make the execution 
   slower, although this may make the code easier.
   To increase the speed of execution, simple recursive algorithms can be 
   recreated in little more complicated iterative algorithms using loops 
   that execute much faster.

   What is the use of recursion if it increases the execution time and 
   memory space compared to an iterative solution?
   There are still cases where it is not possible to do otherwise, where 
   iterative translation does not exist or, where it exists, is much 
   heavier to implement (requiring for example a dynamic storage capacity 
   to substitute for the execution stack).

Recursion beside iteration
   Iteration and recursion both repeatedly execute the instruction set:
      * Iteration occurs when a loop executes repeatedly until the control 
        condition becomes false.
      * Recursion occurs when an instruction in a procedure calls the 
        procedure itself repeatedly.
   The main difference between iteration and recursion is that iteration is 
   a process applied to a set of instructions to execute repeatedly, while 
   recursion is a process always applied to a procedure.

   Definition of iteration
      Iteration is a process of repeatedly executing a set of instructions 
      until the iteration condition becomes false.
      The iteration block includes the initialization, the comparison, the 
      execution of the instructions to be iterated and finally the update 
      of the control variable.
      Once the control variable is updated, it is compared again and the 
      process is repeated until the condition in the iteration is false.
      Iteration blocks are For loop, While loop, ...

      The iteration block does not use the execution stack to store the 
      variables at each cycle. Therefore, the execution of the iteration 
      block is faster than the recursion block. In addition, iteration does 
      not have the overhead of repeated procedure calls that also make its 
      execution faster than a recursion.
      The iteration is complete when the control condition becomes false.

      Simple example with a iterative function which returns the factorial 
      of the integer:
   '' The code body of the iterative function is defined by using the iterative definition of the factorial function:
   ''    Case (n = 0) : factorial(0) = 1
   ''    Case (n > 0) : factorial(n) = (1) * ..... * (n - 2) * (n - 1) * (n)
   ''    The first line allows to determine the cumulative variable initialization: 'result = 1'
   ''    The second line allows to determine the statement syntax which accumulates: 'result = result * I'

   Function iterativeFactorial (ByVal n As Integer) As Integer
      Dim As Integer result = 1  '' variable initialization
      For I As Integer = 1 To n  '' iteration loop
         result = result * I    '' iterative accumulation
      Next I
      Return result
   End Function

   Print iterativeFactorial(6)

   Sleep

   Definition of recursion
      FreeBASIC allows a procedure to call itself in its code. This means 
      that the procedure definition has a procedure call to itself. The set 
      of local variables and parameters used by the procedure are newly 
      created each time the procedure is called and are stored at the top 
      of the execution stack. But every time a procedure calls itself, it 
      does not create a new copy of that procedure. The recursive procedure 
      does not significantly reduce the size of the code and does not even 
      improve the memory usage, but it does a little bit compared to 
      iteration.

      To end recursion, a condition must be tested to force the return of 
      the procedure without giving a recursive call to itself. The absence 
      of a test of a condition in the definition of a recursive procedure 
      would leave the procedure in infinite recursion once called.

      Note: When the parameters of a recursive procedure are passed by 
      reference, take care to work with local variables when the code body 
      needs to modify their values.

      Simple example with a recursive function which returns the factorial 
      of the integer:
   '' The code body of the recursive function is defined by using the recursive definition of the factorial function:
   ''    Case (n = 0) : factorial(0) = 1
   ''    Case (n > 0) : factorial(n) = n * factorial(n-1)
   ''    The first line allows to determine the end condition: 'If (n = 0) Then Return 1'
   ''    The second line allows to determine the statement syntax which calls the function itself: 'Return n * factorial(n - 1)'

   Function recursiveFactorial (ByVal n As Integer) As Integer
      If (n = 0) Then                           '' end condition
         Return 1
      Else                                      '' recursion loop
         Return n * recursiveFactorial(n - 1)  '' recursive call
      End If
   End Function

   Print recursiveFactorial(6)

   Sleep

Recursion structure
   Different types of recursion structure can be found:
      * Tail recursion.
      * Non-tail but final recursion.
      * Non-tail and non-final recursion.
      * Mutual recursion.
      * Nested recursion.

   Tail recursion
      The recursive procedure is a tail recursive procedure if the only 
      recursive call is at the end of the recursion and is therefore not 
      followed by any other statement:
         * for a recursive subroutine, the only recursive call is at the 
           end of the recursion,
         * for a recursive function, the only recursive call is at the end 
           of the recursion and consists in taking into account the return 
           of the function without any other additional operation on it.
      A tail recursive procedure is easy to transform into an iterative 
      procedure.

      Example with the simple "factorial" recursive function (already 
      presented above):
         * This function has a non-tail recursive form because even though 
           the recursive call is at the end of function, this recursive 
           call is not the last instruction of the function because one has 
           to multiplied again by 'n' when 'recursiveFactorial(n - 1)' is 
           got.
         * This calculation is done when popping context from execution 
           stack.

      It is quite easy to transform this function so that the recursion is 
      a tail recursion.
      To achieve this, it is necessary to add a new parameter to the 
      function: the 'result' parameter which will serve as accumulator:
   Function tailRecursiveFactorial (ByVal n As Integer, ByVal result As Integer = 1) As Integer
      If (n = 0) Then                                       '' end condition
         Return result
      Else                                                  '' recursion loop
         Return tailRecursiveFactorial(n - 1, result * n)  '' tail recursive call
      End If
   End Function

   Print tailRecursiveFactorial(6)

   Sleep
         
This time, the calculation is done when pushing context on execution stack.

      Similar transformation steps for the simple "reverse string" 
      recursive function following:
   Function recursiveReverse (ByVal s As String) As String
      If (s = "") Then                                     '' end condition
         Return s
      Else                                                 '' recursion loop
         Return recursiveReverse(Mid(s, 2)) & Left(s, 1)  '' recursive call
      End If
   End Function

   Print recursiveReverse("9876543210")

   Sleep

   Function tailRecursiveReverse (ByVal s As String, ByVal cumul As String = "") As String
      If (s = "") Then                                                '' end condition
         Return cumul
      Else                                                            '' recursion loop
         Return tailRecursiveReverse(Mid(s, 2), Left(s, 1) & cumul)  '' tail recursive call
      End If
   End Function

   Print tailRecursiveReverse("9876543210")

   Sleep
         
Note: As the "&" operator (string concatenation) is not a symmetric 
operator ('(a & b) <> (b & a)', while '(x * y) = (y * x)' like previously), 
the two operand order must to be reversed when pushing context on execution 
stack instead of before when popping context from execution stack.

   Non-tail but final recursion
      A non-tail recursive procedure is final when the recursive call(s) 
      is(are) placed at the end of executed code (no executable instruction 
      line after and between for several recursive calls).

      First example, computation of the combination coefficients nCp 
      (binomial coefficients calculation) and display of the Pascal's 
      triangle:
   Function recursiveCombination (ByVal n As UInteger, ByVal p As UInteger) As LongInt
      If p = 0 Or p = n Then
         Return 1
      Else
         Return recursiveCombination(n - 1, p) + recursiveCombination(n - 1, p - 1)
      End If
   End Function

   Dim As UInteger n = 10
   For I As UInteger = 0 To n
      For J As UInteger = 0 To I
         Locate , 6 * J + 3 * (n - I) + 3
         Print recursiveCombination(I, J);
      Next J
      Print
   Next I

   Sleep

      Second example, recursive drawing of circles:
   Sub recursiveCircle (ByVal x As Integer, ByVal y As Integer, ByVal r As Integer)
      Circle (x, y), r
      If r > 16 Then
         recursiveCircle(x + r / 2, y, r / 2)
         recursiveCircle(x - r / 2, y, r / 2)
         recursiveCircle(x, y + r / 2, r / 2)
         recursiveCircle(x, y - r / 2, r / 2)
      End If
   End Sub

   Screen 12

   Locate 2, 2
   recursiveCircle(160, 160, 150)

   Sleep

      Third example, quick sort algorithm:
   Dim Shared As UByte t(99)

   Sub recursiveQuicksort (ByVal L As Integer, ByVal R As Integer)
      Dim As Integer pivot = L, I = L, J = R
      Do
         If t(I) >= t(J) Then
            Swap t(I), t(J)
            pivot = L + R - pivot
         End If
         If pivot = L Then
            J = J - 1
         Else
            I = I + 1
         End If
      Loop Until I = J
      If L < I - 1 Then
         recursiveQuicksort(L, I - 1)
      End If
      If R > J + 1 Then
         recursiveQuicksort(J + 1, R)
      End If
   End Sub

   Randomize
   For I As Integer = LBound(t) To UBound(t)
      t(i) = Int(Rnd * 256)
   Next I

   Print "raw memory:"
   For K As Integer = LBound(t) To UBound(t)
      Print Using "####"; t(K);
   Next K
   Print

   recursiveQuicksort(LBound(t), UBound(t))

   Print "sorted memory:"
   For K As Integer = LBound(t) To UBound(t)
      Print Using "####"; t(K);
   Next K
   Print

   Sleep

   Non-tail and non-final recursion
      A non-tail recursive procedure is also not final when the recursive 
      call(s) is(are) not all placed at the end of executed code (an 
      executable instruction line at least after or between for several 
      recursive calls).

      Example, tower of Hanoi algorithm:
   '' For this example, the two recursive calls are at the end of executed code block,
   ''   but separated by an instruction line and there is an order constraint.

   Sub recursiveHanoi (ByVal n As Integer, ByVal departure As String, ByVal middle As String, ByVal arrival As String)
      If n > 0 Then
         recursiveHanoi(n - 1, departure, arrival, middle)
         Print "  move one disk from " & departure & " to " & arrival
         recursiveHanoi(n -1 , middle, departure, arrival)
      End If
   End Sub

   recursiveHanoi(3, "A", "B", "C")

   Sleep

   Mutual recursion
      Two functions are said to be mutually recursive if the first calls 
      the second, and in turn the second calls the first.

      Example using mutual recursive, 'even()' and 'odd()' recursive 
      functions:
   Declare Function recursiveIsEven(ByVal n As Integer) As Boolean
   Declare Function recursiveIsOdd(ByVal n As Integer) As Boolean

   Function recursiveIsEven(ByVal n As Integer) As Boolean
      If n = 0 Then
         Return True
      Else
         Return recursiveIsOdd(n - 1)
      End If
   End Function

   Function recursiveIsOdd(ByVal n As Integer) As Boolean
       If n = 0 Then
         Return False
      Else
         Return recursiveIsEven(n - 1)
      End If
   End Function

   Print recursiveIsEven(16), recursiveIsOdd(16)
   Print recursiveIsEven(17), recursiveIsOdd(17)

   Sleep

   Nested recursion
      A recursive function is said nested if an argument passed to the 
      function refers to the function itself.

      Example using nested recursive function, 'Ackermann()' recursive 
      function:
   Function recursiveAckermann (ByVal m As Integer, ByVal n As Integer) As Integer
      If m = 0 Then
         Return n + 1
      Else
         If n = 0 Then
            Return recursiveAckermann(m - 1, 1)
         Else
            Return recursiveAckermann(m - 1, recursiveAckermann(m, n - 1))
         End If
      End If
   End Function

   Print recursiveAckermann(3, 0), recursiveAckermann(3, 1), recursiveAckermann(3, 2), recursiveAckermann(3, 3), recursiveAckermann(3, 4)

   Sleep

See also
   * Replace Recursion with Iteration



--------------------------------------------------------- ProPgCallback ----
Callback

Callback procedures

Description
   From Wikipedia: A callback, also known as a "call-after" function, is 
   any executable code that is passed as an argument to other code; that 
   other code is expected to call back (execute) the argument at a given 
   time. This execution may be immediate as in a synchronous (or blocking) 
   callback, or it might happen at a later time as in an asynchronous (or 
   deferred) callback.

Example
   Example where a mathematical function is an argument in plot function 
   call:
   (the invocation is implemented by calling the 'PlotF()' procedure, and 
   the callback function is the 'Linear()', 'Sinusoidal()', or 
   'Quadratic()' function)
   Type MathFunction As Function( ByVal x As Double ) As Double

   Function Linear( ByVal x As Double ) As Double
      Return x
   End Function

   Function Quadratic( ByVal x As Double ) As Double
      Return x * x
   End Function

   Function Sinusoidal( ByVal x As Double ) As Double
      Return Sin(x)
   End Function

   Sub PlotF( ByVal f As MathFunction )
      PSet( -15, f(-15) )
      For x As Double = -15 To 15 Step 0.1
         Line -( x, f(x) )
      Next
   End Sub

   Screen 19
   Window (-15,-10)-(15,10)

   PlotF( @Linear )
   PlotF( @Sinusoidal )
   PlotF( @Quadratic )

   Sleep
         
The three callback processes are synchronous because each callback function 
is completely executed before 'PlotF()' returns to the caller code.

   Similar plotting example (as above) but with a asynchronous callback. 
   Here an artificial delay is added. A more realistic case would be if the 
   data to be plotted is retrieved form a web-server with a response time 
   larger than acceptable for the main loop of our program (prevent 
   blocking behavior):
   #include "fbthread.bi"

   Type MathFunction As Function( ByVal x As Double ) As Double

   Sub ThreadPlot( ByVal p As Any Ptr )
      Sleep 1500, 1  '' sleep added only to check the asynchronous way of the callback
      Dim f As MathFunction = p
      Window (-15,-10)-(15,10)
      PSet( -15, f(-15) )
      For x As Double = -15 To 15 Step 0.1
         Line -( x, f(x) )
      Next
   End Sub

   Function PlotF( ByVal f As MathFunction ) As String
      Print "Plotting requested"
      ThreadDetach( ThreadCreate( @ThreadPlot, f ) )
      Return "Plotting request taken into account"
   End Function

   Function Linear( ByVal x As Double ) As Double
      Return x
   End Function

   Function Quadratic( ByVal x As Double ) As Double
      Return x * x
   End Function

   Function Sinusoidal( ByVal x As Double ) As Double
      Return Sin(x)
   End Function

   Screen 19

   Print PlotF( @Linear )
   Print PlotF( @Sinusoidal )
   Print PlotF( @Quadratic )

   '' following code added only to check the asynchronous way of callbacks
   Print "Main program continues ";
   For I As Integer = 1 To 15
      Print ".";
      Sleep 200, 1
   Next I
   Print
   Print "Main program finished"

   Sleep
         
The three callback processes are asynchronous because the 'PlotF()' 
function returns immediately, and each callback function is executed in 
parallel with the caller's next code, from a 'ThreadPlot()' thread created 
(previously) by 'PlotF()' for each of them.

   Example of a callback function for comparing values in a array to be 
   sorted by the qsort algorithm:
   (the invocation is implemented by calling the 'qsort()' procedure, and 
   the callback function is the 'CmpVarLenStr()' function)
   #include "crt/stdlib.bi"

   Function CmpVarLenStr cdecl( ByVal p1 As Any Ptr, ByVal p2 As Any Ptr ) As Long  '' compare 2 var-len strings
      Dim As String Ptr ps1 = p1
      Dim As String Ptr ps2 = p2
      If *ps1 < *ps2 Then
         Return -1
      ElseIf *ps1 > *ps2 Then
         Return 1
      Else
         Return 0
      End If
   End Function

   Sub PrintList( array() As String)  '' print a var-len string list
      For I As Integer = LBound(array) To UBound(array)
         Print array(I)
      Next I
      Print
   End Sub

   Dim forename(1 To 12) As String = {"Madison", "Emily", "Hailey", "Sarah", "Kaitlyn", "Hannah", _
                              "Jacob", "Christopher", "Nicholas", "Michael", "Matthew", "Joshua" }

   Print "LIST OF UNSORTED FORENAMES:"
   PrintList( forename() )

   qsort( @forename(LBound(forename)), UBound(forename) - LBound(forename) + 1, SizeOf(String), @CmpVarLenStr )

   Print "LIST OF SORTED FORENAMES:"
   PrintList( forename() )

   Sleep
         
The callback process is synchronous because the callback function is 
completely executed (several times), (successively) called by 'qsort()', 
before 'qsort()' returns to the caller code.

See also
   * Sub Pointer
   * Function Pointer
   * Threads
   * OBJECT built-in and RTTI info



--------------------------------------------------- ProPgProcCtorsDtors ----
Constructors and Destructors

The module Constructors / Destructors executed before / after module-level 
code.

Preamble:

   Do not confuse the module constructor (destructor) with the UDT 
   constructor (destructor) that runs at the creation (destruction) of a 
   UDT instance.

   The module constructors (destructors) allow to specify the execution of 
   procedures at the beginning (at the end) of a program.

Description
   The constructor (destructor) keyword is used to force execution of the 
   procedure prior (posterior) to that of module-level code.
   Procedures defined as module constructors or destructors may be used the 
   same way as ordinary procedures (they may be also called from within 
   module-level code).
   A module may define multiple constructor and destructors procedures.

   In a single module, depending on the build and run-time environment of 
   the target system:
      - module constructors (destructors) may execute in the order in which 
      they are defined, or reverse order,
      - module constructors (destructors) may execute before or after 
      global static variables having constructors (destructors),
      - module constructors (destructors) may execute before or after other 
      module constructors (destructors) having priority attribute,
      - module constructors (destructors) with priority attribute may 
      execute before or after global static variables having constructors 
      (destructors).

   The constructors and destructors of a module are always executed (like 
   its main code), even if it is compiled as secondary module or static 
   library, or even loaded as dynamic library (dll).

Syntax
   [Public | Private] Sub procedure_name [Alias "external_identifier"] [()] 
   {Constructor | Destructor} [priority] [Static]
      { procedure body }
   End Sub

Usage
   The constructor (destructor) keyword is used in Sub definitions only 
   (forbidden at declaration line level).
   Subs defined as constructors (destructors) may be used in the same way 
   as ordinary Subs (they may be called from within module-level code).
   The Sub must have an empty parameter list. 

   The priority attribute, an integer between 101 and 65535, can be used to 
   force constructors (destructors) to be executed in a certain order, 
   relative to other constructors (destructors) also having priority 
   attribute.
   The value of priority has no specific meaning, only the relationship of 
   the number with other constructor (destructor) priorities.
   101 is the highest (lowest) priority and is executed first (last), 
   relative to other constructors (destructors) also having priority 
   attribute.

   Public static member Subs (having an empty parameter list) of UDT can be 
   defined as a module constructors (destructors), by adding the 
   constructor (destructor) keyword in the Sub definitions.

   Accessing global static objects having constructors (destructors) from 
   module constructors (destructors) should be avoided due to variations in 
   execution order on different build systems.

See also
   * UDT Constructors and Destructors



------------------------------------------------ ProPgProcedurePointers ----
Pointers to Procedures

Pointers that point to procedures

   Just as pointers can be made to point to an Integer or Single type, 
   pointers can also point to procedures, that is, they can store the 
   address of a procedure.

Declaration
   To declare a pointer to procedure, use the Sub or Function keywords, 
   followed by any parameters and return value type:
   ' declares a pointer to sub procedure that takes no arguments
   Dim pointerToProcedure As Sub
         

   Procedure pointers store procedure addresses, which are retrieved using 
   Operator @ (Address of) or the Procptr Operator:
   '' pfunc.bi

   Function Add (a As Integer, b As Integer) As Integer
      Return a + b
   End Function

   Dim pFunc As Function (As Integer, As Integer) As Integer = @Add
         

Calling a procedure pointer
   The interesting thing about procedure pointers is that they can be 
   called just like a procedure:
   '' .. Add and pFunc as before ..
   #include Once "pfunc.bi"

   Print "3 + 4 = " & pFunc(3, 4)
         

   For a calling example of subroutine pointer, see the 
   Operator @ (Address Of) page.

   Note: When calling a procedure through a procedure pointer, parentheses 
   surrounding the argument list (even empty) are mandatory to resolve 
   ambiguity with a simple access to the pointer value.

Passing procedure pointers to procedures
   Passing procedure pointers to other procedures is similar as well:
   '' .. Add and pFunc as before ..
   #include Once "pfunc.bi"

   Function DoOperation (a As Integer, b As Integer, operation As Function (As Integer, As Integer) As Integer) As Integer
      Return operation(a, b)
   End Function

   Print "3 + 4 = " & DoOperation(3, 4, @Add)
         

   Because procedure pointer declarations can be lengthy, it often helps to 
   create a type alias for the procedure pointer, in an effort to make 
   clearer code:
   '' .. Add and pFunc as before ..
   #include Once "pfunc.bi"

   Type operation As Function (As Integer, As Integer) As Integer

   Function DoOperation (a As Integer, b As Integer, op As operation) As Integer
      Return op(a, b)
   End Function

   Print "3 + 4 = " & DoOperation(3, 4, @Add)
         

Pointers to procedure pointers
   Because the syntax of a procedure pointer does not allow declaration of 
   a pointer to procedure pointer when the procedure is a function (because 
   ptr applies on return type and not on procedure), a type alias is used. 
   Notice how it is necessary to surround a dereferenced pointer to 
   procedure pointer by parenthesis when calling the procedure. This is 
   because the function-call operator '()' has higher precedence than 
   Operator * (Value of):
   Function Halve (ByVal i As Integer) As Integer
      Return i / 2
   End Function

   Function Triple (ByVal i As Integer) As Integer
      Return i * 3
   End Function

   Type operation As Function (ByVal As Integer) As Integer

   ' an array of procedure pointers, NULL indicates the
   ' end of the array
   Dim operations(20) As operation = _
   { @Halve, @Triple, 0 }

   Dim i As Integer = 280

   ' apply all of the operations to a variable by iterating through the array
   ' with a pointer to procedure pointer
   Dim op As operation Ptr = @operations(0)
   While (*op <> 0)
      ' call the procedure that is pointed to, note the extra parenthesis
      i = (*op)(i)
      op += 1
   Wend

   Print "Value of 'i' after all operations performed: " & i
         

Pointers to member procedures
   Before fbc 1.10.0, method pointers are not implemented yet, but it is 
   possible to work-around that by using a static wrapper:
   /''
    ' This example shows, before fbc 1.10.0, how you can simulate getting a class method pointer, 
    ' until support is properly implemented in the compiler.
    '
    ' When this is supported (since fbc 1.10.0), you will only need to remove the static wrapper
    ' function presented here, to maintain compatibility. 
    '/

   Type T
      Declare Function test(ByVal number As Integer) As Integer
      Declare Static Function test(ByRef This As T, ByVal number As Integer) As Integer
      Dim As Integer i = 420
   End Type

   Function T.test(ByVal number As Integer) As Integer
      Return i + number
   End Function

   Function T.test(ByRef This As T, ByVal number As Integer) As Integer
      Return this.test(number)
   End Function

   Dim p As Function(ByRef As T, ByVal As Integer) As Integer
   p = @T.test

   Dim As T obj

   Print p(obj, 69) '' prints 489
      

   Since fbc 1.10.0, method pointers are implemented via updating the 
   'Procptr' operator:
   /''
    ' This example shows, since fbc 1.10.0, how to directly obtain a class method pointer,
    '/

   Type T
      Declare Function test(ByVal number As Integer) As Integer
      Dim As Integer i = 420
   End Type

   Function T.test(ByVal number As Integer) As Integer
      Return i + number
   End Function

   Dim p As Function(ByRef As T, ByVal As Integer) As Integer
   p = ProcPtr(T.test)  '' or 'p = @T.test'

   Dim As T obj

   Print p(obj, 69) '' prints 489
      

Typing rule for procedure pointer declaration
   The procedure pointer declaration allows to assign to the pointer:
      * not only a procedure with the same parameters types, and if any, 
        the same result type,
      * but also a procedure with contravariant parameters (by reference 
        or by pointer) or/and a covariant result (by reference or by 
        pointer).

   Assigning to a function pointer a fonction with a contravariant 
   parameter and a covariant result, both by pointer:		
   'Example of assigning to a function pointer a function with:
   '   - a contravariant parameter by pointer,
   '   - and a covariant result by pointer.

   Type A
      Dim As Integer I
      Declare Constructor ()
      Declare Destructor ()
   End Type
   Constructor A ()
      Print "    A instance constructed", @This
   End Constructor
   Destructor A ()
      Print "    A instance destroyed", @This
   End Destructor

   Type B Extends A
      Dim As Integer J
      Declare Constructor ()
      Declare Constructor (ByRef a0 As A)
      Declare Destructor ()
   End Type
   Constructor B ()
      Print "    B instance constructed", @This
   End Constructor
   Constructor B (ByRef a0 As A)
      Cast(A, This) = a0
      Print "    B instance constructed", @This
   End Constructor
   Destructor B ()
      Print "    B instance destroyed", @This
   End Destructor

   Function f (ByVal pa0 As A Ptr) As B Ptr
      Return New B(*pa0)
   End Function

   Scope
      Dim As Function (ByVal As B Ptr) As A Ptr pf = @f
      Print "'Scope : Dim As B b0':"
      Dim As B b0
      Print
      Print "'Dim As A Ptr pab = pf(@b0)':"
      Dim As A Ptr pab = pf(@b0)
      Print
      Print "'Delete CPtr(B Ptr, pab)':"
      Delete CPtr(B Ptr, pab)
      Print
      Print "'End Scope':"
   End Scope

   Sleep
         

   Assigning to a function pointer a function with a contravariant 
   parameter and a covariant result, both by reference:
   'Example of assigning to a function pointer a function with:
   '   - a contravariant parameter by reference,
   '   - and a covariant result by reference.

   Type A Extends Object
      Dim As Integer I
      Declare Constructor ()
      Declare Virtual Destructor ()
   End Type
   Constructor A ()
      Print "    A instance constructed", @This
   End Constructor
   Destructor A ()
      Print "    A instance destroyed", @This
   End Destructor

   Type B Extends A
      Dim As Integer J
      Declare Constructor ()
      Declare Constructor (ByRef a0 As A)
      Declare Virtual Destructor ()
   End Type
   Constructor B ()
      Print "    B instance constructed", @This
   End Constructor
   Constructor B (ByRef a0 As A)
      Cast(A, This) = a0
      Print "    B instance constructed", @This
   End Constructor
   Destructor B ()
      Print "    B instance destroyed", @This
   End Destructor

   Function f (ByRef a0 As A) ByRef As B
      Return *New B(a0)
   End Function

   Scope
      Dim As Function (ByRef As B) ByRef As A pf = @f
      Print "'Scope : Dim As B b0':"
      Dim As B b0
      Print
      Print "'Dim Byref As A rab = pf(b0)':"
      Dim ByRef As A rab = pf(b0)
      Print
      Print "'Delete @rab':"
      Delete @rab
      Print
      Print "'End Scope':"
   End Scope

   Sleep
         

See also
   * Sub
   * Function
   * Pointer
   * Operator @ (Address Of)
   * Procptr Operator



------------------------------------------------ ProPgVariadicArguments ----
Variadic Arguments

Allows a procedure to accept a variable number of arguments.

Preamble:

   Normal procedures take a fixed number of arguments. When such a 
   procedure is defined, the data-type of each argument is specified.
   Every call to this procedure should supply the expected number of 
   arguments, with types that can be converted to the specified ones.

   Variadic arguments allow to define procedures which accept a variable 
   number of arguments.
   Support for variadic procedures differs widely among programming 
   languages.

   Variadic procedures can expose type-safety problems because the language 
   support for variadic procedures is not type-safe:
      - it allows to extract any number of arguments from the stack or 
      elsewhere,
      - and this while defining their types from entered user parameters.
   If the variable arguments are all of same type or compatible with the 
   same type, a sized array can be passed instead, but this requires 
   slightly more work at the caller level.

   Table of Contents
1. Syntax for using variadic procedures
2. ' FB's va_* ' support's keywords family (deprecated va_* support but 
kept for backwards compatibility on some targets)
3. ' C's va_* ' support's keywords family (recommended va_* support for all 
new coding)

1. Syntax for using variadic procedures
   The ellipsis "..." (three dots), as last parameter, is used in procedure 
   declarations (and definitions) to indicate a variable length argument 
   list:
      - A first fixed parameter (at least) must always be specified:
            The fixed parameters(s) can provide information about how many 
            variadic arguments there are, by any mechanism not imposed on 
            the user.
            Otherwise a terminal argument can be added in the variable 
            length argument list, but this reserves a special argument 
            value forbidden to the useful variadic arguments.
               (if one choose to pass the variable arguments all by 
               pointer, in this case an obvious terminal argument is the 
               null pointer)
      - The procedure must be called with the C calling convention cdecl.
      - Two va_* support's keywords families exist to retrieve the variable 
      arguments in the variadic procedure body.
      - A variadic procedure can never be overloaded:
            so this also excludes its use in UDT for constructors and 
            properties,
            but otherwise it can be declared abstract or virtual or even 
            overriding.
      - For variadic procedure members, the implicit passed This parameter 
      is not taken into account as first fixed parameter (at least one 
      explicit fixed parameter must always be specified).

   Declaration syntax
      Declare { Sub | Function } proc_name cdecl ( param_list, ... )  { | [ 
      ByRef ] As return_type }
         param_list
            Parenthesized comma-separated list of fixed parameters.
         return_type
            The return type of a Function.
         proc_name
            The name or symbol of the procedure.

   Calling syntax
      There is nothing special to do for calling a variadic procedure.
      The procedure is simply called by writing the arguments for the fixed 
      parameters, followed by the additional variable arguments, as usual.

      Only numeric types and pointers are supported as variable arguments:
         - All bytes and shorts passed on variable arguments are implicitly 
         converted to integers.
         - All singles passed on variable arguments are implicitly 
         converted to doubles.
         - Strings (or WStrings) can be directly passed by user, in which 
         case a ZString Ptr (or a WString Ptr) to the string (or the 
         wstring) data is taken into account as internal passed argument.

   Retrieving variable arguments
      Variable arguments may use the stack, or registers, as per the normal 
      conventions for the compiler:
         - For some compilers in the past, while registers were used for 
         normal procedures, stack was (always) used for variadic 
         procedures.
         - The gcc compiler family all seem to agree that the call 
         signatures for variadic procedures are exactly the same as 
         properly specified procedures. This means that some of the 
         variable arguments may be in registers and some may be on the 
         stack if there are too many.

      The va_* support's keywords create an interface to retrieve these 
      variable arguments in procedure body:
         - The first FreeBASIC va_* support's keywords family developed 
         have been the FB's va_* support's keywords family:
               These FB's va_* support's keywords are very x86-specific and 
               only work with the gas for x86 GAS assembly backend, because 
               using a pointer to the argument stack.
               These FB's va_* support's keywords don't work on all targets 
               (like 64-bit) because arguments can be passed to procedures 
               in cpu registers.
               These FB's va_* support's keywords are now deprecated but 
               kept for backwards compatibility on some targets.
         - More recently, a FreeBASIC update added a new support's keywords 
         family for variadic procedure argument lists:
               This is the C's va_* support's keywords family compatible 
               for all target platforms.
               These C's va_* support's keywords are now recommended for 
               all new coding.

Back to top

2. ' FB's va_* ' support's keywords family
   Deprecated va_* support but kept for backwards compatibility on some 
   targets.

   There are 3 FB's va_* support's keywords (va_first, va_arg, va_next):
      pointer_variable = va_first( )
         va_first provides an untyped pointer value that points to the 
         first variable argument passed to a procedure.

      variable = va_arg( argument_list, datatype )
         va_arg returns the current argument in the list, argument_list, 
         with an expected data type of datatype.
         (before first va_arg use, argument_list must be initialized with 
         the command va_first)

      argument_pointer = va_next( argument_list, datatype )
         va_next provides a datatype pointer value that points to the next 
         argument within the list argument_list, datatype being the type of 
         the current argument being stepped over.

   Note:
      pointer_variable = va_first( )
      computes the address in the stack following the address of the last 
      passed fixed parameter.

      variable = va_arg( argument_list, datatype )
      is equivalent to:
      variable = *CPtr( datatype Ptr, CPtr( Any Ptr, argument_list ) )

      argument_pointer = va_next( argument_list, datatype )
      is equivalent to:
      argument_pointer = CPtr( datatype Ptr, CPtr( Any Ptr, argument_list ) 
      ) + 1

   Examples:
   ' Variadic function:
   '    The first(fixed) parameter provides the number of elements.
   '    The variable arguments are all strings except the last one which must be a float.
   '    The user's string arguments are in fact passed under the hood through zstring pointers.

   Function concatenation cdecl (ByVal count As Integer, ...) As String
      Dim arg As Any Ptr
      Dim s As String
      
      arg = va_first()

      For i As Integer = 1 To count
         If i < count Then
            s &= *va_arg(arg, ZString Ptr)
            arg = va_next(arg, ZString Ptr)
         Else
            s &= va_arg(arg, Double)
         End If
      Next
      
      Return s
   End Function

   Print concatenation(6, "Free", "BASIC", " ", "version", " ", 0.13)

   Sleep

   ' Output: FreeBASIC version 0.13
         

   ' Variadic sub:
   '    The first(fixed) parameter provides the number of elements.
   '    The variable arguments are all UDT Ptr.

   Type UDT
      Dim As String s
      Dim As Single d
   End Type

   Sub printUDT cdecl (ByVal count As Integer, ...)
      Dim arg As Any Ptr
      Dim pu As UDT Ptr
      
      arg = va_first()

      For i As Integer = 1 To count
         pu = va_arg(arg, UDT Ptr)
         Print pu->s, pu->d
         arg = va_next(arg, UDT Ptr)
      Next
   End Sub

   Dim As UDT u1, u2, u3
   u1.s = "4*Atn(1)" : u1.d = 4 * Atn(1)
   u2.s = "Sqr(2)"   : u2.d = Sqr(2)
   u3.s = "Log(10)"  : u3.d = Log(10)

   printUDT(3, @u1, @u2, @u3)

   Sleep

   ' Output:
   ' 4*Atn(1)       3.141593
   ' Sqr(2)         1.414214
   ' Log(10)        2.302585
         

   ' Variadic sub:
   '    The first (fixed) parameter is the type of the variable arguments (Integer Ptr or Double Ptr).
   '    One terminal argument (added after the useful arguments) must be the null pointer.

   Sub printNumericList cdecl (ByRef argtype As String, ...)
      Dim As Integer datatype = 0
      If UCase(argtype) = "INTEGER PTR" Then
         datatype = 1
         Print "List of integers : ";
      ElseIf UCase(argtype) = "DOUBLE PTR" Then
         datatype = 2
         Print "List of doubles : ";
      Else
         Print "Invalid argument type"
         Exit Sub
      End If
      
      Dim arg As Any Ptr
      Dim pn As Any Ptr
      
      arg = va_first()

      Do
         pn = va_arg(arg, Any Ptr)
         If pn = 0 Then Exit Do
         Print ,
         Select Case As Const datatype
         Case 1
            Print *CPtr(Integer Ptr, pn);
         Case 2
            Print *CPtr(Double Ptr, pn);
         End Select    
         arg = va_next(arg, Any Ptr)
      Loop
      
      Print
   End Sub

   printNumericList("Integer Ptr", @Type<Integer>(123), @Type<Integer>(456), @Type<Integer>(789), CPtr(Integer Ptr, 0))
   printNumericList("Double Ptr", @Type<Double>(1.2), @Type<Double>(3.4), @Type<Double>(5.6), @Type<Double>(7.8), CPtr(Double Ptr, 0))

   Sleep

   ' Output:
   ' List of integers :           123           456           789
   ' List of doubles :            1.2           3.4           5.6           7.8
            

Back to top

3. ' C's va_* ' support's keywords family
   Recommended va_* support for all new coding.

   There are 5 C's va_* support's keywords (Cva_List, Cva_Start, Cva_Copy, 
   Cva_Arg, Cva_End):
      Dim variable As Cva_List
         Cva_List is a built in data type for working with the variable 
         length argument list in a variadic procedure.

      Cva_Start( argument_list, last_param )
         Cva_Start "constructs" the argument_list object declared of 
         Cva_List data-type, settling on the last_param declared in the 
         procedures parameter list before the Ellipsis "...".

      Cva_Copy( dst_list, src_list )
         Cva_Copy "copy-constructs" the dst_list object declared of 
         Cva_List data-type, from an already constructed src_list object.

      variable = Cva_Arg( argument_list, datatype )
         Cva_Arg returns the current argument in the argument_list, with an 
         expected data-type of datatype.
         (Cva_Arg automatically increments argument_list to the next 
         argument within the list after obtaining the value of the current 
         argument)

      Cva_End( argument_list )
         Cva_End "destructs" the argument_list object of Cva_List data-type 
         (previously "constructed" with Cva_Start or Cva_Copy).

   The implementation and code emitted for Cva_List, Cva_Start, Cva_Copy, 
   Cva_Arg, Cva_End varies depending on target, backend, and architecture.

   Note:
      The exact type and size of Cva_List depends on -target, -arch, -gen 
      command line options:
         In -gen gas, Cva_List is a pointer.
         In -gen gcc, Cva_List is a pointer, a struct, or a struct array. 
         The Cva_List type is replaced by "__builtin_va_list" in gcc.
         On 32-bit targets, gas backend: type Cva_List as any alias "char" 
         ptr
         On 32-bit targets, gcc backend: type Cva_List as any alias 
         "__builtin_va_list" ptr
         On Windows 64-bit, gcc backend: type Cva_List as any alias 
         "__builtin_va_list" ptr
         On Linux x86_64, gcc backend: type Cva_List as __va_list_tag alias 
         "__builtin_va_list[]"
         On arm64, gcc backend: type Cva_List as __va_list alias 
         "__builtin_va_list"

      Cva_Start (or Cva_Copy) is like a constructor (or a copy-constructor) 
      for the variadic argument_list object and must finally have a 
      matching call to Cva_End, which is like a destructor.
      After Cva_End for argument_list has been called, argument_list can be 
      reused and reinitialized with another call to Cva_Start (or Cva_Copy)
      .
      The Cva_Start (or Cva_Copy) and Cva_End calls must both be called in 
      pairs in the same procedure (for cross platform compatibility).

   Examples:
   ' Variadic function:
   '    The first(fixed) parameter provides the number of elements.
   '    The variable arguments are all strings except the last one which must be a float.
   '    The user's string arguments are in fact passed under the hood through zstring pointers.

   Function concatenation cdecl (ByVal count As Integer, ...) As String
      Dim s As String
      Dim args As Cva_List
      
      Cva_Start(args, count)
      
      For i As Integer = 1 To count
         If i < count Then
            s &= *Cva_Arg(args, ZString Ptr)
         Else
            s &= Cva_Arg(args, Double)
         End If
      Next
      
      Cva_End(args)
      
      Return s
   End Function

   Print concatenation(6, "Free", "BASIC", " ", "version", " ", 1.07)

   Sleep

   ' Output: FreeBASIC version 1.07
         

   ' Variadic sub:
   '    The first(fixed) parameter provides the number of elements.
   '    The variable arguments are all UDT Ptr.

   Type UDT
      Dim As String s
      Dim As Single d
   End Type

   Sub printUDT cdecl (ByVal count As Integer, ...)
      Dim args As Cva_List
      Dim pu As UDT Ptr
      
      Cva_Start(args, count)

      For i As Integer = 1 To count
         pu = Cva_Arg(args, UDT Ptr)
         Print pu->s, pu->d
      Next
      
      Cva_End(args)
   End Sub

   Dim As UDT u1, u2, u3
   u1.s = "4*Atn(1)" : u1.d = 4 * Atn(1)
   u2.s = "Sqr(2)"   : u2.d = Sqr(2)
   u3.s = "Log(10)"  : u3.d = Log(10)

   printUDT(3, @u1, @u2, @u3)

   Sleep

   ' Output:
   ' 4*Atn(1)       3.141593
   ' Sqr(2)         1.414214
   ' Log(10)        2.302585
         

   ' Variadic sub:
   '    The first (fixed) parameter is the type of the variable arguments (Integer Ptr or Double Ptr).
   '    One terminal argument (added after the useful arguments) must be the null pointer.

   Sub printNumericList cdecl (ByRef argtype As String, ...)
      Dim As Integer datatype = 0
      If UCase(argtype) = "INTEGER PTR" Then
         datatype = 1
         Print "List of integers : ";
      ElseIf UCase(argtype) = "DOUBLE PTR" Then
         datatype = 2
         Print "List of doubles : ";
      Else
         Print "Invalid argument type"
         Exit Sub
      End If
      
      Dim args As Cva_List
      Dim pn As Any Ptr
      
      Cva_Start(args, argtype)
      
      Do
         pn = Cva_Arg(args, Any Ptr)
         If pn = 0 Then Exit Do
         Print ,
         Select Case As Const datatype
         Case 1
            Print *CPtr(Integer Ptr, pn);
         Case 2
            Print *CPtr(Double Ptr, pn);
         End Select    
      Loop
      
      Print
      
      Cva_End(args)
   End Sub

   printNumericList("Integer Ptr", @Type<Integer>(123), @Type<Integer>(456), @Type<Integer>(789), CPtr(Integer Ptr, 0))
   printNumericList("Double Ptr", @Type<Double>(1.2), @Type<Double>(3.4), @Type<Double>(5.6), @Type<Double>(7.8), CPtr(Double Ptr, 0))

   Sleep

   ' Output:
   ' List of integers :           123           456           789
   ' List of doubles :            1.2           3.4           5.6           7.8
         

Back to top

See also
   * ... (Ellipsis)
   * va_first
   * va_arg
   * va_next
   * Cva_List
   * Cva_Start
   * Cva_Copy
   * Cva_Arg
   * Cva_End




============================================================================
    Graphics

---------------------------------------------------------------- GfxLib ----
GfxLib - FreeBASIC graphics library overview

The libary named GfxLib is the built-in graphics library included in FreeBAS
IC. As well as re-creating every QuickBASIC graphics command, GfxLib has 
built-in commands to handle input from the keyboard and mouse. Major 
contributors of the library are Lillo, coderJeff and DrV.

The library supports various drivers depending on the platform: 

   * All:
      * Null Does nothing, allows to use graphics functions on in-memory 
        buffers and such, without anything being displayed in a graphics 
        window.  (gfxlib2/gfx_driver_null.c)

   * Windows:
      * Direct2D the default selection of FB GfxLib. For fbc built on 
        WinXP + mingw.org (very old tool chain now), the Direct2D driver is 
        disabled in the gfxlib.
      * DirectX is fallback if Direct2D can't be initialized. May not be 
        available on old Windows installations. 
        (gfxlib2/win32/gfx_driver_ddraw.c)
      * GDI as last resort, the "safest" one, available in all Windows 
        versions. Bug note: broken in FB versions 0.20 to 0.24 (crash), and 
        minor problems 0.18.5, and 0.90.x and 1.xx ("banding effects", try 
        extra SCREENUNLOCK), (forum discussion: p=106600) 
        (gfxlib2/win32/gfx_driver_gdi.c)
      * OpenGL (gfxlib2/win32/gfx_driver_opengl.c)

   * Linux & others:
      * X11 The default on Unix systems  (gfxlib2/unix/gfx_driver_x11.c)
      * OpenGL (on top of X11) (gfxlib2/unix/gfx_driver_opengl_x11.c)
      * FBDev Linux framebuffer device -- fallback in case X11 is disabled 
        (gfxlib2/linux/gfx_driver_fbdev.c)

   * DOS:
      * BIOS (gfxlib2/dos/gfx_driver_bios.c)
      * ModeX "tuned" 320x240x8bpp VGA mode 
        (gfxlib2/dos/gfx_driver_modex.c)
      * VESA banked compatible with very old VESA 1.x implementations 
        (gfxlib2/dos/gfx_driver_vesa_bnk.c)
      * VESA linear needs VESA version at least 2.0, usually faster than 
        banked VESA (gfxlib2/dos/gfx_driver_vesa_lin.c)
      * VGA (gfxlib2/dos/gfx_driver_vga.c)
      * Bug note: Palette doesn't work well 
        (forum discussion: t=12691 2008) (forum discussion: t=19980 2012)

ScreenControl can be used (SET_DRIVER_NAME 103) to override the default 
driver preferences.

Platform Differences
   * In DOS, GfxLib will create and "manage" a mouse arrow if a mouse 
     driver is detected. There is no "official" way to disable this. Also 
     note that the arrow doesn't react to mouse movements while the screen 
     is locked.
   * In DOS, Windowing and OpenGL related commands and switches are not 
     available (they exist but do nothing, or return some values with no 
     meaning)
   * In DOS, the refresh rate setting is not available (some VESA cards do 
     support it, but FreeBASIC for now doesn't)
   * In DOS, the resolution must match one supported by the graphics card. 
     GfxLib will try to find an appropriate mode from VGA modes, ModeX or 
     VESA, preferring VESA LFB interface if available, or banked VESA 
     otherwise. Unsupported resolutions may currently crash the program (if 
     you fail to check SCREENPTR for ZERO before using it), though in 
     future GfxLib may try to find a close match instead. For optimal 
     compatibility, you should support "safe" resolutions like 640x480 and 
     800x600, and maybe 1024x768. There are various additional modes like 
     768x576 around, but they are vendor specific and lacking on many other 
     cards. Also modes 1024x768 and above are not available on older cards 
     and laptops.
   * It has been observed that SCREEN and SCREENRES may fail to clear the 
     screen in DOS, actually this is probably a BIOS bug that GfxLib 
     currently doesn't workaround.

Differences from QB
   * Graphics support was internally redesigned. QB used VGA graphics 
     modes, and wrote directly into the VGA RAM. Multiple pages were 
     available as long as the card supported them. FB uses backbuffers, one 
     per defined page, and copies them to the video RAM (VGA (DOS), VESA 
     (DOS), DirectX (Win32), ...) in the background. Graphics commands do 
     work as they used to in QB, but a few notable differences are present:
      * The background screen updating eats a considerable amount of CPU 
        performance.
      * There is a thread (Win32 and Linux) or ISR (DOS, uses the PIT) 
        active for this.
      * Mixing FB's graphics support with low-level screen accesses (VGA) 
        is not supported, even in DOS. However direct screen memory access 
        is possible using Screenptr and Screenlock and is fully portable. 
        In DOS VGA and VESA are still available, but can't be mixed with 
        FB's graphics support.

See also
   * GFX Functions Index
   * Screen (Graphics) The QB-like way to set graphics mode
   * ScreenRes More flexible alternative to Screen
   * ScreenList Check display modes available for FB GfxLib to use
   * ScreenControl Select driver and more 
   * ScreenLock
   * ScreenUnlock
   * ScreenPtr Semi-low level access
   * ScreenSet
   * ScreenCopy
   * ScreenInfo
   * ScreenGLProc
   * Internal pixel formats



--------------------------------------------------- ProPgAntiFlickering ----
Graphics Mode Refresh and Anti-Flickering

The Anti-Flikering coding methods for Graphics Mode Refresh (after clearing 
screen or viewport).

Preamble:

   Refreshing (redrawing without precaution) a window in graphics mode can 
   result in annoying flickering (this is due to the display of unwanted 
   intermediate images picked up during the user refreshing phase).
   The phenomenon is obviously intensified if the entire window is first 
   erased before being completely updated, and this repeatedly.

   This page presents the basic FreeBASIC coding techniques to fight 
   against this phenomenon.

Main principles for anti-flickering
   If one takes into account the only graphical user task (regardless of 
   CPU resources needed for the OS), there are two main methods to avoid 
   flickering:
      - In first priority, use of a block '[Screenlock...Screenunlock]' to 
      encapsulate the graphical instructions for refreshing.
         But the documentation enlightens a warning to its use:
            It is strongly recommended that the lock on a page be held for 
            as short a time as possible. Only screen drawing should occur 
            while the screen is locked, input/output and waiting must be 
            avoided. In Win32 and Linux the screen is locked by stopping 
            the thread that processes also the OS' events. If the screen is 
            kept locked for a long time the event queue could overflow and 
            make the system unstable.
      - In a second priority, if the lock time is too long, use the 
      principle of double video paging.

   The instruction 'Screensync' is a reminiscence of the old QuickBASIC 
   where there was only this type of instruction ('wait &h3DA, 8') to 
   improve flickering.
   It is empirical because it only allows to synchronize the drawing 
   relating to the fixed dead time between two frames.
   To be used occasionally with very little time drawing.

   There is usually no interest to mix together these 2 (or 3) methods.

   Then, in the display loop (if exists), user must provide enough CPU 
   resources to OS (smoothed with 'Sleep' instruction at the end of the 
   loop). Otherwise, it will take itself out of user control, resulting in 
   a jerky display.

   Note: Using 'Screensync' provides CPU resources to OS (dead time between 
   end of graphic drawing and end of frame tracing), but by a non 
   controllable way (because linked to the frame period).

Anti-flickering methods learning, through small example
   A small program to enlighten (and compare the different efficiencies) 
   the 4 following different methods from 2 to 5 (after the no method 1) to 
   animate a drawing/printing to a graphic screen by a loop with clearing 
   screen:
         Method 1: Draw/Print loop to screen with raw coding (no method)
            Algorithm:

   '    SCREEN 19, , 2 'to enable double-paging
   '    SCREENSET 0, 0 'to cancel double-paging
   '
   '  â”Œâ”€â–º CLS          'to clear the page
   '  â”‚   Drawing      'to draw on the page
   '  â”‚   Printing     'to print on the page
   '  â””â”€â”€ Temporizing  'to avoid hogging the CPU
   					

         Method 2: Draw/Print loop to screen with synchronizing
            Algorithm:

   '    SCREEN 19, , 2 'to enable double-paging
   '    SCREENSET 0, 0 'to cancel double-paging
   '
   '  â”Œâ”€â–º SCREENSYNC   'to synchronize between two frames
   '  â”‚   CLS          'to clear the page
   '  â”‚   Drawing      'to draw on the page
   '  â”‚   Printing     'to print on the page
   '  â””â”€â”€ Temporizing  'to avoid hogging the CPU
   					

         Method 3: Draw/Print loop to screen with locking
            Algorithm:

   '    SCREEN 19, , 2 'to enable double-paging
   '    SCREENSET 0, 0 'to cancel double-paging
   '
   '  â”Œâ”€â–º SCREENLOCK   'to lock the page's frame buffer
   '  â”‚   CLS          'to clear the page
   '  â”‚   Drawing      'to draw on the page
   '  â”‚   Printing     'to print on the page
   '  â”‚   SCREENUNLOCK 'to unlock the page's frame buffer
   '  â””â”€â”€ Temporizing  'to avoid hogging the CPU
   					

         Method 4: Draw/Print loop to screen with double buffering
            Algorithm:

   '    SCREEN 19, , 2 'to enable double-paging
   '    SCREENSET 1, 0 'to activate double-paging
   '
   '  â”Œâ”€â–º CLS          'to clear the work page
   '  â”‚   Drawing      'to draw on the work page
   '  â”‚   Printing     'to print on the work page
   '  â”‚   SCREENCOPY   'to copy the work page into the visible page
   '  â””â”€â”€ Temporizing  'to avoid hogging the CPU
   					
Note:
                  Double buffering and page flipping (below) are 
                  functionally equivalent (but not under the hood) if the 
                  work page is entirely refreshed at each iteration as 
                  here.

         Method 5: Draw/Print loop to screen with page flipping
            Algorithm:

   '    SCREEN 19, , 2     'to enable double-paging
   '    SCREENSET 1, 0     'to activate double-paging
   '    p0=0 : p1=1        'to initialize flipping
   '
   '  â”Œâ”€â–º CLS              'to clear the work page
   '  â”‚   Drawing          'to draw on the work page
   '  â”‚   Printing         'to print on the work page
   '  â”‚   SCREENSET p0, p1 'to set the work page to the p0 value, and the visible page to the p1 value
   '  â”‚   SWAP p0, p1      'to exchange the values of p0 and p1
   '  â””â”€â”€ Temporizing      'to avoid hogging the CPU
   					
Note:
                  Page flipping and double buffering (above) are 
                  functionally equivalent (but not under the hood) if the 
                  work page is entirely refreshed at each iteration as 
                  here.

         Complete program listing
            Code:
   Declare Sub Draw_circle_recursion (ByVal x As Integer, ByVal y As Integer, ByVal r As Integer, ByVal rmin As Integer)

   Dim I As Integer = 0
   Dim Inc As Integer
   Dim Key As String
   Dim Code As Integer = 1
   Dim Tempo As Integer = 3
   Dim T As Single = Tempo
   Dim p0 As Integer = 0
   Dim p1 As Integer = 1

   Screen 19, , 2

   Do
      If Code = 4 Or Code = 5 Then
         ScreenSet 1, 0
      Else
         ScreenSet 0, 0
      End If
      Do
         Select Case Code
         Case 2
            ScreenSync
         Case 3
            ScreenLock
         End Select
         Cls
         Draw_circle_recursion(10 + I, 300, 9 + I * I / 29 / 29, 10)
         Locate 1, 1
         Select Case Code
         Case 1
            Print "1. Draw/Print loop to screen with raw coding:"
            Print
            Print "   SCREEN 19, , 2 'to enable double-paging"
            Print "   SCREENSET 0, 0 'to cancel double-paging"
            Print
            Print " " & Chr(218) & Chr(196) & Chr(16) & " CLS"
            Print " " & Chr(179) & " " & " " & " Drawing"
            Print " " & Chr(179) & " " & " " & " Printing"
            Print " " & Chr(192) & Chr(196) & Chr(196) & " Temporizing"; T; " ms";
         Case 2
            Print "2. Draw/Print loop to screen with synchronizing:"
            Print
            Print "   SCREEN 19, , 2 'to enable double-paging"
            Print "   SCREENSET 0, 0 'to cancel double-paging"
            Print
            Print " " & Chr(218) & Chr(196) & Chr(16) & " SCREENSYNC"
            Print " " & Chr(179) & " " & " " & " CLS"
            Print " " & Chr(179) & " " & " " & " Drawing"
            Print " " & Chr(179) & " " & " " & " Printing"
            Print " " & Chr(192) & Chr(196) & Chr(196) & " Temporizing"; T; " ms";
         Case 3
            Print "3. Draw/Print loop to screen with locking:"
            Print
            Print "   SCREEN 19, , 2 'to enable double-paging"
            Print "   SCREENSET 0, 0 'to cancel double-paging"
            Print
            Print " " & Chr(218) & Chr(196) & Chr(16) & " SCREENLOCK"
            Print " " & Chr(179) & " " & " " & " CLS"
            Print " " & Chr(179) & " " & " " & " Drawing"
            Print " " & Chr(179) & " " & " " & " Printing"
            Print " " & Chr(179) & " " & " " & " SCREENUNLOCK"
            Print " " & Chr(192) & Chr(196) & Chr(196) & " Temporizing"; T; " ms";
         Case 4
            Print "4. Draw/Print loop to screen with double buffering:"
            Print
            Print "   SCREEN 19, , 2 'to enable double-paging"
            Print "   SCREENSET 1, 0 'to activate double-paging"
            Print
            Print " " & Chr(218) & Chr(196) & Chr(16) & " CLS"
            Print " " & Chr(179) & " " & " " & " Drawing"
            Print " " & Chr(179) & " " & " " & " Printing"
            Print " " & Chr(179) & " " & " " & " SCREENCOPY"
            Print " " & Chr(192) & Chr(196) & Chr(196) & " Temporizing"; T; " ms";
         Case 5
            Print "5. Draw/Print loop to screen with page flipping:"
            Print
            Print "   SCREEN 19, , 2 'to enable double-paging"
            Print "   SCREENSET 1, 0 'to activate double-paging"
            Print "   p0=0 : p1=1    'to initialize flipping"
            Print
            Print " " & Chr(218) & Chr(196) & Chr(16) & " CLS"
            Print " " & Chr(179) & " " & " " & " Drawing"
            Print " " & Chr(179) & " " & " " & " Printing"
            Print " " & Chr(179) & " " & " " & " SCREENSET p0, p1"
            Print " " & Chr(179) & " " & " " & " SWAP p0, p1"
            Print " " & Chr(192) & Chr(196) & Chr(196) & " Temporizing"; T; " ms";
         End Select
         Locate 30, 1
         Print "<1>: Draw/Print with raw coding"
         Print "<2>: Draw/Print with synchronizing"
         Print "<3>: Draw/Print with locking"
         Print "<4>: Draw/Print with double buffering"
         Print "<5>: Draw/Print with page flipping"
         Print "<+/->: Tempo setting (+/-)"
         Print
         Print "<Escape> or click [X]: Quit";
         Select Case Code
         Case 3
            ScreenUnlock
         Case 4
            ScreenCopy
         Case 5
            ScreenSet p0, p1
            Swap p0, p1
         End Select
         If I = 0 Then
            Inc = +1
         ElseIf I = 480 Then
            Inc = -1
         End If
         I = I + Inc
         Key = Inkey
         If Key = "+" And Tempo < 10 Then
            Tempo = Tempo + 1
         ElseIf Key = "-" And Tempo > 0 Then
            Tempo = Tempo - 1
         End If
         If Tempo > 0 Then
            T = Tempo
         Else
            T = 0.5
         End If
         Static As Integer K
         K += 1
         If K >= 25 / T Then
            Sleep 25
            K = 0
         End If
      Loop While Key <> "1" And Key <> "2" And Key <> "3" And Key <> "4" And Key <> "5" And Key <> Chr(27) And Key <> Chr(255) & "k"
      Code = Val(Key)
   Loop Until Key = Chr(27) Or Key = Chr(255) & "k"

   Sub Draw_circle_recursion ( ByVal x As Integer, ByVal y As Integer, ByVal r As Integer, ByVal rmin As Integer )
      Circle (x, y), r, r Shr 1
      If r > rmin Then
         Draw_circle_recursion(x + r Shr 1, y, r Shr 1, rmin)
         Draw_circle_recursion(x - r Shr 1, y, r Shr 1, rmin)
         Draw_circle_recursion(x, y + r Shr 1, r Shr 1, rmin)
         Draw_circle_recursion(x, y - r Shr 1, r Shr 1, rmin)
         Draw_circle_recursion(x + r Shr 1, y + r Shr 1, r Shr 2, rmin)
         Draw_circle_recursion(x - r Shr 1, y + r Shr 1, r Shr 2, rmin)
         Draw_circle_recursion(x + r Shr 1, y - r Shr 1, r Shr 2, rmin)
         Draw_circle_recursion(x - r Shr 1, y - r Shr 1, r Shr 2, rmin)
      End If
   End Sub
                  
Note on temporizing in the loop (for compatibility with any PC):
                  The true temporizing value applied is always 25 ms (
                  'Sleep 25'), but only for one loop on N (with 'N = 25 / 
                  tempo', and 'tempo' the wanted value in ms between 0.5 
                  and 10).

See also
   * ScreenSync
   * ScreenLock, ScreenUnlock
   * ScreenSet, ScreenCopy
   * Lite regulation function to be integrated into user loop for FPS control
   * Fine-grain procedure for waiting and in-loop procedure for fine-regulating FPS



---------------------------------------------------- GfxInternalFormats ----
Internal graphics formats

Information on the internal formats used by FreeBASIC to represent 
graphics.

Pixel formats

   When a graphics mode is set via the Screen (Graphics) or ScreenRes 
   functions, GfxLib creates also a framebuffer in standard system memory 
   and sets an appropriate internal pixel format for the mode. There are 
   basically three internal pixel formats, selected depending on the screen 
   depth, as described in the following table:

      +------------+------------------------+-------------+--------------------------------+
      |Screen depth|Internal bytes per pixel|Range bitmask|Pixel format                    |
      |1bpp        | 1                      | &h1         |palette color index             |
      |2bpp        | 1                      | &h3         |palette color index             |
      |4bpp        | 1                      | &hF         |palette color index             |
      |8bpp        | 1                      | &hFF        |palette color index             |
      |15/16bpp    | 2                      | &hFFFF      |RRRRRGGGGGGBBBBB                |
      |24/32bpp    | 4                      | &hFFFFFFFF  |AAAAAAAARRRRRRRRGGGGGGGGBBBBBBBB|
      +------------+------------------------+-------------+--------------------------------+

   All drawing operations work on this RAM framebuffer; when the actual 
   display needs to be updated, GfxLib copies the contents of the 
   framebuffer to the real display memory, automatically converting in the 
   process from the current internal pixel format to whatever pixel format 
   the real display uses. By limiting the internal pixel formats to 3, the 
   library prevents you having to deal with the plethora of real display 
   formats.

Color values

   When calling a graphics primitive that accepts a color, this can be 
   specified in two ways. In 8bpp or less modes, the color value must be a 
   direct 8 bits color index in the current palette, and this matches the 
   internal pixel format for those modes. In higher color depths, the color 
   value should always have the form &hAARRGGBB. This is what the RGB and 
   RGBA macros return, and is equivalent to the 24/32bpp internal pixel 
   format representation. If the current color depth is 24 or 32bpp, this 
   means the color value passes in unaltered. If a 15/16bpp mode is in use, 
   internally each primitive automatically converts the color from the 
   &hAARRGGBB form into the RRRRRGGGGGGBBBBB internal pixel format (note 
   that in this process the alpha channel is lost, as 15/16bpp modes do not 
   support it). Once the color value is in one of the three pixel formats, 
   the primitive limits its range to the range supported by the current 
   color depth, by using a bitwise And operation with a range bitmask. So 
   if in 8bpp, the color value passed is Anded by &hFF for example.

Notes on transparency

   For 8bpp or less modes, color index 0 is always treated as the 
   transparent color for the Put modes that support transparency. For 
   higher depths, RGB(255, 0, 255) always represents the transparent color. 
   In 15/16bpp modes, this translates to the internal value &hF81F, whereas 
   in 24/32bpp modes it becomes &hFFFF00FF. Note that in 24/32bpp modes, Put
   identifies the transparent color by looking just at the red, green and 
   blue components of the color value, while the alpha value can assume any 
   value. This means that in 24/32bpp modes, &h00FF00FF, &h10FF00FF, 
   &hABFF00FF and &hFFFF00FF for example all represent the transparent 
   color, since the lower 24 bits are always &hFF00FF.

Buffer formats

   In FreeBASIC, images can be used as arrays (as in QB) or as pointers. 
   Either way, the image data is contained in one continuous chunk. The 
   chunk consists of an header followed by the image data. The header can 
   be of two types (old-style and new-style) and determines the format of 
   the following image data.

      Old-style chunk header consists of 4 bytes (32 bits, or 4 bytes). The 
      first 3 bits contain the image color depth in bytes per pixel (8-bit 
      color depth -> 1; 16-bit color depth -> 2; 32-bit color depth -> 4). 
      The next 13 bits contain the image width. The last 16 bits contain 
      the image's height. Please note the intrinsic nature of the header 
      allows only for sizes up to 8191 * 65535 pixels:
   ' inside FB namespace (extracted from fbgfx.bi)

   Type _OLD_HEADER Field = 1
      bpp : 3 As UShort
      Width : 13 As UShort
      height As UShort
   End Type
            

      The actual pixel data follows the header, and is compacted one row of 
      pixels after another; no data alignment is assumed.
      The final size of the chunk can then be computed using the formula:

         size = 4 + ( width * height * bytes_per_pixel )

      New-style chunk header consists of 32 bytes. The first dword (32 
      bits) must be equal to the value 7, allowing GfxLib to identify the 
      new type of chunk. The second dword contains the image color depth in 
      bytes per pixel. The third and fourth dwords contain the image width 
      and height respectively, effectively removing the image size limit 
      enforced by the old-style image chunks. The fifth dword contains the 
      pixel row pitch in bytes; this tells how many bytes a row of pixels 
      in the image takes up. The pitch in new-style chunks is always padded 
      to a multiple of 16, to allow pixels' row data to be aligned on the 
      paragraph boundary. The remaining 3 dwords (total 12 bytes) of the 
      header are currently unused and reserved for future use:
   ' inside FB namespace (extracted from fbgfx.bi)

   Type IMAGE Field = 1  '' in FB namespace
      Union
         old As _OLD_HEADER
         Type As ULong
      End Union
      bpp As Long
      Width As ULong
      height As ULong
      pitch As ULong
      _reserved(1 To 12) As UByte
   End Type
            

      The final size of the image is:

         size = 32 + ( ( ( ( width * bytes_per_pixel ) + &hF ) and not &hF 
         ) * height )

   The format of images created by ImageCreate and Get depend on the 
   dialect used. In the -lang fb dialect, images will be created with the 
   new-style header.  In the -lang fblite and -lang qb dialects, the 
   old-style image header is created.

   All graphics primitives can work with both old-style and new-style image 
   chunks.  For easy access to image information, ImageInfo can be used to 
   obtain useful properties of an image buffer - such as its dimensions, 
   color depth, pitch, and a pointer to the pixel data - whichever format 
   is used.
   It is also possible to access the image header directly to access this 
   information.  For more information on acessing the header structure, 
   please refer to this example.

See also
   * Screen (Graphics)
   * ScreenRes
   * Get (Graphics)
   * Put (Graphics)
   * ImageCreate
   * ImageInfo
   * Trans
   * Alpha



-------------------------------------------------- ProPgExternalFormats ----
External Graphics File Formats (page to be completed)

The external graphics file formats supported by rtlib through Bload and 
Bsave.

Here is a rough starting point, though many bits still to add in... (from 
coderJeff)

Files used with BLOAD/BSAVE
   First byte of file:

   &hFD  QB BSAVED BLOCK 
   &hFE  FB BSAVED BLOCK
   &h42  Windows Bitmap (&h42 = Asc("B"))

	For the QB/FB saved block, &hFD and &hFE identify the file as a QB/FB 
format and the next bytes determine the SIZE of the data contained in the 
file, followed by DATA and optionally PALETTE.

   For the Windows Bitmap, should be binary compatible with standard 
   Windows BMP files. When loading, &h42 only identifies the file as 
   possibly a windows bitmap and other checks on the header may cause it to 
   fail loading.

QB BSAVED Block

   OFS  Len   DESCRIPTION
   0    1     QB BSAVED BLOCK Identifier (&hFD)
   1    4     Ignored
   5    2     Unsigned 16 Bit SIZE, little endian order
   7   ...    Data (expected To be SIZE bytes Long) 
   ?   ...    Palette COLORS

BSAVE and QB/FB Save Block
   BSave( filename, source [,[ size ][,{ pal | pal, bitsperpixel }]] )

   BSAVE always writes using the FB format (&hFE)
   DATA bytes written is the smaller of the SIZE parameter and screen * 
   pitch
   PALETTE is written either from pal parameter or from current screen's 
   palette

BLOAD and QB/FB Save Block
   BLoad filename [, dest [, [pal]]]

   If dest is not given, then DATA is loaded directly to screen memory byte 
   for byte. If SIZE exceeds the current screen * pitch, then DATA is 
   truncated to fit the size of the current graphics mode.

   If dest is given, then DATA is loaded directly to the memory location 
   pointed to by 'dest'.

   RLE (Run-Length Encoding) not supported. So only uncompressed formats.

BLOAD/BSAVE and Windows bitmap
   BLOAD - if first byte is &H42 then file is attempted to be loaded as a 
   bitmap
   BSAVE - if filename has '.bmp' extension, then is saved as bitmap

.....
.....

See also
   * BLoad
   * BSave
   * .....



----------------------------------------------------- ProPgLiteRegulate ----
Lite regulation function to be integrated into user loop for FPS control

Controlling FPS (Frames Per Second) by using an in-loop lite-regulating 
procedure.

Preamble:

   The main objective of this regulation function is to minimize the CPU 
   load which is added to that of the user's own code.
   Therefore, all dead times used by this function to control the user FPS 
   (Frames per second) are generated using exclusively the SLEEP keyword 
   (no CPU consuming waiting loops).

   But the exclusive use of the SLEEP keyword induces a limitation on the 
   maximum accessible FPS value because the delay generated by SLEEP cannot 
   drop below a limit value depending on the OS cycle period.
   A workaround is integrated into this regulation function to provide from 
   values greater than this FPS limit value no longer a true FPS but an 
   apparent FPS which seems to match the requested FPS.

   In addition, as the SLEEP keyword does not have a good accuracy on the 
   generated delay, the FPS obtained fluctuates around the requested value.
   SLEEP also produces a temporal bias which varies over time, but whose 
   average is corrected by the regulation function.

1. Principles to overcome the penalizing behavior of SLEEP keyword
   To implement the best regulation but based only on the SLEEP keyword, 
   some bad behaviors as described above must be overcome or minimized.

   Principle for measuring the minimum delay accessible with SLEEP
      To evaluate the minimum delay 'tos' accessible with SLEEP, the 
      duration of a sequence of ten 'Sleep 1, 1' is measured using the 
      keyword TIMER and the time found is divided by ten.
      But this minimum value 'tos' is not directly usable because a margin 
      must be added to it to preserve an almost linear regulation 
      operation.
      The minimum usable value is thus fixed at '3 * tos / 2'.

      This calibration phase is executed automatically on the first call to 
      the regulation function, or if the time measured is much different 
      than the time ordered, or on request from the user thanks to an 
      optional parameter of the function, or on opportunity measurements 
      when the high limit of regulation is reached (when a heel value of 
      delay with 'Sleep tos / 2, 1' is used).

   Principle for accessing an apparent FPS higher than the maximum true FPS 
   accessible with SLEEP
      When for a required FPS value, the 't' value to be applied in 'Sleep 
      t, 1' becomes less than '3 * tos / 2', an 'image skipping' feature is 
      started to provide an apparent FPS which matches to the required FPS.

      The basic principle of 'image skipping' is to remove all delays 
      between these images (the regulation function returns immediately) so 
      that the persistence of these images is low compared to that which is 
      followed by a true delay.
      The smaller the image tracing time, the less these skipped images are 
      visible.

      The temporal principle for skipping 'n - 1' images over 'n' images is 
      to generate only one delay after viewing the last image, with a value 
      such that the total period of the sequence (of 'n' images) is equal 
      to 'n' times the period corresponding to the required FPS.
      The number of images to skip is stopped as soon as the only delay to 
      generate for the sequence becomes greater than or equal to '3 * tos / 
      2'.
      When 'n - 1' images are skipped over 'n' images, the apparent FPS is 
      equal to the inverse of the full display period of the 'n' images but 
      multiplied by 'n'.

      This functionality of scrolling skipped images can be inhibited by 
      the user thanks to an optional parameter of the function.

      Conversely, the user can reinforce this functionality by downright 
      removing the skipped images by testing an optional parameter of the 
      function which marks these skipped images.
      For this to work, the user code must very well separate the part of 
      the code that concerns only the graphical drawing (the only part that 
      should not be executed when the 'skipped image' tag is true) from the 
      part of the code that concerns only the progress of the movement 
      (which must always be executed). Otherwise, if these two parts of 
      code are skipped at the same time (or even only a small portion of 
      the progress of the movement), the graphical drawing will on the 
      contrary be slowed down (although the returned FPS value says 
      otherwise).

      This operating configuration ('image skipping' +'skipped image' user 
      removing) is therefore the most efficient (from the point of view of 
      apparent FPS) but imposes complete separation rules between two tasks 
      (tracing only and calculating only) in the user animation code loop.

      On the other hand, the 'image skipping' configuration alone (with 
      'skipped image' scrolled by default) does not require any coding 
      rules for the user.

      In case of too high requested FPS and to avoid having an image that 
      is too jerky in the case of image skipping applied, the actual 
      refresh rate of the screen cannot go below 10 Hz in case of skipped 
      images (the apparent FPS can be very much higher), and the number of 
      consecutive skipped images + 1 cannot exceed 20.
      These two limits when 'image skipping' is active induce an apparent 
      displacement quasi-fluid for an initial image moving by 1 pixel every 
      time (a displacement of 20 pixels at a frequency of 10 Hz appears to 
      the user as a fairly smooth movement, not too jerky).

   Principle for compensating for the average temporal bias produced by 
   SLEEP
      The principle is to measure (using the TIMER keyword) the real delay 
      provided by 'Sleep t, 1' in relation with 't'.

      If the time measured is much different than the time ordered, this 
      probably means that there is an error compared to the resolution 
      measured on initialization, and the function then will automatically 
      restart at the next call a new calibration phase (with ten 'Sleep 1, 
      1').
      Example: requested time = 4 Âµs, but measured time = 16 Âµs, probably 
      because the resolution was changed (lowered) while program running.

      If the time measured is only a little different from the time 
      ordered, the differences are averaged to try to correct the average 
      bias of the SLEEP keyword.

2. Description of the function body to include
   The 'regulateLite()' function is described here.
   The code is not thread safe because it uses 'Static' variables.

   The function is well suited to regulate the FPS of an image refresh by 
   inserting a delay into the loop, without adding a notable CPU load to 
   that of the user's own code.

   Note: Like any waiting feature, it is strongly discouraged to use 
   'regulateLite()' when the screen is locked, so no call from inside a 
   [ScreenLock...ScreenUnlock] block.

   The function has a mandatory first parameter 'MyFps' through which the 
   user passes their required FPS.

   For debugging purposes, the function returns the FPS (true or apparent) 
   value it applied. If the user does not wish to use this debug data, then 
   they can call the function as a Sub quite simply.
   If this returned FPS value is much lower than that required, this means 
   that it becomes difficult to reach the FPS setpoint. Otherwise, the 
   fluctuation of the FPS returned is mainly due the use of the only SLEEP 
   keyword to generate the delay in the loop.

   Otherwise, the function proposes 3 optional parameters: 
         - 'Restart' ('False' by default):
               This input parameter allows the user to force a new 
               calibration phase, because for example he knows that the 
               resolution of the OS cycle has just changed.
               Set this parameter to 'True' in the call, then to 'False' on 
               the next call.
         - 'SkipImage' ('True' by default):
               This input parameter allows the user to inhibit the 
               automatic 'image skipping' feature. Whatever happens, there 
               will be no skipped images, but perhaps to the detriment of 
               the FPS obtained which may not follow the requested FPS.
               Set this parameter to 'False' to disable the 'image 
               skipping' feature (can be reset to 'True' later).
         - 'ImageSkipped' ('False' by default bur default value irrelevant) 
         :
               This output parameter is set to 'True' at each image skipped 
               by the function (if the 'image skipping' feature is 
               activated).
               The user can test it to know if the image is skipped or not 
               ("image skipping" feature working in scrolling mode).
               He can also use this parameter to downright not draw this 
               skipped image at all, allowing for example even higher FPS 
               ("image skipping" feature working in removing mode).

   File to be included: "regulateLite.bi"
   ' regulateLite.bi

   Function regulateLite(ByVal MyFps As ULong, ByVal SkipImage As Boolean = True, ByVal Restart As Boolean = False, ByRef ImageSkipped As Boolean = False) As ULong
      '' 'MyFps' : requested FPS value, in frames per second
      '' 'SkipImage' : optional parameter to activate the image skipping (True by default)
      '' 'Restart' : optional parameter to force the resolution acquisition, to reset to False on the next call (False by default)
      '' 'ImageSkipped' : optional parameter to inform the user that the image has been skipped (if image skipping is activated)
      '' function return : applied FPS value (true or apparent), in frames per second
      Static As Single tos
      Static As Single bias
      Static As Long count
      Static As Single sum
      ' initialization calibration
      If tos = 0 Or Restart = True Then
         Dim As Double t = Timer
         For I As Integer = 1 To 10
            Sleep 1, 1
         Next I
         Dim As Double tt = Timer
         #if Not defined(__FB_WIN32__) And Not defined(__FB_LINUX__)
         If tt < t Then t -= 24 * 60 * 60
         #endif
         tos = (tt - t) / 10 * 1000
         bias = 0
         count = 0
         sum = 0
      End If
      Static As Double t1
      Static As Long N = 1
      Static As ULong fps
      Static As Single tf
      ' delay generation
      Dim As Double t2 = Timer
      #if Not defined(__FB_WIN32__) And Not defined(__FB_LINUX__)
      If t2 < t1 Then t1 -= 24 * 60 * 60
      #endif
      Dim As Double t3 = t2
      Dim As Single dt = (N * tf - (t2 - t1)) * 1000 - bias
      If (dt >= 3 * tos / 2) Or (SkipImage = False) Or (N >= 20) Or (fps / N <= 10) Then
         If dt <= tos Then dt = tos / 2
         Sleep dt, 1
         t2 = Timer
         #if Not defined(__FB_WIN32__) And Not defined(__FB_LINUX__)
         If t2 < t1 Then t1 -= 24 * 60 * 60 : t3 -= 24 * 60 * 60
         #endif
         fps = N / (t2 - t1)
         tf = 1 / MyFps
         t1 = t2
         ' automatic test and regulation
         Dim As Single delta = (t2 - t3) * 1000 - (dt + bias)
         If Abs(delta) > 3 * tos Then
            tos = 0
         Else
            bias += 0.1 * Sgn(delta)
         End If
         ' automatic calibation
         If dt < tos Then
            If count = 100 Then
               tos = sum / 100 * 1000
               bias = 0
               sum = 0
               count = 0
            Else
               sum += (t2 - t3)
               count += 1
            End If
         End If
         ImageSkipped = False
         N = 1
      Else
         ImageSkipped = True
         N += 1
      End If
      Return fps
   End Function

   Maximum performance estimation
      Simple modeling of the user loop and its environment:
            - tt : execution time of the tracing task
            - tc : execution time of the calculation task (+ other process)
            - tm : time of the minimum delay generated by 'regulateLite()' 
            (depending on the OS cycle period) = 16 ms (for Windows in 
            normal resolution)
            - fm = minimum frequency of the true FPS authorized by 
            'regulateLite()' in case of 'image skipping' = 10 Hz (fixed in 
            the code)
            - siM = maximum number of skipped images + 1 = 20 (fixed in the 
            code)

      This estimate neglects the execution time of 'regulateLite()' except 
      obviously the delay ('tm') it generates.

      Without 'image skipping':
         FPSmax = 1 / (tt + tc + tm)

      With 'image skipping' alone (skipped images scrolled):
         k0 = Int((1 / fm - tm) / (tt + tc))
         k = Iif(k0 < siM, k0, siM)
         apparent FPSmax = Cint(1 / (k * (tt + tc) + tm) * k)
         ('k' value corresponds to the number of 'skipped images' + 1 : 'k 
         - 1' skipped images over 'k')

      With 'image skipping' + skipped images removed by user:
         k0 = Int((1 / fm - tm - tt) / tc)
         k = Iif(k0 < siM, k0, siM)
         apparent FPSmax = Cint(1 / (k * tc + tt + tm) * k)
         ('k' value corresponds to the number of 'skipped images' + 1 : 'k 
         - 1' skipped images over 'k')

      To highlight the maximum accessible FPS values with 'regulateLite()', 
      depending on the duration of the 2 tasks in the user loop (tracing 
      task and calculation task (+ other process)), a complete table of 
      estimated values is below provided (duration of the 2 tasks ranging 
      from 1 ms to 9 ms each in steps of 1 ms, Windows in normal 
      resolution):
       
   '' Constant tm = 0.016 : time of the minimum delay generated by 'regulateLite()' (depending on the OS cycle period)
   '' Constant fm = 10    : minimum frequence of the true FPS authorized by 'regulateLite()' in case of 'image skipping'
   '' Constant siM = 20   : maximum number of skipped images + 1

   '' Variable tt : execution time of the tracing task
   '' Variable tc : execution time of the calculation task (+ other process)

   '' For each couple (tt,tc) of values, 3 FPS max are estimated, and for each the quota of 'skipped images':
   ''    - FPS without 'image skipping'                                         , number of 'skipped images' (always '0')
   ''    - Apparent FPS with 'image skipping' ('skipped images' only scrolled)  , quota of 'skipped images' (only scrolled)
   ''    - Apparent FPS with 'image skipping' + 'skipped images' removed by user, quota of 'skipped images' removed by user

   ''           | tt = 1 ms | tt = 2 ms | tt = 3 ms | tt = 4 ms | tt = 5 ms | tt = 6 ms | tt = 7 ms | tt = 8 ms | tt = 9 ms |
   '' ----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|
   ''           |  56 0     |  53 0     |  50 0     |  48 0     |  45 0     |  43 0     |  42 0     |  40 0     |  38 0     |
   '' tc = 1 ms | 357 19/20 | 263 19/20 | 208 19/20 | 167 15/16 | 140 13/14 | 120 11/12 | 104 9/10  |  93 8/9   |  83 7/8   |
   ''           | 541 19/20 | 526 19/20 | 513 19/20 | 500 19/20 | 488 19/20 | 476 19/20 | 465 19/20 | 455 19/20 | 444 19/20 |
   '' ----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|
   ''           |  53 0     |  50 0     |  48 0     |  45 0     |  43 0     |  42 0     |  40 0     |  38 0     |  37 0     |
   '' tc = 2 ms | 263 19/20 | 208 19/20 | 167 15/16 | 140 13/14 | 120 11/12 | 104 9/10  |  93 8/9   |  83 7/8   |  75 6/7   |
   ''           | 351 19/20 | 345 19/20 | 339 19/20 | 333 19/20 | 328 19/20 | 323 19/20 | 317 19/20 | 312 19/20 | 308 19/20 |
   '' ----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|
   ''           |  50 0     |  48 0     |  45 0     |  43 0     |  42 0     |  40 0     |  38 0     |  37 0     |  36 0     |
   '' tc = 3 ms | 208 19/20 | 167 15/16 | 140 13/14 | 120 11/12 | 104 9/10  |  93 8/9   |  83 6/7   |  75 6/7   |  70 6/7   |
   ''           | 260 19/20 | 256 19/20 | 253 19/20 | 250 19/20 | 247 19/20 | 244 19/20 | 241 19/20 | 238 19/20 | 235 19/20 |
   '' ----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|
   ''           |  48 0     |  45 0     |  43 0     |  42 0     |  40 0     |  38 0     |  37 0     |  36 0     |  34 0     |
   '' tc = 4 ms | 167 15/16 | 140 13/14 | 120 11/12 | 104 9/10  |  93 8/9   |  83 7/8   |  75 6/7   |  70 6/7   |  64 5/6   |
   ''           | 206 19/20 | 204 19/20 | 202 19/20 | 200 19/20 | 196 18/19 | 194 18/19 | 192 18/19 | 190 18/19 | 186 17/18 |
   '' ----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|
   ''           |  45 0     |  43 0     |  42 0     |  40 0     |  38 0     |  37 0     |  36 0     |  34 0     |  33 0     |
   '' tc = 5 ms | 140 13/14 | 120 11/12 | 104 9/10  |  93 8/9   |  83 7/8   |  75 6/7   |  70 6/7   |  64 5/6   |  60 5/6   |
   ''           | 165 15/16 | 163 15/16 | 162 15/16 | 160 15/16 | 156 14/15 | 155 14/15 | 153 14/15 | 152 14/15 | 150 14/15 |
   '' ----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|
   ''           |  43 0     |  42 0     |  40 0     |  38 0     |  37 0     |  36 0     |  34 0     |  33 0     |  32 0     |
   '' tc = 6 ms | 120 11/12 | 104 9/10  |  93 8/9   |  83 7/8   |  75 6/7   |  70 6/7   |  64 5/6   |  60 5/6   |  55 4/5   |
   ''           | 137 12/13 | 135 12/13 | 134 12/13 | 133 12/13 | 131 12/13 | 130 12/13 | 126 11/12 | 125 11/12 | 124 11/12 |
   '' ----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|
   ''           |  42 0     |  40 0     |  38 0     |  37 0     |  36 0     |  34 0     |  33 0     |  32 0     |  31 0     |
   '' tc = 7 ms | 104 9/10  |  98 8/9   |  83 7/8   |  75 6/7   |  70 6/7   |  64 5/6   |  60 5/6   |  55 4/5   |  52 4/5   |
   ''           | 117 10/11 | 116 10/11 | 115 10/11 | 113 10/11 | 112 10/11 | 111 10/11 | 110 10/11 | 106 9/10  | 105 9/10  |
   '' ----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|
   ''           |  40 0     |  38 0     |  37 0     |  36 0     |  34 0     |  33 0     |  32 0     |  31 0     |  30 0     |
   '' tc = 8 ms |  93 8/9   |  83 7/8   |  75 6/7   |  70 6/7   |  64 5/6   |  60 5/6   |  55 4/5   |  52 4/5   |  48 3/4   |
   ''           | 103 9/10  | 102 9/10  | 101 9/10  | 100 9/10  |  97 8/9   |  96 8/9   |  95 8/9   |  94 8/9   |  93 8/9   |
   '' ----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|
   ''           |  38 0     |  37 0     |  36 0     |  34 0     |  33 0     |  32 0     |  31 0     |  30 0     |  29 0     |
   '' tc = 9 ms |  83 7/8   |  75 6/7   |  70 6/7   |  64 5/6   |  55 5/6   |  55 4/5   |  52 4/5   |  48 3/4   |  45 3/4   |
   ''           |  92 8/9   |  91 8/9   |  90 8/9   |  87 7/8   |  86 7/8   |  85 7/8   |  84 7/8   |  83 7/8   |  82 7/8   |
   '' -----------------------------------------------------------------------------------------------------------------------

3. Examples of test code
   4 code examples for testing the behavior of the 'regulateLite()' 
   function.

   Test code for simple use of 'regulateLite()'
      The 'regulateLite()' function is called as a sub (ignoring the return 
      value) and only the mandatory parameter ('MyFps') is used.
      => "image skipping" feature working in scrolling mode.

      The dynamic part of the display consists of the value of the 
      requested FPS and a graphic progress bar to judge the quality of the 
      regulation.

      The static part of the display is the list of available commands:
            - <+/-> for increase/decrease FPS
            - <escape> to Quit

      Test code 1:
   #include "regulateLite.bi"

   Screen 12
   Dim As ULong FPS = 100
   Do
      Static As ULongInt l
      ScreenLock
      Cls
      Color 15
      Print Using "Requested FPS : ###"; FPS
      Print
      Print
      Print
      Color 14
      Print "<+>      : Increase FPS"
      Print "<->      : Decrease FPS"
      Print
      Print "<Escape> : Quit"
      Line (0, 32)-(639, 48), 7, B
      Line (0, 32)-(l, 48), 7, BF
      ScreenUnlock
      l = (l + 1) Mod 640
      Dim As String s = Inkey
      Select Case s
      Case "+"
         If FPS < 200 Then FPS += 1
      Case "-"
         If FPS > 10 Then FPS -= 1
      Case Chr(27)
         Exit Do
      End Select
      regulateLite(FPS)
   Loop

   Test code for improved use of 'regulateLite()'
      Compared to 'Code for simple test', this code calls 'regulateLite()' 
      as a function and displays the applied FPS (return value).
      Additionally, this code uses the optional 'ImageSkipped' parameter to 
      not display images tagged 'ImageSkipped=True' at all, and also 
      specify the quantum of images displayed.
      => "image skipping" feature working in removing mode.

      Test code 2:
   #include "regulateLite.bi"

   Screen 12
   Dim As ULong FPS = 100
   Do
      Static As ULongInt l
      Static As ULong MyFPS
      Static As Boolean ImageSkipped
      Static As Long nis
      Static As Long tnis
      If ImageSkipped = False Then
         ScreenLock
         Cls
         Color 15
         Print Using "Requested FPS   : ###"; FPS
         Print
         Color 11
         Print Using "Applied FPS        : ###"; MyFPS
         Print "   Image displayed : 1/" & tnis + 1
         Print
         Print
         Print
         Color 14
         Print "<+>      : Increase FPS"
         Print "<->      : Decrease FPS"
         Print
         Print "<Escape> : Quit"
         Line (0, 80)-(639, 96), 7, B
         Line (0, 80)-(l, 96), 7, BF
         ScreenUnlock
      End If
      l = (l + 1) Mod 640
      Dim As String s = Inkey
      Select Case s
      Case "+"
         If FPS < 200 Then FPS += 1
      Case "-"
         If FPS > 10 Then FPS -= 1
      Case Chr(27)
         Exit Do
      End Select
      MyFPS = regulateLite(FPS, , , ImageSkipped)
      If ImageSkipped = True Then
         nis += 1
      Else
         tnis = nis
         nis = 0
      End If
   Loop

   Test code for intensive use of 'regulateLite()'
      Compared to 'Code for improved test', this code additionally uses the 
      other two optional parameters 'SkipImage' and 'Restart'.
      This code is used to test all the combinations of the parameters of 
      the function as well as the type of display of the skipped images 
      (either scrolling of the skipped images, or removing of the skipped 
      images).
      ("image skipping" feature activated and pre-selected in scrolling 
      mode)

      For the Windows platform only, this code allows to change the OS 
      cycle resolution (normal or high) and commands a new calibration 
      phase at each change of resolution.

      Added commands:
            - <T/F> for True/False for image skipping
            - <S/R> for Scroll/Remove image skipped
            - <C> for Calibration phase
            - <N/H> for Normal/High resolution (for Windows platform only)

      Test code 3:
   #include "regulateLite.bi"

   #if defined(__FB_WIN32__)
   Declare Function _setTimer Lib "winmm" Alias "timeBeginPeriod"(ByVal As ULong = 1) As Long
   Declare Function _resetTimer Lib "winmm" Alias "timeEndPeriod"(ByVal As ULong = 1) As Long
   #endif

   Screen 12, , 2
   ScreenSet 1, 0

   Dim As ULongInt MyFps = 100
      
   Dim As String res = "N"
   Dim As Boolean SkipImage = True
   Dim As Boolean Restart = False
   Dim As Boolean RemoveImageSkipped = False

   Do
      Static As ULongInt l
      Static As Double dt
      Static As ULong fps
      Static As Double t
      Static As ULong averageFps
      Static As Double sumFps
      Static As Double averageDelay
      Static As Double sumDelay
      Static As Long N
      Static As Boolean ImageSkipped
      Static As Long ist = 0
      Static As Long mist = 0
      Dim As Double t1
      Dim As Double t2
      If (RemoveImageSkipped = False) Or (ImageSkipped = False) Then
         t = Timer
         Cls
         Print
         Color 15
         Select Case res
         Case "N"
            Print "                      NORMAL RESOLUTION"
         Case "H"
            Print "                      HIGH RESOLUTION (for Windows only)"
         End Select
         Print
         Print " Procedure : regulateLite( "; MyFPS & " [, " & SkipImage & " ])";
         If SkipImage = True Then
            Select Case RemoveImageSkipped
            Case True
               Print "      Images skipped : Removing"
            Case False
               Print "      Images skipped : Scrolling"
            End Select
         Else
               Print "     No image skipping"
         End If
         Print
         Color 11
         If mist = 0 Then
            Print Using " Applied true FPS     : ###         (average : ###)"; fps; averageFps
            Print Using "    Applied delay     : ###.### ms  (average : ###.### ms)"; dt; averageDelay;
         Else
            Print Using " Applied apparent FPS : ###         (average : ###)"; fps; averageFps
            Print Using "    Applied delay     : ###.### ms  (average : ###.### ms)"; dt; averageDelay;
         End If
         If SkipImage = True Then
            Print "  (not skipped image)"
         Else
            Print
         End If
         If SkipImage = True Then
            Select Case RemoveImageSkipped
            Case True
               Print "    Images removed    :  " & IIf(mist > 0, Str(mist) & "/" & Str(mist + 1), "0")
            Case False
               Print "    Images scrolled   :  " & IIf(mist > 0, Str(mist) & "/" & Str(mist + 1), "0")
            End Select
         Else
               Print "    No image skipped"
         End If
         Print
         Print
         Print
         Color 14
         #if defined(__FB_WIN32__)
         Print " <n> or <N> : Normal resolution"
         Print " <h> or <H> : High resolutiion"
         Print
         #endif
         Print " <+>        : Increase FPS"
         Print " <->        : Decrease FPS"
         Print
         Print " Optional parameter :"
         Print "    <t> or <T> : True for image skipping"
         If SkipImage = True Then
            Print "        <r> or <R> : Remove image skipped"
            Print "        <s> or <S> : Scroll image skipped"
         End If
         Print "    <f> or <F> : False for image skipping"
         Print "    <c> or <C> : Calibration phase"
         Print
         Print " <escape>   : Quit"
         Line (8, 144)-(631, 160), 7, B
         Line (8, 144)-(8 + l, 160), 7, BF
         Do
         #if Not defined(__FB_WIN32__) And Not defined(__FB_LINUX__)
            t2 = Timer
            If t2 < t Then t -= 24 * 60 * 60
         Loop Until t2 >= t + 0.002
         #else
         Loop Until Timer >= t + 0.002
         #endif
         ScreenCopy
      End If
      l = (l + 1) Mod 624
      Dim As String s = UCase(Inkey)
      Select Case s
      Case "+"
         If MyFPS < 500 Then MyFPS += 1
      Case "-"
         If MyFPS > 10 Then MyFPS -= 1
      Case "T"
         SkipImage = True
      Case "F"
         SkipImage = False
      #if defined(__FB_WIN32__)
      Case "N"
         If res = "H" Then
            Restart = True
            res = "N"
         End If
      Case "H"
         If res = "N" Then
            Restart = True
            res = "H"
         End If
      #endif
      Case "C"
         Restart = True
      Case "R"
         If SkipImage = True Then RemoveImageSkipped = True
      Case "S"
         If SkipImage = True Then RemoveImageSkipped = False
      Case Chr(27)
         Exit Do
      End Select
      sumFps += fps
      sumDelay += dt
      N += 1
      If N >= fps / 2 Then
         averageFps = sumFps / N
         averageDelay = sumDelay / N
         N = 0
         sumFps = 0
         sumDelay = 0
      End If
      #if defined(__FB_WIN32__)
      If res = "H" Then
         _setTimer()
      End If
      #endif
      t1 = Timer
      fps = regulateLite(MyFPS, SkipImage, Restart, ImageSkipped)
      If ImageSkipped = False Then
         t2 = Timer
         #if Not defined(__FB_WIN32__) And Not defined(__FB_LINUX__)
         If t2 < t1 Then t1 -= 24 * 60 * 60
         #endif
         dt = (t2 - t1) * 1000
      End If
      #if defined(__FB_WIN32__)
      If res = "H" Then
         _resetTimer()
      End If
      #endif
      Restart = False
      If ImageSkipped = True Then
         ist += 1
      Else
         mist = ist
         ist = 0
      End If
   Loop

	
   Test code for maximum performance emulation of 'regulateLite()'
      Consider following notations:
            - tt : execution time of the user tracing task
            - tc : execution time of the user calculation task (+ other 
            process)

      An emulation code is written with two TIMER waiting loops (for 'tt' 
      and 'tc'), and calling the real 'regulateLite()', which allows to 
      estimate the magnitude order of the maximum accessible performance.
      This emulation allows to validate the order of magnitude of the 
      results from the 'Maximum performance estimation' paragraph above.

      Use the runtime commands to adjust the 'tt' and 'tc' values and test 
      the 3 configurations using the optional parameters.
      This test code works with the resolution from the OS cycle.

      Test code 4:
   Dim As Integer tt = 10  ' (in milliseconds)
   Dim As Integer tc =  5  ' (in milliseconds)

   #include "regulateLite.bi"

   Screen 12, , 2
   ScreenSet 1, 0

   Dim As ULongInt MyFps = 9999
      
   Dim As String res = "N"
   Dim As Boolean SkipImage = False
   Dim As Boolean RemoveImageSkipped = False

   Do
      Static As ULong fps
      Static As ULong averageFps
      Static As Double sumFps
      Static As Long N
      Static As Boolean ImageSkipped
      Static As Long ist = 0
      Static As Long mist = 0
      Static As ULongInt l
      Dim As Double t1
      Dim As Double t2
      If (RemoveImageSkipped = False) Or (ImageSkipped = False) Then
         t1 = Timer
         Cls
         Print
         Color 15
         Print "          MAXIMUM PERFORMANCE EMULATION of 'regulateLite()' regulation"
         Print
         Print
         Print Using " tt = ## ms   (execution time of the tracing task)"; tt
         Print Using " tc = ## ms   (execution time of the calculation task + other process)"; tc
         Print
         Print " Procedure : regulateLite( "; MyFPS & " [, " & SkipImage & " ])";
         If SkipImage = True Then
            Select Case RemoveImageSkipped
            Case True
               Print "      Images skipped : Removing"
            Case False
               Print "      Images skipped : Scrolling"
            End Select
         Else
               Print "     No image skipping"
         End If
         Print
         Print
         Color 11
         If mist = 0 Then
            Print Using " Applied true FPS max     :####         (average :####)"; fps; averageFps
         Else
            Print Using " Applied apparent FPS max :####         (average :####)"; fps; averageFps
         End If
         If SkipImage = True Then
            Select Case RemoveImageSkipped
            Case True
               Print "    Images removed        :  " & IIf(mist > 0, Str(mist) & "/" & Str(mist + 1), "0")
            Case False
               Print "    Images scrolled       :  " & IIf(mist > 0, Str(mist) & "/" & Str(mist + 1), "0")
            End Select
         Else
               Print "    No image skipped"
         End If
         Print
         Print
         Color 14
         Print " <+>        : Increment tt"
         Print " <->        : Decrement tt"
         Print
         Print " <i> or <I> : Increment tc"
         Print " <d> or <D> : Decrement tc"
         Print
         Print " Optional parameter :"
         Print "    <t> or <T> : True for image skipping"
         If SkipImage = True Then
            Print "        <r> or <R> : Remove image skipped"
            Print "        <s> or <S> : Scroll image skipped"
         End If
         Print "    <f> or <F> : False for image skipping"
         Print
         Print " <escape>   : Quit"
         Line (0, 197)-(639, 199), 3, B
         Line (0, 198)-(l, 198), 11
         Do
         #if Not defined(__FB_WIN32__) And Not defined(__FB_LINUX__)
            t2 = Timer
            If t2 < t Then t -= 24 * 60 * 60
         Loop Until t2 >= t1 + tt / 1000
         #else
         Loop Until Timer >= t1 + tt / 1000
         #endif
         ScreenCopy
      End If
      t1 = Timer
      Dim As String s = UCase(Inkey)
      Select Case s
      Case "+"
         If tt < 30 Then tt += 1
      Case "-"
         If tt > 1 Then tt -= 1
      Case "I"
         If tc < 30 Then tc += 1
      Case "D"
         If tc > 1 Then tc -= 1
      Case "T"
         SkipImage = True
      Case "F"
         SkipImage = False
      Case "R"
         If SkipImage = True Then RemoveImageSkipped = True
      Case "S"
         If SkipImage = True Then RemoveImageSkipped = False
      Case Chr(27)
         Exit Do
      End Select
      sumFps += fps
      N += 1
      If N >= fps / 2 Then
         averageFps = sumFps / N
         N = 0
         sumFps = 0
      End If
      If ImageSkipped = True Then
         ist += 1
      Else
         mist = ist
         ist = 0
      End If
      l = (l + 1) Mod 640
      Do
      #if Not defined(__FB_WIN32__) And Not defined(__FB_LINUX__)
         t2 = Timer
         If t2 < t Then t -= 24 * 60 * 60
      Loop Until t2 >= t1 + tc / 1000
      #else
      Loop Until Timer >= t1 + tc / 1000
      #endif
      fps = regulateLite(MyFPS, SkipImage, , ImageSkipped)
   Loop

		Note: As the applied FPS is at maximum limit, 'regulateLite()' 
periodically refreshes the value of tm (calibration at runtime), so the FPS 
values found can shift at each new calibration (slow rate).

4. Examples of graphic animation code
   These two graphic animations highlight the interest of the image 
   skipping feature of 'regulateLite()', with scrolling and above all 
   removing of skipped images.

   Graphic animation 1
      This graphic animation (heavy CPU load) comes from dodicat (
      https://www.freebasic.net/forum/viewtopic.php?p=184009#p184009).
      Some initializations and code lines may have been modified from the 
      author's original in order to better highlight the regulation with 
      'regulateLite()' and its different configurations of use.

      This code allows to modify:
            - the value of the requested FPS (and it visualizes the applied 
            FPS),
            - the image skipping activation (false or true),
            - and in case of image skipping activated, the mode for 
            skipping images (scrolling or removing).
            (the removing skipped images adds only three lines to the user 
            code)
            The full status of the image skipping feature is also 
            visualized.

      Graphic animation code 1:
   '' Graphic animation from dodicat (https://www.freebasic.net/forum/viewtopic.php?p=184009#p184009)

   #include "regulateLite.bi"

   Type vector3d
      As Single x,y,z
   End Type
   'assignment macro
   #define vct Type<vector3d>
    
    'macros
      #define map(a,b,x,c,d) ((d)-(c))*((x)-(a))/((b)-(a))+(c)
      #macro combsort(array,begin,finish,dot)
      Scope
         Var size=(finish),switch=0,j=0
         Dim As Single void=size
         Do
            void=void/1.3: If void<1 Then void=1
            switch=0
            For i As Integer =(begin) To size-void
               j=i+void
               If array(i)dot<array(j)dot Then 
                  Swap array(i),array(j): switch=1
               End If
            Next
         Loop Until  switch =0 And void=1
      End Scope
      #endmacro
      
      Operator -(ByRef v1 As vector3d,ByRef v2 As vector3d) As vector3d
         Return Type<vector3d>(v1.x-v2.x,v1.y-v2.y,v1.z-v2.z)
      End Operator
      
      Operator + (ByRef v1 As vector3d,ByRef v2 As vector3d) As vector3d
      Return Type<vector3d>(v1.x+v2.x,v1.y+v2.y,v1.z+v2.z)
      End Operator
      
      Function length(ByRef v1 As vector3d) As Single
         Return Sqr(v1.x*v1.x+v1.y*v1.y+v1.z*v1.z)
      End Function 
      
      Function rotate3d(ByVal pivot As vector3d,ByVal pt As vector3d,ByVal Angle As vector3d, ByVal scale As vector3d=Type<vector3d>(1,1,1)) As vector3d
         #define cr 0.0174532925199433
         Angle=Type<vector3d>(Angle.x*cr,Angle.y*cr,Angle.z*cr)
         #macro Rotate(a1,a2,b1,b2,d)
         temp=Type<vector3d>((a1)*Cos(Angle.d)+(a2)*Sin(Angle.d),(b1)*Cos(Angle.d)+(b2)*Sin(Angle.d))
         #endmacro
         Dim As vector3d p=Type<vector3d>(pt.x-pivot.x,pt.y-pivot.y,pt.z-pivot.z)
         Dim As vector3d rot,temp
         Rotate(p.y,-p.z,p.z,p.y,x)'X
         rot.y=temp.x:rot.z=temp.y 
         p.y = rot.y:p.z = rot.z 
         Rotate(p.z,-p.x,p.x,p.z,y)'Y
         rot.z=temp.x:rot.x=temp.y
         p.x=rot.x
         Rotate(p.x,-p.y,p.y,p.x,z)'Z
         rot.x=temp.x:rot.y=temp.y
         Return Type<vector3d>((scale.x*rot.x+pivot.x),(scale.y*rot.y+pivot.y),(scale.z*rot.z+pivot.z))
      End Function
      
      Function apply_perspective(ByRef p As vector3d,ByRef eyepoint As vector3d) As vector3d
         Dim As Single   w=1+(p.z/eyepoint.z)
         If w=0 Then w=1e-20
         Return Type<vector3d>((p.x-eyepoint.x)/w+eyepoint.x,(p.y-eyepoint.y)/w+eyepoint.y,(p.z-eyepoint.z)/w+eyepoint.z)
      End Function
      '====================== End of rotator and perspective getter ======================================
      Dim Shared As Integer xres,yres
      ScreenRes 800, 640, 8
      Width 800 \ 8, 640 \ 16
      ScreenInfo xres,yres

      'two main arrays
      Dim Shared As vector3d rotated()
      ReDim Shared As vector3d array()
      'extra subs to regulate speed
      'four shapes
      Function create1(ByVal number As Integer) As Integer
         ReDim array(0)
         Dim As Integer count,stepper=10
         For x As Integer=xres/2-number To xres/2+number Step stepper
            For y As Integer=yres/2-number To yres/2+number Step stepper
               For z As Integer=-number To number Step stepper
                  count=count+1
                  ReDim Preserve array(1 To count)
                  array(UBound(array))=vct(x,y,z)
               Next z
            Next y
         Next x
         ReDim rotated(LBound(array) To UBound(array))
         Return 0
      End Function
      
      'variables
      Dim As vector3d centre=vct(xres/2,yres/2,0)
      Dim As vector3d eyepoint=vct(xres/2,yres/2,600)
      Dim As vector3d angle
      Dim As Long fps=150,rfps
      Dim As Boolean skipping=False,remove=False,skipped
      Dim As Long ist,mist
      Dim As ULong averageFps
      Dim As Double sumFps
      Dim As Long N
      Dim As vector3d disp=vct(xres/2,yres/2,0)
      Dim As Integer k,flag=1,border=.2*xres
      Dim As Single sx=1,kx=2,ky=1.9,kz=1.5
      create1(90)
      Do
         angle=angle+vct(.2,2,.1)
         With angle
            If .x>=360 Then .x-=360
            If .y>=360 Then .y-=360
            If .x>=360 Then .z-=360
         End With
         disp=disp+vct(kx,ky,0)
         If disp.x<border Then kx=-kx
         If disp.x>xres-border Then kx=-kx
         If disp.y<border Then ky=-ky
         If disp.y>yres-border Then ky=-ky
         If (remove = False) Or (skipped = False) Then
            ScreenLock
            Cls
            
            For n As Integer=1 To UBound(rotated)
               rotated(n)=rotate3d(centre,(array(n)),angle,vct(sx,sx,sx))
            Next n
            
            combsort(rotated,1,UBound(rotated),.z)
            
            For n As Integer=1 To UBound(rotated)
               Var dist=length(rotated(n)-centre)
               rotated(n)=apply_perspective(rotated(n),eyepoint)
               rotated(n)=rotated(n)+(disp-centre)
               
               Var col=map(0,200,dist,1,15)
               Var radius=map(-400,400,rotated(n).z,10,1)
               Circle (rotated(n).x,rotated(n).y),radius,col,,,,f
            Next n
            
            Draw String (16,16),"Requested FPS = " & Right("  " & fps, 3)
            Draw String (16,32),"Applied FPS   = " & Right("  " & rfps, 3) & "   (average = " & Right("  " & averageFps, 3) & ")"
            Draw String (16,48),"Status : " & _
               IIf(skipping = True, "Image skipping activation = true, with " & _
               IIf(remove = True, "removing images skipped = " & IIf(mist > 0, Str(mist) & "/" & Str(mist + 1), "0"), _
               "scrolling images skipped = " & IIf(mist > 0, Str(mist) & "/" & Str(mist + 1), "0")), _
               "Image skipping activation = false")
            Draw String (16,80),"<+> : Increase FPS"
            Draw String (16,96),"<-> : Decrease FPS"
            Draw String (16,128),"<t> or <T> : True for image skipping activation"
            If Skipping = True Then
               Draw String (16,144),"   <s> or <S> : Scroll image skipped"
               Draw String (16,160),"   <r> or <R> : Remove image skipped"
               Draw String (16,176),"<f> or <F> : False for image skipping activation"
               Draw String (16,208),"<escape> : Quit"
            Else
               Draw String (16,144),"<f> or <F> : False for image skipping activation"
               Draw String (16,176),"<escape> : Quit"
            End If
            Draw String (544,608),"Graphic animation from dodicat"
            ScreenUnlock
         End If
         rfps = regulateLite(fps,skipping, ,skipped)
         If skipped = True Then
            ist += 1
         Else
            mist = ist
            ist = 0
         End If
         sumFps += rfps
         N += 1
         If N >= rfps / 2 Then
            averageFps = sumFps / N
            N = 0
            sumFps = 0
         End If
         Dim As String s = UCase(Inkey)
         Select Case s
         Case "+"
            If fps < 700 Then fps += 1
         Case "-"
            If fps > 10 Then fps -= 1
         Case "T"
            skipping = True
         Case "F"
            skipping = False
         Case "S"
            If skipping = True Then remove = False
         Case "R"
            If skipping = True Then remove = True
         Case Chr(27)
            Exit Do
         End Select
      Loop

   Graphic animation 2
      This graphic animation (heavy CPU load) comes from dodicat (
      https://www.freebasic.net/forum/viewtopic.php?p=195122#p195122).
      Some initializations and code lines may have been modified from the 
      author's original in order to better highlight the regulation with 
      'regulateLite()' and its different configurations of use.

      This code allows to modify:
            - the value of the requested FPS (and it visualizes the applied 
            FPS),
            - the image skipping activation (false or true),
            - and in case of image skipping activated, the mode for 
            skipping images (scrolling or removing).
            (the removing skipped images adds only three lines to the user 
            code)
            The full status of the image skipping feature is also 
            visualized.

      Graphic animation code 2:
   '' Graphic animation from dodicat (https://www.freebasic.net/forum/viewtopic.php?p=195122#p195122)

   #include "regulateLite.bi"

   Sub Thing(ByVal w As Integer=700, _
      ByVal h As Integer=600, _
      ByVal posx As Integer=400, _
      ByVal posy As Integer=300, _
      ByVal morph As Single=24, _
      ByVal aspect As Single=3, _
      ByVal grade As Single=6, _
      ByVal col As UInteger=RGBA(255,255,255,0))
           
      Dim As Single XStep = 1
      Dim As Single YStep = 1
      Dim As Single b=w*w
      Dim As Single y,m,n
      For x As Single = 0 To w Step XStep
         Dim As Single s=x*x
         Dim As Single p=Sqr(b-s)
         For i As Single = -P To P Step grade*YStep
            Dim As Single r = Sqr(s+i*i)/w
            Dim As Single Q = (R - 1) * Sin(morph*r)
            y=i/aspect+q*h
            If i = -p Then m=y:n=y
            If y > m Then m = y
            If y < n Then n = y
            If m=y OrElse n=y Then
               PSet(x/2+posx,-Y/2+posy),col/i 
               PSet(-x/2+posx,-Y/2+posy),col/i
            End If
         Next
      Next
   End Sub

   '===========================================================

   ScreenRes 800, 640, 32, 2
   Width 800 \ 8, 640 \ 16
   Color,RGB(0,0,50)
   ScreenSet 1,0

   Dim As Single Morph=0,k=1
   Dim As Single aspect,counter,pi2=8*Atn(1)
   Dim As Long fps=80,rfps
   Dim As Boolean skipping=False,remove=False,skipped
   Dim As Long ist,mist
   Dim As ULong averageFps
   Dim As Double sumFps
   Dim As Long N

   Do
      counter+=.1
      If counter>=pi2 Then counter=0
      aspect=3+Sin(counter)
      Morph+=.1*k
      If Morph>35 Then k=-k
      If Morph<-35 Then k=-k
      If (remove = False) Or (skipped = False) Then
         Cls
         Thing(800,500,400,300,Morph,aspect) 
         Draw String (16,16),"Requested FPS = " & Right("  " & fps, 3)
         Draw String (16,32),"Applied FPS   = " & Right("  " & rfps, 3) & "   (average = " & Right("  " & averageFps, 3) & ")"
         Draw String (16,48),"Status : " & _
            IIf(skipping = True, "Image skipping activation = true, with " & _
            IIf(remove = True, "removing images skipped = " & IIf(mist > 0, Str(mist) & "/" & Str(mist + 1), "0"), _
            "scrolling images skipped = " & IIf(mist > 0, Str(mist) & "/" & Str(mist + 1), "0")), _
            "Image skipping activation = false")
         Draw String (16,80),"<+> : Increase FPS"
         Draw String (16,96),"<-> : Decrease FPS"
         Draw String (16,128),"<t> or <T> : True for image skipping activation"
         If Skipping = True Then
            Draw String (16,144),"   <s> or <S> : Scroll image skipped"
            Draw String (16,160),"   <r> or <R> : Remove image skipped"
            Draw String (16,176),"<f> or <F> : False for image skipping activation"
            Draw String (16,208),"<escape> : Quit"
         Else
            Draw String (16,144),"<f> or <F> : False for image skipping activation"
            Draw String (16,176),"<escape> : Quit"
         End If
         Draw String (544,608),"Graphic animation from dodicat"
         Flip
      End If
      rfps = regulateLite(fps,skipping, ,skipped)
      If skipped = True Then
         ist += 1
      Else
         mist = ist
         ist = 0
      End If
      sumFps += rfps
      N += 1
      If N >= rfps / 2 Then
         averageFps = sumFps / N
         N = 0
         sumFps = 0
      End If
      Dim As String s = UCase(Inkey)
      Select Case s
      Case "+"
         If fps < 600 Then fps += 1
      Case "-"
         If fps > 10 Then fps -= 1
      Case "T"
         skipping = True
      Case "F"
         skipping = False
      Case "S"
         If skipping = True Then remove = False
      Case "R"
         If skipping = True Then remove = True
      Case Chr(27)
         Exit Do
      End Select
   Loop

   One can notice that for these 2 graphic animations, the mode of 
   operation with 'image skipping' activated plus 'skipped image' removed 
   by the user makes it possible to reach higher FPS, because in these two 
   cases the user code has well separated the drawing part of the new image 
   (the only part that should not be executed when the 'skipped image' tag 
   is true) from the calculation part of the parameters for the new image 
   (which must always be executed).

See also
   * Sleep
   * Timer
   * Graphics Mode Refresh and Anti-Flickering
   * Fine-grain procedure for waiting and in-loop procedure for fine-regulating FPS



---------------------------------------------------- ProPgDelayRegulate ----
Fine-grain procedure for waiting and in-loop procedure for fine-regulating FPS

- Improving SLEEP feature by using a fine-grain waiting procedure.
- Controlling FPS (Frames Per Second) by using an in-loop fine-regulating 
procedure.

Preamble:

   The proper use of the SLEEP and TIMER keywords in user procedures 
   requires a good knowledge of their limits and behaviors.

   SLEEP keyword
      Generally the SLEEP feature has not a good accuracy with respect to 
      the delay requested and does not allow to produce very low waiting 
      times.

      The accuracy of SLEEP is variable depending on the OS cycle time:
         Windows NT/2K/XP: 15 ms, 9x/Me: 50 ms, Linux: 10ms, DOS: 55 ms.
      And using for the delay values lower than these accuracy values does 
      not allow SLEEP to produce the corresponding wait values (always 
      higher wait, and of the order of these values) except for the delay 
      value '0'.

   TIMER keyword
      The accuracy of the time returned by TIMER is much greater than that 
      generally of the SLEEP keyword to generate a wait:
         for modern processors, sub-microsecond accuracy is expected.

      On some platforms (except Windows and Linux), the return value of 
      TIMER is reset at midnight, so if the start and end time are on 
      either side of the reset point, this could cause unexpected behavior 
      in some programs if this event is ignored.

1. Principles to overcome the penalizing behaviors of SLEEP and TIMER 
keywords
   To implement effective time management procedures based on SLEEP and 
   TIMER keywords, some bad behaviors as described above must be overcome.

   Principle for producing a waiting feature with accurate delay
      Using SLEEP does not hog the CPU, but provides poor accuracy and is 
      not compatible with very small delays.
      Using a loop while testing the TIMER value produces a good accuracy 
      but hogs the CPU.

      The principle is to chain:
            - a large-grain delay using SLEEP for the first part of the 
            requested delay,
            - then a fine-grain delay for the rest of the time using a loop 
            that tests the TIMER value.
      A time threshold makes it possible to switch between these two types 
      of operation.

      A typical setting for this threshold corresponds to a value of 2 
      times the OS cycle period.
      This value corresponds to a tradeoff between CPU load and delay 
      accuracy.

   Principle for compensating a possible reset of the TIMER return value
      The detection of a possible reset (at midnight) of the TIMER between 
      two calls is carried out by testing the sign of the difference 
      between the two returned values from the TIMER.
      If the second value is smaller than the first (due to a reset of the 
      TIMER), a negative temporal compensation is applied on the first, 
      corresponding to a day expressed in seconds.

2. Procedures body (without declarations) description
   3 procedures are described here:
         - 'delay()' procedure => to generate the wait for an accurate time 
         (floating value expressed in ms)
         - 'regulate()'procedure => to finely control and regulate a loop 
         frequency (number of loops per second in integer value)
         - 'framerate()' procedure => tool to measure the instantaneous 
         loop frequency (number of loops per second in integer value)

   The 2 first procedures are well suited to finely regulate and/or control 
   the FPS (Frames Per Second) of an image refresh.
   'delay()' is more for one-shot use every now and then, while 
   'regulate()' is more suited for inserting a fine delay into a loop to 
   generally adjust its FPS.

   'regulate()' and 'framerate()' are not thread safe because they each use 
   a 'Static' variable.

   Note: Like any waiting feature, it is strongly discouraged to use 
   'delay()' or 'regulate()' when the screen is locked, so no call from 
   inside a [ScreenLock...ScreenUnlock] block.

   'delay()' procedure body (improving SLEEP feature by using a fine-grain 
   waiting)
      The 'delay()' sub is useful for generating accurate wait 
      functionality, more precise than that provided by the SLEEP keyword, 
      and also compatible with very short wait times.
      If the requested wait 'amount' is greater than the 'threshold' (+ 
      0.5), a first part of the requested waiting time ('amount' - 
      'threshold') is executed thanks to the SLEEP keyword (not hogging the 
      CPU), and the remaining time is generated by testing in loop the 
      accurate values of TIMER up to the target value.
      An eventual resetting of the TIMER is also tested to compensate for 
      it if it occurs.
   Sub delay(ByVal amount As Single, ByVal threshold As ULong)
      '' 'amount'  : requested temporisation to apply, in milliseconds
      '' 'thresold' : fixing threshold for fine-grain temporisation (by waiting loop), in milliseconds
      Dim As Double t1 = Timer
      Dim As Double t2
      Dim As Double t3 = t1 + amount / 1000
      If amount > threshold + 0.5 Then Sleep amount - threshold, 1
      Do
      #if Not defined(__FB_WIN32__) And Not defined(__FB_LINUX__)
         t2 = Timer
         If t2 < t1 Then t1 -= 24 * 60 * 60 : t3 -= 24 * 60 * 60
      Loop Until t2 >= t3
      #else
      Loop Until Timer >= t3
      #endif
   End Sub

		When the 'delay()' sub above is called from the 
"delay_regulate_framerate.bi" file to be included (see its definition below 
in paragraph 3.), a declaration added ahead the body of the sub defines its 
second parameter ('threshold') as an optional parameter and sets its 
default value.

   'regulate()' procedure body (fine-controlling FPS by using an in-loop 
   regulating)
      The 'regulate()' function is built around the 'delay()' sub, but 
      where the waiting time to be applied (if any remains) is deducted 
      from the requested frame period (the inverse of the FPS) and the time 
      already elapsed since the last call.
      For debugging purposes, the 'regulate()' function returns the delay 
      it applied (the one added to the initial loop). If the user does not 
      wish to use this debug data, then they can call the function as a Sub 
      quite simply.
      If this delay value returned is very small, this means that it 
      becomes difficult to reach the FPS setpoint. Otherwise, the 
      fluctuation of the delay returned (assuming that the regulation is 
      very accurate) represents the fluctuation of the user code executed 
      in the loop from frame to frame.
   Function regulate(ByVal MyFps As ULong, ByVal threshold As ULong) As Single
      '' 'MyFps' : requested FPS value, in frames per second
      '' function return : applied delay (for debug), in milliseconds
      '' 'thresold' : fixing threshold for fine-grain temporisation (by waiting loop), in milliseconds
      Static As Double t1
      Dim As Single tf = 1 / MyFps
      Dim As Double t2 = Timer
      #if Not defined(__FB_WIN32__) And Not defined(__FB_LINUX__)
      If t2 < t1 Then t1 -= 24 * 60 * 60
      #endif
      Dim As Single dt = (tf - (t2 - t1)) * 1000
      delay(dt, threshold)
      t1 = Timer
      Return dt
   End Function

		When the 'regulate()' function above is called from the 
"delay_regulate_framerate.bi" file to be included (see its definition below 
in paragraph 3.), a declaration added ahead the body of the function 
defines its second parameter ('threshold') as an optional parameter and 
sets its default value.

   'framerate()' procedure body (tool for FPS measuring)
      For debugging purposes, an instantaneous measurement of FPS (by 
      measuring the frame time and calculating the inverse) can be provided 
      by calling from anywhere in the loop the following very simple 
      tooling function 'framerate()'.
      If 'framerate()' is placed right next to 'regulate()', this measures 
      the intrinsic precision of the regulation.
      If 'framerate()' is placed elsewhere in the program loop, it may be 
      additionally impacted by program execution fluctuations from frame to 
      frame.
   Function framerate() As ULong
      '' function return : measured FPS value (for debug), in frames per second
      Static As Double t1
      Dim As Double t2 = Timer
      #if Not defined(__FB_WIN32__) And Not defined(__FB_LINUX__)
      If t2 < t1 Then t1 -= 24 * 60 * 60
      #endif
      Dim As ULong tf = 1 / (t2 - t1)
      t1 = t2
      Return tf
   End Function

		Unlike 'delay()' and 'regulate()', the 'framerate()' function above can 
be used even when the screen is locked, so called even from inside a [
ScreenLock...ScreenUnlock] block.

3. Complete source code to be included containing all the declarations and 
the procedure bodies
   A header contains the declarations for the bodies of the 3 procedures 
   described above.
   For 'delay()' and 'regulate()', these allow to declare their second 
   parameter as optional and to set the default values according to the 
   platform used (Windows, Linux, DOS, or other).

   File to be included: "delay_regulate_framerate.bi"
   '  delay_regulate_framerate.bi

   #if defined(__FB_WIN32__)
   Declare Sub delay(ByVal amount As Single, ByVal threshold As ULong = 2 * 16)
   Declare Function regulate(ByVal MyFps As ULong, ByVal threshold As ULong = 2 * 16) As Single
   Declare Function _setTimer Lib "winmm" Alias "timeBeginPeriod"(ByVal As ULong = 1) As Long
   Declare Function _resetTimer Lib "winmm" Alias "timeEndPeriod"(ByVal As ULong = 1) As Long
   Declare Sub delayHR(ByVal amount As Single, ByVal threshold As ULong = 2 * 1)
   Declare Function regulateHR(ByVal MyFps As ULong, ByVal threshold As ULong = 2 * 1) As Single
   Sub delayHR(ByVal amount As Single, ByVal threshold As ULong)
      '' 'amount'  : requested temporisation to apply, in milliseconds
      '' 'thresold' : fixing threshold for fine-grain temporisation (by waiting loop), in milliseconds
      Dim As Double t1 = Timer
      Dim As Double t2
      Dim As Double t3 = t1 + amount / 1000
      If amount > threshold + 0.5 Then
         _setTimer()
         Sleep amount - threshold, 1
         _resetTimer()
      End If
      Do
      #if Not defined(__FB_WIN32__) And Not defined(__FB_LINUX__)
         t2 = Timer
         If t2 < t1 Then t1 -= 24 * 60 * 60 : t3 -= 24 * 60 * 60
      Loop Until t2 >= t3
      #else
      Loop Until Timer >= t3
      #endif
   End Sub
   Function regulateHR(ByVal MyFps As ULong, ByVal threshold As ULong) As Single
      '' 'MyFps' : requested FPS value, in frames per second
      '' function return : applied delay (for debug), in milliseconds
      '' 'thresold' : fixing threshold for fine-grain temporisation (by waiting loop), in milliseconds
      Static As Double t1
      Dim As Single tf = 1 / MyFps
      Dim As Double t2 = Timer
      #if Not defined(__FB_WIN32__) And Not defined(__FB_LINUX__)
      If t2 < t1 Then t1 -= 24 * 60 * 60
      #endif
      Dim As Single dt = (tf - (t2 - t1)) * 1000
      delayHR(dt, threshold)
      t1 = Timer
      Return dt
   End Function
   #elseif defined(__FB_LINUX__)
   Declare Sub delay(ByVal amount As Single, ByVal threshold As ULong = 2 * 10)
   Declare Function regulate(ByVal MyFps As ULong, ByVal threshold As ULong = 2 * 10) As Single
   #elseif defined(__FB_DOS__)
   Declare Sub delay(ByVal amount As Single, ByVal threshold As ULong = 2 * 55)
   Declare Function regulate(ByVal MyFps As ULong, ByVal threshold As ULong = 2 * 55) As Single
   #else
   Declare Sub delay(ByVal amount As Single, ByVal threshold As ULong = 2 * 16)
   Declare Function regulate(ByVal MyFps As ULong, ByVal ULong As Single = 2 * 16) As Single
   #endif

   Declare Function framerate() As ULong

   '------------------------------------------------------------------------------

   Sub delay(ByVal amount As Single, ByVal threshold As ULong)
      '' 'amount'  : requested temporisation to apply, in milliseconds
      '' 'thresold' : fixing threshold for fine-grain temporisation (by waiting loop), in milliseconds
      Dim As Double t1 = Timer
      Dim As Double t2
      Dim As Double t3 = t1 + amount / 1000
      If amount > threshold + 0.5 Then Sleep amount - threshold, 1
      Do
      #if Not defined(__FB_WIN32__) And Not defined(__FB_LINUX__)
         t2 = Timer
         If t2 < t1 Then t1 -= 24 * 60 * 60 : t3 -= 24 * 60 * 60
      Loop Until t2 >= t3
      #else
      Loop Until Timer >= t3
      #endif
   End Sub

   Function regulate(ByVal MyFps As ULong, ByVal threshold As ULong) As Single
      '' 'MyFps' : requested FPS value, in frames per second
      '' function return : applied delay (for debug), in milliseconds
      '' 'thresold' : fixing threshold for fine-grain temporisation (by waiting loop), in milliseconds
      Static As Double t1
      Dim As Single tf = 1 / MyFps
      Dim As Double t2 = Timer
      #if Not defined(__FB_WIN32__) And Not defined(__FB_LINUX__)
      If t2 < t1 Then t1 -= 24 * 60 * 60
      #endif
      Dim As Single dt = (tf - (t2 - t1)) * 1000
      delay(dt, threshold)
      t1 = Timer
      Return dt
   End Function

   Function framerate() As ULong
      '' function return : measured FPS value (for debug), in frames per second
      Static As Double t1
      Dim As Double t2 = Timer
      #if Not defined(__FB_WIN32__) And Not defined(__FB_LINUX__)
      If t2 < t1 Then t1 -= 24 * 60 * 60
      #endif
      Dim As ULong tf = 1 / (t2 - t1)
      t1 = t2
      Return tf
   End Function

	This code ('delay_regulate_framerate.bi' file) should be included at the 
top of the user source program so that they can call the 3 procedures:
      #include "delay_regulate_framerate.bi"

4. Examples of use
   Two examples are available here:
         - first example using the 'delay()' sub,
         - second example using the 'regulate()' function (and also the 
         'framerate()' function as debug tool).

   Example using 'delay()' sub
      An example generating, thanks to 'delay()', 4 small waits of 
      decreasing values:
         100 ms, 10 ms, 1 ms, 0.1 ms
   #include "delay_regulate_framerate.bi"

   Dim As Double t
   Dim As Single t0 = 100

   For N As Integer = 1 To 4
      Print "Requested delay :"; t0; " ms"
      For I As Integer = 1 To 4
         t = Timer
         delay(t0)
         Print Using"  Measured delay : ###.### ms"; (Timer - t) * 1000
      Next I
      Print
      t0 /= 10
   Next N

   Sleep

		The measured results seem fairly accurate throughout the full range of 
use.

   Example using 'regulate()' function and 'framerate()' tooling function
      An example controlling, thanks to 'regulate()', the FPS (Frames Per 
      Second) refreshing of a graphic image:
         FPS range available from 10 to 100 in steps of 1
   #include "delay_regulate_framerate.bi"

   Screen 12
   Dim As ULong FPS = 60
   Do
      Static As ULongInt l
      Static As Single dt
      ScreenLock
      Cls
      Color 11
      Print Using "Requested FPS : ###"; FPS
      Print
      Print Using "Applied delay : ###.### ms"; dt
      Print Using "Measured FPS  : ###"; framerate()
      Print
      Print
      Print
      Color 14
      Print "<+>      : Increase FPS"
      Print "<->      : Decrease FPS"
      Print "<Escape> : Quit"
      Line (0, 80)-(639, 96), 7, B
      Line (0, 80)-(l, 96), 7, BF
      ScreenUnlock
      l = (l + 1) Mod 640
      Dim As String s = Inkey
      Select Case s
      Case "+"
         If FPS < 100 Then FPS += 1
      Case "-"
         If FPS > 10 Then FPS -= 1
      Case Chr(27)
         Exit Do
      End Select
      dt = regulate(FPS)
   Loop

		The measured FPS is almost stable and tracks the requested FPS well.
      To monitor the regulation, the delay added in the loop by 
      'regulate()' is also visualized.

5. Adjusting the commutation threshold (large-grain/fine-grain) for 
'delay()' and 'regulate()' procedures depending on the real OS cycle period
   If the user wants to refine or modify the default value of the 
   large-grain/fine-grain commutation threshold for the 'delay()' or 
   'regulate()' procedures, just call it by explicitly specifying the 
   second parameter (integer value given in ms).
   But a typical setting for this threshold corresponds to a value of 2 
   times the OS cycle period (default values set in the file to be 
   included: "delay_regulate_framerate.bi"):
         - 2 times the OS cycle period is the recommended value => tradeoff 
         between CPU load and delay accuracy.
         - A higher threshold would promote the delay accuracy 
         (increasing), but to the detriment of CPU load (increasing).
         - A lower threshold would promote the CPU load (decreasing), but 
         to the detriment of delay accuracy (decreasing).
         - A downright null threshold would induce no CPU load as long as 
         the required delay is greater than 0.5 ms. Only for a necessary 
         required delay < 0.5 ms, the CPU load would not be minimized, but 
         this small value already means that it will become difficult to 
         reach the FPS setpoint.

   Default values set in the header of the 'delay_regulate_framerate.bi' 
   file to be included, according to the platform used:
         - Windows (basic resolution OS cycle period = 16 ms) => threshold 
         = 2 * 16 ms
         - Windows (high resolution OS cycle period = 1 ms) => threshold = 
         2 * 1 ms (only used by 'delayHR() and 'regulateHR(), see paragraph 
         6 below).
         - Linux (OS cycle period = 10 ms) => threshold = 2 * 10 ms.
         - DOS (OS cycle period = 55 ms) => threshold = 2 * 55 ms.
         - Other (OS cycle period per default = 16 ms) => threshold = 2 * 
         16 ms by default.
   If the actual resolution of the OS cycle period is better than the 
   default one above (depending on platform), the user can call 'delay()' 
   and 'regulate()' by explicitly specifying the second parameter (two 
   times this actual resolution value given in ms).

6. Windows platform
   For the Windows platform only, the user can force temporarily the high 
   resolution of the OS cycle period to 1 ms (instead of 16 ms) by calling 
   'delayHR()' or 'regulateHR()' instead.
   The correct threshold (2 * 1 ms) is also temporarily applied.
   This mainly reduces the CPU load because the threshold can be low.

   'delayHR()' procedure included in the "delay_regulate_framerate.bi" 
   file:
   Sub delayHR(ByVal amount As Single, ByVal threshold As ULong)
      '' 'amount'  : requested temporisation to apply, in milliseconds
      '' 'thresold' : fixing threshold for fine-grain temporisation (by waiting loop), in milliseconds
      Dim As Double t1 = Timer
      Dim As Double t2
      Dim As Double t3 = t1 + amount / 1000
      If amount > threshold + 0.5 Then
         _setTimer()
         Sleep amount - threshold, 1
         _resetTimer()
      End If
      Do
      #if Not defined(__FB_WIN32__) And Not defined(__FB_LINUX__)
         t2 = Timer
         If t2 < t1 Then t1 -= 24 * 60 * 60 : t3 -= 24 * 60 * 60
      Loop Until t2 >= t3
      #else
      Loop Until Timer >= t3
      #endif
   End Sub

   'regulateHR()' procedure included in the "delay_regulate_framerate.bi" 
   file:
   Function regulateHR(ByVal MyFps As ULong, ByVal threshold As ULong) As Single
      '' 'MyFps' : requested FPS value, in frames per second
      '' function return : applied delay (for debug), in milliseconds
      '' 'thresold' : fixing threshold for fine-grain temporisation (by waiting loop), in milliseconds
      Static As Double t1
      Dim As Single tf = 1 / MyFps
      Dim As Double t2 = Timer
      #if Not defined(__FB_WIN32__) And Not defined(__FB_LINUX__)
      If t2 < t1 Then t1 -= 24 * 60 * 60
      #endif
      Dim As Single dt = (tf - (t2 - t1)) * 1000
      delayHR(dt, threshold)
      t1 = Timer
      Return dt
   End Function

	'regulateHR()' is not thread safe because it uses a 'Static' variable.

   In any cases, a call to 'delay()' and 'regulate()' always runs in the 
   default resolution, but with a threshold adapted to the basic resolution 
   (2 * 16 ms).
   So if the OS cycle period is already in high resolution (1 ms), it is 
   necessary to use 'delayHR()' and 'regulateHR()' to also apply the 
   correct corresponding threshold, otherwise this high resolution combined 
   with a much too high threshold will not reduce CPU load compared to 
   basic resolution (on the other hand the delay accuracy will be good).
   Preferably use 'delay()' and 'regulate()' only when the OS cycle period 
   is in basic resolution (16 ms).

   Note:
      For the Windows platform, the "delay_regulate_framerate.bi" file is 
      only supported from Windows 2000 (because it refers to high 
      resolution for OS cycle period).
      For earlier Windows systems, remove all references to high resolution 
      from the "delay_regulate_framerate.bi" file (last part of the '#if 
      defined(__FB_WIN32__)'):
            - remove declarations of '-setTimer', '_resetTimer', 'delayHR' 
            and 'regulateHR',
            - delete the body of the 'delayHR' and 'regulateHR' procedures.

7. Enhanced example of use
   This example is improved compared to the second example of the paragraph 
   4.

   It allows in addition to:
      - Switch between the normal resolution and the high resolution of the 
      OS cycle period for the Windows platform only.
      - Modify the value of the optional parameter 'threshold'.
   #include "delay_regulate_framerate.bi"

   Screen 12, , 2
   ScreenSet 1, 0

   Dim As ULongInt MyFps = 100
      
   Dim As String res = "N"
   Dim As ULong thresholdNR = 32
   Dim As ULong thresholdHR = 2

   Do
      Static As ULongInt l
      Static As Double dt
      Static As ULong fps
      Static As Double t
      Static As ULong averageFps
      Static As Double sumFps
      Static As Double averageDelay
      Static As Double sumDelay
      Static As Long N
      Static As ULong fpsE
      Dim As Double t1
      Dim As Double t2
      t = Timer
      Cls
      Print
      Color 15
      Select Case res
      Case "N"
         Print "                      NORMAL RESOLUTION"
      Case "H"
         Print "                      HIGH RESOLUTION (for Windows only)"
      End Select
      Print
      Select Case res
      Case "N"
         Print " Procedure : regulate( " & MyFPS & " [, " & thresholdNR & " ])"
      Case "H"
         Print " Procedure : regulateHR( " & MyFPS & " [, " & thresholdHR & " ])"
      End Select
      Print
      Color 11
      Print Using " Measured FPS  : ###          (average : ###)"; fpsE; averageFps
      Print Using " Applied delay : ###.### ms   (average : ###.### ms)"; dt; averageDelay
      Print
      Print
      Print
      Color 14
      #if defined(__FB_WIN32__)
      Print " <n> or <N> : Normal resolution"
      Print " <h> or <H> : High resolutiion"
      Print
      #endif
      Print " <+>        : Increase FPS"
      Print " <->        : Decrease FPS"
      Print
      Print " Optional parameter :"
      Select Case res
      Case "N"
         Print "    <i> or <I> : Increase NR threshold"
         Print "    <d> or <D> : Decrease NR threasold"
         Draw String (320, 280), "(optimal value : 32)"
      Case "H"
         Print "    <i> or <I> : Increase HR threshold"
         Print "    <d> or <D> : Decrease HR threasold"
         Draw String (320, 280), "(optimal value : 2)"
      End Select
      Print
      Print " <escape>   : Quit"
      Line (8, 128)-(631, 144), 7, B
      Line (8, 128)-(8 + l, 144), 7, BF
      Do
      #if Not defined(__FB_WIN32__) And Not defined(__FB_LINUX__)
         t2 = Timer
         If t2 < t Then t -= 24 * 60 * 60
      Loop Until t2 >= t + 0.002
      #else
      Loop Until Timer >= t + 0.002
      #endif
      ScreenCopy
      l = (l + 1) Mod 624
      Dim As String s = UCase(Inkey)
      Select Case s
      Case "+"
         If MyFPS < 500 Then MyFPS += 1
      Case "-"
         If MyFPS > 10 Then MyFPS -= 1
      #if defined(__FB_WIN32__)
      Case "N"
         If res = "H" Then
            res = "N"
         End If
      Case "H"
         If res = "N" Then
            res = "H"
         End If
      #endif
      Case "I"
         Select Case res
         Case "N"
            If thresholdNR < 64 Then thresholdNR += 16
         Case "H"
            If thresholdHR < 4 Then thresholdHR += 1
         End Select
      Case "D"
         Select Case res
         Case "N"
            If thresholdNR > 0 Then thresholdNR -= 16
         Case "H"
            If thresholdHR > 0 Then thresholdHR -= 1
         End Select
      Case Chr(27)
         Exit Do
      End Select
      sumFps += fpsE
      sumDelay += dt
      N += 1
      If N >= MyFps / 2 Then
         averageFps = sumFps / N
         averageDelay = sumDelay / N
         N = 0
         sumFps = 0
         sumDelay = 0
      End If
      Select Case res
      Case "N"
         dt = regulate(MyFps, thresholdNR) 
      #if defined(__FB_WIN32__)
      Case "H"
         dt = regulateHR(MyFps, thresholdHR)
      #endif
      End Select
      fpsE = framerate()
   Loop

See also
   * Sleep
   * Timer
   * Graphics Mode Refresh and Anti-Flickering
   * Lite regulation function to be integrated into user loop for FPS control




============================================================================
    Multi-Threading

--------------------------------------------------- ProPgMultiThreading ----
Multi-Threading

The Multi-threading programming by using the built-in support provided by 
FreeBASIC.

Preamble:

   Multi-threading programming allows to spawn concurrent process flow.
   It is most effective on multi-processor or multi-core systems where the 
   process flow can be scheduled to run on another processor/core thus 
   gaining speed through parallel or distributed processing.

   While most effective on a multi-processor or multi-core system, gains 
   are also found on single-processor or single-core systems which exploit 
   latency in I/O and other system functions that may halt process 
   execution.
   One thread may execute while another is waiting for I/O or some other 
   system latency.

   Threads require less overhead than spawning a new process because the 
   system does not initialize a new system virtual memory space and 
   environment for the process.
   All threads within a process share the same address space.

Definitions
   A multi-threaded process contains two or more parts that can run 
   concurrently.
   Each part of such a program is called a thread, and each thread defines 
   a separate path of execution.

   Difference between a process and a thread:
      * Process:
            Intuitively, a process is nothing more than the program placed 
            in memory or running with all the run-time environment (or all 
            the resources) associated with it.
            In other words, when your program is located on the hard disk 
            of your machine it is always a program or a simple application, 
            but once executed (or placed in memory) a set of resources 
            (amount of memory space occupied, used processor registers and 
            its status, the owner of the process, the permitted operations, 
            ...) is assigned to it and it simply changes its name. It 
            becomes a process.

            So to simplify, process rhymes with program running.

      * Thread:
            A thread is a portion or part of the process and the smallest 
            sequential unit of instructions processed independently by the 
            scheduler of the operating system.
            It is simply an execution or processing unit composed of a set 
            of instructions contained in the process. See it as the 
            smallest task or operation within the process that is 
            manageable by the scheduler.

            A thread shares information such as a data segment, a code 
            segment, ..., with its peer threads spawned by the same 
            base-thread (see below), while it contains its own registers, 
            stack, ....

            Obviously, a process can be composed of one or more threads, 
            everything will depend on the programmer.
            In the case of a single-threaded process we speak of 
            single-threading, in the opposite case of multi-threading.

   Threads are the popular way to improve program through parallelism.

Multi-threaded programming
   Single-threaded program executes one line of code at a time, then move 
   onto the next line in sequential order (except for branches, function 
   calls etc.).
   This is generally the default behavior when programmer writes code.

   There are a few main reasons to create threads, for example:
      - You need to perform a task which takes a long time to complete but 
      donâ€™t want to make the user wait for it to finish. This is called 
      task parallelisms. The purpose of creating threads is to ensure the 
      application maintains responsiveness in the user interface, rather 
      than to actually make the task run faster. Importantly, the task must 
      be able to run largely independently of the implicit main thread for 
      this design pattern to be useful.
      - You have a complex task which can gain a performance advantage by 
      being split up into chunks. Here you create several threads, each 
      dedicated to one piece of the task. When all the pieces have 
      completed, the main thread aggregates the sub-results into a final 
      result. This pattern is called the parallel aggregation pattern. For 
      this to work, portions of the total result of the task or calculation 
      must be able to be calculated independently â€“ the second part of 
      the result cannot rely on the first part etc.

   Multi-threaded program is executing from two or more locations in the 
   program at the same time (or at least, with the illusion of running at 
   the same time):
      * Sequencing overview:
            When a program starts up, one implicit thread already begins 
            running immediately.
            This is usually called the "main" thread of the program, 
            because it is the one that is executed when a program begins:
               - The main thread is the thread from which programmer may 
               spawn other â€œchildâ€� threads (which in turn may spawn 
               other "sub-child" threads).
               - Main thread and other threads run concurrently.
               - Generally, a "parent" thread needs to wait for the result 
               of a child thread, and so waits for the relevant thread to 
               finish.
               - Often, the main thread must be the last thread to finish 
               execution because it performs various shutdown actions (as a 
               "child" thread must also do so with respect to its eventual 
               "sub-child" threads spawned).
               - But other than that, the implicit main thread can also 
               compete with all other threads explicitly spawned by 
               programmer.

      * Threading on multi-processor or multi-core systems:
            If the system has a multi-processor or multi-core capacity, 
            creating a new thread may cause the new thread to be executed 
            on an unused or least busy processor/core. If your application 
            is multi-threaded, you can be mostly assured that it will 
            automatically take advantage of multiple processors/cores.
            In contrast, on a single processor/core, the threads will be 
            time-sliced by the operating system in the same way processes 
            are in a multi-tasking environment and all run on the single 
            processor/core, so there is no effective performance gain.

            Note:
               - Creating for example 4 threads will not necessarily lead 
               to a 4-fold performance increase. Depending on the 
               algorithms in use, the amount of co-ordination between 
               threads, overhead from accessing memory shared between 
               threads and other factors, the speedup will be sub-linear.
               - Algorithms which are well-designed for sequential (single 
               thread) use are not necessarily optimized for multi-threaded 
               use and may need to be significantly redesigned.

      * Thread safety:
            Sometimes running several parts of the program at once can lead 
            to unexpected behavior or even cause memory corruption and 
            crashes if precautions are not taken into account.
            If the same procedure can be executed in several threads 
            simultaneously and independently without affecting each other, 
            and additionally is designed to cooperate with other threads 
            when accessing or changing their variables etc., the procedure 
            is said to be thread safe.

            Creating thread safe code is essentially the biggest problem 
            and stumbling block for programmers getting to grips with 
            multi-threaded programming. Even experienced programmers can 
            come up across subtle and dangerous bugs which are very 
            difficult to understand and debug.

      * Synchronization objects:
            Synchronization objects allow threads to communicate with each 
            other by signalling events of any kind. For example, indicating 
            that a resource is being accessed and that other threads 
            wanting to use the resource should wait to avoid a problems.
            The most commonly used synchronization objects are "mutual 
            exclusion" and "conditional variables" used in critical 
            sections of a multi-threaded program, the code blocks that has 
            to be executed as atomic actions (no concurrence with other 
            threads executing similar actions).

   Multi-threading is quite dangerous, the mistakes here are very costly. 
   When a problem is found, itâ€™s either hard or impossible to debug, but 
   itâ€™s not the worst.

   The worst is when the code has a mistake, but it works correctly.
   This can happen because once threads are used, the execution flow is not 
   deterministic anymore.
   How long does it take to create a new thread?
   How many concurrent threads can there be?
   How is the CPU time distributed among the threads?

   It is advised to always set a 'Sleep x, 1' tempo in each 'For' loop of 
   each thread (including the main thread), in order to release time-slice 
   allowing the other threads to execute as well.

   All these factors affect the overall execution. Writing multi-threaded 
   code is about being prepared to anything, and thatâ€™s making it both 
   dangerous and exciting.

Multi-threaded built-in support
   The thread-safe runtime library is automatically used if the FreeBASIC 
   built-in threading functions are used (so the '-mt' compiler option for 
   the linker, is only needed if programmer wants to use his own threading 
   routines).

   The following pages of this section ("Multi-Threading") explain:
      * On the 'Threads' page:
            the built-in procedures that create, and detach/wait-for the 
            threads.
      * On the 'Mutual Exclusion' page:
            the built-in procedures that create, lock/unlock, and destroy 
            the mutexes.
      * On the 'Conditional Variables' page:
            the built-in procedures that create, wait-for/signal, and 
            destroy conditional variables.
      * On the 'Critical Sections' page:
            the use of these built-in procedures in code blocks for 
            handling the concurrency with other threads.
      * On the 'Critical Sections FAQ' page:
            the "Critical Sections" related questions in multi-threading".

See also
   * Threads
   * Mutual Exclusion
   * Conditional Variables
   * Critical Sections
   * Critical Sections FAQ



-------------------------------------------------------- ProPgMtThreads ----
Threads

The built-in procedures that create, and detach/wait-for the Threads.

Preamble:

   When a program starts executing, it has one implicit thread running 
   (this is already a full-fledged thread).
   This "main" thread executes the main function of the program.
   This same program can explicitly launch additional threads that will run 
   in a competitive manner (both between them and with the main thread).

   All threads (including the main thread) share the same memory, and thus 
   can access the same global variables, same heap memory, same set of file 
   descriptors, etc.
   All these threads execute in parallel (i.e. using time slices, or if the 
   system has several processors/cores, then really in parallel).

Creating a thread
   There are two methods to create a thread:
      - a "classic" method ThreadCreate that starts a specific user-defined 
      subroutine type (which has obligatorily one single parameter, an 'Any 
      Ptr' type pointer) in a separate execution thread, this first method 
      being 100% safe,
      - a "specific" method ThreadCall that should have start any 
      user-defined subroutine type (which may have almost any number and 
      any type of parameters) in a separate execution thread, but for the 
      moment this second method is bugged.

   Classic method (100% safe) - ThreadCreate
      - Syntax:
         Declare Function ThreadCreate ( ByVal procptr As Sub ( ByVal 
         userdata As Any Ptr ), ByVal param As Any Ptr = 0, 		ByVal 
         stack_size As Integer = 0 ) As Any Ptr
      - Usage:
         threadid = ThreadCreate ( procptr [, [ param ] [, stack_size ] ] )
      - Parameters:
         procptr
            A pointer to the Sub intended to work as a thread. The sub must 
            have the following signature (same parameters, same calling 
            convention) to be compatible to procptr:
               Declare Sub myThread ( ByVal userdata As Any Ptr )
         userdata
            The Any Ptr parameter of the Sub intended to work as a thread. 
            FreeBASIC expects this parameter to be present, it must not be 
            omitted! 
         param
            Any Ptr argument that will be passed to the thread Sub pointed 
            to by procptr through its userdata parameter. For example, this 
            can be a pointer to a structure or an array containing various 
            information for the thread sub to work with. If param is not 
            given, 0 (zero) will be passed to the thread sub's userdata 
            parameter instead.
         stack_size
            Optional number of bytes to reserve for this thread's stack.
      - Return value:
         The Any Ptr handle (threadid) to the thread created, or the null 
         pointer (0) on failure.

      Note:
         - The userdata parameter can be unused in the body of the myThread 
         sub, but declaring it as an Any Ptr parameter is always mandatory 
         in the header. In this case, the corresponding param parameter can 
         then be omitted when calling ThreadCreate, or else a needless 
         argument can still be passed ('0' is commonly used because this 
         value is directly compatible with any pointer). See the 1st and 
         2nd example.
         - In the case where data must be passed to myThread, the Any Ptr 
         param can be used to reference them, usually requiring a type 
         conversion (implicit or explicit) into Any Ptr before passing it 
         to ThreadCreate, and a reverse type conversion from Any Ptr in the 
         body of myThread before using it. See the 3rd example.

   Specific method (bugged) - ThreadCall
      - Syntax:
         Declare Function ThreadCall subname ( [paramlist] ) As Any Ptr
      - Usage:
         threadid = ThreadCall subname ( [paramlist] )
      - Parameters:
         subname
            The name of a subroutine
         paramlist
            A list of parameters to pass to the subroutine, as with a 
            normal sub call.	
      - Return value:
         The Any Ptr handle (threadid) to the thread created, or the null 
         pointer (0) on failure.

      Warning:
         Presently when ThreadCall involves to pass parameters to the 
         thread, there is no guarantee that the corresponding data are 
         still maintained after the end of the ThreadCall statement and 
         this until the thread is really launched. That can cause bad 
         behavior.
         Therefore it is more advisable for the moment to use ThreadCreate 
         (100% safe) instead.

   Description
      Several different threads can be created from the same Sub, with 
      different passed arguments allowing to define the behavior of each.

      There may be a long time between the end of the ThreadCreate/
      ThreadCall statement execution and the effective launch of the 
      thread. So some statements following the ThreadCreate/ThreadCall 
      statement can be executed before the actual launch of the thread.
      Conversely, the thread body can start executing even before 
      ThreadCreate/ThreadCall returns.

      There is no guarantee about the order in which different threads 
      execute, and no assumptions can be made about the order in which 
      multiple created threads actually start executing (except in Linux).

      By default, a thread is always created in the "joinable" state, ie 
      its handle is accessible by its 'threadid' identifier.
      If a thread ends in this state (joinable), the resources that were 
      assigned to it will not be released automatically (but only at the 
      main thread termination).

      So a good habit is to always use one and only one of the following 
      two methods for a thread to finish properly (see the paragraph 
      below):
         - either  waiting for the thread end,
         - otherwise detaching the thread (the thread becomes no longer 
         joinable).

      Each running thread can be identified by its handle which is unique 
      among all running threads.
      When a new thread is created, a handle to the thread is returned by 
      the creation function.
      When the thread runs code, ThreadSelf (from fbc version 1.08) allows 
      to also return the handle of the thread (the implicit main thread 
      also has its own unique handle).
      ThreadSelf may be used to code some sort of TLS (Thread Local 
      Storage) from the unique handle of each thread (including the 
      implicit main thread). Therefore, a same global variable name may be 
      defined, but with a stored value specific to the thread that accesses 
      it. This allows generic procedures to be coded, but with parameters 
      depending on the thread which executes them.

Waiting for a thread end, otherwise detaching a thread
   There are two methods to induce a proper thread termination:
      - either a first method ThreadWait where another thread waits for 
      this thread to finish,
      - otherwise a second method ThreadDetach where another thread 
      detaches this thread and continues.

   First method - ThreadWait
      - Syntax:
         Declare Sub ThreadWait ( ByVal threadid As Any Ptr )
      - Usage:
         ThreadWait ( threadid )
      - Parameters:
         threadid
            Any Ptr handle of a thread created by ThreadCreate or ThreadCall
      - Note:
         In other language (as C++), the 'wait()' suffix is called 'join()'
         .

   Second method - ThreadDetach
      - Syntax:
         Declare Sub ThreadDetach ( ByVal threadid As Any Ptr )
      - Usage:
         #include "fbthread.bi"
         ThreadDetach ( threadid )
      - Parameters:
         threadid
            Any Ptr handle of a thread created by ThreadCreate or ThreadCall

   Description
      After creating it, the programmer must make sure that the thread is 
      either waited for (joined) otherwise detached, and this from another 
      thread (including the main thread).

      ThreadWait waits for a thread to complete its execution, and then 
      release the resources associated with the thread handle. ThreadWait 
      does not return until the thread (designated by the identifier) ends.
      During the wait, the caller does not consume CPU time.
      ThreadWait does not force the thread to end. If a thread requires a 
      signal to force an end, a mechanism such as a shared flag must be 
      used.

      ThreadDetach releases resources associated with the thread handle. 
      The thread handle will be destroyed by ThreadDetach and can no longer 
      be used.
      Unlike ThreadWait, ThreadDetach does not wait for the end of the 
      thread, and its execution continues independently. All allocated 
      resources will be freed once the thread is complete.

      After ThreadWait or ThreadDetach is applied, the thread can no longer 
      be joined, so the handle identifier value must not be used again in 
      any of these commands.

      Generally, before finishing, a 'parent' thread is waiting for the 
      'child' thread to finish.
      But if the programmer chooses not to wait until the end of the thread 
      (and necessarily detaches it only), then he must make sure that the 
      data accessed by that thread is valid until the thread has finished 
      with it. Otherwise, one may encounter a situation where the 'parent' 
      thread holds pointers/references to local variables and the 'child' 
      thread hasn't finished when the 'parent' thread finishes (the 
      variables being destroyed because becoming out of scope).

Example
   * Small example proving multi-threading capacity:
      - In a non multi-threading code, we cannot do anything else while 
      waiting for the "Line Input" instruction to return.
      - Multi-threading makes this possible.
   Sub thread(ByVal p As Any Ptr)
      Do
         Static As String t
         Draw String (0, 16), t, 0
         t = Time
         Draw String (0, 16), t
         Do
            If *Cast(String Ptr, p) = "quit" Then Exit Sub
            Sleep 100, 1
         Loop Until Time <> t  ' to limit flickering
      Loop
   End Sub

   Dim As String s
   Dim As Any Ptr pThread

   Screen 12
   Print "Time is updated by thread even while 'Line Input' is waiting for characters:";
   Locate 4, 1
   Print "Enter any character line to test, or 'quit' to finish:"
   pThread = ThreadCreate(@thread, @s)
   Do
      Locate 5, 1
      Print Space(Len(s));
      Locate 5, 1
      Line Input s
   Loop Until s = "quit"
   ThreadWait(pThread)

   * The 'Main' thread displays ten "M" characters while the 'Child' 
     thread simultaneously displays ten "C" characters.
   A 'Sleep x, 1' tempo is put in the 'For' loop of each thread (main 
   thread and child thread) to release time-slice allowing the other thread 
   to execute as well.
   The tempos are set so that the execution time of the child thread 'For' 
   loop is greater than the one of the main thread 'For' loop.

      - Using ThreadCreate ..... ThreadWait:
   Declare Sub thread (ByVal userdata As Any Ptr)

   Dim As Any Ptr threadID  '' declaration of an 'Any Ptr' thread-ID of the child thread

   Print """M"": from 'Main' thread"
   Print """C"": from 'Child' thread"
   Print

   threadID = ThreadCreate(@thread)  '' creation of the child thread from the main thread

   For I As Integer = 1 To 10  '' 'For' loop of the main thread
      Print "M";
      Sleep 150, 1
   Next I

   ThreadWait(threadID)  '' waiting for the child thread termination
   Print
   Print "'Child' thread finished"

   Sleep

   Sub thread (ByVal userdata As Any Ptr)  '' sub executed by the child thread
      For I As Integer = 1 To 10          '' 'For' loop of the child thread
         Print "C";
         Sleep 350, 1
      Next I
   End Sub
            
Output example:

   "M": from 'Main' thread
   "C": from 'Child' thread

   MCMMCMMCMMCMMMCCCCCC
   'Child' thread finished
   				

      - Using ThreadCreate + ThreadDetach ..... (a global end-flag is added 
      at the end of the child thread):
   #include "fbthread.bi"

   Declare Sub thread (ByVal userdata As Any Ptr)

   Dim As Any Ptr threadID          '' declaration of an 'Any Ptr' thread-ID of the child thread
   Dim Shared As Boolean threadEnd  '' declaration of a global 'Boolean' thread-End flag for the child thread

   Print """M"": from 'Main' thread"
   Print """C"": from 'Child' thread"
   Print

   threadID = ThreadCreate(@thread)  '' creation of the child thread from the main thread
   ThreadDetach(threadID)            '' detaching the child thread

   For I As Integer = 1 To 10  '' 'For' loop of the main thread
      Print "M";
      Sleep 150, 1
   Next I

   While threadEnd = False  '' waiting for the thread-End flag = 'True' from the child thread
   Wend
   Print
   Print "'Child' thread finishing or finished"

   Sleep

   Sub thread (ByVal userdata As Any Ptr)  '' sub executed by the child thread
      For I As Integer = 1 To 10          '' 'For' loop of the child thread
         Print "C";
         Sleep 350, 1
      Next I
      threadEnd = True                    '' set the thrend-End flag to 'True'
   End Sub
            
Output example:

   "M": from 'Main' thread
   "C": from 'Child' thread

   MCMMCMMCMMCMMMCCCCCC
   'Child' thread finishing or finished
   				

   * A UDT for a multi-timer feature:
      - using internally a joinable thread (ThreadCreate ..... ThreadWait) 
      to sequence each timer,
      - and call-backing externally a detached thread (ThreadCreate + 
      ThreadDetach .....) as event for user.
   The user event being triggered by a detached-thread callback from the 
   timer loop, the requested time-out is only biased by the execution time 
   of ThreadCreate + ThreadDetach (small time about constant) and not by a 
   ThreadWait waiting-for:
   '    Only 4 member procedures in public access (the first 3 returning 'true' if success, 'false' else):
   '        - Function 'Set' to parametrize the considered timer (time-out in ms, pointer to user thread)
   '        - Function 'Start' to start the considered timer
   '        - Function 'Stop' to stop the considered timer (then, the considered timer may be re-Set and re-Start)
   '        - Property 'Counter' to get the occurrence number of the timer
   '    Plus an 'Any Ptr' in public access:
   '        - Pointer field 'userdata' to point to any user data structure (optional usage)
   '
   '    Remark:
   '        - Pointer to the considered timer instance is provided to the user thread procedure
   '          in order to be able to factorize the treatment per timers group,
   '          and to address the right user data structure if used (see example for usage).
   '
   '    In private access:
   '        - 4 internal variables (time-out value, pointer to user thread, handle to timer thread, counter of occurence)
   '        - Static timer thread

   #include "fbthread.bi"
   Type UDT_timer_thread
      Public:
         Declare Function Set (ByVal time_out As UInteger, _
                          ByVal timer_procedure As Sub(ByVal param As Any Ptr)) _
                          As Boolean
         Declare Function Start () As Boolean
         Declare Function Stop () As Boolean
         Declare Property Counter () As UInteger
         Dim As Any Ptr userdata
      Private:
         Dim As UInteger tempo
         Dim As Sub(ByVal param As Any Ptr) routine
         Dim As Any Ptr handle
         Dim As UInteger count
         Declare Static Sub thread (ByVal param As Any Ptr)
   End Type

   Function UDT_timer_thread.Set (ByVal time_out As UInteger, _
                          ByVal timer_procedure As Sub(ByVal param As Any Ptr)) _
                          As Boolean
      If timer_procedure > 0 And This.handle = 0 Then
         This.tempo = time_out
         This.routine = timer_procedure
         This.count = 0
         Function = True
      Else
         Function = False
      End If
   End Function

   Function UDT_timer_thread.Start () As Boolean
      If This.handle = 0 And This.routine > 0 Then
         This.handle = ThreadCreate(@UDT_timer_thread.thread, @This)
         Function = True
      Else
         Function = False
      End If
   End Function

   Function UDT_timer_thread.Stop () As Boolean
      If This.handle > 0 Then
         Dim p As Any Ptr = 0
         Swap p, This.handle
         ThreadWait(p)
         Function = True
      Else
         Function = False
      End If
   End Function

   Property UDT_timer_thread.Counter () As UInteger
      Return This.count
   End Property

   Static Sub UDT_timer_thread.thread (ByVal param As Any Ptr)
      Dim As UDT_timer_thread Ptr pu = param
      While pu->handle > 0
         Sleep pu->tempo, 1
         pu->count += 1
         If pu->routine > 0 Then
            Dim As Any Ptr p = ThreadCreate(Cast(Any Ptr, pu->routine), param)
            ThreadDetach(p)
         End If
      Wend
   End Sub

   '---------------------------------------------------------------------------------------------------

   Dim As UInteger tempo1 = 950
   Dim As UInteger tempo2 = 380
   Dim As UDT_timer_thread timer1
      timer1.userdata = New String("        callback from timer #1 (" & tempo1 & "ms)")
   Dim As UDT_timer_thread timer2
      timer2.userdata = New String("        callback from timer #2 (" & tempo2 & "ms)")

   Sub User_thread (ByVal param As Any Ptr)
      Dim As UDT_timer_thread Ptr pu = param
      Dim As String Ptr ps = pu->userdata
      Print *ps & ", occurrence: " & pu->Counter
   End Sub

   Print "Beginning of test"
   If timer1.Set(tempo1, @User_thread) Then
      Print "    timer #1 set OK"
      If timer1.Start Then
         Print "        timer #1 start OK"
      End If
   End If
   If timer2.Set(tempo2, @User_thread) Then
      Print "    timer #2 set OK"
      If timer2.Start Then
         Print "        timer #2 start OK"
      End If
   End If
   Print "    Then, any key to stop the timers"

   Sleep

   If timer1.stop Then
      Print "    timer #1 stop OK"
   End If
   If timer2.stop Then
      Print "    timer #2 stop OK"
   End If
   Sleep 500, 1
   Print "End of test"
   Delete Cast(String Ptr, timer1.userdata)
   Delete Cast(String Ptr, timer2.userdata)

   Sleep
         
Output example:

   Beginning of test
   	Timer #1 set OK
   		Timer #1 start OK
   	Timer #2 set OK
   		Timer #2 start OK
   	Then, Any key To Stop the timers
   		callback from Timer #2 (380ms), occurrence: 1
   		callback from Timer #2 (380ms), occurrence: 2
   		callback from Timer #1 (950ms), occurrence: 1
   		callback from Timer #2 (380ms), occurrence: 3
   		callback from Timer #2 (380ms), occurrence: 4
   		callback from Timer #1 (950ms), occurrence: 2
   		callback from Timer #2 (380ms), occurrence: 5
   		callback from Timer #2 (380ms), occurrence: 6
   		callback from Timer #2 (380ms), occurrence: 7
   		callback from Timer #1 (950ms), occurrence: 3
   		callback from Timer #2 (380ms), occurrence: 8
   		callback from Timer #2 (380ms), occurrence: 9
   		callback from Timer #1 (950ms), occurrence: 4
   		callback from Timer #2 (380ms), occurrence: 10
   		callback from Timer #2 (380ms), occurrence: 11
   		callback from Timer #2 (380ms), occurrence: 12
   	Timer #1 Stop OK
   		callback from Timer #1 (950ms), occurrence: 5
   	Timer #2 Stop OK
   		callback from Timer #2 (380ms), occurrence: 13
   End of test
   			

See also
   * ThreadCreate, ThreadCall
   * ThreadSelf
   * ThreadWait, ThreadDetach
   * Multi-Threading Overview
   * Mutual Exclusion
   * Conditional Variables
   * Critical Sections
   * Critical Sections FAQ



------------------------------------------------ ProPgMtMutualExclusion ----
Mutual Exclusion

The built-in procedures that deal with mutexes for Mutual Exclusion 
(create, lock/unlock, and destroy the mutexes).

Preamble:

   Mutual exclusion is the method of serializing access to shared 
   resources. If programmer do not want a thread to be accessing a shared 
   resource that is already in the process of being accessed by another 
   thread, he can use a mutex.

   Logically a mutex is a lock with only one key:
      - If a thread wishes to access a shared resource, the thread must 
      first gain the lock.
      - Once it has the lock it may do what it wants with the shared 
      resource without concerns of other threads accessing the shared 
      resource because other threads will have to wait.
      - Once the thread finishes using the shared resource, it unlocks the 
      mutex, which allows other threads to access the shared resource.

   A mutex is a lock that guarantees three things:
      - Atomicity - Locking a mutex is an atomic operation, meaning that 
      the operating system (or threads library) assures you that if you 
      locked a mutex, no other thread succeeded in locking this mutex at 
      the same time.
      - Singularity - If a thread managed to lock a mutex, it is assured 
      that no other thread will be able to lock the thread until the 
      original thread releases the lock.
      - Non-Busy Wait - If a thread attempts to lock a thread that was 
      locked by a second thread, the first thread will be suspended (and 
      will not consume any CPU resources) until the lock is freed by the 
      second thread. At this time, the first thread will wake up and 
      continue execution, having the mutex locked by it.

   This is a protocol that serializes access to a shared resource.
   Note that such a protocol must be enforced for resource a mutex is 
   protecting across all threads that may touch the resource being 
   protected (including the implicit main thread).

   Mutex capability can be fully used even with a detached thread (only its 
   handler is no longer accessible by its identifier).

Creating / Destructing a mutex
   MutexCreate creates a mutex, returning a handle identifier which is to 
   be referred to when destroying the mutex.
   Mutexes created with MutexCreate should be destroyed when no longer 
   needed or before the end of the program with MutexDestroy.

   Create
      - Syntax:
         Declare Function MutexCreate ( ) As Any Ptr
      - Usage:
         mutexid = MutexCreate
      - Return value:
         The Any Ptr handle (mutexid) to the mutex created, or the null 
         pointer (0) on failure.

   Destroy
      - Syntax:
         Declare Sub MutexDestroy ( ByVal mutexid As Any Ptr )
      - Usage:
         MutexDestroy( mutexid )
      - Parameter:
         mutexid
            The Any Ptr handle of the mutex to be destroyed.

   Description
      The call to MutexCreate must be executed before creating any thread 
      using it (and before its use in the thread that creates it).
      The call to MutexDestroy must be executed after any threads using the 
      mutex are no longer in use (and after its last use in the thread that 
      destroys it).

Locking / Unlocking a mutex
   MutexLock/MutexUnlock allow to lock/unlock a mutex by referring to its 
   handle identifier get at its creation.

   Lock
      - Syntax:
         Declare Sub MutexLock ( ByVal mutexid As Any Ptr )
      - Usage:
         MutexLock( mutexid )
      - Parameter:
         mutexid
            The Any Ptr handle of the mutex to be locked.

   Unlock
      - Syntax:
         Declare Sub MutexUnlock ( ByVal mutexid As Any Ptr )
      - Usage:
         MutexUnlock( mutexid )
      - Parameter:
         mutexid
            The Any Ptr handle of the mutex to be unlocked.

   Description
      The code between the lock and unlock calls to the mutex, is referred 
      to as a critical section.
      Minimizing time spent in the critical section allows for greater 
      concurrency because it potentially reduces the amount of time other 
      threads must wait to gain the lock.
      Therefore, it is important for a thread programmer to minimize 
      critical sections if possible. 

Pseudo-code section
   By applying all proper above rules:

   '  Principle of mutual exclusion between 2 threads
   '  (connecting lines join the sender(s) and receiver(s) impacted by each action occurring during the sequence)
   '
   '          Thread                                         Other Thread
   '      MUTEXLOCK(mutexID) <----------------.    .---> MUTEXLOCK(mutexID)
   '      Do_something_with_exclusion    .--- | ---'     Do_something_with_exclusion
   '      MUTEXUNLOCK(mutexID) ----------'    '--------- MUTEXUNLOCK(mutexID)
   		

Example
   The first example on the previous page (Threads) is modified so that 
   each thread no longer displays a single character ("M" or "C") but now a 
   sequence of three characters ("[M]" from the main thread, "(C)" for the 
   child thread).
   The tempo in each thread loop has been cut into three chunks to help 
   interleave the display between threads.

   * Using this example as is:
   Declare Sub thread (ByVal userdata As Any Ptr)

   Dim As Any Ptr threadID  '' declaration of an 'Any Ptr' thread-ID of the child thread

   Print """[M]"": from 'Main' thread"
   Print """(C)"": from 'Child' thread"
   Print

   threadID = ThreadCreate(@thread)  '' creation of the child thread from the main thread

   For I As Integer = 1 To 10  '' 'For' loop of the main thread
      Print "[";
      Sleep 50, 1
      Print "M";
      Sleep 50, 1
      Print "]";
      Sleep 50, 1
   Next I

   ThreadWait(threadID)  '' waiting for the child thread termination
   Print
   Print "'Child' thread finished"

   Sleep

   Sub thread (ByVal userdata As Any Ptr)  '' sub executed by the child thread
      For I As Integer = 1 To 10          '' 'For' loop of the child thread
         Print "(";
         Sleep 50, 1
         Print "C";
         Sleep 50, 1
         Print ")";
         Sleep 250, 1
      Next I
   End Sub
         
Output example:

   "[M]": from 'Main' thread
   "(C)": from 'Child' thread

   [(CM])[M][(MC])[M][(MC])[M][(MC])[M][M(]C)[M](C)(C)(C)(C)(C)
   'Child' thread finished
   			
The display highlights an interlace in the sequence (of three characters) 
outputted from each thread.
         In each thread, the code section displaying the three-character 
         sequence should not be interrupted by the display of the other 
         thread.
         These two sections of code must therefore be considered as 
         critical sections to be protected by a block [Mutexlock ... 
         Mutexunlock].

   * Using mutual exclusion with a mutex:
   '  Principle of mutual exclusion
   '      Main thread                      XOR            Child thread
   '  .....                                           .....
   '  MUTEXLOCK(mutID)                                MUTEXLOCK(mutID)
   '      Do_something_with_exclusion                     Do_something_with_exclusion
   '  MUTEXUNLOCK(mutID)                              MUTEXUNLOCK(mutID)
   '  .....                                           .....

   Declare Sub thread (ByVal userdata As Any Ptr)

   Dim As Any Ptr threadID      '' declaration of an 'Any Ptr' thread-ID of the child thread
   Dim Shared As Any Ptr mutID  '' declaration of a global 'Any Ptr' mutex-ID
      mutID = MutexCreate      '' creation of the mutex

   Print """[M]"": from 'Main' thread"
   Print """(C)"": from 'Child' thread"
   Print

   threadID = ThreadCreate(@thread)  '' creation of the child thread from the main thread

   For I As Integer = 1 To 10  '' 'For' loop of the main thread
      MutexLock(mutID)        '' set mutex locked at the beginning of the exclusive section
      Print "[";
      Sleep 50, 1
      Print "M";
      Sleep 50, 1
      Print "]";
      MutexUnlock(mutID)      '' set mutex unlocked at the end of the exclusive section
      Sleep 50, 1
   Next I

   ThreadWait(threadID)  '' waiting for the child thread termination
   Print
   Print "'Child' thread finished"

   MutexDestroy(mutID)  '' destruction of the mutex

   Sleep

   Sub thread (ByVal userdata As Any Ptr)  '' sub executed by the child thread
      For I As Integer = 1 To 10          '' 'For' loop of the child thread
         MutexLock(mutID)                '' set mutex locked at the beginning of the exclusive section
         Print "(";
         Sleep 50, 1
         Print "C";
         Sleep 50, 1
         Print ")";
         MutexUnlock(mutID)              '' set mutex unlocked at the end of the exclusive section
         Sleep 250, 1
      Next I
   End Sub
         
Output example:

   "[M]": from 'Main' thread
   "(C)": from 'Child' thread

   [M](C)[M][M](C)[M][M](C)[M][M](C)[M][M](C)[M](C)(C)(C)(C)(C)
   'Child' thread finished
   			
So, display becomes coherent compared to each three-character sequence.

See also
   * MutexCreate, MutexDestroy
   * MutexLock, MutexUnlock
   * Multi-Threading Overview
   * Threads
   * Conditional Variables
   * Critical Sections
   * Critical Sections FAQ



------------------------------------------- ProPgMtConditionalVariables ----
Conditional Variables

The built-in procedures that create, wait-for/signal, and destroy Conditiona
l Variables.

Preamble:

   A condition variable is a mechanism that allows threads to wait (without 
   wasting CPU cycles) for some even to occur.
   Several threads may wait on a condition variable, until some other 
   thread signals this condition variable (thus sending a notification).
   At this time, one of the threads waiting on this condition variable 
   wakes up, and can act on the event. It is possible to also wake up all 
   threads waiting on this condition variable by using a broadcast method 
   on this variable.

   A condition variable does not provide locking. Thus, a mutex must be 
   used along with the condition variable, to provide the necessary locking 
   when accessing this condition variable.

   Conditional variable capability (and also mutex capability) can be fully 
   used even with a detached thread (only its handler is no longer 
   accessible by its identifier).

Creating / Destructing a conditional variable
   CondCreate creates a condition variable, returning a handle identifier 
   which is to be referred to when destroying the condition variable.
   Condition variables created with CondCreate should be destroyed when no 
   longer needed or before the end of the program with CondDestroy (to 
   avoid leaking resources in the OS).

   Create
      - Syntax:
         Declare Function CondCreate ( ) As Any Ptr
      - Usage:
         conditionalid = CondCreate
      - Return value:
         The Any Ptr handle (conditionalid) to the conditional variable 
         created, or the null pointer (0) on failure.

   Destroy
      - Syntax:
         Declare Sub CondDestroy ( ByVal conditionalid As Any Ptr )
      - Usage:
         CondDestroy ( conditionalid )
      - Parameter:
         conditionalid
            The Any Ptr handle of the conditional variable to be destroyed.

   Description
      CondDestroy destroys a condition variable, freeing the resources it 
      might hold.
      No threads must be waiting on the condition variable on entrance to 
      CondDestroy.

Waiting-for/Signaling a conditional variable
   The condition variable mechanism allows threads to suspend execution and 
   relinquish the processor until some condition is true.

   CondWait stops execution of the current thread until some condition 
   becomes true.
   CondSignal allows to restart one thread waiting on the conditional,  
   while CondBroadcast allows to restart all threads waiting on the 
   conditional.

   Wait-for
      - Syntax:
         Declare Sub CondWait ( ByVal conditionalid As Any Ptr, ByVal 
         mutexid As Any Ptr )
      - Usage:
         CondWait ( conditionalid, mutexid )
      - Parameters:
         conditionalid
            The handle identifier of a conditional variable.
         mutexid
            The handle identifier of the mutex associated with this 
            conditional variable, which must be locked when testing the 
            condition and calling CondWait.

   Signal
      - Syntax:
            Declare Sub CondSignal ( ByVal conditionalid As Any Ptr )
         or
            Declare Sub CondBroadcast ( ByVal conditionalid As Any Ptr )
      - Usage:
            CondSignal ( conditionalid )
         or
            CondBroadcast ( conditionalid )
      - Parameter:
         conditionalid
            The Any Ptr handle of the conditional variable to be signaled.

   Description
      Once the conditional variable is created with CondCreate and the 
      threads are started, one of more of them (including the implicit main 
      thread executing main program) can be set in waiting for the 
      conditional state by CondWait.
      They will be stopped until another thread signals by CondSignal that 
      one among the waiting threads can restart.
      CondBroadcast can be used to restart all threads waiting for the 
      conditional.

      A condition variable must always be associated with a mutex to avoid 
      a race condition created by one thread preparing to wait and another 
      thread which may signal the condition before the first thread 
      actually waits on it resulting in a deadlock. The thread will be 
      perpetually waiting for a signal that is never sent. Any mutex can be 
      used, there is no explicit link between the mutex and the condition 
      variable.

      When calling CondWait, mutex should already be locked (using the same 
      mutex as one used with CondSignal or CondBroadcast).
      The detailed sequence is the following:
         - An atomic unlock of the mutex is applied before entering in 
         waiting on the conditional variable in order to release other 
         eventual threads using this mutex (this is why CondWait takes as 
         arguments both the mutex and condition variable).
         - The thread execution is suspended and does not consume any CPU 
         time until the condition variable is signaled.
         - When the condition variable becomes signaled, mutex is 
         atomically re-locked.
         - The thread execution can resume after the CondWait statement, 
         but is suspended because of the locked mutex owned by the 
         signal-caller.
         - So, the signal-caller is then responsible for unlocking mutex in 
         order that the called-thread completes the CondWait subroutine and 
         that execution after the CondWait call can then really resume.

      CondSignal restarts one thread waiting. It should be called after 
      mutex is locked (using the same mutex as one used with CondWait):
         - If no threads are waiting on the conditional, nothing happens 
         (the signal is lost forever).
         - if several are waiting, only one is restarted:
            . It might be that a condition variable that has several 
            threads waiting on it is signaled many times, and yet one of 
            the threads waiting on it never awakened.
            . This is because it is not known which of the waiting threads 
            is awakened when the variable is signaled.
            . It might be that the awakened thread quickly comes back to 
            waiting on the condition variables, and gets awakened again 
            when the variable is signaled again, and so on (no wake-up 
            priority based on history is assured).
            . It is up to the programmer to make sure this situation does 
            not occur if it implies bad behavior.

      When using CondBroadcast, this does not mean all threads are running 
      together:
         - Each of them tries to lock the mutex again before returning from 
         their wait function.
         - And thus they will start running one by one, each one locking 
         the mutex, doing their work, and freeing the mutex before the next 
         thread gets its chance to run.

      Note:
         - It is a good habit to use CondWait in a protected way against 
         eventual spurious wake-ups.
         - For that, CondWait is put within a loop for checking that a 
         Boolean predicate is indeed true (predicate set true by another 
         thread just before executing CondSignal or CondBroadcast) when the 
         thread has finished waiting:
               signal-caller:
                  predicate = True
                  Condsignal(conditionalid)
               waiting-called:
                  While predicate <> True
                     Condwait(conditionalid, mutexid)
                  Wend
                  predicate = False
         - The loop can terminate only when the predicate is true.
         - On the other hand, if the predicate is already true before the 
         thread reaches the loop, CondWait is downright skipped (allowing 
         to take into account a case of CondSignal or CondBroadcast that 
         would have been lost otherwise, because prematurely executed in a 
         second thread before the first thread is really waiting for this).

      Pseudo-codes for detailed coding by applying all proper above rules:
         * Pseudo-code sub-section for a thread:
               - Pseudo-code for the "waiting-for" critical sub-section 
               (with the links to/from critical section items of other 
               thread):

   '  Principle of mutual exclusion + waiting-for, for a thread sub-section
   '  (connecting lines join the sender(s) and receiver(s) impacted by each action occurring during the sequence)
   '
   '          Thread                                         Other Thread
   '      MUTEXLOCK(mutexID) <-------------------------- from ( atomic_mutex_unlock(mutexID) ) or MUTEXUNLOCK(mutexID)
   '      .......
   '      While booleanT <> True <---------------------- from booleanT = True
   '          ( atomic_mutex_unlock(mutexID) ) --------> to MUTEXLOCK(mutexID) or ( atomic_mutex_re-lock(mutexID) )
   '          CONDWAIT(conditionalID, mutexID) <-------- from CONDSIGNAL(conditionalID)
   '          ( atomic_mutex_re-lock(mutexID) ) <------- from ( atomic_mutex_unlock(mutexID) ) or MUTEXUNLOCK(mutexID)
   '      Wend
   '      booleanT = False
   '      .......
   '      MUTEXUNLOCK(mutexID) ------------------------> to MUTEXLOCK(mutexID) or ( atomic_mutex_re-lock(mutexID) )
   						

               - Pseudo-code for the "signaling" critical sub-section (with 
               the links to/from the critical section items of other 
               thread):

   '  Principle of mutual exclusion + signaling, for a thread sub-section
   '  (connecting lines join the sender(s) and receiver(s) impacted by each action occurring during the sequence)
   '
   '          Thread                              Other Thread
   '      MUTEXLOCK(mutexID) <--------------- from ( atomic_mutex_unlock(mutexID) ) or MUTEXUNLOCK(mutexID)
   '      .......
   '      booleanOT = True -----------------> to While booleanOT <> True
   '      CONDSIGNAL(conditionalID) --------> to CONDWAIT(conditionalID, mutexID)
   '      .......
   '      MUTEXUNLOCK(mutexID) -------------> to MUTEXLOCK(mutexID) or ( atomic_mutex_re-lock(mutexID) )
   						

         * Pseudo-code section for a thread:
               - Pseudo-code for the "signaling, then waiting-for" critical 
               section (with the links to/from the critical section items 
               of other thread):

   '  Principle (1) of mutual exclusion + mutual synchronization, for a thread section
   '  (connecting lines join the sender(s) and receiver(s) impacted by each action occurring during the sequence)
   '
   '          Thread                                        Other Thread
   '      MUTEXLOCK(mutexID) <------------------------- from ( atomic_mutex_unlock(mutexID) ) or MUTEXUNLOCK(mutexID)
   '      Do_something_1_with_exclusion
   '      booleanOT = True ---------------------------> to While booleanOT <> True
   '      CONDSIGNAL(conditionalID) ------------------> to CONDWAIT(conditionalID, mutexID)
   '      While booleanT <> True <--------------------- from booleanT = True
   '          ( atomic_mutex_unlock(mutexID) ) -------> to MUTEXLOCK(mutexID) or ( atomic_mutex_re-lock(mutexID) )
   '          CONDWAIT(conditionalID, mutexID) <------- from CONDSIGNAL(conditionalID)
   '          ( atomic_mutex_re-lock(mutexID) ) <------ from ( atomic_mutex_unlock(mutexID) ) or MUTEXUNLOCK(mutexID)
   '      Wend
   '      booleanT = False
   '      Do_something_2_with_exclusion
   '      MUTEXUNLOCK(mutexID) -----------------------> to MUTEXLOCK(mutexID) or ( atomic_mutex_re-lock(mutexID) )
   						

               - Pseudo-code for the "waiting-for, then signaling" critical 
               section (with the links to/from  critical section items of 
               other thread):

   '  Principle (2) of mutual exclusion + mutual synchronization, for a thread section
   '  (connecting lines join the sender(s) and receiver(s) impacted by each action occurring during the sequence)
   '
   '          Thread                                         Other Thread
   '      MUTEXLOCK(mutexID) <-------------------------- from ( atomic_mutex_unlock(mutexID) ) or MUTEXUNLOCK(mutexID)
   '      Do_something_1_with_exclusion
   '      While booleanT <> True <---------------------- from booleanT = True
   '          ( atomic_mutex_unlock(mutexID) ) --------> to MUTEXLOCK(mutexID) or ( atomic_mutex_re-lock(mutexID) )
   '          CONDWAIT(conditionalID, mutexID) <-------- from CONDSIGNAL(conditionalID)
   '          ( atomic_mutex_re-lock(mutexID) ) <------- from ( atomic_mutex_unlock(mutexID) ) or MUTEXUNLOCK(mutexID)
   '      Wend
   '      booleanT = False
   '      Do_something_2_with_exclusion
   '      booleanOT = True ----------------------------> to While booleanOT <> True
   '      CONDSIGNAL(conditionalID) -------------------> to CONDWAIT(conditionalID, mutexID)
   '      MUTEXUNLOCK(mutexID) ------------------------> to MUTEXLOCK(mutexID) or ( atomic_mutex_re-lock(mutexID) )
   						

         * Pseudo-code section example for each of 2 threads:
               - Pseudo-code for the "signaling, then waiting-for" critical 
               section of a main thread and for "waiting-for, then 
               signaling" critical section of a child thread (with the 
               links to/from critical section items of both threads):

   '  Principle (example) of mutual exclusion + mutual synchronization sections, between 2 threads,
   '  using the principle (1) for the main thread, and the principle (2) for the child thread
   '  (connecting lines join the sender(s) and receiver(s) impacted by each action occurring during the sequence)
   '
   '          Main Thread                                                                          Child Thread
   '      MUTEXLOCK(mutexID) <-----------------------------.     .-------------.-------------> MUTEXLOCK(mutexID)
   '      Do_something_1_with_exclusion                    |     |             |               Do_something_1_with_exclusion
   '      boolC = True ----------------------------------- | --- | ----------- | ------------> While boolC <> True
   '      CONDSIGNAL(conditionalID) ---------------------- | --- | ----------- | ---.    .-------- ( atomic_mutex_unlock(mutexID) )
   '      While boolM <> True <--------------------------- | --- | ---------.  |    '--- | ------> CONDWAIT(conditionalID, mutexID)
   '          ( atomic_mutex_unlock(mutexID) ) ------.     |     |          |  '-------- | ------> ( atomic_mutex_re-lock(mutexID) )
   '          CONDWAIT(conditionalID, mutexID) <---- | --- | --- | ------.  |            |     Wend
   '          ( atomic_mutex_re-lock(mutexID) ) <--- | ----'---- | ---.  |  |            |     boolC = False
   '      Wend                                       |           |    |  |  |            |     Do_something_2_with_exclusion
   '      boolM = False                              |           |    |  |  '----------- | --- boolM = True
   '      Do_something_2_with_exclusion              |           |    |  '-------------- | --- CONDSIGNAL(conditionalID)
   '      MUTEXUNLOCK(mutexID) ----------------------'-----------'    '------------------'---- MUTEXUNLOCK(mutexID)
   						

Example
   The second example on the previous page (Mutual Exclusion) is modified 
   by using a conditional variable to exhibit a synchronization example.
   So, the two sections of code, previously protected by a mutual exclusion 
   block [Mutexlock ... Mutexunlock], are now synchronized in order that 
   each thread displays one after the other its character sequence ("[M]" 
   or "(C)").

   In this example, the two threads critical sections have their 
   sub-sections in an reverse order:
      - main thread critical section: at first signaling, then waiting for,
      - child thread critical section: at first waiting for, then 
      signaling.
   Therefore the main thread will always be the first to display its 
   sequence:

   '  Principle of mutual exclusion + mutual synchronization between 2 threads with loop
   '  (connecting lines join the sender(s) and receiver(s) impacted by each action occurring during the sequence)
   '
   '          Main Thread                                                                  Child Thread
   '  .....                                                                          .....
   '  Loop                                                                           Loop
   '      MUTEXLOCK(mutID) <-----------------------------.     .-------------.---------> MUTEXLOCK(mutID)
   '      Do_something_with_exclusion              .---- | --- | ----------- | --------> While boolC <> True
   '      boolC = True ----------------------------'     |     |             |     .-------- ( atomic_mutex_unlock(mutID) )
   '      CONDSIGNAL(condID) --------------------------- | --- | ----------- | --- | ------> CONDWAIT(condID, mutID)
   '      While boolM <> True <------------------------- | --- | ---------.  '---- | ------> ( atomic_mutex_re-lock(mutID) )
   '          ( atomic_mutex_unlock(mutID) ) ------.     |     |          |        |     Wend
   '          CONDWAIT(condID, mutID) <----------- | --- | --- | ------.  |        |     boolC = False
   '          ( atomic_mutex_re-lock(mutID) ) <--- | ----'---- | ---.  |  |        |     Do_something_with_exclusion
   '      Wend                                     |           |    |  |  '------- | --- boolM = True
   '      boolM = False                            |           |    |  '---------- | --- CONDSIGNAL(condID)
   '      MUTEXUNLOCK(mutID) ----------------------'-----------'    '--------------'---- MUTEXUNLOCK(mutID)
   '  End Loop                                                                       End Loop
   '  .....                                                                          .....
   		

   Declare Sub thread (ByVal userdata As Any Ptr)

   Dim As Any Ptr threadID             '' declaration of an 'Any Ptr' thread-ID of the child thread
   Dim Shared As Any Ptr mutID         '' declaration of a global 'Any Ptr' mutex-ID
      mutID = MutexCreate             '' creation of the mutex
   Dim Shared As Boolean boolM, boolC  '' declaration of 2 global 'Boolean' boolM and boolC as predicates
   Dim Shared As Any Ptr condID        '' declaration of a global 'Any Ptr' conditional-ID
      condID = CondCreate             '' creation of the conditional

   Print """[M]"": from 'Main' thread"
   Print """(C)"": from 'Child' thread"
   Print

   threadID = ThreadCreate(@thread)  '' creation of the child thread from the main thread

   For I As Integer = 1 To 10       '' 'For' loop of the main thread
      MutexLock(mutID)             '' set mutex locked at the beginning of the exclusive section
      Print "[";
      Sleep 50, 1
      Print "M";
      Sleep 50, 1
      Print "]";
      boolC = True                 '' set to 'True' the predicate for the child thread
      CondSignal(condID)           '' signal to the child thread
      While boolM <> True          '' test predicate from the child thread
         CondWait(condID, mutID)  '' wait for signal from the child thread
      Wend
      boolM = False                '' reset the predicate from the child thread
      MutexUnlock(mutID)           '' set mutex unlocked at the end of the exclusive section
      Sleep 50, 1
   Next I

   ThreadWait(threadID)  '' waiting for the child thread termination
   Print
   Print "'Child' thread finished"

   MutexDestroy(mutID)  '' destruction of the mutex
   CondDestroy(condID)  '' destruction of the conditional

   Sleep

   Sub thread (ByVal userdata As Any Ptr)  '' sub executed by the child thread
      For I As Integer = 1 To 10          '' 'For' loop of the child thread
         MutexLock(mutID)                '' set mutex locked at the beginning of the exclusive section
         While boolC <> True             '' test predicate from the main thread
            CondWait(condID, mutID)     '' wait for signal from the main thread
         Wend
         boolC = False                   '' reset the predicate from the main thread
         Print "(";
         Sleep 50, 1
         Print "C";
         Sleep 50, 1
         Print ")";
         boolM = True                    '' set to 'True' the predicate for the main thread
         CondSignal(condID)              '' signal to the child thread
         MutexUnlock(mutID)              '' set mutex unlocked at the end of the exclusive section
         Sleep 250, 1
      Next I
   End Sub
         
Output:

   "[M]": from 'Main' thread
   "(C)": from 'Child' thread

   [M](C)[M](C)[M](C)[M](C)[M](C)[M](C)[M](C)[M](C)[M](C)[M](C)
   'Child' thread finished
   			

See also
   * CondCreate, CondDestroy,
   * CondWait, CondSignal, CondBroadcast
   * Multi-Threading Overview
   * Threads
   * Mutual Exclusion
   * Critical Sections
   * Critical Sections FAQ



----------------------------------------------- ProPgMtCriticalSections ----
Critical Sections

The proper use of the built-in procedures in Critical Sections for handling 
the concurrency with other threads.

Preamble:

   A critical section is a part of a multi-threading program that has to be 
   executed as atomic actions (no concurrence with other threads executing 
   similar actions):
      - It is a piece of a program that requires mutual exclusion of 
      access.
      - Typically, the critical section accesses a shared resource, such as 
      a data structure, a peripheral device, or a network connection, that 
      does not allow multiple concurrent accesses.

   When a program starts up, one thread already begins running immediately. 
   This is usually called the "main" thread of the program, because it is 
   the one that is executed when a program begins:
      - It is the thread from which user may spawn other "child" threads 
      (which in turn may spawn other "sub-child" threads).
      - Often, it must be the last thread to finish execution because it 
      performs various shutdown actions (as a "child" thread must also do 
      so with respect to its eventual "sub-child" threads spawned).
      - But other than that, it can also compete (with its own critical 
      sections) with all other threads explicitly spawned by user.

Basic algorithms
   Using the built-in procedures provided by FreeBASIC, the method to 
   ensure exclusive use of a critical section may be designed in a 
   algorithm either asynchronous or synchronous, which applies to the 
   threads.

   * Basic algorithm for an asynchronous method using a mutex:
         By getting the mutex locking, the thread can take the exclusive 
         control to access the shared resource.
         When shared resource access is ended, the thread unlocks the 
         mutex.

         Algorithm:

   '   Mutexlock
   '   |
   '   Critical section of code
   '   |
   '   Mutexunlock
   				

   * Basic algorithm for a synchronous method using a condwait then a 
     condsignal/condbroadcast (and mutex):
         The thread waits for a Boolean predicate is indeed true and also a 
         condition signal (condwait) before executing its critical section.
         When shared resource access is ended, the thread sets another 
         Boolean predicate then sends a condition signal to other thread(s) 
         (condsignal or condbroadcast).

         Algorithm:

   '   Mutexlock
   '   |
   '   While my_predicate <> True
   '   |   Condwait
   '   Wend
   '   my_predicate = False
   '   |
   '   Critical section of code
   '   |
   '   other_predicate = True
   '   Condsignal or Condbroadcast
   '   |
   '   Mutexunlock
   				

         Similar algorithm with waiting-for, then signaling are put in 
         reverse order:

   '   Mutexlock
   '   |
   '   Critical section of code
   '   |
   '   other_predicate = True
   '   Condsignal or Condbroadcast
   '   |
   '   While my_predicate <> True
   '   |   Condwait
   '   Wend
   '   my_predicate = False
   '   |
   '   Mutexunlock
   				

Examples
   In the two following examples, the shared resource is the input/output 
   display device:
      - Print its counter for each of 6 user threads (and read the flag 
      'quit').
      - Catching a key-press (any one) for the main thread (and if yes, set 
      the flag 'quit' to 'true').

   The outputting procedure ('Sub Counter()') has voluntarily a tempo 
   between cursor positioning and printing, and also a repositioning of 
   text cursor at middle of line before ending, in order to thoroughly 
   check that there is no overlap between the critical sections executions 
   (at opposite, one can see the result by removing some code dedicated to 
   mutual exclusion processing).
   A different tempo value is set at the end of each thread loop (from 
   smaller to bigger).
   A structure (UDT) groups all variables necessary to the threads. A 
   pointer to each UDT instance is passed to each thread at its creation 
   phase (with threadcreate).

   * Asynchronous method example using one mutex for all threads:

   ' User thread algorithm (same principle for the main thread):
   '
   '   Do
   '   |
   '   |   Mutexlock
   '   |   |
   '   |   Critical section of code
   '   |   |
   '   |   Mutexunlock
   '   |   |
   '   |   Sleep my_tempo, 1
   '   |
   '   Loop Until quit = true
   '
   ' There is no any advantage or disadvantage between threads for running their critical sections.
   		

   Type UDT
      Dim As Integer number
      Dim As Integer tempo
      Dim As Any Ptr pThread
      Dim As ULongInt count
      Static As Any Ptr pMutex
      Static As Integer numberMax
      Static As Integer quit
   End Type
   Dim As Any Ptr UDT.pMutex
   Dim As Integer UDT.numberMax
   Dim As Integer UDT.quit

   Sub Counter (ByVal pt As UDT Ptr)
      With *pt
         Locate .number, .number, 0
         Sleep 5, 1
         .count += 1
         Print .count;
         Locate .number, 30 + .number, 0
      End With
   End Sub

   Sub Thread (ByVal p As Any Ptr)
      Dim As Integer myquit
      Dim As UDT Ptr pUDT = p
      With *pUDT
         Do
            MutexLock(.pMutex)
            Counter(pUDT)
            myquit = .quit
            MutexUnlock(.pMutex)
            Sleep .tempo, 1
         Loop Until myquit = 1
      End With
   End Sub

   UDT.numberMax = 6
   Dim As UDT u(0 To UDT.numberMax)
   For I As Integer = 0 To UDT.numberMax
      u(I).number = i
      u(I).tempo = 100 + 15 * I - 95 * Sgn(I)
   Next I
   UDT.pMutex = MutexCreate

   Dim As Single t = Timer
   For I As Integer = 1 To UDT.numberMax
      u(I).pThread = ThreadCreate(@Thread, @u(I))
   Next I

   Dim As String s
   Do
      MutexLock(UDT.pMutex)
      s = Inkey
      If s <> "" Then
         UDT.quit = 1
      End If
      MutexUnlock(UDT.pMutex)
      Sleep u(0).tempo, 1
   Loop Until s <> ""

   For I As Integer = 1 To UDT.numberMax
      ThreadWait(u(I).pThread)
   Next I
   t = Timer - t

   MutexDestroy(UDT.pMutex)
   Dim As ULongInt c
   For I As Integer = 1 To UDT.numberMax
      c += u(I).count
   Next I
   Locate UDT.numberMax+2, 1
   Print CULngInt(c / t) & " increments per second"

   Sleep
         
Output example:

   '   159
   '    127
   '     105
   '      85
   '       78
   '        71
   '
   '   63 increments per second
   			
Different result values because asynchronous counting (decreasing count 
values because increasing tempo values).

   * Synchronous method example using a condwait then a condbroadcast (and 
     one mutex) for all threads:

   ' User thread algorithm (same principle for the main thread):
   '
   '   Do
   '   |
   '   |   Mutexlock
   '   |   |
   '   |   While thread_priority_number <> my_number
   '   |   |   Condwait
   '   |   Wend
   '   |   |
   '   |   Critical section of code
   '   |   |
   '   |   thread_priority_number = next thread_priority_number
   '   |   Condbroadcast
   '   |   |
   '   |   Mutexunlock
   '   |   |
   '   |   Sleep my_tempo, 1
   '   |
   '   Loop Until quit = true
   '
   ' The critical sections of the threads are run synchronously one after the other, with a predefined order.
   		

   Type UDT
      Dim As Integer number
      Dim As Integer tempo
      Dim As Any Ptr pThread
      Dim As ULongInt count
      Static As Integer threadPriorityNumber
      Static As Any Ptr pMutex
      Static As Any Ptr pCond
      Static As Integer numberMax
      Static As Integer quit
   End Type
   Dim As Integer UDT.threadPriorityNumber
   Dim As Any Ptr UDT.pMutex
   Dim As Any Ptr UDT.pCond
   Dim As Integer UDT.numberMax
   Dim As Integer UDT.quit

   Sub Counter (ByVal pt As UDT Ptr)
      With *pt
         Locate .number, .number, 0
         Sleep 5, 1
         .count += 1
         Print .count;
         Locate .number, 30 + .number, 0
      End With
   End Sub

   Sub Thread (ByVal p As Any Ptr)
      Dim As Integer myquit
      Dim As UDT Ptr pUDT = p
      With *pUDT
         Do
            MutexLock(.pMutex)
            While .threadPriorityNumber <> .number  '' synchronous condwait for expected condition
               CondWait(.pCond, .pMutex)
            Wend
            Counter(pUDT)
            myquit = .quit
            .threadPriorityNumber = (.threadPriorityNumber + 1) Mod (.numberMax + 1)
            CondBroadcast(.pCond)
            MutexUnlock(.pMutex)
            Sleep .tempo, 1
         Loop Until myquit = 1
      End With
   End Sub

   UDT.numberMax = 6
   Dim As UDT u(0 To UDT.numberMax)
   For I As Integer = 0 To UDT.numberMax
      u(I).number = i
      u(I).tempo = 100 + 15 * I - 95 * Sgn(I)
   Next I
   UDT.pMutex = MutexCreate
   UDT.PCond = CondCreate

   Dim As Single t = Timer
   For I As Integer = 1 To UDT.numberMax
      u(I).pThread = ThreadCreate(@Thread, @u(I))
   Next I

   Dim As String s
   Do
      MutexLock(UDT.pMutex)
      While UDT.threadPriorityNumber <> u(0).number
         CondWait(UDT.pCond, UDT.pMutex)
      Wend
      s = Inkey
      If s <> "" Then
         UDT.quit = 1
      End If
      UDT.threadPriorityNumber = (UDT.threadPriorityNumber + 1) Mod (UDT.numberMax + 1)
      CondBroadcast(UDT.pCond)
      MutexUnlock(UDT.pMutex)
      Sleep u(0).tempo, 1
   Loop Until s <> ""

   For I As Integer = 1 To UDT.numberMax
      ThreadWait(u(I).pThread)
   Next I
   t = Timer - t

   MutexDestroy(UDT.pMutex)
   CondDestroy(UDT.pCond)
   Dim As ULongInt c
   For I As Integer = 1 To UDT.numberMax
      c += u(I).count
   Next I
   Locate UDT.numberMax+2, 1
   Print CULngInt(c / t) & " increments per second"

   Sleep
         
Output example:

   '   116
   '    116
   '     116
   '      116
   '       116
   '        116
   '
   '   51 increments per second
   			
Same result values because synchronous counting (despite of increasing 
tempo values).

   * Weird synchronous algorithm using a mutex for each thread, by self 
     lock and mutual unlock:
      - When one thread has run its critical section, it unlocks the mutex 
      of the next thread and attempts to re-obtain its own mutex.
      - At initialization all mutexes are locked, except the mutex of the 
      main thread.

   ' User thread (#N) algorithm (same principle for the main thread):
   '
   '   Do
   '   |
   '   |   Mutexlock(own thread mutex (#N))
   '   |   |
   '   |   Critical section of code
   '   |   |
   '   |   Mutexunlock(next thread mutex (#N+1))
   '   |   |
   '   |   Sleep tempo, 1
   '   |
   '   Loop Until quit = 1
   		

   Type UDT
      Dim As Integer number
      Dim As Integer tempo
      Dim As Any Ptr pThread
      Dim As ULongInt count
      Static As Any Ptr pMutex(Any)
      Static As Integer numberMax
      Static As Integer quit
   End Type
   Dim As Any Ptr UDT.pMutex(Any)
   Dim As Integer UDT.numberMax
   Dim As Integer UDT.quit

   Sub Counter (ByVal pt As UDT Ptr)
      With *pt
         Locate .number, .number, 0
         Sleep 5, 1
         .count += 1
         Print .count;
         Locate .number, 30 + .number, 0
      End With
   End Sub

   Sub Thread (ByVal p As Any Ptr)
      Dim As Integer quit
      Dim As UDT Ptr pUDT = p
      With *pUDT
         Do
            MutexLock(.pMutex(.number))
            Counter(pUDT)
            quit = .quit
            MutexUnlock(.pMutex((.number + 1) Mod (UDT.numberMax + 1)))
            Sleep .tempo, 1
         Loop Until quit = 1
      End With
   End Sub

   UDT.numberMax = 6
   ReDim UDT.pMutex(UDT.numberMax)
   Dim As UDT u(0 To UDT.numberMax)
   For I As Integer = 0 To UDT.numberMax
      u(I).number = i
      u(I).tempo = 100 + 15 * I - 95 * Sgn(I)
      UDT.pMutex(I) = MutexCreate
      MutexLock(UDT.pMutex(I))
   Next I
   MutexUnlock(UDT.pMutex(u(0).number))

   Dim As Single t = Timer
   For I As Integer = 1 To UDT.numberMax
      u(I).pThread = ThreadCreate(@Thread, @u(I))
   Next I

   Dim As String s
   Do
      MutexLock(UDT.pMutex(u(0).number))
         s = Inkey
         If s <> "" Then
            UDT.quit = 1
         End If
      MutexUnlock(UDT.pMutex((u(0).number + 1) Mod (UDT.numberMax + 1)))
      Sleep u(0).tempo, 1
   Loop Until s <> ""

   For I As Integer = 1 To UDT.numberMax
      ThreadWait(u(I).pThread)
   Next I
   t = Timer - t

   For I As Integer = 0 To UDT.numberMax
      MutexDestroy(UDT.pMutex(I))
   Next I
   Dim As ULongInt c
   For I As Integer = 1 To UDT.numberMax
      c += u(I).count
   Next I
   Locate UDT.numberMax+2, 1
   Print CULngInt(c / t) & " increments per second"

   Sleep
         
Output example:

   '   102
   '    102
   '     102
   '      102
   '       102
   '        102
   '
   '   51 increments per second
   			
Same result values because synchronous counting (despite of increasing 
tempo values).

See also
   * Multi-Threading Overview
   * Threads
   * Mutual Exclusion
   * Conditional Variables
   * Critical Sections FAQ
   * Emulate a TLS (Thread Local Storage) and a TP (Thread Pooling) feature



-------------------------------------------- ProPgMtCriticalSectionsFAQ ----
Critical Sections FAQ

The "Critical Sections" related questions in multi-threading.

'Critical sections' related questions
1. When is it not mandatory to protect by a mutex one shared variable between several threads?
2. What is the chronology of code execution of 2 critical sections (with a mutex locking and a conditional variable signaling) that compete between 2 threads?
3. What happens if calling 'Condsignal()' or 'Condbroadcast()' without mutex locked?
4. Why is it mandatory to put 'Condwait' within a 'While...Wend' loop for checking a Boolean predicate (set by other thread before activate 'Condsignal' or 'Condbroadcast', and reset after the 'Wend')?
4.1. Is 'Condwait' (and 'Condsignal' or 'Condbroadcast') still useful when there is already a 'While' loop for checking a Boolean predicate set by other thread?
5. How to implement a user input-line function fully thread-safe?
6. How to use 'Screenlock' with multi-threading?
7. How to use 'video paging (double buffering or page flipping)' with multi-threading?
8. How to use the FB runtime library for multi-threaded applications (gfxlib2) with multi-threading?
9. How to use console statements and keyboard inputs with multi-threading?
10. Is it better to take precautions when using the keyword 'Sleep' in threads?
11. Can all tools to handle multi-threading be encapsulated in a base Class (that the user extends with a derived Type for his own implementing)?
12. What is the execution delay of the code of a thread after the thread is created by 'ThreadCreate'?
13. What is the synchronization latency when synchronizing threads either by mutual exclusions or by conditional variables?
14. What happens when multiple threads are waiting on the same condition variable?
15. How to optimize sequencing of successive user tasks executed by threading?
16. Why is multi-threading performance penalized by many shared memory accesses (even more in writing mode)?
17. Why is multi-threading performance heavily penalized by many manipulation of var-len strings and var-len arrays?

'Critical sections' related questions

1. When is it not mandatory to protect by a mutex one shared variable 
between several threads?
      When accessing to shared variables between several threads, all their 
      accesses must be generally put inside blocks Mutexlock...Mutexunlock, 
      in all threads:
         - When the shared variable is only one simple predefined numeric 
         type of size <= sizeof(integer) (only one assembler instruction 
         for access), the mutex use may be not mandatory.
         - But if this is for example one shared variable LongInt with a 
         win32 compilation, it is advised here to use a mutex (otherwise 
         the reading phase by a thread may be interlaced with the writing 
         phase of another thread).

      That is because to access a variable in memory (for reading or for 
      writing), a processor uses its internal registers.
      A N-bit processor has N-bit registers but none greater:
         - So one only assembler instruction allows it to access a N-bit 
         variable in memory.
         - At opposite, to access a 2N-bit variable, it must use 2 
         assembler instructions.
         - If between these two assembler instructions (for writing), 
         another thread accesses this same variable (for reading), the got 
         value may be incoherent (N-bit highest and N-bit lowest incoherent 
         together).

      This behavior can be checked with a graphic program using two threads 
      and a shared LongInt (64-bit) without mutex:
         - by compiling in 32-bit, many read values are incoherent.
         - by compiling in 64-bit, no read value is incoherent.

      Compile the below test program:
         - in 32-bit => Many erroneous points not on the circle but 
         anywhere in the square containing the circle. If you uncomment the 
         four lines 37/39/58/60 to activate the mutex, then all the got 
         points are now on the circle only.
         - in 64-bit => All points are valid, on the circle only, even if 
         the mutex is not activated.
   '   - The "user-defined thread" computes the points coordinates on a circle,
   '     and write those in a LongInt (32-bit & 32-bit = 64-bit)
   '   - The "main thread" plots the points from the LongInt value.
   '
   '   Behavior:
   '      - The first point must be pre-determined.
   '      - Nothing prevents that a same calculated point could be plotted several times
   '      (depends on execution times of the loops between main thread and user thread).
   '      - Nothing prevents that a calculated point could be not plotted
   '      (same remark on the loop times).
   '
   '   Remark:
   '      Voluntarily, there is no Sleep in the loop of each thread (normally strongly discouraged),
   '      but this is just in this special case to amplify the behavior effects to observe.

   Union Point2D
      Dim As LongInt xy
      Type
         Dim As Long y
         Dim As Long x
      End Type
   End Union

   Dim As Any Ptr handle
   Dim Shared As Any Ptr mutex
   Dim Shared As Integer quit

   Sub Thread (ByVal param As Any Ptr)
      Const pi As Single = 4 * Atn(1)
      Dim As Point2D Ptr p = param
      Do
         Dim As Point2D P2D0
         Dim As Single teta = 2 * pi * Rnd
         P2D0.x = 320 + 200 * Cos(teta)
         P2D0.y = 240 + 200 * Sin(teta)
   '        Mutexlock(mutex)
         p->xy = P2D0.xy
   '        Mutexunlock(mutex)
   '        Sleep 5, 1
      Loop Until quit = 1
   End Sub

   Screen 12

   Dim As Point2D P2D
   P2D.x = 520
   P2D.y = 240

   mutex = MutexCreate
   handle = ThreadCreate(@Thread, @P2D)

   Dim As Integer c

   Do
      Dim As Point2D P2D0
   '    Mutexlock(mutex)
      P2D0.xy = P2D.xy
   '    Mutexunlock(mutex)
      PSet (P2D0.x, P2D0.y), c
      c = (c Mod 15) + 1
   '    Sleep 5, 1
   Loop Until Inkey <> ""
    
   quit = 1
   ThreadWait(handle)
   MutexDestroy(mutex)
            

Back to top

2. What is the chronology of code execution of 2 critical sections (with a 
mutex locking and a conditional variable signaling) that compete between 2 
threads?
      Chronology for one thread signaling which occurs:
         a) while another thread is waiting (within a While loop on 
         predicate),
         b) before another thread is waiting (within a While loop on 
         predicate).
   #define while_loop_on_predicate

   Dim As Any Ptr handle
   Dim Shared As Any Ptr mutex
   Dim Shared As Any Ptr cond
   Dim As Integer sleep0
   Dim As Integer sleep1
   #ifdef while_loop_on_predicate
   Dim Shared As Integer ready
   #endif

   Sub Thread1 (ByVal param As Any Ptr)
      Sleep *Cast(Integer Ptr, param), 1
      MutexLock(mutex)
      Color 11 : Print "        Thread#1 locks the mutex"
      Color 11 : Print "        Thread#1 executes code with exclusion"
      #ifdef while_loop_on_predicate
      ready = 1
      #endif
      Color 11 : Print "        Thread#1 is signaling"
      CondSignal(cond)
      Color 11 : Print "        Thread#1 executes post-code with exclusion"
      Color 11 : Print "        Thread#1 unlocks the mutex"
      MutexUnlock(mutex)
   End Sub

   Sub Thread0 (ByVal param As Any Ptr)
      Sleep *Cast(Integer Ptr, param), 1
      MutexLock(mutex)
      Color 10 : Print "    Thread#0 locks the mutex"
      Color 10 : Print "    Thread#0 executes pre-code with exclusion"
      #ifdef while_loop_on_predicate
      While ready <> 1
      #endif
         Color 10 : Print "    Thread#0 is waiting"
         CondWait(cond, mutex)
         Color 10 : Print "    Thread#0 is waked"
      #ifdef while_loop_on_predicate
      Wend
      #endif
      Color 10 : Print "    Thread#0 executes code with exclusion"
      #ifdef while_loop_on_predicate
      ready = 0
      #endif
      Color 10 : Print "    Thread#0 unlocks the mutex"
      MutexUnlock(mutex)
   End Sub

   mutex = MutexCreate
   cond = CondCreate

   sleep0 = 0
   sleep1 = 1000
   Color 7 : Print "Chronology for Thread#1 signaling while Thread#0 is waiting:"
   handle = ThreadCreate(@Thread1, @sleep1)
   Thread0(@sleep0)
   ThreadWait(handle)
   Color 7 : Print "Thread#1 finished": Print
   Sleep 1000, 1

   sleep0 = 1000
   sleep1 = 0
   Color 7 : Print "Chronology for Thread#1 signaling before Thread#0 is waiting:"
   handle = ThreadCreate(@Thread1, @sleep1)
   Thread0(@sleep0)
   ThreadWait(handle)
   Color 7 : Print "Thread#1 finished": Print

   MutexDestroy(mutex)
   CondDestroy(cond)
   Sleep
            

         Output part a - Chronology for Thread#1 signaling while Thread#0 
         is waiting:

   Chronology For Thread#1 signaling While Thread#0 Is waiting:
   	Thread#0 locks the mutex
   	Thread#0 executes pre-code With exclusion
   	Thread#0 Is waiting
   		Thread#1 locks the mutex
   		Thread#1 executes code With exclusion
   		Thread#1 Is signaling
   		Thread#1 executes post-code With exclusion
   		Thread#1 unlocks the mutex
   	Thread#0 Is waked
   	Thread#0 executes code With exclusion
   	Thread#0 unlocks the mutex
   Thread#1 finished
   				

         Output part b - Chronology for Thread#1 signaling before Thread#0 
         is waiting:

   Chronology For Thread#1 signaling before Thread#0 Is waiting:
   		Thread#1 locks the mutex
   		Thread#1 executes code With exclusion
   		Thread#1 Is signaling
   		Thread#1 executes post-code With exclusion
   		Thread#1 unlocks the mutex
   	Thread#0 locks the mutex
   	Thread#0 executes pre-code With exclusion
   	Thread#0 executes code With exclusion
   	Thread#0 unlocks the mutex
   Thread#1 finished	
   				

         Note: If CondWait is not within a While loop on predicate (by 
         putting in comment the first line of above program), one can check 
         in the second case (thread#1 signaling before thread#0 waiting), 
         that thread#0 remains blocked in its waiting phase (Ctrl-C to 
         quit).

Back to top

3. What happens if calling 'Condsignal()' or 'Condbroadcast()' without 
mutex locked?
      Referring to the example 2 on the Critical Sections, one takes this 
      opportunity to recall that:
         - The mutex must always be also locked while executing 
         Condsignal() or Condbroadcast() to wake up a thread (it may be 
         unlocked but only after Condsignal() or Condbroadcast()).
         - If the mutex is not locked (or even if the mutex is unlocked 
         only just before executing Condsignal() or Condbroadcast()), the 
         behavior may become unpredictable (it may work or not, depending 
         on the threads configuration and execution real time).

      In the example 2 on the Critical Sections "Synchronous method example 
      using a condwait then a condbroadcast (and a mutex) for all threads":
         - If one at least Mutexunlock() is moved just before its 
         Condbroadcast(), the program hangs very quickly.
         - Although some users certify that the mutex can always be 
         unlocked just before Condsignal() or Condbroadcast(), and others 
         more cautious assert that one can do it only for a Condbroadcast()
         , experiment shows the opposite!

      The general rule is that:
         - The condition must not be signaled (by Condsignal() or 
         Condbroadcast()) between the time a thread locks the mutex and the 
         time it waits on the condition variable (CondWait()), otherwise it 
         seems that it may damage the waiting queue of threads on that 
         condition variable.
         - Thus to avoid that and follow this rule, it is necessary that 
         the mutex remains locked when the condition is signaled.

Back to top

4. Why is it mandatory to put 'Condwait' within a 'While...Wend' loop for 
checking a Boolean predicate (set by other thread before activate 
'Condsignal' or 'Condbroadcast', and reset after the 'Wend')?
      While predicate <> True
         Condwait(conditionalid, mutexid)
      Wend
      predicate = False

      In all documentations, it is highly advisable to do so, mainly 
      justified to fight against eventual spurious wake-ups.

      This is probably true, but it is also advisable to do so to avoid to 
      loose a CondSignal (or CondBroadcast) if it is prematurely activated 
      while the receiving thread is not yet waiting on CondWait (the signal 
      is lost forever):
         - In that case, the receiving thread has even not yet locked the 
         mutex before that CondSignal (or CondBroadcast) is activated.
         - So the predicate will already true before the receiving thread 
         reaches the 'While...Wend' loop, inducing that CondWait is 
         downright skipped, so avoiding a definitive blocking phenomenon.

      Let two threads (thread #0 in main program, thread #1 in a user 
      procedure, each that prints its number in a loop), having about the 
      same execution time, and each one synchronizing the other in order to 
      well interlace their numbers (by using one mutex, two condition 
      variables and CondSignal/CondWait):
         * Without a 'While...Wend' loop on predicate, the program hangs 
           quickly (Ctrl-C to quit):

   '            Thread#0                           XOR + <==>                       Thread#1
   '   .....                                                             .....
   '   MutexLock(mut) <-------------------------.             .----------> MutexLock(mut)
   '   ( atomic_mutex_unlock(mut) ) ------.     |             |            Do_something_with_exclusion
   '   CondWait(cond#1, mut) <----------- | --- | ----------- | ---------- CondSignal(cond#1)
   '   ( atomic_mutex_re-lock(mut) ) <--- | ----'----.        |     .----- ( atomic_mutex_unlock(mut) )
   '   Do_something_with_exclusion        |     .--- | ------ | --- | ---> CondWait(cond#2, mut)
   '   CondSignal(cond#2) --------------- | ----'    |    .---'---- | ---> ( atomic_mutex_re-lock(mut) )
   '   Do_something_with_exclusion        |     .--- | ---'         |      Do_something_with_exclusion
   '   MutexUnlock(mut) ------------------'-----'    '--------------'----- MutexUnlock(mut)
   '   .....                                                               .....
   '
   '  (connecting lines join the sender(s) and receiver(s) impacted by each action occurring during the sequence)
   					

   Dim As Any Ptr handle
   Dim Shared As Any Ptr mutex
   Dim Shared As Any Ptr cond1
   Dim Shared As Any Ptr cond2
   Dim Shared As Integer quit

   Sub Thread (ByVal param As Any Ptr)
      Do
         MutexLock(mutex)
         Print "1";
         CondSignal(cond1)
         CondWait(cond2, mutex)
         If quit = 1 Then
            MutexUnlock(mutex)
            Exit Do
         End If
         MutexUnlock(mutex)
         Sleep 1, 1
      Loop
   End Sub

   mutex = MutexCreate
   cond1 = CondCreate
   cond2 = CondCreate
   handle = ThreadCreate(@Thread)

   Do
      MutexLock(mutex)
      CondWait(cond1, mutex)
      Print "0";
      CondSignal(cond2)
      If Inkey <> "" Then
         quit = 1
         MutexUnlock(mutex)
         Exit Do
      End If
      MutexUnlock(mutex)
      Sleep 1, 1
   Loop
    
   ThreadWait(handle)
   MutexDestroy(mutex)
   CondDestroy(cond1)
   CondDestroy(cond2)
   Print

   Sleep
                  

         * With a 'While...Wend' loop on predicate around each CondWait, 
           no blocking phenomenon:

   '            Thread#0                                 XOR + <==>                            Thread#1
   '   .....                                                                          .....
   '   MutexLock(mut) <-----------------------------.                          .----> MutexLock(mut)
   '   While bool#1 <> true <---------------------- | --------.                |      Do_something_with_exclusion
   '       ( atomic_mutex_unlock(mut) ) ------.     |         '--------------- | ---- bool#1 = true
   '       CondWait(cond#1, mut) <----------- | --- | ------------------------ | ---- CondSignal(cond#1)
   '       ( atomic_mutex_re-lock(mut) ) <--- | ----'----.    .--------------- | ---> While bool#2 <> true
   '   Wend                                   |          |    |          .---- | -------- ( atomic_mutex_unlock(mut) )
   '   bool#1 = false                .------- | -------- | ---'  .------ | --- |--------> CondWait(cond#2, mut)
   '   Do_something_with_exclusion   |   .--- | -------- | ------'  .--- | ----'--------> ( atomic_mutex_re-lock(mut) )
   '   bool#2 = true ----------------'   |    |     .--- | ---------'    |            Wend
   '   CondSignal(cond#2) ---------------'    |     |    |               |            bool#2 = false
   '   Do_something_with_exclusion            |     |    |               |            Do_something_with_exclusion
   '   MutexUnlock(mut) ----------------------'-----'    '---------------'----------- MutexUnlock(mut)
   '   .....                                                                          .....
   '
   '  (connecting lines join the sender(s) and receiver(s) impacted by each action occurring during the sequence)
   					

   Dim As Any Ptr handle
   Dim Shared As Any Ptr mutex
   Dim Shared As Any Ptr cond1
   Dim Shared As Any Ptr cond2
   Dim Shared As Integer new1
   Dim Shared As Integer new2
   Dim Shared As Integer quit

   Sub Thread (ByVal param As Any Ptr)
      Do
         MutexLock(mutex)
         Print "1";
         new1 = 1
         CondSignal(cond1)
         While new2 <> 1
            CondWait(cond2, mutex)
         Wend
         new2 = 0
         If quit = 1 Then
            MutexUnlock(mutex)
            Exit Do
         End If
         MutexUnlock(mutex)
         Sleep 1, 1
      Loop
   End Sub

   mutex = MutexCreate
   cond1 = CondCreate
   cond2 = CondCreate
   handle = ThreadCreate(@Thread)

   Do
      MutexLock(mutex)
      While new1 <> 1
         CondWait(cond1, mutex)
      Wend
      new1 = 0
      Print "0";
      new2 = 1
      CondSignal(cond2)
      If Inkey <> "" Then
         quit = 1
         MutexUnlock(mutex)
         Exit Do
      End If
      MutexUnlock(mutex)
      Sleep 1, 1
   Loop
    
   ThreadWait(handle)
   MutexDestroy(mutex)
   CondDestroy(cond1)
   CondDestroy(cond2)
   Print

   Sleep
                  

   4.1. Is 'Condwait' (and 'Condsignal' or 'Condbroadcast') still useful 
   when there is already a 'While...Wend' loop for checking a Boolean 
   predicate set by other thread?
      (another question induced by the previous one)
         - The recommended structure is as follows:

   '  Principle of mutual exclusion + CONDWAIT in a While...Wend loop with predicate check, for a thread sub-section
   '  (connecting lines join the sender(s) and receiver(s) impacted by each action occurring during the sequence)
   '
   '
   '          Thread                                        Other Thread
   '      MUTEXLOCK(mutexID) <------------------------- from ( atomic_mutex_unlock(mutexID) ) or MUTEXUNLOCK(mutexID)
   '      .......
   '      While booleanT <> True <--------------------- from booleanT = True
   '          ( atomic_mutex_unlock(mutexID) ) -------> to MUTEXLOCK(mutexID) or ( atomic_mutex_re-lock(mutexID) )
   '          CONDWAIT(conditionalID, mutexID) <------- from CONDSIGNAL(conditionalID)
   '          ( atomic_mutex_re-lock(mutexID) ) <------ from ( atomic_mutex_unlock(mutexID) ) or MUTEXUNLOCK(mutexID)
   '      Wend
   '      booleanT = False
   '      .......
   '      MUTEXUNLOCK(mutexID) -----------------------> to MUTEXLOCK(mutexID) or ( atomic_mutex_re-lock(mutexID) )
   				


   '  Principle of mutual exclusion + CONDSIGNAL with predicate check, for a thread sub-section
   '  (connecting lines join the sender(s) and receiver(s) impacted by each action occurring during the sequence)
   '
   '          Thread                                        Other Thread
   '      MUTEXLOCK(mutexID) <------------------------- from ( atomic_mutex_unlock(mutexID) ) or MUTEXUNLOCK(mutexID)
   '      .......
   '      booleanOT = True ---------------------------> to While booleanOT <> True
   '      CONDSIGNAL(conditionalID) ------------------> to CONDWAIT(conditionalID, mutexID)
   '      .......
   '      MUTEXUNLOCK(mutexID) -----------------------> to MUTEXLOCK(mutexID) or ( atomic_mutex_re-lock(mutexID) )
   				

         - If 'CondWait' is not used, it is mandatory to put instead a 
         'Sleep x, 1' instruction in the 'While...Wend' loop on the Boolean 
         flag, in order to release time-slice when looping (in addition, 
         this 'Sleep x, 1' must be put inside a 
         ['Mutexunlock'...'Mutexlock'] block to release another thread):

   '  Principle of mutual exclusion + SLEEP in a While...Wend loop with predicate check, for a thread sub-section
   '  (connecting lines join the sender(s) and receiver(s) impacted by each action occurring during the sequence)
   '
   '          Thread                                        Other Thread
   '      MUTEXLOCK(mutexID) <------------------------- from MUTEXUNLOCK(mutexID)
   '      .......
   '      While booleanT <> True <--------------------- from booleanT = True
   '          MUTEXUNLOCK(mutexID) -------------------> to MUTEXLOCK(mutexID)
   '          SLEEP(tempo, 1)
   '          MUTEXLOCK(mutexID) <--------------------- from MUTEXUNLOCK(mutexID)
   '      Wend
   '      booleanT = False
   '      .......
   '      MUTEXUNLOCK(mutexID) -----------------------> to MUTEXLOCK(mutexID)
   				


   '  Principle of mutual exclusion + predicate check only, for a thread sub-section
   '  (connecting lines join the sender(s) and receiver(s) impacted by each action occurring during the sequence)
   '
   '          Thread                                        Other Thread
   '      MUTEXLOCK(mutexID) <------------------------- from MUTEXUNLOCK(mutexID)
   '      .......
   '      booleanOT = True ---------------------------> to While booleanOT <> True
   '      .......
   '      MUTEXUNLOCK(mutexID) -----------------------> to MUTEXLOCK(mutexID)
   				

         During 'CondWait', the thread execution is suspended and does not 
         consume any CPU time until the condition variable is signaled.
         But if 'Sleep x, 1' is put instead, the waiting time is 
         predetermined and not self adaptive like that of 'CondWait'.

         => 'CondWait' is useful to optimize the execution time.

Back to top

5. How to implement a user input-line function fully thread-safe?
      The Input keyword may be not thread-safe, when another thread must 
      also access to input/output resource:
         - When executing the Input statement, the other running threads 
         must not change the position of the text cursor, which prohibits 
         instructions such as Locate, Print, ...
         - Moreover, one cannot enclosed the Input keyword inside a mutex 
         locking (as we can do it for the Inkey keyword), because while the 
         inputting line would be not completed and validated, the other 
         threads that want to also access to input/output would be fully 
         blocked (waiting for mutex unlocking).

      Thread-safe input-line function (versus input/output resource):
         Input position, prompt message, sleeping time, line-blanking 
         command, mutex pointer can be passed to the following 
         threadInput() function that simulates a simplified input function, 
         but thread-safe, by using a looping around the Inkey keyword (all 
         input/output keywords must be enclosed inside a mutex locking 
         block, and the cursor position must be restored at each mutex 
         locking block ending):
   Function threadInput (ByVal row As Integer, ByVal column As Integer, ByRef prompt As String = "", _
                    ByVal sleeptime As Integer = 15, ByVal blank As Integer = 0, ByVal mutex As Any Ptr = 0 _
                    ) As String
      Dim As String inputchr
      Dim As String inputline
      Dim As Integer cursor
      Dim As Integer cursor0
      Dim As Integer r
      Dim As Integer c

    
      MutexLock(mutex)
      r = CsrLin()
      c = Pos()
      Locate row, column
      Print prompt & " _";
      cursor0 = Pos() - 1
      Locate r, c
      MutexUnlock(mutex)

      Do
         MutexLock(mutex)
         r = CsrLin()
         c = Pos()
         inputchr = Inkey
         If inputchr <> "" Then
            If inputchr >= Chr(32) And inputchr < Chr(255) Then
               inputline = Left(inputline, cursor) & inputchr & Mid(inputline, cursor + 1)
               cursor += 1
            ElseIf inputchr = Chr(08) And Cursor > 0 Then                         'BkSp
               cursor -= 1
               inputline = Left(inputline, cursor) & Mid(inputline, cursor + 2)
            ElseIf inputchr = Chr(255) & "S" And Cursor < Len(inputline) Then     'Del
               inputline = Left(inputline, cursor) & Mid(inputline, cursor + 2)
            ElseIf inputchr = Chr(255) + "M" And Cursor < Len(inputline) Then     'Right
               Cursor += 1
            ElseIf inputchr = Chr(255) + "K" And Cursor > 0 Then                  'Left
               Cursor -= 1
            End If
            If inputchr = Chr(27) Then                                            'Esc
               Locate row, cursor0
               Print Space(Len(inputline) + 1);
               inputline = ""
               cursor = 0
            End If
            Locate row, cursor0
            Print Left(inputline, cursor) & Chr(95) & Mid(inputline, cursor + 1) & " ";
         End If
         Locate r, c
         MutexUnlock(mutex)
         Sleep sleeptime, 1
      Loop Until inputchr = Chr(13)

      If blank <> 0 Then
         MutexLock(mutex)
         r = CsrLin()
         c = Pos()
         Locate row, cursor0
         Print Space(Len(inputline) + 1);
         Locate r, c
         MutexUnlock(mutex)
      End If

      Return inputline
   End Function
               

         * From the example 1 on the Critical Sections page "Asynchronous 
           method example using a mutex for all threads", now the running 
           multi-threading code is waiting for the "quit" command in order 
           to exit the program:

   '   User thread algorithm:
   '
   '     Do
   '     |  Mutexlock
   '     |  .....
   '     |  Critical section of code
   '     |  .....
   '     |  Mutexunlock
   '     |  Sleep my_tempo, 1
   '     Loop Until quit = true
   '
   '   There is no any advantage or disadvantage between threads for running their critical sections.
   					

   Function threadInput (ByVal row As Integer, ByVal column As Integer, ByRef prompt As String = "", _
                    ByVal sleeptime As Integer = 15, ByVal blank As Integer = 0, ByVal mutex As Any Ptr = 0 _
                    ) As String
      Dim As String inputchr
      Dim As String inputline
      Dim As Integer cursor
      Dim As Integer cursor0
      Dim As Integer r
      Dim As Integer c

    
      MutexLock(mutex)
      r = CsrLin()
      c = Pos()
      Locate row, column
      Print prompt & " _";
      cursor0 = Pos() - 1
      Locate r, c
      MutexUnlock(mutex)

      Do
         MutexLock(mutex)
         r = CsrLin()
         c = Pos()
         inputchr = Inkey
         If inputchr <> "" Then
            If inputchr >= Chr(32) And inputchr < Chr(255) Then
               inputline = Left(inputline, cursor) & inputchr & Mid(inputline, cursor + 1)
               cursor += 1
            ElseIf inputchr = Chr(08) And Cursor > 0 Then                         'BkSp
               cursor -= 1
               inputline = Left(inputline, cursor) & Mid(inputline, cursor + 2)
            ElseIf inputchr = Chr(255) & "S" And Cursor < Len(inputline) Then     'Del
               inputline = Left(inputline, cursor) & Mid(inputline, cursor + 2)
            ElseIf inputchr = Chr(255) + "M" And Cursor < Len(inputline) Then     'Right
               Cursor += 1
            ElseIf inputchr = Chr(255) + "K" And Cursor > 0 Then                  'Left
               Cursor -= 1
            End If
            If inputchr = Chr(27) Then                                            'Esc
               Locate row, cursor0
               Print Space(Len(inputline) + 1);
               inputline = ""
               cursor = 0
            End If
            Locate row, cursor0
            Print Left(inputline, cursor) & Chr(95) & Mid(inputline, cursor + 1) & " ";
         End If
         Locate r, c
         MutexUnlock(mutex)
         Sleep sleeptime, 1
      Loop Until inputchr = Chr(13)

      If blank <> 0 Then
         MutexLock(mutex)
         r = CsrLin()
         c = Pos()
         Locate row, cursor0
         Print Space(Len(inputline) + 1);
         Locate r, c
         MutexUnlock(mutex)
      End If

      Return inputline
   End Function

   '------------------------------------------------------------------------------

   Type UDT
      Dim As Integer number
      Dim As Integer tempo
      Dim As Any Ptr pThread
      Dim As ULongInt count
      Static As Any Ptr pMutex
      Static As Integer numberMax
      Static As Integer quit
   End Type
   Dim As Any Ptr UDT.pMutex
   Dim As Integer UDT.numberMax
   Dim As Integer UDT.quit

   Sub Counter (ByVal pt As UDT Ptr)
      With *pt
         Locate .number, .number, 0
         Sleep 5, 1
         .count += 1
         Print .count;
      End With
   End Sub

   Sub Thread (ByVal p As Any Ptr)
      Dim As Integer myquit
      Dim As UDT Ptr pUDT = p
      With *pUDT
         Do
            MutexLock(.pMutex)
            Counter(pUDT)
            myquit = .quit
            MutexUnlock(.pMutex)
            Sleep .tempo, 1
         Loop Until myquit = 1
      End With
   End Sub

   Screen 12
   UDT.numberMax = 6

   Dim As UDT u(0 To UDT.numberMax)
   For I As Integer = 0 To UDT.numberMax
      u(I).number = i
      u(I).tempo = 100 + 15 * I - 95 * Sgn(I)
   Next I
   UDT.pMutex = MutexCreate

   Dim As Single t = Timer
   For I As Integer = 1 To UDT.numberMax
      u(I).pThread = ThreadCreate(@Thread, @u(I))
   Next I

   Do
   Loop Until LCase(threadInput(8, 1, """quit"" for exit?", 10, 1, UDT.pMutex)) = "quit"

   UDT.quit = 1

   For I As Integer = 1 To UDT.numberMax
      ThreadWait(u(I).pThread)
   Next I
   t = Timer - t

   MutexDestroy(UDT.pMutex)
   Dim As ULongInt c
   For I As Integer = 1 To UDT.numberMax
      c += u(I).count
   Next I
   Locate UDT.numberMax + 4, 1
   Print CULngInt(c / t) & " increments per second"

   Sleep
                  

      Note:
         Otherwise, by using only graphics keywords (using the only 
         position of the graphic cursor) as Line, Draw String, Put in the 
         thread, induces a thread-safe procedure that is compatible with 
         the Line Input keyword in the main code with no mutex:
   Type UDT
      Dim As Integer number
      Dim As Integer tempo
      Dim As Any Ptr pThread
      Dim As ULongInt count
      Dim As Any Ptr img
      Static As Integer numberMax
      Static As Integer quit
   End Type
   Dim As Integer UDT.numberMax
   Dim As Integer UDT.quit

   Const As String prompt = "Enter ""quit"" for exit"
   Dim As String s

   Sub Counter (ByVal pt As UDT Ptr)  ' for a graphic character size 8x16
      With *pt
         Line .img, (0, 0)-(20 * 8 - 1, 16 - 1), 0, BF            ' clearing the image buffer
         Sleep 5, 1
         .count += 1
         Draw String .img, (0, 0), Str(.count)                    ' drawing in the image buffer
         Put ((.number - 1) * 8, (.number - 1) * 16), .img, PSet  ' copying the image buffer to screen
      End With
   End Sub

   Sub Thread (ByVal p As Any Ptr)    ' for a graphic character size 8x16
      Dim As UDT Ptr pUDT = p
      With *pUDT
         .img = ImageCreate(20 * 8, 16)  ' using an image buffer to avoid flickering
         Do
            Counter(pUDT)
            Sleep .tempo, 1
         Loop Until .quit = 1
         ImageDestroy .img  ' destroying the image buffer
      End With
   End Sub

   Screen 12
   UDT.numberMax = 6

   Dim As UDT u(0 To UDT.numberMax)
   For I As Integer = 0 To UDT.numberMax
      u(I).number = i
      u(I).tempo = 100 + 15 * I - 95 * Sgn(I)
   Next I

   Dim As Single t = Timer
   For I As Integer = 1 To UDT.numberMax
      u(I).pThread = ThreadCreate(@Thread, @u(I))
   Next I

   Do
      Locate 8, 1, 0
      Line Input; prompt; s
      Locate , Len(prompt) + 3
      Print Space(Len(s));
   Loop Until LCase(s) = "quit"
   UDT.quit = 1

   For I As Integer = 1 To UDT.numberMax
      ThreadWait(u(I).pThread)
   Next I
   t = Timer - t

   Dim As ULongInt c
   For I As Integer = 1 To UDT.numberMax
      c += u(I).count
   Next I
   Locate UDT.numberMax + 4, 1
   Print CULngInt(c / t) & " increments per second"

   Sleep
               

Back to top

6. How to use 'Screenlock' with multi-threading?
      - Screenlock...Scrennunlock blocks are not compatible with 
      multi-threading (otherwise, the program hangs). This is why a mutex 
      block must be used around each such block to ensure the mutual 
      exclusion.
      - The input keywords (like for keyboard, mouse) cannot be safely run 
      when the screen is locked, therefore a such keyword must be outside 
      of any Screenlock...Screenunlock block, so outside any 
      Screenlock...Screenunlock block in its own thread, and protected of 
      all Screenlock...Screenunlock blocks of other threads by a mutex 
      block. Therefore, Getkey and Input, the statements that wait for 
      keypress or line input are unusable, but Inkey that does not wait can 
      work.

      By applying some rules scrupulously, one can use Screenlock/
      Screenunlock inside the threads.
      Principle of coding for all threads including the main code (main 
      thread):

   Do
   	' instructions without display (printing/drawing, ...) neither input (input/inkey/mouse getting, ...)
   	MutexLock(m)
   	ScreenLock
   	' instructions with only display (printing/drawing, ...)
   	ScreenUnlock
   	' instructions with only input without waiting (inkey/mouse getting, ...)
   	MutexUnlock(m)
   	Sleep tempo, 1
   Loop Until condition
   			

      * For example, it is mandatory to use one Mutexlock...Mutexunlock 
        block around each Screenlock...Screenunlock block, and one other 
        around the Inkey instruction which itself must always be outside of 
        any Screenlock...Screenunlock bloc:
   Type ThreadUDT
      Dim handle As Any Ptr
      Static sync As Any Ptr
      Static quit As Byte
   End Type
   Dim ThreadUDT.sync As Any Ptr
   Dim ThreadUDT.quit As Byte

   Function ClockTime () As String
      Return Time
   End Function

   Function Counter () As Integer
      Static C As Integer
      C = (C + 1) Mod 1000000
      Return C
   End Function

   Sub ProcedureThread (ByVal param As Any Ptr)
      With *Cast(ThreadUDT Ptr, param)
         Do
            MutexLock(.sync)
            ScreenLock
            Line (544, 0)-(639, 49), 0, BF  'clear the print area
            Sleep 100, 1
            Locate 2, 71
            Print ClockTime();
            ScreenUnlock
            MutexUnlock(.sync)
            Sleep 100, 1
         Loop Until .quit = 1
      End With
   End Sub

   Screen 12
   Locate 30, 2
   Print "<q/Q> : quit";

   Dim TTptr As ThreadUDT Ptr = New ThreadUDT
   ThreadUDT.sync = MutexCreate
   TTptr->handle = ThreadCreate(@ProcedureThread, TTptr)

   Dim As String s
   Do
      MutexLock(ThreadUDT.sync)
      ScreenLock
      Line (296, 208)-(376, 256), 0, BF  'clear the print area
      Sleep 100, 1
      Locate 15,40
      Print Using "######"; Counter();
      ScreenUnlock
      s = Inkey
      MutexUnlock(ThreadUDT.sync)
      Sleep 100, 1
   Loop Until LCase(s) = "q"
    
   ThreadUDT.quit = 1
   ThreadWait(TTptr->handle)
   MutexDestroy(ThreadUDT.sync)
   Delete TTptr
               
Note: The Sleep x, 1 keyword just after the 'clear the print area' lines is 
only here to highlight the flickering if no screen locking is used.

Back to top

7. How to use 'video paging (double buffering or page flipping)' with 
multi-threading?
      Instead of "screen locking" (see the above paragraph), "video paging 
      (double buffering or page flipping)" can more simply be used with 
      multi-threading, but be careful that many states in the gfxlib2 are 
      thread-dependent like Screenset (and also View settings, graphic 
      cursor position, graphic colors, ...).
      Therefore, the setting for the working page and the visible page must 
      always be controlled in each thread code which want to work with a 
      multi-video page configuration.

      * Example for a double buffering method (at each step, each thread 
        needs to update the working page and copy it to the visible page, 
        from within a mutual exclusion mutex code block):
   Type ThreadUDT
      Dim handle As Any Ptr
      Static sync As Any Ptr
      Static quit As Byte
   End Type
   Dim ThreadUDT.sync As Any Ptr
   Dim ThreadUDT.quit As Byte

   Function ClockTime () As String
      Return Time
   End Function

   Function Counter () As Integer
      Static C As Integer
      C = (C + 1) Mod 1000000
      Return C
   End Function

   Sub ProcedureThread (ByVal param As Any Ptr)
      ScreenSet 1, 0  '' setting to define in each thread
      With *Cast(ThreadUDT Ptr, param)
         Do
            MutexLock(.sync)
            Line (544, 0)-(639, 49), 0, BF  '' clear the print area
            Sleep 100, 1
            Locate 2, 71
            Print ClockTime();
            ScreenCopy
            MutexUnlock(.sync)
            Sleep 100, 1
         Loop Until .quit = 1
      End With
   End Sub

   Screen 12, , 2
   ScreenSet 1, 0  '' setting to define in each thread
   Locate 30, 2
   Print "<q/Q> : quit";
   ScreenCopy

   Dim TTptr As ThreadUDT Ptr = New ThreadUDT
   ThreadUDT.sync = MutexCreate
   TTptr->handle = ThreadCreate(@ProcedureThread, TTptr)

   Dim s As String
   Do
      MutexLock(ThreadUDT.sync)
      Line (296, 208)-(376, 256), 0, BF  '' clear the print area
      Sleep 100, 1
      Locate 15,40
      Print Using "######"; Counter();
      ScreenCopy
      s = Inkey
      MutexUnlock(ThreadUDT.sync)
      Sleep 100, 1
   Loop Until LCase(s) = "q"
    
   ThreadUDT.quit = 1
   ThreadWait(TTptr->handle)
   MutexDestroy(ThreadUDT.sync)
   Delete TTptr
               
Note: The Sleep x, 1 keyword just after the 'clear the print area' lines is 
only here to highlight the flickering if no double buffering is used.

      * Example for a two page flipping method (at each step, each thread 
        needs to update and flip, from within the same exclusion mutex code 
        block, the two screen pages):
   Type ThreadUDT
      Dim handle As Any Ptr
      Static sync As Any Ptr
      Static quit As Byte
   End Type
   Dim ThreadUDT.sync As Any Ptr
   Dim ThreadUDT.quit As Byte

   Function ClockTime () As String
      Return Time
   End Function

   Function Counter () As Integer
      Static C As Integer
      C = (C + 1) Mod 1000000
      Return C
   End Function

   Sub ProcedureThread (ByVal param As Any Ptr)
      Dim p0 As Integer = 0
      Dim p1 As Integer = 1
      ScreenSet 1, 0  '' setting to define in each thread
      With *Cast(ThreadUDT Ptr, param)
         Do
            MutexLock(.sync)
            Dim s As String = ClockTime()
            For I As Integer = 1 To 2  '' updating the two screen pages
               Line (544, 0)-(639, 49), 0, BF  '' clear the print area
               Sleep 100, 1
               Locate 2, 71
               Print s;
               ScreenSet p0, p1
               Swap p0, p1
            Next I
            MutexUnlock(.sync)
            Sleep 100, 1
         Loop Until .quit = 1
      End With
   End Sub

   Screen 12, , 2
   Dim p0 As Integer = 0
   Dim p1 As Integer = 1
   ScreenSet 1, 0  '' setting to define in each thread
   For I As Integer = 1 To 2  '' updating the two screen pages
      Locate 30, 2
      Print "<q/Q> : quit";
      ScreenSet p0, p1
      Swap p0, p1
   Next I

   Dim TTptr As ThreadUDT Ptr = New ThreadUDT
   ThreadUDT.sync = MutexCreate
   TTptr->handle = ThreadCreate(@ProcedureThread, TTptr)

   Dim s As String
   Do
      MutexLock(ThreadUDT.sync)
      Dim C As Integer = Counter()
      For I As Integer = 1 To 2  '' updating the two screen pages
         Line (296, 208)-(376, 256), 0, BF  '' clear the print area
         Sleep 100, 1
         Locate 15,40
         Print Using "######"; c;
         ScreenSet p0, p1
         Swap p0, p1
      Next I
      s = Inkey
      MutexUnlock(ThreadUDT.sync)
      Sleep 100, 1
   Loop Until LCase(s) = "q"
    
   ThreadUDT.quit = 1
   ThreadWait(TTptr->handle)
   MutexDestroy(ThreadUDT.sync)
   Delete TTptr
               
Note: The Sleep x, 1 keyword just after the 'clear the print area' lines is 
only here to highlight the flickering if no two page flipping is used.

      Note: In these two examples, a mutual exclusion mutex code block is 
      mandatory in the two threads, not only because of using console 
      statements + Inkey, but around also the graphics statements + 
      Screencopy only because of using double buffering method (without 
      anti-flickering process, the graphics statements could be outside the 
      exclusion mutex code block).

Back to top

8. How to use the FB runtime library for multi-threaded applications 
(gfxlib2) with multi-threading?
      The source code of gfxlib2 uses TLS (Thread Local Storage) to store 
      many states, so many things are thread-specific.
      Since gfxlib2 is thread-safe, mutual mutex exclusion between threads 
      is not necessary for the graphics statements themselves (including 
      Draw String).
      In contrast, console statements such as Locate, Print, ... are not 
      thread-safe as previously mentioned (for example, text cursor 
      position is common to all threads).

      * Simple example showing that graphic states (such as graphic cursor 
        position, graphic colors) are thread-dependent:
   Screen 12

   Sub thread(ByVal p As Any Ptr)
      Color 10
      PSet(150, 10)
      For I As Integer = 1 To 40
         Line -Step(10, 10)
         Sleep 150, 1
      Next I
      Draw String Step (-40, 10), "user thread"
   End Sub

   Dim As Any Ptr p = ThreadCreate(@thread)

   Color 14
   PSet(10, 100)
   For I As Integer = 1 To 24
      Line -Step(10, 10)
      Sleep 250, 1
   Next I
   Draw String Step (-40, 10), "main thread"

   ThreadWait(p)

   Color 15
   Locate 4, 2
   Print "Any key for exit"

   Sleep
               

      * Example showing that graphics statements (such as Line and Draw 
        String and Screencopy) in a thread can compete with console 
        statements (such as Inkey) in another thread, without using any 
        exclusion (by mutex):
   #include "vbcompat.bi"

   Screen 12, , 2
   ScreenSet 1, 0   
   Color 0, 7
   Cls

   Dim Shared terminate As Integer = 0

   Sub thread (ByVal param As Any Ptr)   
      ScreenSet 1, 0
      Do
         Line (16, 432)-Step(96, 32), 11, BF  'clear print area
         Sleep 100, 1
         Draw String (24, 432), Format(Now,"dd/mm/yyyy"), 0
         Draw String (32, 448), Format(Now,"hh:mm:ss"), 0
         ScreenCopy
         Sleep 100, 1
      Loop Until terminate = 1
   End Sub

   Dim As String reply
   Locate 2, 2
   Print "Enter ""q"" to quit"
   ScreenCopy

   Dim p As Any Ptr = ThreadCreate(@thread)

   Do
      reply = Inkey
      Sleep 100, 1
   Loop Until LCase(reply) = "q"

   Print " Stop the thread"
   ScreenCopy
   terminate=1
   ThreadWait (p)
   Print " Thread terminated"
   ScreenCopy

   Sleep
               
Note: The Sleep x, 1 keyword just after the 'clear the print area' line is 
only here to highlight the flickering if no double buffering is used.

      * From the above example, if the date displaying and the time 
        displaying are now two separate threads, a mutual exclusion mutex 
        code block between these two threads is mandatory, not due to the 
        graphics statements themselves competing, but only due to the 
        double buffering method used (against flickering) that puts 
        competing these two threads:
   #include "vbcompat.bi"

   Screen 12, , 2
   ScreenSet 1, 0   
   Color 0, 7
   Cls

   Dim Shared terminate As Integer = 0
   Dim Shared mutex As Any Ptr

   Sub thread1 (ByVal param As Any Ptr)   
      ScreenSet 1, 0
      Do
         MutexLock(mutex)
         Line (16, 432)-Step(96, 16), 11, BF  'clear the print area
         Sleep 200, 1
         Draw String (24, 432), Format(Now,"dd/mm/yyyy"), 0
         ScreenCopy
         MutexUnlock(mutex)
         Sleep 100, 1
      Loop Until terminate = 1
   End Sub

   Sub thread2 (ByVal param As Any Ptr)   
      ScreenSet 1, 0
      Do
         MutexLock(mutex)
         Line (16, 448)-Step(96, 16), 11, BF  'clear the print area
         Sleep 100, 1
         Draw String (32, 448), Format(Now,"hh:mm:ss"), 0
         ScreenCopy
         MutexUnlock(mutex)
         Sleep 100, 1
      Loop Until terminate = 1
   End Sub

   Dim As String reply
   Locate 2, 2
   Print "Enter ""q"" to quit"
   ScreenCopy

   mutex = MutexCreate
   Dim p1 As Any Ptr = ThreadCreate(@thread1)
   Dim p2 As Any Ptr = ThreadCreate(@thread2)

   Do
      reply = Inkey
      Sleep 100, 1
   Loop Until LCase(reply) = "q"

   Print " Stop the threads"
   ScreenCopy
   terminate=1
   ThreadWait (p1)
   ThreadWait (p2)
   MutexDestroy(mutex)
   Print " Threads terminated"
   ScreenCopy

   Sleep
               
Note: The Sleep x, 1 keyword just after the 'clear the print area' lines is 
only here to highlight the flickering if no double buffering is used, or if 
no mutex is used.

Back to top

9. How to use console statements and keyboard inputs with multi-threading?
      Console statements (such as Locate, Print, Color, ...), as well as 
      Locate and Print on Graphics window (but not Color on Graphics 
      Window), and keyboard inputs (such as Inkey, Getkey, Input, ...) are 
      not thread-safe:
         - Thus when they are used in competing sections of different 
         threads, mutual exclusion is mandatory by means of mutex locking 
         blocks in which in addition code can restore states (such as text 
         cursor position, console color, ...) at end of the block (after 
         its own usage), as they were before (at begin of the block).
         - But the Getkey or Input keyword cannot be enclosed inside a 
         mutex locking block (as it can be do with the Inkey keyword), 
         because as long as the keyboard input is not completed, the other 
         threads in compete would be fully blocked (waiting for the mutex 
         unlocking).

         * Example showing that the keywords Locate and Print are not 
           thread-safe both when applied on a console window or when 
           applied on a graphics window (the text cursor states being not 
           thread dependent in the two cases):
   Sub Thread (ByVal p As Any Ptr)
      Locate Cast(Integer, p), Cast(Integer, p)
      For I As Integer = 1 To 50 - 2 * Cast(Integer, p)
         Sleep 20 * Cast(Integer, p), 1
         Print Str(Cast(Integer, p));
      Next I
   End Sub

   Sub test ()
      Dim As Any Ptr p(1 To 9)
      For I As Integer = 1 To 9
         p(I) = ThreadCreate(@Thread, Cast(Any Ptr, I))
         Sleep 25, 1
      Next I
      For I As Integer = 1 To 9
         ThreadWait(p(I))
      Next I
   End Sub

   Screen 0
   test()
   Locate 15, 1
   Print "Any key to continue"
   Sleep

   Screen 12
   test()
   Locate 15, 1
   Print "Any key to quit"
   Sleep
                  
Note: One can see that each thread does not write on its own line 
corresponding to its thread number (id between 1 and 9), on the console 
window and on the graphics window.

         * From the above example, the thread code has been completed in 
           its competing sections by mutex locking blocks and by 
           saving/restoring cursor states before/after its own cursor 
           moving:
   Dim Shared As Any Ptr mutex

   Sub Thread (ByVal p As Any Ptr)
      MutexLock(mutex)
      Dim As Long l0 = Locate()
      Locate Cast(Integer, p), Cast(Integer, p)
      Dim As Long l = Locate()
      Locate HiByte(LoWord(l0)), LoByte(LoWord(l0)), HiWord(l0)
      MutexUnlock(mutex)
      For I As Integer = 1 To 50 - 2 * Cast(Integer, p)
         Sleep 20 * Cast(Integer, p), 1
         MutexLock(mutex)
         l0 = Locate()
         Locate HiByte(LoWord(l)), LoByte(LoWord(l)), HiWord(l)
         Print Str(Cast(Integer, p));
         l = Locate()
         Locate HiByte(LoWord(l0)), LoByte(LoWord(l0)), HiWord(l0)
         MutexUnlock(mutex)
      Next I
   End Sub

   Sub test ()
      Dim As Any Ptr p(1 To 9)
      For I As Integer = 1 To 9
         p(I) = ThreadCreate(@Thread, Cast(Any Ptr, I))
         Sleep 25, 1
      Next I
      For I As Integer = 1 To 9
         ThreadWait(p(I))
      Next I
   End Sub

   mutex = MutexCreate

   Screen 0
   test()
   Locate 15, 1
   Print "Any key to continue"
   Sleep

   Screen 12
   test()
   Locate 15, 1
   Print "Any key to quit"
   Sleep

   MutexDestroy(mutex)
                  
Note: One can see that each thread writes now on its own line corresponding 
to its thread number (id between 1 and 9), on the console window and on the 
graphics window.

         * Example showing that the Color keyword is not thread-safe when 
           applied on a console window, but is thread-safe when applied on 
           a graphics window (the color states being thread dependent in 
           that case):
   Sub Thread (ByVal p As Any Ptr)
      Color Cast(Integer, p) + 8, Cast(Integer, p)
      For I As Integer = 1 To 50 - 2 * Cast(Integer, p)
         Print " " & Cast(Integer, p) & " ";
         Sleep 20 * Cast(Integer, p), 1
      Next I
   End Sub

   Sub test ()
      Dim As Any Ptr p(1 To 9)
      Locate 1, 1
      For I As Integer = 1 To 9
         p(I) = ThreadCreate(@Thread, Cast(Any Ptr, I))
         Sleep 25, 1
      Next I
      For I As Integer = 1 To 9
         ThreadWait(p(I))
      Next I
      Locate 16, 1
   End Sub

   Screen 0
   test()
   Print "Any key to continue"
   Sleep

   Screen 12
   test()
   Print "Any key to quit"
   Sleep
                  
Note: One can see that the foreground/background colors are not specific to 
the thread number (id between 1 and 9) on the console window, but this 
works great on the graphics window.

         * From the above example, the thread code has been completed in 
           its competing sections by mutex locking blocks and by 
           saving/restoring color states before/after its own color values 
           usage:
   Dim Shared As Any Ptr mutex

   Sub Thread (ByVal p As Any Ptr)
      MutexLock(mutex)
      Dim As ULong c0 = Color(Cast(Integer, p) + 8, Cast(Integer, p))
      Dim As ULong c = Color()
      Color(LoWord(c0), HiWord(c0))
      MutexUnlock(mutex)
      For I As Integer = 1 To 50 - 2 * Cast(Integer, p)
         MutexLock(mutex)
         c0 = Color(LoWord(c), HiWord(c))
         Print " " & Cast(Integer, p) & " ";
         Color(LoWord(c0), HiWord(c0))
         MutexUnlock(mutex)
         Sleep 20 * Cast(Integer, p), 1
      Next I
   End Sub

   Sub test ()
      Dim As Any Ptr p(1 To 9)
      Locate 1, 1
      For I As Integer = 1 To 9
         p(I) = ThreadCreate(@Thread, Cast(Any Ptr, I))
         Sleep 25, 1
      Next I
      For I As Integer = 1 To 9
         ThreadWait(p(I))
      Next I
      Locate 16, 1
   End Sub

   mutex = MutexCreate

   Screen 0
   test()
   Print "Any key to continue"
   Sleep

   Screen 12
   test()
   Print "Any key to quit"
   Sleep

   MutexDestroy(mutex)
                  
Note: One can see that the foreground/background colors are now specific to 
the thread number (id between 1 and 9) on the console window (obviously 
this always works on the graphics window).

      Therefore, for using Getkey or Input in competing sections of 
      threads:
         - Only a single thread (for example, the main thread) can uses 
         Getkey or Input in addition to console statements (such as Locate, 
         Print, Color, ...) and also Inkey, in its competing sections.
         - The other threads must not to use in their competing sections 
         any console statement neither any keyboard input keyword, but can 
         use by cons graphics statements (such as Pset, Line, Circle, Draw 
         String, graphic Color, ...) which are themselves thread-safe (they 
         can interlace graphically with the main thread without any 
         problem).
         - Input and Getkey also exclude the screen locking usage in 
         competing sections of threads (double buffering is recommended as 
         anti-flickering method).

         * Example showing that graphics statements (such as Line and Draw 
           String and Screencopy) in a thread (user thread here) can 
           compete with console statements (such as Locate and Print and 
           Input) in another thread (main thread here), without using any 
           mutual exclusion (by mutex):
   #include "vbcompat.bi"

   Screen 12, , 2
   ScreenSet 1, 0   
   Color 0, 7
   Cls

   Dim Shared terminate As Integer = 0

   Sub thread (ByVal param As Any Ptr)   
      ScreenSet 1, 0
      Do
         Line (16, 432)-Step(96, 32), 11, BF  'clear the print area
         Sleep 100, 1
         Draw String (24, 432), Format(Now,"dd/mm/yyyy"), 0
         Draw String (32, 448), Format(Now,"hh:mm:ss"), 0
         ScreenCopy
         Sleep 100, 1
      Loop Until terminate = 1
   End Sub

   Dim As String reply
   Locate 2, 2
   Print "Enter ""quit"" to quit"
   ScreenCopy

   Dim p As Any Ptr = ThreadCreate(@thread)

   Do
      Locate 3, 2
      Print Space(Len(reply) + 2);
      Locate 3, 2
      Input reply
   Loop Until LCase(reply) = "quit"

   Print " Stop the thread"
   ScreenCopy
   terminate=1
   ThreadWait (p)
   Print " Thread terminated"
   ScreenCopy

   Sleep
                  
Note: The Sleep x, 1 keyword just after the 'clear the print area' line is 
only here to highlight the flickering if no double buffering is used 
(screen locking being forbidden by Input usage).

         * From the above example, if the date displaying and the time 
           displaying are now two separate user threads, a mutual exclusion 
           mutex code block between these two threads only is mandatory, 
           not due to the graphics statements themselves competing, but 
           only due to the double buffering method used (against 
           flickering) that puts competing these two user threads only:
   #include "vbcompat.bi"

   Screen 12, , 2
   ScreenSet 1, 0   
   Color 0, 7
   Cls

   Dim Shared terminate As Integer = 0
   Dim Shared mutex As Any Ptr

   Sub thread1 (ByVal param As Any Ptr)   
      ScreenSet 1, 0
      Do
         MutexLock(mutex)
         Line (16, 432)-Step(96, 16), 11, BF  'clear the print area
         Sleep 200, 1
         Draw String (24, 432), Format(Now,"dd/mm/yyyy"), 0
         ScreenCopy
         MutexUnlock(mutex)
         Sleep 100, 1
      Loop Until terminate = 1
   End Sub

   Sub thread2 (ByVal param As Any Ptr)   
      ScreenSet 1, 0
      Do
         MutexLock(mutex)
         Line (16, 448)-Step(96, 16), 11, BF  'clear the print area
         Sleep 100, 1
         Draw String (32, 448), Format(Now,"hh:mm:ss"), 0
         ScreenCopy
         MutexUnlock(mutex)
         Sleep 100, 1
      Loop Until terminate = 1
   End Sub

   Dim As String reply
   Locate 2, 2
   Print "Enter ""quit"" to quit"
   ScreenCopy

   mutex = MutexCreate
   Dim p1 As Any Ptr = ThreadCreate(@thread1)
   Dim p2 As Any Ptr = ThreadCreate(@thread2)

   Do
      Locate 3, 2
      Print Space(Len(reply) + 2);
      Locate 3, 2
      Input reply
   Loop Until LCase(reply) = "quit"

   Print " Stop the threads"
   ScreenCopy
   terminate=1
   ThreadWait (p1)
   ThreadWait (p2)
   MutexDestroy(mutex)
   Print " Threads terminated"
   ScreenCopy

   Sleep
                  
Note: The Sleep x, 1 keyword just after the 'clear the print area' lines is 
only here to highlight the flickering if no double buffering is used 
(screen locking being forbidden by Input usage).

Back to top

10. Is it better to take precautions when using the keyword 'Sleep' in 
threads?
      There is still some doubt about the perfect behavior of the keyword 
      Sleep in a multi-threading context.

      It is therefore advisable to take the following precautions for its 
      use:
         - If it is absolutely necessary in a critical section of a thread, 
         the syntax Sleep x or Sleep x, 0, because inducing an internal 
         test of a key-press, must for greatest safety be preferably 
         treated in the same way as the Inkey keyword to avoid as much as 
         possible any concurrent conflict with other threads.
         - Otherwise, the syntax Sleep x, 1 (inducing no internal test of 
         key-press) is rather advised when there is no protection by mutual 
         exclusion, which is very often the case in order to release 
         time-slice for the other threads.

Back to top

11. Can all tools to handle multi-threading be encapsulated in a base Class 
(that the user extends with a derived Type for his own implementing)?
      A simple 'threadUDT' base Class can be defined as follows:
         - with a private 'Any Ptr' non-static member field for each 
         handle,
         - with a private 'Any Ptr' static member field for one shared 
         mutex,
         - with a private 'Any Ptr' static member field for one shared 
         conditional variable,
         - with its own public member procedures 'Sub()' calling the 
         corresponding built-in procedures for multi-threading (with same 
         procedure names), including also value integrity tests on the 3 
         above pointers (non-static procedures for the 3 'thread...()' 
         member Subs, and static procedures for the 4 'mutex...()' member 
         Subs and the 5 'cond...()' member Subs),
         - with an abstract private 'Sub()' thread to be overridden by 
         another 'Sub()' from inside the user derived Type (therefore its 
         static address is available in the virtual table of the object, 
         and the hidden 'This' parameter passed by reference is compatible 
         with the 'Any Ptr' parameter to be passed to the thread).
   #include Once "fbthread.bi"
   Type threadUDT Extends Object
      Public:
         Declare Sub ThreadCreate ()
         Declare Sub ThreadWait ()
         Declare Sub ThreadDetach ()
         Declare Static Sub MutexCreate ()
         Declare Static Sub MutexLock ()
         Declare Static Sub MutexUnlock ()
         Declare Static Sub MutexDestroy ()
         Declare Static Sub CondCreate ()
         Declare Static Sub CondWait ()
         Declare Static Sub CondSignal ()
         Declare Static Sub CondBroadcast ()
         Declare Static Sub CondDestroy ()
      Private:
         Declare Abstract Sub thread ()
         Dim As Any Ptr pThread
         Static As Any Ptr pMutex
         Static As Any Ptr pCond
   End Type
   Dim As Any Ptr threadUDT.pMutex
   Dim As Any Ptr threadUDT.pCond

   Sub threadUDT.threadCreate ()
      If This.pThread = 0 Then
        This.pThread = .ThreadCreate(Cast(Any Ptr Ptr Ptr, @This)[0][0], @This)
      End If
   End Sub

   Sub threadUDT.threadWait ()
      If This.pThread > 0 Then
         .ThreadWait(This.pThread)
         This.pThread = 0
      End If
   End Sub

   Sub threadUDT.threadDetach ()
      If This.pThread > 0 Then
         .ThreadDetach(This.pThread)
         This.pThread = 0
      End If
   End Sub
     
   Sub threadUDT.mutexCreate ()
      If threadUDT.pMutex = 0 Then
         threadUDT.pMutex = .MutexCreate
      End If
   End Sub
     
   Sub threadUDT.mutexLock ()
      If threadUDT.pMutex > 0 Then
         .MutexLock(threadUDT.pMutex)
      End If
   End Sub

   Sub threadUDT.mutexUnlock ()
      If threadUDT.pMutex > 0 Then
         .MutexUnlock(threadUDT.pMutex)
      End If
   End Sub

   Sub threadUDT.mutexDestroy ()
      If threadUDT.pMutex > 0 Then
         .MutexDestroy(threadUDT.pMutex)
         threadUDT.pMutex = 0
      End If
   End Sub

   Sub threadUDT.condCreate ()
      If threadUDT.pCond = 0 Then
         threadUDT.pCond = .CondCreate
      End If
   End Sub

   Sub threadUDT.condWait ()
      If threadUDT.pCond > 0 And threadUDT.pMutex > 0 Then
         .CondWait(threadUDT.pCond, threadUDT.pMutex)
      End If
   End Sub

   Sub threadUDT.condSignal ()
      If threadUDT.pCond > 0 And threadUDT.pMutex > 0 Then
         .CondSignal(threadUDT.pCond)
      End If
   End Sub

   Sub threadUDT.condBroadcast ()
      If threadUDT.pCond > 0 And threadUDT.pMutex > 0 Then
         .CondBroadcast(threadUDT.pCond)
      End If
   End Sub

   Sub threadUDT.condDestroy ()
      If threadUDT.pCond > 0 Then
         .CondDestroy(threadUDT.pCond)
         threadUDT.pCond = 0
      End If
   End Sub
               

      * From the example 2 on the Critical Sections page "Synchronous 
        method example using a condwait then a condbroadcast (and a mutex) 
        for all threads", now the user implementation is modified to be 
        compatible with the base Class 'threadUDT':
   #include Once "fbthread.bi"
   Type threadUDT Extends Object
      Public:
         Declare Sub ThreadCreate ()
         Declare Sub ThreadWait ()
         Declare Sub ThreadDetach ()
         Declare Static Sub MutexCreate ()
         Declare Static Sub MutexLock ()
         Declare Static Sub MutexUnlock ()
         Declare Static Sub MutexDestroy ()
         Declare Static Sub CondCreate ()
         Declare Static Sub CondWait ()
         Declare Static Sub CondSignal ()
         Declare Static Sub CondBroadcast ()
         Declare Static Sub CondDestroy ()
      Private:
         Declare Abstract Sub thread ()
         Dim As Any Ptr pThread
         Static As Any Ptr pMutex
         Static As Any Ptr pCond
   End Type
   Dim As Any Ptr threadUDT.pMutex
   Dim As Any Ptr threadUDT.pCond

   Sub threadUDT.threadCreate ()
      If This.pThread = 0 Then
        This.pThread = .ThreadCreate(Cast(Any Ptr Ptr Ptr, @This)[0][0], @This)
      End If
   End Sub

   Sub threadUDT.threadWait ()
      If This.pThread > 0 Then
         .ThreadWait(This.pThread)
         This.pThread = 0
      End If
   End Sub

   Sub threadUDT.threadDetach ()
      If This.pThread > 0 Then
         .ThreadDetach(This.pThread)
         This.pThread = 0
      End If
   End Sub
     
   Sub threadUDT.mutexCreate ()
      If threadUDT.pMutex = 0 Then
         threadUDT.pMutex = .MutexCreate
      End If
   End Sub
     
   Sub threadUDT.mutexLock ()
      If threadUDT.pMutex > 0 Then
         .MutexLock(threadUDT.pMutex)
      End If
   End Sub

   Sub threadUDT.mutexUnlock ()
      If threadUDT.pMutex > 0 Then
         .MutexUnlock(threadUDT.pMutex)
      End If
   End Sub

   Sub threadUDT.mutexDestroy ()
      If threadUDT.pMutex > 0 Then
         .MutexDestroy(threadUDT.pMutex)
         threadUDT.pMutex = 0
      End If
   End Sub

   Sub threadUDT.condCreate ()
      If threadUDT.pCond = 0 Then
         threadUDT.pCond = .CondCreate
      End If
   End Sub

   Sub threadUDT.condWait ()
      If threadUDT.pCond > 0 And threadUDT.pMutex > 0 Then
         .CondWait(threadUDT.pCond, threadUDT.pMutex)
      End If
   End Sub

   Sub threadUDT.condSignal ()
      If threadUDT.pCond > 0 And threadUDT.pMutex > 0 Then
         .CondSignal(threadUDT.pCond)
      End If
   End Sub

   Sub threadUDT.condBroadcast ()
      If threadUDT.pCond > 0 And threadUDT.pMutex > 0 Then
         .CondBroadcast(threadUDT.pCond)
      End If
   End Sub

   Sub threadUDT.condDestroy ()
      If threadUDT.pCond > 0 Then
         .CondDestroy(threadUDT.pCond)
         threadUDT.pCond = 0
      End If
   End Sub

   '------------------------------------------------------------------------------

   Type UDT Extends threadUDT
      Declare Sub counter ()
      Declare Sub thread ()
      Dim As Integer number
      Dim As Integer tempo
      Dim As ULongInt count
      Static As Integer threadPriorityNumber
      Static As Integer numberMax
      Static As Integer quit
   End Type
   Dim As Integer UDT.threadPriorityNumber
   Dim As Integer UDT.numberMax
   Dim As Integer UDT.quit

   Sub UDT.counter ()
      Locate This.number, This.number, 0
      Sleep 5, 1
      This.count += 1
      Print This.count;
      Locate This.number, 30 + This.number, 0
   End Sub

   Sub UDT.Thread ()
      Dim As Integer myquit
      Do
         This.mutexLock()
         While UDT.threadPriorityNumber <> This.number  '' synchronous condwait for expected condition
            This.condWait()
         Wend
         This.counter()
         myquit = UDT.quit
         UDT.threadPriorityNumber = (UDT.threadPriorityNumber + 1) Mod (UDT.numberMax + 1)
         This.condBroadcast()
         This.mutexUnlock()
         Sleep This.tempo, 1
      Loop Until myquit = 1
   End Sub

   UDT.numberMax = 6
   Dim As UDT u(0 To UDT.numberMax)
   For I As Integer = 0 To UDT.numberMax
      u(I).number = i
      u(I).tempo = 100 + 15 * I - 95 * Sgn(I)
   Next I
   UDT.mutexCreate()
   UDT.condCreate()

   Dim As Single t = Timer
   For I As Integer = 1 To UDT.numberMax
      u(I).ThreadCreate()
   Next I

   Dim As String s
   Do
      UDT.mutexLock()
      While UDT.threadPriorityNumber <> u(0).number
         UDT.condWait()
      Wend
      s = Inkey
      If s <> "" Then
         UDT.quit = 1
      End If
      UDT.threadPriorityNumber = (UDT.threadPriorityNumber + 1) Mod (UDT.numberMax + 1)
      UDT.condBroadcast()
      UDT.mutexUnlock()
      Sleep u(0).tempo, 1
   Loop Until s <> ""

   For I As Integer = 1 To UDT.numberMax
      u(I).ThreadWait()
   Next I
   t = Timer - t

   UDT.mutexDestroy()
   UDT.condDestroy()
   Dim As ULongInt c
   For I As Integer = 1 To UDT.numberMax
      c += u(I).count
   Next I
   Locate UDT.numberMax+2, 1
   Print CULngInt(c / t) & " increments per second"

   Sleep
               

Back to top

12. What is the execution delay of the code of a thread after the thread is 
created by 'ThreadCreate'?
   One might think that the first code line of the thread is always 
   executed at least after the 'ThreadCreate()' returns, but this is 
   neither guaranteed nor even observed.

   One can estimate the delay (positive or negative) between the 
   'ThreadCreate()' return and the the thread start, by a time memorization 
   as similar as possible between the line following 'ThreadCreate()' and 
   the first thread code line (the delay calculation is executed after the 
   end of the thread).
   After a while of observation, one can find both small negative values 
   and large positive values.

   Interesting to see the min time, average time, and max time, between the 
   executing start of thread body and the returning point of 
   'ThreadCreate()':
   Dim As Any Ptr ptid
   Dim As Double t0
   Dim As Any Ptr p0 = @t0
   Dim As Double t1
   Dim As Double count
   Dim As Single tmean
   Dim As Single tmin = 10   '' start value
   Dim As Single tmax = -10  '' start value

   Sub myThread (ByVal p As Any Ptr)
      *Cast(Double Ptr, p) = Timer  '' similar code line as in main code
   End Sub

   Print "Tmin/Tmean/Tmax between begin of thread code and return from ThreadCreate() :"
   Do
      count += 1
      ptid = ThreadCreate(@myThread, @t1)
      *Cast(Double Ptr, p0) = Timer  '' similar code line as in thread code
      
      ThreadWait(ptid)
      
      tmean = (tmean * (count - 1) + (t1 - t0)) / count
      If t1 - t0 < tmin Or t1 - t0 > tmax Then
         If t1 - t0 < tmin Then
            tmin = t1 - t0
         End If
         If t1 - t0 > tmax Then
            tmax = t1 - t0
         End If
         Print Time; Using "    Tmin=+###.###### ms    Tmean=+###.###### ms    Tmax=+###.###### ms"; tmin * 1000; tmean * 1000; tmax * 1000
      End If
   Loop Until Inkey <> ""

		Output (for example):

   Tmin/Tmean/Tmax between begin of thread code And Return from ThreadCreate() :
   21:30:13    Tmin=  +0.151800 ms    Tmean=  +0.151800 ms    Tmax=  +0.151800 ms
   21:30:13    Tmin=  +0.006000 ms    Tmean=  +0.078900 ms    Tmax=  +0.151800 ms
   21:30:13    Tmin=  +0.006000 ms    Tmean=  +0.098394 ms    Tmax=  +0.172500 ms
   21:30:13    Tmin=  +0.006000 ms    Tmean=  +0.121555 ms    Tmax=  +0.884900 ms
   21:30:45    Tmin=  +0.006000 ms    Tmean=  +0.055810 ms    Tmax=  +1.104200 ms
   21:30:54    Tmin=  +0.006000 ms    Tmean=  +0.055764 ms    Tmax=  +4.056600 ms
   21:31:44    Tmin=  -0.116300 ms    Tmean=  +0.055516 ms    Tmax=  +4.056600 ms
   21:32:10    Tmin=  -0.136800 ms    Tmean=  +0.057177 ms    Tmax=  +4.056600 ms
   21:32:12    Tmin=  -0.150300 ms    Tmean=  +0.057265 ms    Tmax=  +4.056600 ms
   21:33:17    Tmin=  -0.150300 ms    Tmean=  +0.060048 ms    Tmax=  +4.979900 ms
   21:33:18    Tmin=  -0.150300 ms    Tmean=  +0.060157 ms    Tmax=  +7.086300 ms
   21:33:23    Tmin=  -0.150600 ms    Tmean=  +0.060347 ms    Tmax=  +7.086300 ms
   21:33:38    Tmin=  -0.205900 ms    Tmean=  +0.060878 ms    Tmax=  +7.086300 ms
   21:35:30    Tmin=  -0.208700 ms    Tmean=  +0.061315 ms    Tmax=  +7.086300 ms

   Note:
      If the user safely wish to always delay the thread execution at least 
      after some code lines following the 'ThreadCreate()' line, a mutual 
      exclusion between the 'ThreadCreate()' line and the start of the 
      thread body can be used as this principle follows:
   Dim Shared As Any Ptr pMutexForThreadStart

   '-------------------------------------------

   Sub Thread (ByVal p As Any Ptr)
      MutexLock(pMutexForThreadStart)
      MutexUnlock(pMutexForThreadStart)
      '
      ' user thread body
      '
   End Sub

   '--------------------------------------------

   '
   ' user main code
   '
   pMutexForThreadStart = MutexCreate()
   '
   ' user main code continues
   '
   MutexLock(pMutexForThreadStart)
   Dim As Any Ptr pThread = ThreadCreate(@Thread)
   '
   ' lines of code to be executed before the executing start of the user body of the thread
   '
   MutexUnlock(pMutexForThreadStart)
   '
   ' user main code continues
   '
   ThreadWait(pThread)
   MutexDestroy(pMutexForThreadStart)

Back to top

13. What is the synchronization latency when synchronizing threads either 
by mutual exclusions or by conditional variables?
      The synchronization waiting phase of each thread should not consume 
      any CPU resources like 'Sleep', which is the case of 'MutexLock()' 
      and 'CondWait()' instructions.
      Thread synchronization by mutual exclusions or by conditional 
      variables adds latency to the initial execution time of the threads, 
      but this latency (a few microseconds) is infinitely shorter than that 
      of a simple simple wait loop (a few milliseconds at best) containing 
      the shortest sleep ('Sleep 1, 1') with a flag test.

      The following code allows to estimate this synchronization latency 
      between the main thread and a child thread, by using either simple 
      flags, either mutual exclusions, or conditional variables:
   Dim Shared As Any Ptr mutex0, mutex1, mutex2, mutex, cond1, cond2, pt
   Dim Shared As Integer flag1, flag2
   Dim As Double t

   '----------------------------------------------------------------------------------

   #if defined(__FB_WIN32__)
   Declare Function _setTimer Lib "winmm" Alias "timeBeginPeriod"(ByVal As ULong = 1) As Long
   Declare Function _resetTimer Lib "winmm" Alias "timeEndPeriod"(ByVal As ULong = 1) As Long
   #endif

   Sub ThreadFlag(ByVal p As Any Ptr)
      MutexUnlock(mutex0)  '' unlock mutex for main thread
      For I As Integer = 1 To 100
         While flag1 = 0
            Sleep 1, 1
         Wend
         flag1 = 0
         ' only child thread code runs (location for example)
         flag2 = 1
      Next I
   End Sub

   mutex0 = MutexCreate()
   MutexLock(mutex0)

   pt = ThreadCreate(@ThreadFlag)
   MutexLock(mutex0)  '' wait for thread launch (mutex unlock from child thread)
   Print "Thread synchronization latency by simple flags:"
   #if defined(__FB_WIN32__)
      _setTimer()
      Print "(in high resolution OS cycle period)"
   #else
      Print "(in normal resolution OS cycle period)"
   #endif
   t = Timer
   For I As Integer = 1 To 100
      flag1 = 1
      While flag2 = 0
         Sleep 1, 1
      Wend
      flag2 = 0
      ' only main thread code runs (location for example)
   Next I
   t = Timer - t
   #if defined(__FB_WIN32__)
      _resetTimer()
   #endif
   ThreadWait(pt)
   Print Using "####.## milliseconds per double synchronization (round trip)"; t * 10
   Print

   MutexDestroy(mutex0)

   '----------------------------------------------------------------------------------

   Sub ThreadMutex(ByVal p As Any Ptr)
      MutexUnlock(mutex0)  '' unlock mutex for main thread
      For I As Integer = 1 To 100000
         MutexLock(mutex1)    '' wait for mutex unlock from main thread
         ' only child thread code runs
         MutexUnlock(mutex2)  '' unlock mutex for main thread
      Next I
   End Sub

   mutex0 = MutexCreate()
   mutex1 = MutexCreate()
   mutex2 = MutexCreate()
   MutexLock(mutex0)
   MutexLock(mutex1)
   MutexLock(mutex2)

   pt = ThreadCreate(@ThreadMutex)
   MutexLock(mutex0)  '' wait for thread launch (mutex unlock from child thread)
   Print "Thread synchronization latency by mutual exclusions:"
   t = Timer
   For I As Integer = 1 To 100000
      MutexUnlock(mutex1)  '' mutex unlock for child thread
      MutexLock(mutex2)    '' wait for mutex unlock from child thread
      ' only main thread code runs
   Next I
   t = Timer - t
   ThreadWait(pt)
   Print Using "####.## microseconds per double synchronization (round trip)"; t * 10
   Print

   MutexDestroy(mutex0)
   MutexDestroy(mutex1)
   MutexDestroy(mutex2)

   '----------------------------------------------------------------------------------

   Sub ThreadCondVar(ByVal p As Any Ptr)
      MutexUnlock(mutex0)  '' unlock mutex for main thread
      For I As Integer = 1 To 100000
         MutexLock(mutex)
         While flag1 = 0
            CondWait(cond1, mutex)  '' wait for conditional signal from main thread
         Wend
         flag1 = 0
         ' only child thread code runs (location for example)
         flag2 = 1
         CondSignal(cond2)  '' send conditional signal to main thread
         MutexUnlock(mutex)
      Next I
   End Sub

   mutex0 = MutexCreate()
   mutex = MutexCreate()
   MutexLock(mutex0)
   cond1 = CondCreate()
   cond2 = CondCreate()

   pt = ThreadCreate(@ThreadCondVar)
   MutexLock(mutex0)  '' wait for thread launch (mutex unlock from child thread)
   Print "Thread synchronization latency by conditional variables:"
   t = Timer
   For I As Integer = 1 To 100000
      MutexLock(mutex)
      flag1 = 1
      CondSignal(cond1)  '' send conditional signal to main thread
      While flag2 = 0
         CondWait(Cond2, mutex)  '' wait for conditional signal from child thread
      Wend
      flag2 = 0
      ' only child thread code runs (location for example)
      MutexUnlock(mutex)
   Next I
   t = Timer - t
   ThreadWait(pt)
   Print Using "####.## microseconds per double synchronization (round trip)"; t * 10
   Print

   MutexDestroy(mutex0)
   MutexDestroy(mutex)
   CondDestroy(cond1)
   CondDestroy(cond2)

   '----------------------------------------------------------------------------------

   Sleep

			Example of results:

   Thread synchronization latency by simple flags:
   (in high resolution OS cycle period)
      2.02 milliseconds per Double synchronization (round trip)

   Thread synchronization latency by mutual exclusions:
      5.93 microseconds per Double synchronization (round trip)

   Thread synchronization latency by conditional variables:
      7.54 microseconds per Double synchronization (round trip)

      Example of thread synchronization for executing in concurrent or 
      exclusive mode by using conditional variable:
   Dim Shared As Any Ptr pt, mutex1, mutex2, cond1, cond2
   Dim Shared As Integer quit, flag1, flag2

   Print "'1': Main thread procedure running (alone)"
   Print "'2': Child thread procedure running (alone)"
   Print "'-': Main thread procedure running (with the one of child thread)"
   Print "'=': Child thread procedure running (with the one of main thread)"
   Print

   Sub Prnt(ByRef s As String, ByVal n As Integer)
      For I As Integer = 1 To n
         Print s;
         Sleep 20, 1
      Next I
   End Sub

   Sub ThreadCondCond(ByVal p As Any Ptr)
      Do
         MutexLock(mutex1)
         While flag1 = 0              '' test flag set from main thread
            CondWait(cond1, mutex1)  '' wait for conditional signal from main thread
         Wend
         flag1 = 0                    '' reset flag
         MutexUnlock(mutex1)
         If quit = 1 Then Exit Sub    '' exit the threading loop
         Prnt("=", 10)
         MutexLock(mutex2)
         flag2 = 1                    '' set flag to main thread
         CondSignal(cond2)            '' send conditional signal to main thread
         Prnt("2", 10)
         MutexUnlock(mutex2)
      Loop
   End Sub

   mutex1 = MutexCreate()
   mutex2 = MutexCreate()
   cond1 = CondCreate()
   cond2 = CondCreate()

   pt = ThreadCreate(@ThreadCondCond)
   For I As Integer = 1 To 5
      MutexLock(mutex1)
      flag1 = 1                    '' set flag to child thread
      CondSignal(cond1)            '' send conditional signal to child thread
      MutexUnlock(mutex1)
      Prnt("-", 10)
      MutexLock(mutex2)
      While flag2 = 0              '' test flag set from child thread
         CondWait(Cond2, mutex2)  '' wait for conditional signal from child thread
      Wend
      flag2 = 0                    '' reset flag
      Prnt("1", 10)
      MutexUnlock(mutex2)
   Next I

   MutexLock(mutex1)
   quit = 1                         '' set quit for child thread
   flag1 = 1
   CondSignal(cond1)                '' send conditional signal to child thread
   MutexUnlock(mutex1)
   ThreadWait(pt)                   '' wait for child thread to end
   Print

   MutexDestroy(mutex1)
   MutexDestroy(mutex2)
   CondDestroy(cond1)
   CondDestroy(cond2)

   Sleep

			Output:

   '1': Main thread procedure running (alone)
   '2': Child thread procedure running (alone)
   '-': Main thread procedure running (with the one of child thread)
   '=': Child thread procedure running (with the one of main thread)

   -==-=-=--==--==-=-=-22222222221111111111-=-=-=-==--==-=--==-22222222221111111111-=-=-==-=-=--=-=-==-22222222221111111111
   -=-=-=-=-=-=--==-=-=22222222221111111111-==--==--==-=-=--==-22222222221111111111

Back to top

14. What happens when multiple threads are waiting on the same condition 
variable?
   * If 'CondSignal()' is used:
         The specification states that the thread scheduler arbitrarily 
         notifies one of the threads waiting on the condition variable.
         Since this method notifies an arbitrary thread, some documentation 
         also states that it is therefore possible for a waiting thread to 
         never be notified if it is never alone in the queue on the 
         condition variable.
         But my tests on Windows seem to show that the order of entry into 
         the queue on a same condition variable determines the order of 
         exit: first in, first out.
         I have not tested this on Linux or any other platform, but in any 
         case this behavior I observed is unspecified.

   * If 'CondBroadcast()' is used:
         The specification states that the thread scheduler notifies all 
         threads waiting on the condition variable in an arbitrary order.

   The example below works with 6 threads (in addition to the main thread).
   The first 3 threads (#1 to #3) are waiting on their own condition 
   variable, while the last 3 threads (#4 to #6) are waiting on a same 
   other condition variable.
   These last 3 threads are awakened either on 'CondSignal()' or on 
   'CondBroadcast()'.
   Type ThreadData
      Dim As Integer id
      Dim As Any Ptr mutex
      Dim As Any Ptr cond
      Dim As Boolean flag
      Dim As Boolean quit
      Dim As Any Ptr handle
      Declare Static Sub Thread(ByVal p As Any Ptr)
   End Type

   Sub ThreadData.Thread(ByVal p As Any Ptr)
      Dim As ThreadData Ptr pdata = p
      Print "   thread #" & pdata->id & " is running"
      Do
         MutexLock(pdata->mutex)
            While pdata->flag = False
               CondWait(pdata->cond, pdata->mutex)
            Wend
            pdata->flag = False
         MutexUnlock(pdata->mutex)
         If pdata->quit = False Then
            Print "   thread #" & pdata->id & " is signaled"
         Else
            Exit Do
         End If
      Loop
      Print "   thread #" & pdata->id & " is finishing"
   End Sub

   Dim As Any Ptr mutex = MutexCreate()
   Dim As Any Ptr cond(0 To 3) = {CondCreate(), CondCreate(), CondCreate(), CondCreate()}
   Dim As ThreadData mythreads(1 To 6) = {Type(1, mutex, cond(1)), Type(2, mutex, cond(2)), Type(3, mutex, cond(3)), _
                                 Type(4, mutex, cond(0)), Type(5, mutex, cond(0)), Type(6, mutex, cond(0))}

   Print "Threads from #1 to #6 are created:"
   For I As Integer = LBound(mythreads) To UBound(mythreads)
      mythreads(I).handle = ThreadCreate(@ThreadData.Thread, @mythreads(I))
   Next I
   Sleep 1000, 1  '' wait for all threads started
   Print
   Print "----------------------------------------------------------"
   Print

   For I As Integer = 3 To 1 Step -1
      Print "Send a CondSignal to thread #" & I &":"
      MutexLock(mutex)
         mythreads(I).flag = True
         CondSignal(cond(I))
      MutexUnlock(mutex)
      Sleep 1000, 1  '' wait for the thread loop completed
      Print
   Next I
   Print "----------------------------------------------------------"
   Print

   Print "Send a single CondBroadcast to all threads from #4 to #6:"
   MutexLock(mutex)
      For I As Integer = 4 To 6
         mythreads(I).flag = True
      Next I
      CondBroadcast(cond(0))
   MutexUnlock(mutex)
   Sleep 1000, 1  '' wait for all thread loops completed
   Print "Send a single CondBroadcast to all threads from #4 to #6:"
   MutexLock(mutex)
      For I As Integer = 4 To 6
         mythreads(I).flag = True
      Next I
      CondBroadcast(cond(0))
   MutexUnlock(mutex)
   Sleep 1000, 1  '' wait for all thread loops completed
   Print "Send a single CondBroadcast to all threads from #4 to #6:"
   MutexLock(mutex)
      For I As Integer = 4 To 6
         mythreads(I).flag = True
      Next I
      CondBroadcast(cond(0))
   MutexUnlock(mutex)
   Sleep 1000, 1  '' wait for all thread loops completed
   Print
   Print "----------------------------------------------------------"
   Print

   Print "Send a CondSignal to any thread among #4 to #6:"
   MutexLock(mutex)
      For I As Integer = 4 To 6
         mythreads(I).flag = True
      Next I
      CondSignal(cond(0))
   MutexUnlock(mutex)
   Sleep 1000, 1  '' wait for a thread loop completed
   Print "Send a CondSignal to any thread among #4 to #6:"
   MutexLock(mutex)
      For I As Integer = 4 To 6
         mythreads(I).flag = True
      Next I
      CondSignal(cond(0))
   MutexUnlock(mutex)
   Sleep 1000, 1  '' wait for a thread loop completed
   Print "Send a CondSignal to any thread among #4 to #6:"
   MutexLock(mutex)
      For I As Integer = 4 To 6
         mythreads(I).flag = True
      Next I
      CondSignal(cond(0))
   MutexUnlock(mutex)
   Sleep 1000, 1  '' wait for a thread loop completed
   Print

   Print "Send a CondSignal to any thread among #4 to #6:"
   MutexLock(mutex)
      For I As Integer = 4 To 6
         mythreads(I).flag = True
      Next I
      CondSignal(cond(0))
   MutexUnlock(mutex)
   Sleep 1000, 1  '' wait for a thread loop completed
   Print "Send a CondSignal to any thread among #4 to #6:"
   MutexLock(mutex)
      For I As Integer = 4 To 6
         mythreads(I).flag = True
      Next I
      CondSignal(cond(0))
   MutexUnlock(mutex)
   Sleep 1000, 1  '' wait for a thread loop completed
   Print "Send a CondSignal to any thread among #4 to #6:"
   MutexLock(mutex)
      For I As Integer = 4 To 6
         mythreads(I).flag = True
      Next I
      CondSignal(cond(0))
   MutexUnlock(mutex)
   Sleep 1000, 1  '' wait for a thread loop completed
   Print

   Print "Send a CondSignal to any thread among #4 to #6:"
   MutexLock(mutex)
      For I As Integer = 4 To 6
         mythreads(I).flag = True
      Next I
      CondSignal(cond(0))
   MutexUnlock(mutex)
   Sleep 1000, 1  '' wait for a thread loop completed
   Print "Send a CondSignal to any thread among #4 to #6:"
   MutexLock(mutex)
      For I As Integer = 4 To 6
         mythreads(I).flag = True
      Next I
      CondSignal(cond(0))
   MutexUnlock(mutex)
   Sleep 1000, 1  '' wait for a thread loop completed
   Print "Send a CondSignal to any thread among #4 to #6:"
   MutexLock(mutex)
      For I As Integer = 4 To 6
         mythreads(I).flag = True
      Next I
      CondSignal(cond(0))
   MutexUnlock(mutex)
   Sleep 1000, 1  '' wait for a thread loop completed
   Print
   Print "----------------------------------------------------------"
   Print

   For I As Integer = 1 To 3
      Print "Send to finish a CondSignal to thread #" & I &":"
      MutexLock(mutex)
         mythreads(I).flag = True
         mythreads(I).quit = True
         CondSignal(cond(I))
      MutexUnlock(mutex)
      Sleep 1000, 1  '' wait for the thread loop completed
      Print
   Next I
   Print "----------------------------------------------------------"
   Print

   Print "Send to finish a single CondBroadcast to all threads from #4 to #6:"
   MutexLock(mutex)
      For I As Integer = 4 To 6
         mythreads(I).flag = True
         mythreads(I).quit = True
      Next I
      CondBroadcast(cond(0))
   MutexUnlock(mutex)
   Sleep 1000, 1  '' wait for all thread loops completed
   Print
   Print "----------------------------------------------------------"
   Print

   For I As Integer = 1 To 3
      ThreadWait(mythreads(I).handle)
      CondDestroy(cond(I))
   Next I
   For I As Integer = 4 To 6
      ThreadWait(mythreads(I).handle)
   Next I
   Print "All threads from #1 to #6 are finished."
   Print

   MutexDestroy(mutex)
   CondDestroy(cond(0))

   Sleep

		Output (for example):

   Threads from #1 To #6 are created:
      thread #1 Is running
      thread #3 Is running
      thread #2 Is running
      thread #5 Is running
      thread #4 Is running
      thread #6 Is running

   ----------------------------------------------------------

   Send a CondSignal To thread #3:
      thread #3 Is signaled

   Send a CondSignal To thread #2:
      thread #2 Is signaled

   Send a CondSignal To thread #1:
      thread #1 Is signaled

   ----------------------------------------------------------

   Send a Single CondBroadcast To all threads from #4 To #6:
      thread #5 Is signaled
      thread #6 Is signaled
      thread #4 Is signaled
   Send a Single CondBroadcast To all threads from #4 To #6:
      thread #6 Is signaled
      thread #4 Is signaled
      thread #5 Is signaled
   Send a Single CondBroadcast To all threads from #4 To #6:
      thread #5 Is signaled
      thread #4 Is signaled
      thread #6 Is signaled

   ----------------------------------------------------------

   Send a CondSignal To Any thread among #4 To #6:
      thread #5 Is signaled
   Send a CondSignal To Any thread among #4 To #6:
      thread #4 Is signaled
   Send a CondSignal To Any thread among #4 To #6:
      thread #6 Is signaled

   Send a CondSignal To Any thread among #4 To #6:
      thread #5 Is signaled
   Send a CondSignal To Any thread among #4 To #6:
      thread #4 Is signaled
   Send a CondSignal To Any thread among #4 To #6:
      thread #6 Is signaled

   Send a CondSignal To Any thread among #4 To #6:
      thread #5 Is signaled
   Send a CondSignal To Any thread among #4 To #6:
      thread #4 Is signaled
   Send a CondSignal To Any thread among #4 To #6:
      thread #6 Is signaled

   ----------------------------------------------------------

   Send To finish a CondSignal To thread #1:
      thread #1 Is finishing

   Send To finish a CondSignal To thread #2:
      thread #2 Is finishing

   Send To finish a CondSignal To thread #3:
      thread #3 Is finishing

   ----------------------------------------------------------

   Send To finish a Single CondBroadcast To all threads from #4 To #6:
      thread #4 Is finishing
      thread #5 Is finishing
      thread #6 Is finishing

   ----------------------------------------------------------

   All threads from #1 To #6 are finished.

Back to top

15. How to optimize sequencing of successive user tasks executed by 
threading?
   The delay between the return of 'ThreadCreate()' and the start of the 
   thread code (first line of thread code) can be estimated at about 50 
   microseconds on average, but can go up to a few milliseconds at worst.
   (see FAQ 12. What is the execution delay of the code of a thread after the thread is created by 'ThreadCreate'?)

   This is why a child thread can be launched only once (by a constructor 
   for example) and execute a permanent waiting loop of user tasks (to 
   avoid a thread launch latency each time), then at end stopped (by a 
   destructor).
   The synchronization between the main thread and the child thread (start 
   of each user task and user task completed) can be managed by means of 2 
   mutexes.

   Example to estimate the average time to execute a sequence of user tasks 
   (with empty user procedure body):
      - either launched by successive threads,
      - or launched by a single thread. 
   Sub userTask(ByVal p As Any Ptr)   '' task to execute
   End Sub

   Dim As Double t

   '---------------------------------------------------------------------------

   Print "Successive (empty) user tasks executed by one thread for each:"
   t = Timer
   For i As Integer = 1 To 10000
      Dim As Any Ptr p = ThreadCreate(@userTask)
      ThreadWait(p)
   Next i
   t = Timer - t
   Print Using "######.### microdeconds per user task"; t * 100
   Print

   '---------------------------------------------------------------------------

   Type thread
      Public:
         Dim As Sub(ByVal p As Any Ptr) task  '' pointer to user task
         Declare Sub Launch()                 '' launch user task
         Declare Sub Wait()                   '' wait for user task completed
         Declare Constructor()
         Declare Destructor()
      Private:
         Dim As Any Ptr mutex1
         Dim As Any Ptr mutex2
         Dim As Any Ptr handle
         Dim As Boolean quit
         Declare Static Sub proc(ByVal pthread As thread Ptr)
   End Type

   Constructor thread()
      This.mutex1 = MutexCreate
      This.mutex2 = MutexCreate
      MutexLock(This.mutex1)
      MutexLock(This.mutex2)
      This.handle = ThreadCreate(CPtr(Any Ptr, @thread.proc), @This)
   End Constructor

   Destructor thread()
      This.quit = True
      MutexUnlock(This.mutex1)
      ThreadWait(This.handle)
      MutexDestroy(This.mutex1)
      MutexDestroy(This.mutex2)
   End Destructor

   Sub thread.proc(ByVal pthread As thread Ptr)
      Do
         MutexLock(pthread->mutex1)    '' wait for launching task
         If pthread->quit = True Then Exit Sub
         pthread->task(pthread)
         MutexUnlock(pthread->mutex2)  '' task completed
      Loop
   End Sub

   Sub thread.Launch()
      MutexUnlock(This.mutex1)
   End Sub

   Sub thread.Wait()
      MutexLock(This.mutex2)
   End Sub

   Print "Successive (empty) user tasks executed by a single thread for all:"
   t = Timer
   Dim As thread Ptr pThread = New Thread
   pThread->task = @userTask
   For i As Integer = 1 To 10000
      pThread->Launch()
      pThread->Wait()
   Next i
   Delete pThread
   t = Timer - t
   Print Using "######.### microdeconds per user task"; t * 100
   Print

   Sleep

		Output (for example):

   Successive (empty) user tasks executed by one thread For each:
      145.004 microdeconds per user task

   Successive (empty) user tasks executed by a Single thread For all:
   	 6.691 microdeconds per user task

Back to top

16. Why is multi-threading performance penalized by many shared memory 
accesses (even more in writing mode)?
   Each core has its own cache memory that allows to buffer the useful data 
   (in read and write) of the shared memory.
   Consequently, a cache coherence algorithm between cores is executed, to 
   keep, in case of writing in the cache and for the common memory areas 
   between caches, the most recent values â€‹â€‹among all the caches 
   concerned.
   It is this algorithm which penalizes the performance of multi-threading 
   in the case of multiple accesses in shared memory, even more 
   particularly in write mode.

   It is therefore necessary to limit as much as possible the access of 
   threads to shared memory, even more in writing.
   For example, all intermediate results of threads could be performed in 
   local memory, and only the final useful ones put in shared memory.

   Example of a member thread procedures computing the sum of the first N 
   integers, by accumulation directly in the shared memory ('SumUpTo_1()') 
   or internally in its local memory before copy back ('SumUpTo_2'()'): 
   Type Thread
      Dim As UInteger valueIN
      Dim As Double valueOUT
      Dim As Any Ptr pHandle
      Declare Static Sub SumUpTo_1(ByVal pt As Thread Ptr)
      Declare Static Sub SumUpTo_2(ByVal pt As Thread Ptr)
   End Type

   Sub Thread.SumUpTo_1(ByVal pt As Thread Ptr)
      pt->valueOut = 0
      For I As UInteger = 1 To pt->valueIN
         pt->valueOUT += I
      Next I
   End Sub

   Sub Thread.SumUpTo_2(ByVal pt As Thread Ptr)
      Dim As Double value = 0
      For I As UInteger = 1 To pt->valueIN
         value += I
      Next I
      pt->valueOUT = value
   End Sub

   Sub MyThreads(ByVal pThread As Any Ptr, ByVal threadNB As UInteger = 1)
      Dim As Thread td(1 To threadNB)
      Dim As Double t
      
      t = Timer
      For i As Integer = 1 To threadNB
         td(i).valueIN = 100000000 + i
         td(i).pHandle = ThreadCreate(pThread, @td(i))
      Next I
      For i As Integer = 1 To threadNB
         ThreadWait(td(i).pHandle)
      Next I
      t = Timer - t

      For i As Integer = 1 To threadNB
         Print "   SumUpTo(" & td(i).valueIN & ") = " & td(i).valueOUT, _
              "(right result : " & (100000000# + i) * (100000000# + i + 1) / 2 & ")"
      Next I
      Print "      total time : " & t & " s"
      Print
   End Sub

   Print
   For i As Integer = 1 To 4
      Print "Each thread (in parallel) accumulating result directly in shared memory:"
      Mythreads(@Thread.SumUpTo_1, I)
      Print "Each thread (in parallel) accumulating result internally in its local memory:"
      Mythreads(@Thread.SumUpTo_2, I)
      Print "-----------------------------------------------------------------------------"
      Print
   Next i

   Sleep

		Output (for example):

   Each thread (in parallel) accumulating result directly in Shared memory:
      SumUpTo(100000001) = 5000000150000001  (Right result : 5000000150000001)
   	  total Time : 1.668927300015184 s

   Each thread (in parallel) accumulating result internally in its Local memory:
      SumUpTo(100000001) = 5000000150000001  (Right result : 5000000150000001)
   	  total Time : 1.004467599958389 s

   -----------------------------------------------------------------------------

   Each thread (in parallel) accumulating result directly in Shared memory:
      SumUpTo(100000001) = 5000000150000001  (Right result : 5000000150000001)
      SumUpTo(100000002) = 5000000250000003  (Right result : 5000000250000003)
   	  total Time : 4.314032700025791 s

   Each thread (in parallel) accumulating result internally in its Local memory:
      SumUpTo(100000001) = 5000000150000001  (Right result : 5000000150000001)
      SumUpTo(100000002) = 5000000250000003  (Right result : 5000000250000003)
   	  total Time : 1.032165899962706 s

   -----------------------------------------------------------------------------

   Each thread (in parallel) accumulating result directly in Shared memory:
      SumUpTo(100000001) = 5000000150000001  (Right result : 5000000150000001)
      SumUpTo(100000002) = 5000000250000003  (Right result : 5000000250000003)
      SumUpTo(100000003) = 5000000350000006  (Right result : 5000000350000006)
   	  total Time : 6.727616399944395 s

   Each thread (in parallel) accumulating result internally in its Local memory:
      SumUpTo(100000001) = 5000000150000001  (Right result : 5000000150000001)
      SumUpTo(100000002) = 5000000250000003  (Right result : 5000000250000003)
      SumUpTo(100000003) = 5000000350000006  (Right result : 5000000350000006)
   	  total Time : 1.128656100041894 s

   -----------------------------------------------------------------------------

   Each thread (in parallel) accumulating result directly in Shared memory:
      SumUpTo(100000001) = 5000000150000001  (Right result : 5000000150000001)
      SumUpTo(100000002) = 5000000250000003  (Right result : 5000000250000003)
      SumUpTo(100000003) = 5000000350000006  (Right result : 5000000350000006)
      SumUpTo(100000004) = 5000000450000010  (Right result : 5000000450000010)
   	  total Time : 6.829728199980309 s

   Each thread (in parallel) accumulating result internally in its Local memory:
      SumUpTo(100000001) = 5000000150000001  (Right result : 5000000150000001)
      SumUpTo(100000002) = 5000000250000003  (Right result : 5000000250000003)
      SumUpTo(100000003) = 5000000350000006  (Right result : 5000000350000006)
      SumUpTo(100000004) = 5000000450000010  (Right result : 5000000450000010)
   	  total Time : 1.164915200012842 s

   -----------------------------------------------------------------------------

      One can check that the multi-threading performance is strongly 
      penalized by many shared memory accesses in write mode:
         For the case where the thread accumulates the result in shared 
         memory, there is no longer any gain from multi-threading (and even 
         a little loss), whereas for the case where the thread accumulates 
         the result in internal memory, the gain is almost at the 
         theoretical maximum value.

   On the other hand, we observe a smaller degradation in multi-threading 
   performance when accessing shared memory in read-only mode.

Back to top

17. Why is multi-threading performance heavily penalized by many 
manipulation of var-len strings and var-len arrays?
   For all pseudo-objects like var-len strings and var-len arrays, only the 
   descriptors can be put into local memory but not the data itself which 
   is always on the heap (only fixed-length data can be put into local 
   memory).
   The heap is shared memory and this incurs penality on multi-threading 
   performance as described in the above FAQ.
   (see FAQ 16. Why is multi-threading performance penalized by many shared memory accesses (even more in writing mode)?)

   For var-len arrays, local fixed-len arrays can be used instead, since 
   this array data is always placed in local scope memory.
   Not only do you have to define a fixed maximum size to allocate for each 
   array, but for each of them you have to associate an index variable (per 
   dimension if necessary) that points to the last useful element ('Redim' 
   is replaced by updating this index variable).

   For var-len strings, local fix-len [z]strings can be used instead, since 
   these [z]string data are always placed in local scope memory.
   All built-in string functions except 'Len()' and 'Asc()' and all string 
   operators should also not be used on [z]strings since they work 
   internally with var-len strings. Instead, use user code that only works 
   on [z]string indexes.
   Note:
      But fix-len strings ('Dim As String * N') are less convenient to use 
      than fix-len zstrings ('Dim As Zstring * N'), because the former 
      cannot be passed by reference to a procedure (but only by copy), 
      unlike the latter ('Byref As Zstring').

   Additionally, all dynamic memory allocation/reallocation/deallocation 
   requests (to be thread-safe) are serialized internally using mutex 
   locking and unlocking.

   The following example compares the multithreaded performance of two 
   types of code:
      - code with var-len strings using its built-in functions and 
      operators like '= (assign)', 'Instr()', 'Mid()' and 'Ucase()',
      - code with fix-len zstrings with user code equivalent to the 
      previous built-in functions and operators, but operating only on 
      zstring indexes.
         ("Asc()" and "Len()" are the only ones used because they have no 
         impact on performance)
   Type Thread
      Dim As UInteger value
      Dim As Any Ptr pHandle
      Declare Static Sub thread1(ByVal pt As Thread Ptr)
      Declare Static Sub thread2(ByVal pt As Thread Ptr)
   End Type

   Sub Thread.thread1(ByVal pt As Thread Ptr)
      Dim As Integer result
      For n As Integer = 1 To pt->value
         Dim As String s1
         Dim As String s2
         Dim As String s3
         s1 = "FreeBASIC rev 1.20"
         result = InStr(s1, "rev")
         s2 = Mid(s1, result)
         s3 = UCase(s2)
      Next n
   End Sub

   Sub Thread.thread2(ByVal pt As Thread Ptr)
      Dim As Integer result
      For n As Integer = 1 To pt->value
         Dim As ZString * 256 z1
         Dim As ZString * 256 z2
         Dim As ZString * 256 z3
         ' instead of: z1 = "FreeBASIC rev 1.20"
         For i As Integer = 0 To Len("FreeBASIC rev 1.20")
            z1[i] = ("FreeBASIC rev 1.20")[i]
         Next i
         ' instead of: result = Instr(z1, "rev")
         result = 0
         For i As Integer = 0 To Len(z1) - Len("rev")
            For j As Integer = 0 To Len("rev") - 1
               If z1[i + j] <> ("rev")[j] Then Continue For, For
            Next j
            result = i + 1
            Exit For
         Next i
         ' instead of: z2 = Mid(z1, result)
         For i As Integer = result - 1 To Len(z1)
            z2[i - result + 1] = z1[i]
         Next i
         ' instead of: z3 = Ucase(z2)
         For i As Integer = 0 To Len(z2)
            z3[i] = z2[i]
            If z3[i] >= Asc("a") AndAlso z3[i] <= Asc("z") Then z3[i] -= 32
         Next i
      Next n
   End Sub

   Sub MyThreads(ByVal pThread As Any Ptr, ByVal threadNB As UInteger = 1)
      Dim As Thread td(1 To threadNB)
      Dim As Double t
      
      t = Timer
      For i As Integer = 1 To threadNB
         td(i).value = 100000
         td(i).pHandle = ThreadCreate(pThread, @td(i))
      Next I
      For i As Integer = 1 To threadNB
         ThreadWait(td(i).pHandle)
      Next I
      t = Timer - t

      Print "      total time for " & threadNB & " threads in parallel: " & t & " s"
      Print
   End Sub

   Print
   For i As Integer = 1 To 8
      Print "Each thread using var-len strings, with its built-in functions and operators:"
      Mythreads(@Thread.thread1, I)
      Print "Each thread using fix-len zstrings, with user code working on zstring indexes:"
      Mythreads(@Thread.thread2, I)
      Print "------------------------------------------------------------------------------"
      Print
   Next i

   Sleep

		Output (for example):

   Each thread Using Var-Len strings, With its built-in functions And operators:
   	  total Time For 1 threads in parallel: 0.08449090004432946 s

   Each thread Using Fix-Len zstrings, With user code working On ZString indexes:
   	  total Time For 1 threads in parallel: 0.02201449999120086 s

   ------------------------------------------------------------------------------

   Each thread Using Var-Len strings, With its built-in functions And operators:
   	  total Time For 2 threads in parallel: 0.1947050000308082 s

   Each thread Using Fix-Len zstrings, With user code working On ZString indexes:
   	  total Time For 2 threads in parallel: 0.02090729994233698 s

   ------------------------------------------------------------------------------

   Each thread Using Var-Len strings, With its built-in functions And operators:
   	  total Time For 3 threads in parallel: 0.3338784999214113 s

   Each thread Using Fix-Len zstrings, With user code working On ZString indexes:
   	  total Time For 3 threads in parallel: 0.0279372000368312 s

   ------------------------------------------------------------------------------

   Each thread Using Var-Len strings, With its built-in functions And operators:
   	  total Time For 4 threads in parallel: 0.4927077000029385 s

   Each thread Using Fix-Len zstrings, With user code working On ZString indexes:
   	  total Time For 4 threads in parallel: 0.02361949998885393 s

   ------------------------------------------------------------------------------

   Each thread Using Var-Len strings, With its built-in functions And operators:
   	  total Time For 5 threads in parallel: 0.7089884000597522 s

   Each thread Using Fix-Len zstrings, With user code working On ZString indexes:
   	  total Time For 5 threads in parallel: 0.02638950000982732 s

   ------------------------------------------------------------------------------

   Each thread Using Var-Len strings, With its built-in functions And operators:
   	  total Time For 6 threads in parallel: 0.9172402999829501 s

   Each thread Using Fix-Len zstrings, With user code working On ZString indexes:
   	  total Time For 6 threads in parallel: 0.0310587000567466 s

   ------------------------------------------------------------------------------

   Each thread Using Var-Len strings, With its built-in functions And operators:
   	  total Time For 7 threads in parallel: 1.159198799985461 s

   Each thread Using Fix-Len zstrings, With user code working On ZString indexes:
   	  total Time For 7 threads in parallel: 0.02898070006631315 s

   ------------------------------------------------------------------------------

   Each thread Using Var-Len strings, With its built-in functions And operators:
   	  total Time For 8 threads in parallel: 1.403980100061744 s

   Each thread Using Fix-Len zstrings, With user code working On ZString indexes:
   	  total Time For 8 threads in parallel: 0.03312029992230237 s

   ------------------------------------------------------------------------------

      One can check that the multi-threading performance is strongly 
      penalized by many var-len string manipulation:
         For the case where the thread uses var-len strings and its 
         built-in functions and operators, there is no longer any gain from 
         multi-threading (and even losses), whereas for the case where the 
         thread uses fix-len zstrings and user code working on zstring 
         indexes only (except 'Asc()' and 'Len()' usage), the gain is 
         almost at the theoretical maximum value.

Back to top

See also
   * Multi-Threading Overview
   * Threads
   * Mutual Exclusion
   * Conditional Variables
   * Critical Sections
   * Emulate a TLS (Thread Local Storage) and a TP (Thread Pooling) feature




============================================================================
    Making Binaries

------------------------------------------------------ ProPgExecutables ----
Executables

Making a binary executable file from FreeBASIC source files.

Preamble:

   A binary file is simply one in a binary (i.e. non-text) format:
      - The binary format means that the file's contents should not be 
      transformed for platform-specific reasons (e.g. replacing newlines 
      from \n to \r\n).
      - Binary files are not necessarily executable, for example a library 
      compiled to '*.dll' or '*.a' form is a binary but not an executable.
      - Executable files are not necessarily binary, for example a script 
      in text form can be made executable on Operating Systems.

   An executable file is one which can be executed (it can be run on the 
   command-line by writing the name of the file itself as the command).
   On Windows, the file's extension must be one of a fixed set of 
   executable file extensions, including '*.exe'.
   On Unix systems, the file's "executable" flag must also be set.

   FreeBASIC consists of fbc (the command line compiler/linker), the 
   runtime libraries, and FreeBASIC header files for third-party libraries.
   In order to produce executables, fbc uses the GNU binutils (assembler, 
   linker). When compiling for architectures other than 32bit x86, fbc 
   depends on gcc to generate assembly.

   FreeBASIC provides the FreeBASIC compiler/linker program (fbc or 
   fbc.exe), as well as the tools and libraries it uses:
      - fbc is a command line program that takes FreeBASIC source/include 
      files ('*.bas'/'*.bi') and object/library files ('*.o'/'*.a'), then 
      compiles them into executables.
      - fbc is typically invoked by Integrated Development Environments 
      (IDEs) or text editors, from a terminal or command prompt, or through 
      build-systems such as makefiles.
      - fbc itself is not a graphical code editor or IDE!

   By default, FreeBASIC programs are linked against various system and/or 
   support libraries, depending on the platform.
   Those include the DJGPP libraries used by FreeBASIC for DOS and the 
   MinGW/GCC libraries used by FreeBASIC for Windows.

Compiling an executable, in general
   fbc is a compiler that takes fbc source code and transforms it in to a 
   file that can be loaded and executed (run) by the operating system.
   fbc doesn't do this all on it's own. It uses some intermediate files and 
   other tools to complete this transformation.

   The "main" entry point of an executable
      An executable needs a starting point.
      This starting point which we will call the "main" function or "main" 
      entry point needs to be recorded in the executable so that when the 
      executable file is loaded by the operating system, the operating 
      system knows where to begin execution of the program.

      By default, the "main" function or starting point will be the first 
      line of the first basic source file on the command line:
         $ fbc program.bas module1.bas module2.bas
            "program" becomes the main module because it is first, and fbc 
            will generate an implicit "main" function that will be executed 
            first when the executable is loaded.

      This default can be overridden with the '-m module' option to specify 
      a main module that is not the first source file given on the command 
      line:
         $ fbc -m program module1.bas module2.bas program.bas
            The "-m program" option tells fbc to use "program.bas" as the 
            main module, even though "program.bas" is not listed first.

      If no other option is given that will affect the compile process, 
      this "main" function is generated implicitly by fbc.
      There can be only one "main" function for an executable. It's not 
      possible to have more than one "main" function.

Compile process for an executable
   When fbc compiles basic source code, it translates the source in to 
   another format that can be used by other tools that eventually create an 
   executable.
   By default, fbc will use these other tools automatically:

   '     .-------------------------------------.
   '     |              COMPILER               |
   '     '------.----------------------.-------'
   '            | GAS backend          | GCC backend
   '            |                      |
   '     .------V-----.    gcc     .---V----.
   '     |  ASM CODE  |<-----------| C CODE |
   '     | .s or .asm |  compiler  |   .c   |
   '     '------.-----'            '--------'
   '            | (G)AS assembler
   '            |
   '     .------V------.
   '     | OBJECT CODE |
   '     | .o or .obj  |-------------.
   '     '------.------'             |
   '            | (G)AR archiver     |
   '            |                    |
   '    .-------V--------.           |
   '    | STATIC LIBRARY |           |
   '    |   .a or .lib   |---------->|
   '    '----------------'           | (G)LD linker
   '                                 |
   '                                 |----------------------------.
   '                                 |                            |
   '                      .----------V-----------.    .-----------V-----------.
   '                      |        BINARY        |    |    SHARED LIBRARY     |
   '                      | no extension or .exe |    | .so or .dll or .dylib |
   '                      '----------------------'    '-----------------------'
   '
   '
   '      Extensions are Unix convention vs Windows (ld does .lib too nowadays).
   '      In the case of shared libs, the name for Mac deviates (.dylib).
   		

   To see all the steps that fbc uses, specify '-v' on the command line to 
   see the steps.
   For example, on win32:

   $ fbc a.bas -v
   FreeBASIC Compiler - Version 1.08.0 (2021-01-24), built For win32 (32Bit)
   Copyright (C) 2004-2021 The FreeBASIC development team.
   standalone
   target:       win32, 486, 32Bit
   backend:      gas
   compiling:    a.bas -o a.asm (main module)
   assembling:   D:\fb.git\Bin\win32\as.exe --32 --strip-Local-absolute "a.asm" -o "a.o"
   linking:      D:\fb.git\Bin\win32\ld.exe -m i386pe -o "a.exe" -subsystem console
   "D:\fb.git\lib\win32\fbextra.x" --stack 1048576,1048576 -s -L "D:\fb.git\lib\win32"
   -L "." "D:\fb.git\lib\win32\crt2.o" "D:\fb.git\lib\win32\crtbegin.o" "D:\fb.git\lib\win32\fbrt0.o"
   "a.o" "-(" -lfb -lgcc -lmsvcrt -lkernel32 -luser32 -lmingw32 -lmingwex -lmoldname -lgcc_eh "-)"
   "D:\fb.git\lib\win32\crtend.o"
   		

   Tools:
      - [ fbc ] compiler translate *.bas in to *.asm or *.c files
      - [ gcc ] compiler translate *.c files in to *.asm files
      - [ as ] assembler translate *.asm files in to *.o object files
      - [ ld ] linker join *.o files (and other files) in to executable 
      files
      - emscripten backend has other tools
      - llvm backend has other tools

   - GNU assembler 32-bit backend (-gen gas):
         *.bas => [ fbc ] => *.asm compile (first stage) to assembly (-r or 
         -rr, -R or -RR)
         *.asm => [ as ] => *.o assemble to object file (-c, -C)
         *.o => [ ld ] => *[.exe] link to executable

   - GNU assembler 64-bit backend (-gen gas64):
         *.bas => [ fbc ] => *.asm compile (first stage) to assembly (-r or 
         -rr, -R or -RR)
         *.asm => [ as ] => *.o assemble to object file (-c, -C)
         *.o => [ ld ] => *[.exe] link to executable

   - GCC compiler backend (-gen gcc):
         *.bas => [ fbc ] => *.c compile (first stage) to C (-r, -R)
         *.c => [ gcc ] => *.asm compile (second stage) to assembly (-rr, 
         -RR)
         *.asm => [ as ] => *.o assemble to object file (-c, -C)
         *.o => [ ld ] => *[.exe] link to executable

   Options controlling compile / assemble / link stages
      There are a few options that can control what fbc does with the 
      intermediate files and at what point the process may be stopped 
      early.

      -r, -rr, -c : stop the compile / assemble process sometime before the 
      link stage
         Compiler Option -r : compile up to first stage, keep file 
         (*.asm/*.c), and stop
         Compiler Option -rr : compile up to second stage, keep file 
         (*.asm), and stop
         Compiler Option -c : compile up to assembly stage, keep file 
         (*.o), and stop

      -R, -RR, -C : keep intermediate files at compile / assemble stages 
      then continue to next stage
         Compiler Option -R : don't delete compile (first stage) 
         intermediate file (*.asm/*.c)
         Compiler Option -RR : don't delete compile (second stage) 
         intermediate file (*.asm)
         Compiler Option -C : don't delete assemble stage intermediate file 
         (*.o)

      -r : option overrides -rr, -RR, -c, -C
      -rr : overrides overrides -c, -C
      -r and -rr : behave the same if there is only one compile stage
      -R and -RR : behave the same if there is only one compile stage

      -r, -rr, -c : override the default behaviour of creating an implicit 
      "main" entry point, and no "main" function is created by default.
      To have a "main" entry point when using the -r, -rr, -c, options, 
      then '-m module' option needs to be used to indicate which module 
      should have an "main" function.

   Note:
      Before fbc version 1.09.0, -gen gas64 generated a .a64 file extension 
      for assembler (instead of .asm).

Execution order of the different modules
   An executable program needs a "main" point of entry (in the main module 
   user code).
   fbc may or may not create an implicit main function, depending on 
   options or method of building an executable.
   The module constructors of modules run before main, the module 
   destructors of modules run after main.

   The module-level codes of other modules (than the main module) are put 
   in implicit module constructors which are consequently executed before 
   the module-level code of the main module.
   But it would be good practice that module-level code only be in the main 
   module.
   More generally, all module constructors and module destructors should be 
   noted with a big WARNING on their use. Because the corresponding code is 
   run outside of user code, it's quite likely that fbc's error checking 
   and some runtime facilities won't work as expected.

   A high level description of the start-up framework:
      - At compile time make arrays of addresses for all the module 
      constructors and destructors.
      - At link time, store the arrays in the executable.
      - At run time, the start-up framework will:
            - call all the module constructors in the array,
            - call the main module user code,
            - on exit (or error), call all the module destructors (usually, 
            depends on how the program failed though).

See also
   * fbc command-line
   * Static Libraries
   * Shared Libraries (DLLs)
   * Profiling with fb's profiler
   * Profiling for gmon/gprof
   * Embed and Access binary Data in Executable



-------------------------------------------------- ProPgStaticLibraries ----
Static Libraries

A static library is compiled code that can be later used when building an 
executable.

When the compiler makes an executable, the basic source files are first 
turned in to object files.  The object files are then linked together to 
make an executable.  When we compile source code, we don't necessarily have 
to make an executable.  We could instead group all of the object files 
(made from sources) in to a single file called a static library.

The library is referred to as static, because when the object files which 
it contains are later linked in to an executable, a copy of all the needed 
code in the library is added to the executable.

Once the library is made, we can then use the code that it contains just as 
if we were compiling the source directly with our program.

Exchanging/Sharing variables with static library
   A static library allows the direct sharing of variables by using the 
   Common or Extern keyword, both in library code and module code.
   Otherwise, passing a parameter (by value or by reference) to a library 
   procedure or returning a variable (by value or by reference) from a 
   library function allows to indirectly exchange data (by value) or share 
   data (by reference) with a shared library.

Simple example of static library
   Following is a simple example of creating a static library using these 
   three files:
      * mylib.bas - the source for the library
      * mylib.bi - the header for the library
      * mytest.bas - a test program

   Our library will be a single module providing a single function:
   '' mylib.bas
   '' compile with: fbc -lib mylib.bas

   '' Add two numbers together and return the result
   Public Function Add2( ByVal x As Integer, ByVal y As Integer ) As Integer
     Return( x + y )
   End Function
         

      Compile the library with:
         fbc -lib mylib.bas

      The -lib option tells the compiler to take the source code, mylib.bas
      , and turn it in to an object file mylib.o, then store the object 
      file in to a library file, also called an archive, libmylib.a.  A 
      library might contain many modules (source files) each with many 
      functions, but for this simple example, it is just one each.

   To make use of the library in some other source code, we need some way 
   of telling the compiler what exactly is in the library. A good way to do 
   this is to put the declarations ( also called an interface, or API ) for 
   the library in to a header file:
   '' mylib.bi
   #inclib "mylib"
   Declare Function Add2( ByVal x As Integer, ByVal y As Integer ) As Integer
         

      There is no need to compile the header.  We want this in its source 
      form so it can be included with other source files.  The #inclib 
      statement will tell the compiler the name of a static library that we 
      need to link with when eventually making an executable.

   With our library (.a file) and a header (.bi file) we can try them out 
   in a test program:
   '' mytest.bas
   '' compile with: fbc mytest.bas
   #include Once "mylib.bi"
   Print Add2(1,2)
         

      The #include statement tells the compiler to include the source code 
      from mylib.bi just as if we had typed it in to the original source.  
      With the way we have written our include file, it tells the compiler 
      everything it needs to know about the library.

      We compile this with:
         fbc mytest.bas

      Then when we run the mytest executable, we should get the result of:

    3
   			

Advanced example of OOP static library
   Following is an advanced example of creating an OOP static library using 
   these three files:
      * varZstring.bi - the header for the library
      * varZstring.bas - the source for the library
      * varZstringTest.bas - a test program

   Similar method than above to compile the library, then compile and 
   execute the test program.

   Header file for the library:
   '' header file: 'varZstring.bi'

   Type varZstring Extends ZString
      Public:
         Declare Constructor (ByRef z As Const ZString)
         Declare Operator Cast () ByRef As ZString
         Declare Operator Let (ByRef z As Const ZString)
         Declare Property allocated () As Integer
         Declare Destructor ()
      Private:
         Dim As ZString Ptr _p
         Dim As UInteger _allocated
   End Type

   Declare Operator Len (ByRef v As varZstring) As Integer  '' mandatory for the user code to call
                                              ''    the overload Len operator and
                                              ''    not the prebuilt-in Len operator
         
Note: Take care to declare also each overload procedure, because the 
absence of declaration will not necessarily lead to a compilation error if 
its usage in the user code is syntactically compatible with the pre-built 
in procedure, but the result will obviously not be as expected.

   Source file for the library:
   '' library module: 'varZstring.bas'

   #include "varZstring.bi"

   Constructor varZstring (ByRef z As Const ZString)
      If This._p <> 0 Then
         Deallocate(This._p)
      End If
      This._allocated = Len(z) + 1
      This._p = CAllocate(This._allocated, SizeOf(ZString))
      *This._p = z
   End Constructor

   Operator varZstring.Cast () ByRef As ZString
      Return *This._p
   End Operator

   Operator varZstring.Let (ByRef z As Const ZString)
      If This._allocated < Len(z) + 1 Then
      Deallocate(This._p)
      This._allocated = Len(z) + 1
      This._p = CAllocate(This._allocated, SizeOf(ZString))
     End If
     *This._p = z
   End Operator

   Property varZstring.allocated () As Integer
      Return This._allocated
   End Property

   Destructor varZstring ()
      Deallocate(This._p)
      This._p = 0
   End Destructor

   Operator Len (ByRef v As varZstring) As Integer
      Return Len(Type<String>(v))  '' found nothing better than this
   End Operator                     ''     (or: 'Return Len(Str(v))')
         

   Test program file:
   '' test program: 'varZstringTest.bas'

   #include "varZstring.bi"  '' must contain also the overload Len operator declaration,
                       ''    otherwise the prebuilt-in Len operator is called and applied
                       ''    on the object variable (providing the length of its member data)
                     
   #inclib "varZstring"      '' one can also put this line in the 'varZstring.bi' file
                       ''   (and not in this file), but it seems a bit crooked

   Print "VARIABLE",,, "|     LEN|  SIZEOF|"
   Print "------------------------------------------|--------|--------|"

   Dim As varZstring v = "FreeBASIC"  '' adjusts memory allocation to minimum
   Print "varZstring v:", "'" & v & "'",, "|"; Using "########|"; Len(v); v.allocated

   Dim As ZString * 256 z
   z = v
   Print "Zstring    z:", "'" & z & "'",, "|"; Using "########|"; Len(z); SizeOf(z)

   v = z & " & SourceForge"  '' only increases memory allocation if necessazy
   Print "varZstring v:", "'" & v & "'", "|"; Using "########|"; Len(v); v.allocated

   v = z & " & Wiki" '' only increases memory allocation if necessazy
   Print "varZstring v:", "'" & v & "'", "|"; Using "########|"; Len(v); v.allocated

   v.Constructor(v)  '' readjusts memory allocation to minimum
   Print "varZstring v:", "'" & v & "'", "|"; Using "########|"; Len(v); v.allocated

   Sleep
         

      Output:

   VARIABLE                                  |     Len|  SizeOf|
   ------------------------------------------|--------|--------|
   varZstring v: 'FreeBASIC'                 |       9|      10|
   ZString    z: 'FreeBASIC'                 |       9|     256|
   varZstring v: 'FreeBASIC & SourceForge'   |      23|      24|
   varZstring v: 'FreeBASIC & Wiki'          |      16|      24|
   varZstring v: 'FreeBASIC & Wiki'          |      16|      17|
   			

   More than one source module can be used when making a library.  And 
   basic programs can use more than one library by including each needed 
   header.  Some libraries are so large that they might use several 
   headers.  On very large projects, making libraries out of some code 
   modules that seldom change can improve compile times dramatically.

Libraries can optionally contain debugging information specified with the -g
command line option.

A library can optionally have module constructors, a main code, and module 
destructors. The module constructors, then the main code are executed at 
library load. The module destructors are executed at library unload.

Object files, and therefore libraries, are platform specific and in some 
cases specific to a particular version of the compiler and FreeBASIC 
runtime library.

See also
   * Shared Libraries
   * #inclib
   * #include
   * Compiler Option: -lib
   * Compiler Option: -static



-------------------------------------------------- ProPgSharedLibraries ----
Shared Libraries

A shared library is compiled code that can be loaded and used later when 
running an executable.

When the compiler makes an executable, the basic source files are first 
turned in to object files.  The object files are then linked together to 
make an executable.  A shared library is much like a static library in that 
it contains object files.  But a shared library is also like an executable 
in that it only gets loaded when the executable is running.  

The library is referred to as shared, because the code in the library is 
loaded by an executable at runtime and can be loaded by more than one 
executable, even though there might only be one copy of the shared library.

Once the library is made, we can then use the code that it contains just as 
if we were compiling the source directly with our program.

Shared Library Example
Using Shared Libraries on Windows
Using Shared Libraries on Linux
Using Shared Libraries on DOS => see its own page:Shared Libraries - DOS
Executables that export symbols
Loading Shared Libraries Dynamically
Exchanging/Sharing variables with shared library on Windows
Creating import Libraries from def files, or import libraries or def files from DLL files, on Windows

Shared Library Example
   Following is a simple example of creating a shared library using these 
   three files:
      * mylib.bas - the source for the library
      * mylib.bi - the header for the library
      * mytest.bas - a test program

   Our library will be a single module providing a single function:
   '' mylib.bas
   '' compile with: fbc -dll mylib.bas

   '' Add two numbers together and return the result
   Public Function Add2( ByVal x As Integer, ByVal y As Integer ) As Integer Export
     Return( x + y )
   End Function

      Compile the library with:
         fbc -dll mylib.bas

      The -dll option tells the compiler to take the source code, mylib.bas
      , and turn it in to an object file mylib.o, then store the object 
      file in to a shared library.  The name of the shared library will 
      have a .so extension or .dll extension depending on if the platform 
      is the linux or windows version. A library might contain many modules 
      (source files) each with many functions, but for this simple example, 
      it is just one each.

      Making a shared library is almost identical to making a static 
      library except for the addition of Export specifier at first line of 
      procedure definition.  Export tells the compiler to make the function 
      visible to other executables loading the shared library.

   To make use of the library in some other source code, we need some way 
   of telling the compiler what exactly is in the library.  A good way to 
   do this is to put the declarations ( also called an interface, or API ) 
   for the library in to a header file:
   '' mylib.bi
   #inclib "mylib"
   Declare Function Add2( ByVal x As Integer, ByVal y As Integer ) As Integer

      There is no need to compile the header.  We want this in its source 
      form so it can be included with other source files.  The #inclib 
      statement will tell the compiler the name of a shared library that we 
      need to link with at runtime running an executable that needs it.

   With our library (.dll / .so file) and a header (.bi file) we can try 
   them out in a test program:
   '' mytest.bas
   '' compile with: fbc mytest.bas
   #include Once "mylib.bi"
   Print Add2(1,2)

      The #include statement tells the compiler to include the source code 
      from mylib.bi just as if we had typed it in to the original source.  
      With the way we have written our include file, it tells the compiler 
      everything it needs to know about the library.

      We compile this with:
         fbc mytest.bas

      Then when we run the mytest executable, we should get the result of:

    3
   			

   More than one source module can be used when making a library.  And 
   basic programs can use more than one library by including each needed 
   header.  Some libraries are so large that they might use several 
   headers.  On very large projects, making shared libraries out of some 
   code modules that seldom change can improve compile times and link times 
   dramatically.

   Shared libraries can optionally contain debugging information specified 
   with the -g command line option.

   A shared library can optionally have module constructors, a main code, 
   and module destructors. The module constructors, then the main code are 
   executed at library load. The module destructors are executed at library 
   unload.

   Object files, and therefore shared libraries, are platform specific and 
   in some cases specific to a particular version of the compiler and 
   FreeBASIC runtime library.

Using Shared Libraries on Windows
   On Windows, the shared library must be stored in a location where it can 
   be found by the executable that needs it a run-time.  

   The operating system may search the following directories:
      * The directory from which the executable was loaded.
      * The current directory.
      * The Windows and Windows system folder.
      * Directories list in the PATH environment variable.

   The order in which directories are searched may depend on the Windows 
   version in use, and on what settings that the operating system is 
   configured with.

Using Shared Libraries on Linux
   By default, Linux will not normally search the current directory or the 
   directory from which the executable was loaded.  You will need to 
   either:
      * copy the .so file to a directory that has shared libraries (e.g. 
        /usr/lib) and run ldconfig to configure the library.
      * modify the environment variable LD_LIBRARY_PATH to search the 
        current directory or a specific directory for the newly created 
        shared library.

   To run the executable ./mytest/ and temporarily tell linux to search the 
   current directory, use the following shell command:
   LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH ./mytest

Executables that export symbols
   If an executable has symbols that must be available to other shared 
   libraries when those shared libraries are loaded, use the Export export 
   specifier at first line of procedure definition, and the -export command 
   line option when making (linking) the executable.

   The -export option has no extra effect when used with the -dylib or -dll 
   command line options.

Loading Shared Libraries Dynamically
   Shared libraries can be loaded and used at run time by dynamically 
   loading the library and its symbols at runtime.
      * DyLibLoad can be used to load and obtain a handle to a shared 
        library.
      * DyLibSymbol is used to obtain the address of a symbol in a loaded 
        shared library (variable names not supported on Windows but only 
        procedure names).
      * DyLibFree is used to unload a shared library when it is no longer 
        needed.

   Procedures in the shared library must use the Export specifier at first 
   line of procedure definition to ensure that the symbols name is placed 
   in the shared library's export table:
   '' mydll.bas
   '' compile as: fbc -dll mydll.bas
   '' This will create mydll.dll (and libmydll.dll.a import library) on Windows,
   '' and libmydll.so on Linux.
   ''
   '' Note: libmydll.dll.a is an import library, it's only needed when creating 
   '' an executable that calls any of mydll's functions, only distribute 
   '' the DLL files with your apps, do not include the import libraries, 
   '' they are useless to end-users.

   '' Simple exported function; the <alias "..."> disables FB's default
   '' all-upper-case name mangling, so the DLL will export AddNumbers() instead of
   '' ADDNUMBERS().
   Function AddNumbers Alias "AddNumbers"( ByVal a As Integer, ByVal b As Integer ) As Integer Export
      Function = a + b
   End Function

   '' load.bas: Loads mydll.dll (or libmydll.so) at runtime, calls one of mydll's
   '' functions and prints the result. mydll is not needed at compile time.
   '' compile as: fbc test.bas
   ''
   '' Note: The compiled mydll.dll (or libmydll.so) dynamic library is expected
   '' to be available in the current directory.

   '' Note we specify just "mydll" as library file name; this is to ensure
   '' compatibility between Windows and Linux, where a dynamic library
   '' has different file name and extension.
   Dim As Any Ptr libhandle = DyLibLoad( "mydll" )
   If( libhandle = 0 ) Then
      Print "Failed to load the mydll dynamic library, aborting program..."
      End 1
   End If

   '' This function pointer will be used to call the function from mydll, after
   '' the address has been found. Note: It must have the same calling
   '' convention and parameters.
   Dim AddNumbers As Function( ByVal As Integer, ByVal As Integer ) As Integer
   AddNumbers = DyLibSymbol( libhandle, "AddNumbers" )
   If( AddNumbers = 0 ) Then
      Print "Could not retrieve the AddNumbers() function's address from the mydll library, aborting program..."
      End 1
   End If

   Randomize Timer

   Dim As Integer x = Rnd * 10
   Dim As Integer y = Rnd * 10

   Print x; " +"; y; " ="; AddNumbers( x, y )

   '' Done with the library; the OS will automatically unload libraries loaded
   '' by a process when it terminates, but we can also force unloading during
   '' our program execution to save resources; this is what the next line does.
   '' Remember that once you unload a previously loaded library, all the symbols
   '' you got from it via dylibsymbol will become invalid, and accessing them
   '' will cause the application to crash.
   DyLibFree( libhandle )

Exchanging/Sharing variables with shared library on Windows
   Windows does not support the Common or Extern keywords for directly 
   sharing variables with a shared library.
   Otherwise (running on any platform), passing a parameter (by value or by 
   reference) to a library procedure or returning a variable (by value or 
   by reference) from a library function allows to indirectly exchange data 
   (by value) or share data (by reference) with a shared library.

   Example of workaround on Windows for sharing data (by reference) between 
   main and dll code (works on any platform):
   (dll loadable statically or dynamically as desired)
   ' dllShareData.bas to be compile with -dll
   ' Sharing data between main and dll code

   ' 'Alias' clause (in addition to 'Export') allows compatibility with dll loaded statically or dynamically

   ' share main variable
   Dim Shared ByRef As Integer Idll = *CPtr(Integer Ptr, 0)
   Sub passIntByRef Alias"passIntByRef"(ByRef i As Integer) Export
      Print "   dll code receives by reference main integer"
      @Idll = @i
   End Sub

   Sub printIdll Alias"printIdll"() Export
      Print "   dll code prints its own reference"
      Print "   " & Idll
   End Sub

   Sub incrementIdll Alias"incrementIdll"() Export
      Idll += 1
   End Sub

   ' share dll variable
   Dim Shared As Integer Jdll = 5
   Function returnIntByRef Alias"returnIntByRef"() ByRef As Integer Export
      Print "   dll code returns by reference dll integer"
      Return Jdll
   End Function

   Sub printJdll Alias"printJdll"() Export
      Print "   dll code prints its dll integer"
      Print "   " & Jdll
   End Sub

   Sub incrementJdll Alias"incrementJdll"() Export
      Jdll +=1
   End Sub

   ' mainShareData.bas
   ' Sharing data between main and dll code

   ' 'Alias' clause allows compatibility with dll loaded statically or dynamically

   ' dll loaded statically
      #inclib "dllShareData"
      Declare Sub passIntByRef Alias"passIntByRef"(ByRef i As Integer)
      Declare Function returnIntByRef Alias"returnIntByRef"() ByRef  As Integer
      Declare Sub printIdll Alias"printIdll"()
      Declare Sub printJdll Alias"printJdll"()
      Declare Sub incrementIdll Alias"incrementIdll"()
      Declare Sub incrementJdll Alias"incrementJdll"()
    ' or dll loaded dynamically
      'Dim As Any Ptr libhandle = DyLibLoad("dllShareData")
      'Dim As Sub(Byref i As Integer) passIntByRef = DyLibSymbol(libhandle, "passIntByRef")
      'Dim As Function() Byref  As Integer returnIntByRef = DyLibSymbol(libhandle, "returnIntByRef")
      'Dim As Sub() printIdll = DyLibSymbol(libhandle, "printIdll")
      'Dim As Sub() printJdll = DyLibSymbol(libhandle, "printJdll")
      'Dim As Sub() incrementIdll = DyLibSymbol(libhandle, "incrementIdll")
      'Dim As Sub() incrementJdll = DyLibSymbol(libhandle, "incrementJdll")

   ' share main variable
   Dim Shared As Integer Imain = 1
   Print "main code passes by reference main integer to dll code"
   passIntByref(Imain)
   Print "main code requests dll code to print its own reference"
   printIdll()
   Print "main code increments its main integer value"
   Imain += 1
   Print "main code requests dll code to print its own reference"
   printIdll()
   Print "main code requests dll to increments its own reference"
   incrementIdll()
   Print "main code prints its main integer"
   Print "" & Imain

   Print

   ' share dll variable
   Dim Shared ByRef As Integer Jdll = *CPtr(Integer Ptr, 0)
   Print "main code requests by reference dll integer from dll code"
   Dim As Integer Ptr pJdll = @(returnIntByRef())
   Print "main code receives by reference dll integer"
   @Jdll = pJdll
   Print "main code prints its own reference"
   Print "" & Jdll
   Print "main code requests dll to increment its dll integer value"
   incrementJdll()
   Print "main code prints its own reference"
   Print "" & Jdll
   Print "main code increments its own reference"
   Jdll += 1
   Print "main code requests dll code to print its dll integer"
   printJdll()
   Print

   ' for dll loaded dynamically
      'DyLibFree(libhandle)

   Sleep

   Simpler example of workaround on Windows for sharing data (by a single 
   static function returning by reference) between main and dll code (works 
   on any platform):
   (dll loadable statically or dynamically as desired)
   ' dllShareData2.bas to be compile with -dll
   ' Sharing data between main and dll code by using static funtion returning by reference

   ' 'Alias' clause (in addition to 'Export') allows compatibility with dll loaded statically or dynamically

   Function returnIntByRef Alias"returnIntByRef"() ByRef As Integer Export
      Static As Integer Jdll = 1
      Return Jdll
   End Function

   Sub printJdll Alias"printJdll"() Export
      Print "   dll code prints the reference"
      Print "   " & returnIntByRef()
   End Sub

   Sub incrementJdll Alias"incrementJdll"() Export
      returnIntByRef() +=1
   End Sub

   ' mainShareData2.bas
   ' Sharing data between main and dll code by using static funtion returning by reference

   ' 'Alias' clause allows compatibility with dll loaded statically or dynamically

   ' dll loaded statically
      #inclib "dllShareData2"
      Declare Function returnIntByRef Alias"returnIntByRef"() ByRef  As Integer
      Declare Sub printJdll Alias"printJdll"()
      Declare Sub incrementJdll Alias"incrementJdll"()
    ' or dll loaded dynamically
      'Dim As Any Ptr libhandle = DyLibLoad("dllShareData2")
      'Dim As Function() Byref As Integer returnIntByRef = DyLibSymbol(libhandle, "returnIntByRef")
      'Dim As Sub() printJdll = DyLibSymbol(libhandle, "printJdll")
      'Dim As Sub() incrementJdll = DyLibSymbol(libhandle, "incrementJdll")

   Print "main code requests dll code to print the reference"
   printJdll()
   Print "main code prints the reference"
   Print "" & returnIntByRef()
   Print
   Print "main code requests dll to increment the reference"
   incrementJdll()
   Print "main code requests dll code to print the reference"
   printJdll()
   Print "main code prints the reference"
   Print "" & returnIntByRef()
   Print
   Print "main code increments the reference"
   returnIntByRef() += 1
   Print "main code prints the reference"
   Print "" & returnIntByRef()
   Print "main code requests dll code to print the reference"
   printJdll()
   Print

   ' for dll loaded dynamically
      'DyLibFree(libhandle)

   Sleep

   Note:
      If the shared variable (by reference) is a pointer to any structure 
      (memory buffer, type instance, etc.) then this structure is itself 
      also shared with the library (passing the pointer by reference even 
      allows a dynamic reallocation of the structure).

Creating import Libraries from def files, or import libraries or def files 
from DLL files, on Windows
   When using a third-party dll in FreeBASIC on Windows, it may be 
   necessary to manually build an import library or a def file to satisfy 
   the linker.

   Syntax to create the import library file (*.dll.a) for Windows, from the 
   def file (*.def) of an existing DLL (*.dll):
      - 32-bit:
         drive:\FreeBASIC\bin\win32\dlltool.exe -d XXX.def -l libXXX.dll.a
      - 64-bit:
         drive:\FreeBASIC\bin\win64\dlltool.exe -m i386:x86-64 --as-flags 
         --64 -d XXX.def -l libXXX.dll.a

   Syntax to create the import library file (*.dll.a) for Windows, directly 
   from an existing DLL (*.dll):
         - 32-bit:
            drive:\FreeBASIC\bin\win32\dlltool -k -d XXX.dll -l 
            libXXX.dll.a
         - 64-bit:
            drive:\FreeBASIC\bin\win64\dlltool -k -d XXX.dll -l 
            libXXX.dll.a

   Syntax to create the def file (*.def) for Windows, from an existing DLL 
   (*.dll):
         - 32-bit:
            drive:\FreeBASIC\bin\win32\dlltool --dllname XXX.dll 
            --output-def XXX.def
         - 64-bit:
            drive:\FreeBASIC\bin\win64\dlltool --dllname XXX.dll 
            --output-def XXX.def
      or using -D and -z:
         - 32-bit:
            drive:\FreeBASIC\bin\win32\dlltool -D XXX.dll -z XXX.def
         - 64-bit:
            drive:\FreeBASIC\bin\win64\dlltool -D XXX.dll -z XXX.def

   with:
      drive:\FreeBASIC\
         FreeBASIC installation path
      XXX
         name of the lib and def file

See also
   * Shared Libraries - DOS
   * Static Libraries
   * #inclib
   * #include
   * Compiler Option: -dll
   * Compiler Option: -export
   * Compiler Option: -dylib



---------------------------------------------- ProPgProfilingFbProfiler ----
Profiling with fb's profiler

Profiling can be used to analyze the performance of an application.

Since fbc 1.20.0, FreeBASIC can use fb's profiler for analyzing the 
execution of an application. The profiler information is collected while 
the program is running.
This profiling feature may give an easy to use tool to help novice and 
experienced users analyze their programs.

Some of the capabilities of this profiler implemented through fb:
      - easy to use,
      - no extra tools needed,
      - can profile (analyze) calls to external libraries.

This profiling feature may give an easy to use tool to help novice and 
experienced users analyze their programs.

The three basic steps to profiling a program are:
      - Prepare the program for profiling by passing the the appropriate 
      -profgen ... option to the FreeBASIC compiler or compile the source 
      with appropriate '-profgen ...' #Cmdline option.
      - Run the program to build the profiling report stored by default in 
      <filename[.exe]>.prf (where <filename[.exe]> is the name of the 
      executable).
      - Analyze directly the profiling report (text file).

The fb's profiler offers two types of profiling:
      1. Function call profiling
      2. Cycle count profiling (currently a work in progress on -gen gas64 
      only)

1. Function Call Profiling (with fb's profiler)

   The performance of an application might be measured by how many times 
   functions are called, how much time is spent executing those functions, 
   and which functions are calling other functions.
   This can help to identify functions that might be taking too long to 
   execute or executed too many times and that might be worth reviewing for 
   optimization.

   This feature is a reimplentation of Angelo Mottola's (lillo's) profiler 
   from 2008, rewritten to fix some issues, and then some new features 
   added on. This latest side quest started due to a desire to run some 
   kind of profiling on the fbc compiler itself, and having no luck at all 
   with gprof on windows. Years ago lillo's function call profiler was 
   removed in favor of gmon/gprof.

   This tool is not suitable for high resolution timing profiling. However, 
   it helps identify potential problem areas in a program, or gives a 
   better understanding of procedures called as starting point for 
   investigations.

   FreeBASIC supports function profiling; not basic-block or line-by-line 
   profiling.

   1.1 Preparing a Program for Profiling (with function call fb's profiler)
      Only code that is compiled with the -profgen fb command line option 
      can be so profiled.
      Pass the -profgen fb option to the FreeBASIC compiler to prepare the 
      program to be profiled or compile the source with '-profgen fb' 
      #Cmdline option:

   fbc program.bas -profgen fb
   ' or
   #cmdline "-profgen fb"

		 This will tell the compiler to insert special startup code at the 
beginning of the application as well as at the beginning of each function.

   1.2 Profiling (with function call fb's profiler) the Program
      The information needed to analyze execution of the program is 
      gathered while the program is running.
      Run the program to begin collecting the function call information.
      The profiling report is automatically stored in a file named by 
      default <filename[.exe]>.prf in the same directory as the program.

   1.3 Analyzing the Profiling Report (from function call fb's profiler)
      After compiling and running the program, the user can open the 
      default named profiling report <filename[.exe]>.prf (text file).

      There are two sections:
         - per function results - profile of individual procedures and the 
         procedures called
         - global results - profile of all procedures with respect to the 
         whole program run time

         Function: the parent function / child function profiled. Parents 
         are on the left, children are indented
         Count: number of times the procedure was called
         Time: number of seconds executing the procedure
         Total%: the percentage of execution time versus the whole run time
         Proc%: the percentage of execution time versus the procedure run 
         time

      Times are based on fb's built-in TIMER function.

      In case of multi-threading, each thread has a separate instance of 
      the profiler storing its data in thread-local storage.
      The final profiling report groups together one after the other the 
      elementary profiling reports of each thread (including firstly that 
      of the main thread). There is no inter-thread grouping.

      * Simple example:
   #cmdline "-profgen fb"

   Sub Pause_100
      Sleep 100, 1
   End Sub

   Sub Pause_200
      Sleep 200, 1
   End Sub

   Sub Pause_400
      Sleep 400, 1
   End Sub

   For i As Integer = 1 To 3
      Pause_100
   Next i

   Pause_200

   Pause_400

			Example of profiling report:
   '	.....
   '	
   '	
   '   Per function results:
   '   
   '           Function:         Count:       Time:    Total%:    Proc%:
   '   
   '   (main)                         1     0.92307    100.00%
   '   
   '           PAUSE_400              1     0.40091     43.43%    43.43%
   '           PAUSE_100              3     0.32153     34.83%    34.83%
   '           PAUSE_200              1     0.20060     21.73%    21.73%
   '           FB___MAIN              1     0.00000      0.00%     0.00%
   '   
   '   PAUSE_100                      3     0.32153     34.83%
   '   
   '           SLEEP                  3     0.32152     34.83%   100.00%
   '   
   '   PAUSE_200                      1     0.20060     21.73%
   '   
   '           SLEEP                  1     0.20059     21.73%   100.00%
   '   
   '   PAUSE_400                      1     0.40091     43.43%
   '   
   '           SLEEP                  1     0.40086     43.43%    99.99%
   '   
   '   
   '   
   '   Global results:
   '   
   '   (main)                         1     0.92307    100.00%
   '   FB___MAIN                      1     0.00000      0.00%
   '   PAUSE_100                      3     0.32153     34.83%
   '   PAUSE_200                      1     0.20060     21.73%
   '   PAUSE_400                      1     0.40091     43.43%
   '   SLEEP                          5     0.92297     99.99%

   1.4 Advanced Profiling Features (with function call fb's profiler)
      The following features allow the user to control the information 
      collected by the profiler as well as modify the profiling report, 
      compared to the default operating.

      1.4.1 Advanced procedures in the ./inc/fbc-int/profile.bi include 
      file
         The ./inc/fbc-int/profile.bi include file allows user to access 
         some advanced procedures (declared inside Namespace: FBC) for 
         working with the fb's profiler.
         These procedures expose fb's profiler as an API that can then be 
         called directly and used to generate a profiling report based on 
         whatever structure of call recording is made by the user:
               - To set the output report file name at run-time:
                     function ProfileSetFileName ( byval filename as const 
                     zstring ptr ) as long
               - To set/get options for the profiler:
                     function ProfileSetOptions ( byval options as 
                     PROFILE_OPTIONS ) as PROFILE_OPTIONS
                     function ProfileGetOptions ( ) as PROFILE_OPTIONS
                     both associated with the PROFILE_OPTIONS Enum 
                     structure (see ./inc/fbc-int/profile.bi include file)
               - To ignore a procedure when profiling:
                     sub ProfileIgnore ( byval procedurename as zstring ptr 
                     )
               - To call fb's profiler directly to perform custom profiling 
               and a report:
                  Examples of procedures:
                     sub ProfileInit () '' Initialize the profiler
                     function ProfileEnd ( byval errorcode as long ) as 
                     long '' Generate the profiling report and terminate 
                     the profiler
                     function ProfileBeginCall ( byval procedurename as 
                     const zstring ptr ) as any ptr '' Begin a call and 
                     return a caller_id pointer
                     sub ProfileEndCall ( byval procctx as any ptr ) '' End 
                     a call

         * Example for setting the profiling report file name at run-time:
   #cmdline "-profgen fb"
   #include Once "fbc-int/profile.bi"
   Using FBC

   '' automatically change the profile report name
   Dim t As String = Time
   Dim n As String = Left(t, 2) & Mid(t, 4, 2) & Right(t, 2)
   ProfileSetFileName( "prof-" & n & ".txt" )

         * Example for telling the profiler to generate a call tree 
           instead of timings and counts:
   #cmdline "-profgen fb" 
   #include Once "fbc-int/profile.bi"
   Using FBC

   ProfileSetOptions( PROFILE_OPTION_REPORT_CALLTREE ) 

   Sub A
      Print "A"
   End Sub

   Sub B
      Print "B"
   End Sub

   Sub C
      Print "C"
   End Sub

   Sub D
      Print "D"
      A
      A
      B
      B
      C
      C
   End Sub

   D

					Example of profiling report:

   '	.....
   '	
   '	
   '	Call Tree:
   '	
   '	\- (main)
   '	   |- D
   '	   |  |- A
   '	   |  |  |- FB_PRINTSTRING
   '	   |  |  \- FB_STRALLOCTEMPDESCZEX
   '	   |  |- B
   '	   |  |  |- FB_PRINTSTRING
   '	   |  |  \- FB_STRALLOCTEMPDESCZEX
   '	   |  |- C
   '	   |  |  |- FB_PRINTSTRING
   '	   |  |  \- FB_STRALLOCTEMPDESCZEX
   '	   |  |- FB_PRINTSTRING
   '	   |  \- FB_STRALLOCTEMPDESCZEX
   '	   |- FB___MAIN
   '	   \- PROFILESETOPTIONS

         * Example for calling fb's profiler directly to perform custom 
           profiling and a report:
   #include Once "fbc-int/profile.bi"
   Using FBC

   #if __FB_PROFILE__ = PROFILE_OPTION_REPORT_CALLS
   #error Do Not compile With -profgen fb
   #endif

   ProfileInit()

   Var ctx = ProfileBeginCall( @"Begin" )

   Scope
      Var ctx = ProfileBeginCall( @"Step 1" )
         Sleep 100, 1
      ProfileEndCall( ctx )
   End Scope

   Scope
      Var ctx = ProfileBeginCall( @"Step 2" )
         Sleep 200, 1
      ProfileEndCall( ctx )
   End Scope

   ProfileEndCall( ctx )

   ProfileEnd(0)

					Example of profiling report:
   '	.....
   '	
   '	
   '	Per function results:
   '	
   '	        Function:         Count:       Time:    Total%:    Proc%:
   '	
   '	(main)                         1     0.30183    100.00%
   '	
   '	        Begin                  1     0.30183    100.00%   100.00%
   '	
   '	Begin                          1     0.30183    100.00%
   '	
   '	        Step 2                 1     0.20057     66.45%    66.45%
   '	        Step 1                 1     0.10125     33.54%    33.54%
   '	
   '	
   '	
   '	Global results:
   '	
   '	(main)                         1     0.30183    100.00%
   '	Begin                          1     0.30183    100.00%
   '	Step 1                         1     0.10125     33.54%
   '	Step 2                         1     0.20057     66.45%

      1.4.2 Conditional generation of profiling code
         The user can also control a conditional generation of profiling 
         code:
            #Pragma Profile controls the generation of profiling code.
            This allows optionally including or excluding sections of 
            source code to be profiled.

            User can optionally disable profiling code generation with 
            #pragma profile = false or #pragma push( profile , false )
            Profiling code generation can be reactivated with #pragma 
            profile = true or #pragma pop( profile ) respectively

            The __FB_OPTION_PROFILE__ intrinsic define allows to indicate 
            that the profiling code is generated or not:
                  __FB_OPTION_PROFILE__ is set to non-zero when profiling 
                  code is generated
                  __FB_OPTION_PROFILE__ is set to zero when profiling code 
                  is not generated

         * Purely academic example:
   #cmdline "-profgen fb"

   Print "__FB_OPTION_PROFILE__ = " & __FB_OPTION_PROFILE__

   #pragma push( profile , False )
   Print "__FB_OPTION_PROFILE__ = " & __FB_OPTION_PROFILE__
   Sleep 100, 1
   #pragma pop( profile )

   Print "__FB_OPTION_PROFILE__ = " & __FB_OPTION_PROFILE__

					Example of profiling report:
   '	.....
   '	
   '	
   '	Per function results:
   '	
   '	        Function:                     Count:       Time:    Total%:    Proc%:
   '	
   '	(main)                                     1     0.11714    100.00%
   '	
   '	        FB_PRINTSTRING                     2     0.00517      4.42%     4.42%
   '	        FB_STRALLOCTEMPDESCZEX             2     0.00001      0.01%     0.01%
   '	        FB___MAIN                          1     0.00000      0.00%     0.00%
   '	
   '	
   '	
   '	Global results:
   '	
   '	(main)                                     1     0.11714    100.00%
   '	FB_PRINTSTRING                             2     0.00517      4.42%
   '	FB_STRALLOCTEMPDESCZEX                     2     0.00001      0.01%
   '	FB___MAIN                                  1     0.00000      0.00%

						The code profiler only takes into account 2 PRINTs (instead of 3) and 
not the SLEEP.

2. Cycle Count Profiling (with fb's profiler)

   This is currently a work in progress on -gen gas64 only.

   Cycle count fb's profiler enables cpu cycle count profiling on some 
   targets.
   It uses completely different methods than the function call fb's 
   profiler. It stores data in specially named data sections, so will only 
   work with linkers supporting arbitrarily named sections.
   After running an executable compiled with this command, it can generate 
   a basic report of cycle counts.

   For each called user procedure body, there are two different counts:
      - The profiler sums the CPU cycle counts for all internal code blocks 
      that separate possible calls from any other user procedure or 
      built-in procedure (all other called procedures are therefore 
      excluded from this first count).
      - The profiler also counts the total number of CPU cycles when 
      executing the entire user procedure body.

   2.1 Preparing a Program for Profiling (with cycle count fb's profiler)
      Only code that is compiled with the -profgen cycles command line 
      option can be so profiled.
      Pass the -profgen cycles option to the FreeBASIC compiler to prepare 
      the program to be profiled or compile the source with '-profgen 
      cycles' #Cmdline option:

   fbc program.bas -profgen cycles
   ' or
   #cmdline "-profgen cycles"

			
   2.2 Profiling (with cycle count fb's profiler) the Program
      The information needed to analyze execution of the program is 
      gathered while the program is running.
      Run the program to begin collecting the function call information.
      The profiling report is automatically stored in a file named by 
      default <filename[.exe]>.prf in the same directory as the program.

   2.3 Analyzing the Profiling Report (from cycle count fb's profiler)
      After compiling and running the program, the user can open the 
      default named profiling report <filename[.exe]>.prf (text file).

      Profile of individual procedures per module:
         total: the number of cycles between the end of the procedure and 
         its beginning
         inside: the number of cycles really "spent" inside the procedure 
         (procedure calls inside the procedure body are not taken into 
         account)
         call count: number of times the procedure was called

      * Simple example:
   #cmdline "-gen gas64"
   #cmdline "-profgen cycles"

   Sub A()
      Dim As Integer I
      For J As Integer = 1 To 1000
         I = I + 1
      Next J
   End Sub

   Sub B()
      A()
   End Sub

   Sub C()
      B()
      Print "End"
   End Sub

   C()

			Example of profiling report:
   '	.....
   '	
   '	
   '   module  function             total             inside         call count
   '   
   '   *.bas
   '   
   '           A
   '                                 4242               4242                  1
   '           B
   '                                 4473                 42                  1
   '           C
   '                               858301                169                  1
   '           main
   '                                    0                 63                  1



----------------------------------------------- ProPgProfilingGmonGprof ----
Profiling for gmon/gprof

Profiling can be used to analyze the performance of an application.

The performance of an application might be measured by how many times 
functions are called, how much time is spent executing those functions, and 
which functions are calling other functions.  This can help to identify 
functions that might be taking too long to execute or executed too many 
times and that might be worth reviewing for optimization.

FreeBASIC can use GPROF for analyzing the execution of an application.  The 
profiler information is collected while the program is running, and GPROF 
is used to report on the collected data afterward.

The three basic steps to profiling a program are:
      * 1) Prepare the program for profiling by compiling source with the 
        -profile or -profgen gmon option.
      * 2) Run the program to collection information ( stored in gmon.out 
        ).
      * 3) Analyze the information collected using GPROF.

Full documentation on GPROF is available here: 
https://ftp.gnu.org/old-gnu/Manuals/gprof-2.9.1/html_mono/gprof.html.  If 
the documentation has moved from that location, simply search the web for 
"GNU GPROF" and a relevant link should be returned.

FreeBASIC supports function profiling; not basic-block or line-by-line 
profiling.

Preparing a Program for Profiling (for gmon/gprof)
   Only code that is compiled with the -profile or -profgen gmon command 
   line option can be so profiled.
   Pass the -profile or -profgen gmon option to the FreeBASIC compiler to 
   prepare the program to be profiled.
   For example:

   fbc program.bas -profile
   Or
   fbc program.bas -profgen gmon

		This will tell the compiler to insert special startup code at the 
beginning of the application as well as at the beginning of each function.

Profiling (for gmon/gprof) the Program
   The information needed to analyze execution of the program is gathered 
   while the program is running.  Run the program to begin collecting the 
   function call information.  This information is automatically stored in 
   a file named gmon.out in the same directory as the program.

Analyzing the Program's Output
   Use GPROF to analyze the output.  The default report for GPROF includes 
   descriptions on what each of the columns of values mean.  If you are new 
   to using GPROF, you may want to first run the default report and read 
   through the descriptions.  The output from GPROF can be saved to a file 
   by redirection.

   Save output from GPROF to profile.txt:

   gprof program[.exe] > profile.txt

   Show just the flat report with no descriptions:

   gprof program[.exe] --brief --flat-profile > profile.txt

Combining the Results of More than One Session
   GPROF also has a '--sum' option for conveniently combining results from 
   multiple execution sessions.  Here is an example of usable:
   * Run your program once. This will create gmon.out.
   * Use the command :
         mv gmon.out gmon.sum 
         or 
         rename gmon.out gmon.sum.
   * Run your program again.  This will create new data in gmon.out.
   * Merge the new data in gmon.out into gmon.sum using the command: 
         gprof --sum program[.exe] gmon.out gmon.sum
   * Repeat the last two steps as often as needed. 
   * Analyze the summary data using the command: 
         gprof program[.exe] gmon.sum > profile.txt

FreeBASIC Profiling (for gmon/gprof) Internals
   When the '-profile' option is enabled, one or more bits of code are 
   added to the program.
      * Call to "_monstartup()" at the beginning of the implicit main to 
        initialize the profiling library.
      * Call to "mcount()" at the beginning of each procedure.  This is 
        how the profiling library keeps track of what function is being and 
        by which other function.
      * Linking of additional program startup object code.  (e.g. gcrt?.o 
        )

   The profiling library itself may be in a separate library or part of the 
   C runtime library.
      * mingw will require gcrt2.o and libgmon.a 
      * cygwin will require gcrt0.o and libgmon.a
      * dos will require gcrt0.o (profiler code is in libc.a) 
      * linux will require gcrt1.o (profiler code is in libc.a) 

   The details may vary from one port of FreeBASIC to the next, but source 
   code built for profiling with FreeBASIC should be compatible with other 
   languages also supporting GPROF.




============================================================================
    Preprocessor

----------------------------------------------------- ProPgPreprocessor ----
Preprocessor

The Preprocessor performs some processing on source code before the next 
step of compilation.

The preprocessor is a program that parses a text file and makes it submit 
to certain transformations.
These transformations can be the inclusion of a file, the deletion of a 
text block or the replacement of a text block.

The preprocessor performs these operations through specific commands that 
it reads in the file being scanned.

It is automatically called by the compiler, before compilation, to process 
the files to compile.

Preprocessor commands
   All preprocessor commands begin at the beginning of the line with the 
   pound sign ("#").
   See 'Preprocessor commands' to get all commands that control the 
   preprocessor.

   The main types of commands are the followings:
      * File inclusion:
            Text file inclusion allows you to factorize text that is common 
            to many other files (for example, type, constant, function, 
            etc.).
            The common text is usually put in a file with the extension 
            ".bi".
            Syntax:
               #include [once] "file"
                  file is the name of the file to include.
            The included file is also processed by the preprocessor.

            File inclusion also allows to include a library in the linking 
            process.
            Syntax:
               #inclib "libname"
                  libname is the name of the library file to include in the 
                  linking process.

      * Text replacement:
            The preprocessor makes it possible to define identifiers which, 
            used in the program, will be replaced textually by their value.
            Syntax:
               #define identifier body
                  where identifier is the identifier that will be used in 
                  the rest of the program, and body will be the replacement 
                  text that the preprocessor will use.
            Whenever the identifier identifier is encountered by the 
            preprocessor, it will be replaced by the text body throughout 
            the rest of the program (#undef identifier to undefine an 
            identifier previously defined).

            Defines are scoped (they are only visible in the scope they 
            were defined in).
            Namespaces on the other hand do not have any effect on the 
            visibility of the defines.

      * Compilation constants and conditional compilation:
            See the next 'Conditional Compilation' page of this section.

      * Macros:
            See the last page 'Macros' of this section.

      * Other commands:
            The preprocessor is able to perform other actions than those 
            mentioned above.
            The directives for performing these actions are listed below:
               - #assert condition (conditional directive for debugging)
               - #error error_text (directive for displaying error message)
               - #lang "lang" (directive to set compiler dialect)
               - #libpath "path" (directive to add search path for 
               libraries)
               - #line number ["name"](directive to set current line number 
               [and file name])
               - #pragma / #Cmdline (directive to set compiler options)
               - #Pragma Reserve (directive to reserve symbol name)
               - #print text (directive to print text)

Example
   Example with #include and #define:
   #include "vbcompat.bi"
   #define TEMPLATE "hh:mm:ss yyyy/mm/dd"

   Dim As String * Len(TEMPLATE) hour_date

   hour_date = Format(Now, TEMPLATE)

   Print hour_date, "(" & TEMPLATE & ")"

   Sleep
         

See also
   * Conditional Compilation
   * Macros



------------------------------------------- ProPgConditionalCompilation ----
Conditional Compilation

Conditional Compilation allows to change the way code is generated using '
Preprocessor commands'.

The '#define' command allows to define compilation constants, that is 
constants that describe the parameters of the platform for which the 
program is compiled.
These constants make it possible to carry out conditional compilations, 
that is to say to modify the behavior of the program according to 
parameters defined during its compilation.

The '#define' command is also used to replace identifiers of the program 
with other identifiers, for example to test several versions of the same 
function without modifying the entire program.

Compilation constants
   A clear distinction will be made between compilation constants defined 
   with the '#define' directive of the preprocessor and the constants 
   defined with the 'Const' keyword.
   Indeed, the literal constants do not reserve memory. These are immediate 
   values, defined by the compiler.
   On the other hand, the 'Const' can still have a reserved memory space. 
   This is for example the case when manipulating string literals.

   A literal constant declared with the '#define' directive of the 
   preprocessor will always retain its value (provided that it is not 
   redefined). These literal constants have no type, which can be very 
   annoying and error-prone in code.
   Their use will be reserved for compilation constants only, and the 'Const
   ' keyword will be preferred for all other constants of the program.

   The preprocessor sets a number of built-in constants automatically.
   These are the 'Intrinsic Defines' (see their list).

Conditional compilation
   The definition of identifiers and compilation constants is widely used 
   to perform so-called conditional compilation.
   Conditional compilation consists of replacing certain portions of source 
   code with others, depending on the presence or value of compilation 
   constants.
   This is achievable using conditional compilation directives.

   The most common of which are probably:
      #ifdef symbol
         ' Conditionally included statements
      #endif
         the text between the #ifdef (ie, "if defined") and the #endif is 
         left as it is if the identifier symbol is known to the 
         preprocessor. Otherwise, it is deleted (the identifier can be 
         declared using just the #define command seen previously).

   There are other conditional compilation directives like:
      - #ifndef (if not defined ...)
      - #else / #elseif (otherwise ... / otherwise, if ...)
      - #if (if ...)
         the #if directive expects a constant expression as parameter (the 
         text that follows is included in the file if and only if this 
         expression is true).

   Another common application of compilation directives is the protection 
   of header files against multiple inclusions:
      #ifndef AlreadyThere
         #define AlreadyThere
         ' Text to include only once at most.
      #endif
   This prevents the text from being included multiple times, as a result 
   of multiple #include calls.
   Indeed, at the first call, AlreadyThere is not known to the 
   preprocessor. It is therefore declared and the text is included.
   On any subsequent call, AlreadyThere exists, and the text is not 
   included.
   This kind of writing is found in header files, for which in general we 
   do not want a multiple inclusion to take place.

Example
   Example of conditional compilation using the Intrinsic define 
   __FB_DEBUG__ to debug a recursive function:
   Function recursiveFactorial (ByVal n As Integer) As Integer
      If (n = 0) Then                         '' end condition
         #if __FB_DEBUG__ <> 0
            Print "end of recursion and result:";
         #endif
         Return 1
      Else                                    '' recursion loop
         #if __FB_DEBUG__ <> 0
            Print "multiply by: " & n
         #endif
        Return n * recursiveFactorial(n - 1)  '' recursive call
      End If
   End Function

   Print recursiveFactorial(5)

   Sleep
         
Output after compiling without -g option:

    120		
Output after compiling with -g option:

   multiply by: 5
   multiply by: 4
   multiply by: 3
   multiply by: 2
   multiply by: 1
   End of recursion And result: 120
   		

See also
   * Preprocessor Overview
   * Macros



----------------------------------------------------------- ProPgMacros ----
Macros

Macros are named code segments that are substituted to their names each 
time they are encountered in a program.

Macros offer a powerful way to extend the language and create reusable 
code.
One reason macros are used is performance.
They are a way of eliminating procedure call overhead because they are 
always expanded in-line.
There is no alternative for this in FreeBASIC because it does not support 
inline procedures.

Macros definition
   The preprocessor can, during the text replacement mechanism, use 
   parameters supplied to the identifier to be replaced.
   These parameters are then replaced without modification in the 
   replacement text.
   The replacement text is then called macro.

   The syntax to define a macro is as follows (see 'Preprocessor commands
   '):
      - one-line macro:
            #define identifier([parameters]) body
               parameters turn a define into a function-like macro, 
               allowing text arguments to be passed to the macro.
               identifier should be followed by the opening parentheses (() 
               immediately without any white-space in between, otherwise 
               the compiler will treat it as part of the body.
      - multi-line macro:
            #macro identifier([parameters])
               body
            #endmacro
               #macro is the multi-line version of #define.

   The # Stringize operator can be used on macro parameters to turn them 
   into string literals, and the ## Concatenate operator can be used to 
   merge tokens together.
   (see 'Preprocessor Operators')

   Defines and macros are scoped (they are only visible in the scope they 
   were defined in).
   Namespaces on the other hand do not have any effect on the visibility of 
   the defines and macros.

   The mechanism of macros allows to do the equivalent of general 
   procedures, which work for all types.
   However, care must be taken that parameters passed to a macro are 
   evaluated by it each time they are used in the macro definition. This 
   can cause performance issues or, worse, cause unwanted edge effects.

   Parentheses should always be placed around the parameters of the macro:
      - Indeed, these parameters can be compound expressions, which must be 
      computed completely before being used in the macro.
      - Parentheses force this calculation.
      - If they are not set, priority rules can generate a logic error in 
      the macro itself.
   Similarly, macros that return a value should be surrounded by 
   parentheses, in order to force their complete evaluation before using 
   them in another expression.

   Example of incorrect and correct macros:
   #define MUL1(x, y) x * y              '' incorect macro  (parameters must be enclosed in parentheses)
   #define MUL2(x, y) ( x ) * ( y )      '' incorrect macro (and returned result must also be in parentheses)
   #define MUL3(x, y) ( ( x ) * ( y ) )  '' correct macro

   Print MUL1(5-3, 1+2)^2  '' 6  (incorrect result)
   Print MUL2(5-3, 1+2)^2  '' 18 (incorrect result)
   Print MUL3(5-3, 1+2)^2  '' 36 (correct result)

   Sleep

		Thus, the parentheses ensure a consistent behavior of the macro 
(parentheses can add to macro definitions, but they are absolutely 
necessary).

Macros debug
   Using macros can be extremely unsafe and they hide a lot of pitfalls 
   which are very hard to find.
   Procedures give type checking and scoping, but macros just substitute 
   the passed argument.
   Another disadvantage of the macro is the size of the program. The reason 
   is, the pre-processor will replace all the macros in the program by its 
   real definition prior to the compilation process of the program.

   Looking only at the source code file, the only way to find out what the 
   problem is to look at the definition of the macro and try to understand 
   what happened.
   The most common error when using macros is the unbalanced open 
   parentheses (inducing error at compile-time).
   Another is to forget putting parentheses around arguments (or returned 
   result if exists) in macro definitions. That can cause some pretty nasty 
   side effects because of operator precedence (inducing error at 
   compile-time or bug at run-time).

   When the compiler detects an error inside a macro (after expanding), it 
   provides a rustic error message containing only:
      - the line number where is the call of the macro,
      - the error type,
      - the text of the call (of the macro).

   When the error is not obvious (type of error reported blurred), the only 
   solution (with only the call line number) is presently to iteratively 
   execute the following 5 steps until correction successful:
      Do
         1. call fbc on the source file, but with the '-pp' compile option 
         (fbc command emitting only the pre-processed input file, without 
         compiling),
         2. recover the pre-processed file,
         3. edit and compile directly from this pre-processed file,
         4. analyze the error, understand it, correct it, and compile again 
         the pre-processed file thus modified,
         5. postpone the equivalent correction in the concerned macro body 
         of the original source file.
      Loop

   Example of error on a short code:
      * Source file (*.bas):
   #macro FIRST(array, Operator)
     For index As Integer = LBound(array) To UBound(array) - 1
      Print " " Operator array(index) Operator ",";
     Next index
     Print array(UBound(array))
   #endmacro

   #macro Second(array)
     Print #array + ":"
     FIRST(array, +)
   #endmacro

   Dim As String test1(0 To ... ) => {"First", "Second", "Third"}
   Dim As Integer test2(0 To ...) => {1, 2 ,3}

   Second(test1)
   Print
   Second(test2)

   Sleep

				Compiler output:
               ...\FBIDETEMP.bas(18) error 20: Type mismatch, found '+' in 
               'SECOND(test2)'

      * Pre-processed file (*.pp.bas):
   Dim As String test1(0 To ... ) => {"First", "Second", "Third"}
   Dim As Integer test2(0 To ...) => {1, 2 ,3}

    Print $"test1" + ":"
    For index As Integer =LBound(test1) To UBound(test1) -1
    Print " " + test1(index) + ",";
    Next index
    Print test1(UBound(test1))
   Print
    Print $"test2" + ":"
    For index As Integer =LBound(test2) To UBound(test2) -1
    Print " " + test2(index) + ",";
    Next index
    Print test2(UBound(test2))

   Sleep

				Compiler output:
               ...\FBIDETEMP.bas(14) error 20: Type mismatch, found '+' in 
               'Print " " + test2(index) + ",";'

      * Example macro correction in source code (*.bas):
   #macro FIRST(array, Operator)
     For index As Integer = LBound(array) To UBound(array) - 1
      Print " " Operator array(index) Operator ",";
     Next index
     Print array(UBound(array))
   #endmacro

   #macro Second(array)
     Print #array + ":"
     FIRST(array, &)     ''corrected line ("&" instead of "+")
   #endmacro

   Dim As String test1(0 To ... ) => {"First", "Second", "Third"}
   Dim As Integer test2(0 To ...) => {1, 2 ,3}

   Second(test1)
   Print
   Second(test2)

   Sleep

				Output:

   test1:
    First, Second,Third

   test2:
    1, 2, 3

      Note: Another solution could be a more detailed error message from 
      compiler, relating to the call of the macro (proposal of improved 
      error message already filled in in a feature request).

Variadic macros
   Using an ellipsis "..." (3 dots) behind the last parameter in a #macro 
   or #define declaration allows creation of a variadic macro:
         #macro identifier([parameters,] variadic_parameter...)
            body
         #endmacro
      or:
         #define identifier([parameters,] variadic_parameter...) body

   So, it is possible to pass any number of arguments through the 
   variadic_parameter, which can be used in the body as if it was a normal 
   macro parameter.
   During macro expansion each occurrence of the variadic_parameter in the 
   macro replacement list is replaced by the passed arguments. The 
   variadic_parameter will expand to the full list of arguments passed to 
   it, including commas, and can also be completely empty.

   No direct means is provided to recursively access individual arguments 
   in the variable argument list.
   To distinguish between the different arguments passed by the 
   variadic_parameter, one can first convert the variadic_parameter to a 
   string literal using the # Stringize operator, then differentiate in 
   this string literal (#variadic_parameter) each passed argument by 
   locating the separators (a comma).

Examples
   Example with one-line and multi-line macros:
   #define MIN(x, y) IIf( ( x ) < ( y ), x, y )      '' maximum function-like macro
   #define MAX(x, y) IIf( ( x ) > ( y ), x, y )      '' minimum function-like macro
   #define MUL(x, y) ( ( x ) * ( y ) )               '' multiply function-like macro

   #macro REV_STR(str_dest, str_src)                 '' reverse-string sub-like macro
      For i As Integer = Len(str_src) To 1 Step -1
         str_dest &= Mid(str_src, i, 1)
      Next I
   #endmacro

   Print MIN(5 - 3, 1 + 2)    '' 2
   Print MAX(5 - 3, 1 + 2)    '' 3
   Print MUL(5 - 3, 1 + 2)^2  '' 36

   Dim As String s
   REV_STR(s, "CISABeerF")  '' FreeBASIC
   Print s

   Sleep
         

   Example with variadic macro:
   ' macro with a variadic parameter which can contain several sub-parameters:
   '   To distinguish between the different arguments passed by variadic_parameter,
   '   you can first convert variadic_parameter to a string using the Operator # (Preprocessor Stringize),
   '   then differentiate in this string (#variadic_parameter) each passed argument by locating the separators (usually a comma).

   #macro average(result, arg...)
      Scope
         Dim As String s = #arg
         If s <> "" Then
            result = 0
            Dim As Integer n
            Do
               Dim As Integer k = InStr(1, s, ",")
               If k = 0 Then
                  result += Val(s)
                  result /= n + 1
                  Exit Do
               End If
               result += Val(Left(s, k - 1))
               n += 1
               s = Mid(s, k + 1)
            Loop
         End If
      End Scope
   #endmacro

   Dim As Double result
   average(result, 1, 2, 3, 4, 5, 6)
   Print result

   ' Output : 3.5
         

See also
   * Preprocessor Overview
   * Conditional Compilation




============================================================================
    Other Topics

-------------------------------------------------------------- CptAscii ----
Table of ASCII Characters

FreeBASIC graphics programs support in all versions the same "ASCII 
extended" USA character set the old DOS (and QBasic) supported. It is also 
called CP437 or Code page 437.  Each character is represented with one (1) 
byte of data.  Here is a table.  Each entry has decimal code, hex code, and 
printed representation.

      
     0  0  ³ 16 10  ³ 32 20  ³ 48 30 0³ 64 40 @³ 80 50 P³ 96 60 `³112 70 p
     1  1  ³ 17 11  ³ 33 21 !³ 49 31 1³ 65 41 A³ 81 51 Q³ 97 61 a³113 71 q
     2  2  ³ 18 12  ³ 34 22 "³ 50 32 2³ 66 42 B³ 82 52 R³ 98 62 b³114 72 r
     3  3  ³ 19 13  ³ 35 23 #³ 51 33 3³ 67 43 C³ 83 53 S³ 99 63 c³115 73 s
     4  4  ³ 20 14  ³ 36 24 $³ 52 34 4³ 68 44 D³ 84 54 T³100 64 d³116 74 t
     5  5  ³ 21 15  ³ 37 25 %³ 53 35 5³ 69 45 E³ 85 55 U³101 65 e³117 75 u
     6  6  ³ 22 16  ³ 38 26 &³ 54 36 6³ 70 46 F³ 86 56 V³102 66 f³118 76 v
     7  7  ³ 23 17  ³ 39 27 '³ 55 37 7³ 71 47 G³ 87 57 W³103 67 g³119 77 w
     8  8  ³ 24 18  ³ 40 28 (³ 56 38 8³ 72 48 H³ 88 58 X³104 68 h³120 78 x
     9  9  ³ 25 19  ³ 41 29 )³ 57 39 9³ 73 49 I³ 89 59 Y³105 69 i³121 79 y
    10  A  ³ 26 1A  ³ 42 2A *³ 58 3A :³ 74 4A J³ 90 5A Z³106 6A j³122 7A z
    11  B  ³ 27 1B  ³ 43 2B +³ 59 3B ;³ 75 4B K³ 91 5B [³107 6B k³123 7B {
    12  C  ³ 28 1C  ³ 44 2C ,³ 60 3C <³ 76 4C L³ 92 5C \³108 6C l³124 7C |
    13  D  ³ 29 1D  ³ 45 2D -³ 61 3D =³ 77 4D M³ 93 5D ]³109 6D m³125 7D }
    14  E  ³ 30 1E  ³ 46 2E .³ 62 3E >³ 78 4E N³ 94 5E ^³110 6E n³126 7E ~
    15  F  ³ 31 1F  ³ 47 2F /³ 63 3F ?³ 79 4F O³ 95 5F _³111 6F o³127 7F 

   128 80 €³144 90 �³160 A0  ³176 B0 °³192 C0 À³208 D0 Ð³224 E0 à³240 F0 ð
   129 81 �³145 91 ‘³161 A1 ¡³177 B1 ±³193 C1 Á³209 D1 Ñ³225 E1 á³241 F1 ñ
   130 82 ‚³146 92 ’³162 A2 ¢³178 B2 ²³194 C2 Â³210 D2 Ò³226 E2 â³242 F2 ò
   131 83 ƒ³147 93 “³163 A3 £³179 B3 ³³195 C3 Ã³211 D3 Ó³227 E3 ã³243 F3 ó
   132 84 „³148 94 ”³164 A4 ¤³180 B4 ´³196 C4 Ä³212 D4 Ô³228 E4 ä³244 F4 ô
   133 85 …³149 95 •³165 A5 ¥³181 B5 µ³197 C5 Å³213 D5 Õ³229 E5 å³245 F5 õ
   134 86 †³150 96 –³166 A6 ¦³182 B6 ¶³198 C6 Æ³214 D6 Ö³230 E6 æ³246 F6 ö
   135 87 ‡³151 97 —³167 A7 §³183 B7 ·³199 C7 Ç³215 D7 ×³231 E7 ç³247 F7 ÷
   136 88 ˆ³152 98 ˜³168 A8 ¨³184 B8 ¸³200 C8 È³216 D8 Ø³232 E8 è³248 F8 ø
   137 89 ‰³153 99 ™³169 A9 ©³185 B9 ¹³201 C9 É³217 D9 Ù³233 E9 é³249 F9 ù
   138 8A Š³154 9A š³170 AA ª³186 BA º³202 CA Ê³218 DA Ú³234 EA ê³250 FA ú
   139 8B ‹³155 9B ›³171 AB «³187 BB »³203 CB Ë³219 DB Û³235 EB ë³251 FB û
   140 8C Œ³156 9C œ³172 AC ¬³188 BC ¼³204 CC Ì³220 DC Ü³236 EC ì³252 FC ü
   141 8D �³157 9D �³173 AD ­³189 BD ½³205 CD Í³221 DD Ý³237 ED í³253 FD ý
   142 8E Ž³158 9E ž³174 AE ®³190 BE ¾³206 CE Î³222 DE Þ³238 EE î³254 FE þ
   143 8F �³159 9F Ÿ³175 AF ¯³191 BF ¿³207 CF Ï³223 DF ß³239 EF ï³255 FF ÿ

 

Many of the standard ASCII characters cannot be Printed in FreeBASIC, 
because the console interprets some characters as controls: 7 is bell, 8 is 
backspace, 9 is tab, 10 is line feed, 13 is carriage return, and others.  
There are symbols associated with these characters also, but there is no 
way in FreeBASIC to output them to the screen. 

The acronym ASCII stands for American Standard Code for Information 
Interchange. For more information, see http://en.wikipedia.org/wiki/Ascii.  
The symbols for codes 32 through 127 are the same as the standard 
Latin ISO-8859-1 char set most Windows fonts use. Others are often very 
different.

In console mode (i.e. Screen (Graphics) 0/ non-graphics mode) the 
characters less than 32 or greater than 127 may display using different 
characters, depending on the operating system and code page of the screen / 
console in use.
UNICODE is a newer standard of character sets involving two or more bytes 
per character, and may be used to print other characters to a 
Unicode-enabled console.

In graphics modes, Draw String does not give special meaning to control 
characters allowing an alternative to display all characters in the set. 



------------------------------------------------------------ ProPgDates ----
Date Serials

A floating point number representing a date and time

Description
   A date serial is a number that holds a date and time value in the same 
   format used by PDS or VBDOS. The value is a count of the days from 0:00 
   AM of December 30,1899; it's mainly used for easy counting of the time 
   between two dates.

   The date serial unit is one day and the fractional part represents the 
   time of the day. If a date serial is written into an integer, the time 
   is lost. FreeBASIC date serials are not limited to dates between 1753 
   and 2078 as in VBDOS. FreeBASIC date serial handling functions use Double
   arguments.

   FreeBASIC date serial handling functions require the inclusion of 
   vbcompat.bi or datetime.bi in the source.

   A date serial can be created by the functions Now, TimeSerial+DateSerial
   , or DateValue+TimeValue.

   The functions Year, Month, Weekday, Day, Hour, Minute, Second allow to 
   recover the different components of a date serial.

   The Format function has formatting expressions to print date serials in 
   a human readable way.

Example
   #include "vbcompat.bi"
   Dim a As Double, b As Double

   a = 0
   Print "The origin of the date serials is:"
   Print Format(a, "yyyy/mm/dd hh:mm:ss")
   Print

   a = Now
   Print "The time now is: "
   Print Format(a, "yyyy/mm/dd hh:mm:ss")
   Print

   b = DateSerial(2000,1,1)
   Print Int(a-b) & " days have passed since 2000/01/01"

   


---------------------------------------------------------- ProPgRadians ----
Radian system of measuring angles

All of the built-in trigonometric functions in FreeBASIC express angles in 
radians.

Let pi the constant equal to the ratio of the circumference of a circle to 
its diameter. It can be calculated programmatically by multiplying the 
arctangent of 1 by 4.
A full circle is divided into 2 * pi radians or 360 degrees, which leads to 
the following conversions:

   pi = Atn(1) * 4
   radians = degrees * pi / 180
   degrees = radians * 180 / pi

These 3 formulas can be expressed by using macros:

   #define   pi          ( Atn(1) * 4 )
   #define   radian(x)   ( (x) * pi / 180 )
   #define   degree(x)   ( (x) * 180 / pi )
The added parentheses compared to the raw formulas are mandatory to not 
undergo an unwanted precedence change of operators when the macros are used 
in any context of expressions.



---------------------------------------------------- ProPgErrorHandling ----
Error Handling

Handling runtime errors.

   FreeBASIC can handle the errors in the following ways:
   * By default the program does nothing with the errors - they are 
     silently ignored and code continues. In this case code should process 
     possible errors in the next line by using the Err function.
   * If compiled with -e, -ex or -exx options, FreeBASIC uses QB-like 
     error handling.
   * Future OOP versions of FreeBASIC may have a java-like 
     TRY..CATCH...FINALLY exception handler implemented.

   NOTE: The following information is valid unless the error produces an OS 
   General Protection Fault (for example if the program writes outside the 
   process memory area). In these cases the OS will immediately stop the 
   program and issue an error: nothing can avoid it from inside FreeBASIC.

Default error handling
   The default FreeBASIC behavior is to set the ERR variable and continue. 

   Dim As Integer e
   Open "xzxwz.zwz" For Input As #1
   e = Err
   Print e
   Sleep
      

   (The example program supposes there is no xzxwz.zwz file). The program 
   does not stop; it sets the ERR variable and continues. The error can be 
   processed in the next line.

   Some IO functions such as Open and Put #... can be used in function 
   form, returning an error number or zero if successful.

   Print Open ("xzxwz.zwz" For Input As #1)
   Sleep
      

QuickBASIC-like error handling
   If the  -e, -ex or -exx switch is used at compile time, the program is 
   expected to have a QB-like error handler enabled. If no handler 
   processes the error, the program stops with an error.

   Notice: if QB-Like error handling is used, the programmer should be 
   prepared to handle all error conditions.

   '' Compile with QB (-lang qb) dialect

   '$lang: "qb"

   On Error Goto FAILED
   Open "xzxwz.zwz" For Input As #1
   On Error Goto 0
   Sleep
   End

   FAILED:
   Dim e As Integer
   e = Err
   Print e
   Sleep
   End
      

   On Error sets an error handling routine which the program will jump to 
   when an error is found. On Error Goto 0 disables the error handling.

   If an error handling routine is not set when an error occurs, the 
   program will stop and send the console an error message.

   Aborting program due To runtime Error 2 (file Not found)
   	

   The error handler routine can be at the end of the program, as in QB. 
   The On Local Error statement allows the setting of a local error handler 
   routine at the end of the same Sub or Function in which the error 
   occurs.

   '' Compile with -e
   '' The -e command line option is needed to enable error handling.

   Declare Sub foo
     foo
   Sleep

   Sub foo
      
      Dim filename As String
      Dim errmsg As String
      filename = ""
      On Local Error Goto fail
     Open filename For Input Access Read As #1
      Print "No error"
      On Local Error Goto 0
      Exit Sub
      
     fail:
     errmsg = "Error " & Err & _
            " in function " & *Erfn & _
            " on line " & Erl
     Print errmsg
      
   End Sub
      

   If the -e switch is used (whatever the -lang dialect), the error handler 
   must terminate the program. 
   With (-ex or -exx) and -lang qb dialect only, the error routine can end 
   by using Resume (retries the statement that caused the error) or 
   Resume Next (continues at the next instruction) .

Error codes
   See Runtime Error Codes for a listing of runtime error numbers and their 
   associated meaning.

   No user error code range is defined. If Error is used to set an error 
   code it is wise to use high values to avoid collisions with the list of 
   built-in error codes. (This built-in list may be expanded later.)

'On [Local] Error Goto' statement use
   'On [Local] Error Goto label' causes a program jump to a specified label 
   as soon as an error occurs. Such errors can be triggered by built-in 
   statements such as 'Open', 'Get', 'Put', or when the Error statement is 
   used.
   The error checking for built-in statements is only enabled if the 
   program is compiled with one of the -e, -ex or -exx options. Otherwise, 
   no jump will be performed, but the command will still consume processor 
   time.
   When triggered by the only Error statement, 'On [Local] Error Goto 
   label' remains always working even when none of these compile options 
   are used.
   'On Error Goto 0' deactivates the current error handler. If an error 
   occurs, FreeBASIC will not jump.

   The optional Local keyword (authorized only inside Sub/Function) was 
   intended to be used to define an error handler only in the same 
   procedure the 'On Local Error' is in (for compatibility with PDS 7.1 and 
   VB Dos 1.0 for example). In this case, FreeBASIC should have searched 
   for the label in the current procedure only.
   But presently, the Local clause is ignored by the compiler, and the 
   error handler can be either in the scope of the same procedure the 'On 
   [Local] Error' is in, or in the main part of the module (if defined 
   before the procedure).
   Exception when -gen gcc is used (or for the fbc 64-bit): the Local 
   clause seems to be rightly taken into account, but except inside a local 
   scope!

   'On [Local] Error Goto label' is not the best way to catch errors from a 
   built-in procedure when a syntax in the form of a function is available. 
   The return error code can be directly tested (using the returned error 
   code from function inhibits the QuickBASIC-like error checking and 
   statement 'On Error Goto').

   It is advisable to try to write programs compatible with the -lang fb 
   dialect and -exx option, because to test programs with option -exx for 
   debugging purposes is a great helping:
      - Avoid to use the statement Resume or Resume Next, because it is not 
      at all supported by -lang fb (compilation error).
      - On the other hand, sometimes when it is useful (when no form of a 
      function is available), use the statement 'On [Local] Error Goto', 
      because it runs with any option among -e, -ex, -exx. Otherwise (no 
      error checking option), 'On [Local] Error Goto' is inactive (without 
      compilation error), but it consumes CPU time.

   Accordingly and if necessary, usually write QuickBasic-like error 
   handling ('On [Local] Error Goto label' ..... 'label:' .....), with 
   conditional assembly directive depending on the value of __FB_ERR__, in 
   order not to penalize the execution speed (if not error checking option 
   is used).

   The behavior of statement 'On Error Goto' (-lang fb) regarding 
   compilation options (none, -e/-ex/-exx) is enlighten with the following 
   program including several examples (4), to be compiled with or without 
   error checking option (4*2=8 tests):
   #define Config 1
   '#DEFINE Config 2
   '#DEFINE Config 3
   '#DEFINE Config 4

   #if Config = 1 '-----------------------------------------------------------

   Open "does_not_exist" For Input As #1

   Print "main end"
   Sleep
   System

   ' - with compiler option 'none' :
   '     console output :
   '       'main end'
   '
   ' - with compiler option '-e' or '-ex' or '-exx' :
   '     console output :
   '       'Aborting due to runtime error 2 (file not found) at line 10 of .....'

   #endif '-------------------------------------------------------------------

   #if Config = 2 '-----------------------------------------------------------

   Dim As Integer Result = Open("does_not_exist" For Input As #1)
   If Result <> 0 Then
      Print "error code returned: " & Result
      Print "file not found (processed by 'Result = Open(.....)')"
   End If

   Print "main end"
   Sleep
   End

   ' - with compiler option 'none' or '-e' or '-ex' or '-exx' :
   '     console output :
   '       'error code returned: 2'
   '       'file not found (processed by 'Result = Open(.....)')'
   '       'main end'

   #endif '-------------------------------------------------------------------

   #if Config = 3 '-----------------------------------------------------------

   On Error Goto Error_Handler
   Open "does_not_exist" For Input As #1

   Print "main end"
   Sleep
   End

   error_handler:
   Print "file not found (processed by 'On Error Goto')"
   On Error Goto 0
   Print "QB-like error handling end"
   Sleep
   End

   ' - with compiler option 'none' :
   '     console output :
   '       'main end'
   '
   ' - with compiler option '-e' or '-ex' or '-exx' :
   '     console output :
   '       'file not found (processed by 'On Error Goto')'
   '       'QB-like error handling end'

   #endif '-------------------------------------------------------------------

   #if Config = 4 '-----------------------------------------------------------

   On Error Goto error_handler
   Dim As Integer Result = Open("does_not_exist" For Input As #1)
   If Result <> 0 Then
      Print "error code returned: " & Result
      Print "file not found (processed by 'Result = Open(.....)')"
   End If

   Print "main end"
   Sleep
   End

   error_handler:
   Print "file not found (processed by 'On Error Goto')"
   On Error Goto 0
   Print "QB-like error handling end"
   Sleep
   End

   ' - with compiler option 'none' or '-e' or '-ex' or '-exx' :
   '     console output :
   '       'error code returned: 2'
   '       'file not found (processed by 'Result = Open(.....)')'
   '       'main end'

   #endif '-------------------------------------------------------------------
      
The Config=2 and Config=4 sections highlight that when FB function is 
called using explicitly its returned error code (-lang fb dialect), 'On 
Error Goto' is by-passed whatever the error checking level ('none', '-e', 
'-ex', '-exx').

See also
   * Error Handling Functions
   * Runtime Error Codes



---------------------------------------------------- ProPgEventHandling ----
Event Handling

Handling (querying and processing) keyboard, mouse, and window Events.

Preamble:

   Events are basically user actions like key press, clicks, mouse 
   movements, etc., or some occurrence like system generated notifications.

   The Event type plus the ScreenEvent function constitute a built-in 
   interface provided by FreeBASIC for accessing events (keyboard, mouse, 
   and window events).
   ScreenEvent signals the events so the user can write his own event 
   handlers (which require that he keeps track of the data himself).

   By using ScreenEvent, the user can check the events as they are returned 
   by the function.
   It is assumed that this function is regularly called to fetch events as 
   they are queued internally by the system.

Event type
   The Event type is a pre-defined structure in "fbgfx.bi" (in the FB 
   Namespace for the lang fb dialect only). 
   When the user calls ScreenEvent passing an instance of Event type, 
   ScreenEvent fills in it with the event data (if an event flag is 
   returned).

   Syntax
      #include once "fbgfx.bi"
      Using FB
      Dim variable As Event

   "Event" structure
      This structure is extracted from "fbgfx.bi".

   Type Event Field = 1
      Type As Long
      Union
         Type
            scancode As Long
            ascii As Long
         End Type
         Type
            x As Long
            y As Long
            dx As Long
            dy As Long
         End Type
         button As Long
         z As Long
         w As Long
      End Union
   End Type
         

      * .type field contains the event type ID value corresponding to one 
        of the following symbols defined in "fbgfx.bi":
            - For key events, one among:
                  EVENT_KEY_PRESS
                  EVENT_KEY_RELEASE
                  EVENT_KEY_REPEAT
            - For mouse event, one among:
                  EVENT_MOUSE_MOVE
                  EVENT_MOUSE_BUTTON_PRESS
                  EVENT_MOUSE_BUTTON_RELEASE
                  EVENT_MOUSE_DOUBLE_CLICK
                  EVENT_MOUSE_WHEEL
                  EVENT_MOUSE_HWHEEL
                  EVENT_MOUSE_ENTER
                  EVENT_MOUSE_EXIT
            - For window event, one among:
                  EVENT_WINDOW_GOT_FOCUS
                  EVENT_WINDOW_LOST_FOCUS
                  EVENT_WINDOW_CLOSE
      * .scancode and .ascii fields contain respectively the scancode 
        value and the ascii representation (if exists, otherwise 0) of the 
        key impacted by one event among:
            EVENT_KEY_PRESS
            EVENT_KEY_RELEASE
            EVENT_KEY_REPEAT
      * .x, .y and .dx, .dy fields contain respectively the new mouse 
        position (x, y) relative to the upper-left corner of the screen and 
        the motion deltas (dx, dy) induced by the event:
            EVENT_MOUSE_MOVE
      * .button field contains the identification (bit 0: left button, bit 
        1: right button, and bit 2: middle button) of the mouse button 
        impacted by one event among:
            EVENT_MOUSE_BUTTON_PRESS
            EVENT_MOUSE_BUTTON_RELEASE
            EVENT_MOUSE_DOUBLE_CLICK
      * .z field contains the new wheel position induces by the event:
            EVENT_MOUSE_WHEEL
      * .w field contains the new horizontal wheel position induces by the 
        event:
            EVENT_MOUSE_HWHEEL

      Note:
         - The last five field blocks [.scancode and .ascii], [.x, .y and 
         .dx, .dy], [.button], [.z] and [.w] are aligned on the same memory 
         location (because declared inside a Union type), so that filling 
         in one field block overwrites the other field blocks previously 
         filled in.
         - Therefore for example if the mouse position (mx, my) must be 
         available when the MOUSE_BUTTON_PRESS event is detected, this 
         position must have been previously stored in (mx, my) at each 
         MOUSE_MOVE event from its own event data (.x, .y), because (.x, .y
         ) is overwritten by any other event returned by ScreenEvent.

ScreenEvent function
   The ScreenEvent function allows querying and retrieving system events.

   Syntax
      Declare Function ScreenEvent ( ByVal event_instance_ptr As Any Ptr = 
      0 ) As Long

   Usage
      result = ScreenEvent( [ event_instance_ptr ] )
         with:
            event_instance_ptr: the buffer address where the function 
            should fill in the event data with a structure as the Event 
            type defined above.
            result: -1 if there are pending events to be retrieved, 0 
            otherwise.

Description
   The ScreenEvent function checks if there are any pending system events:
      - If there are no events, the function simply returns 0 (false).
      - If there is any, it returns -1 (true), and if the 
      event_instance_ptr pointer is not NULL, it copies the event data into 
      the user passed structure and removes the event (the latest 
      available) from the internal GfxLib events queue.
      - So to simply check if there are any pending events without 
      retrieving them (if there are any), nor even dequeue it from the 
      internal events queue, it is enough to call the function without 
      parameters (or with a NULL parameter).

   The user must first call ScreenEvent once to get one event, and then 
   check that one event against each event type he is interested in.
   Once the user has handled that event, he must quickly call ScreenEvent 
   again to handle the next event. Otherwise he will almost certainly miss 
   events (like for example EVENT_MOUSE_MOVE at least).
   This is why the program loop which tests the successive events must have 
   a period compatible with the rate of the events that the user wants to 
   intercept (for example, difference between keyboard input and mouse 
   move).
   Conversely, having an event test loop with a period significantly less 
   than 10 ms unnecessarily hogs the CPU.

   Event querying program skeleton
      As only one event is served by the ScreenEvent function at a given 
      time, the event querying program skeleton can be properly structured 
      around a [Select Case As Const...End Select] block.
      The different cases correspond to the different events that the user 
      wishes to handle.

   #include Once "fbgfx.bi"
   Using FB
   ' .....
   Dim e As Event
   ' .....
   Do
      If (ScreenEvent(@e)) Then
         Select Case As Const e.type
         Case EVENT_xxx
            ' handle the event xxx
         Case EVENT_yyy
            ' handle the event yyy
         ' .....
         ' .....
         Case EVENT_zzz
            ' handle the event zzz
         Case Else
            ' event not handled
         End Select
      End If
      Sleep 10, 1
   Loop
   ' .....
         

   If for example a key is held down for some seconds, this will induce:
      - a first EVENT_KEY_PRESS,
      - followed by several EVENT_KEY_REPEAT (for as long as the key is 
      held down),
      - and EVENT_KEY_RELEASE when the key is released.

   Two successive simple-click actions on a mouse obviously induce four 
   successive mouse events:
      EVENT_MOUSE_BUTTON_PRESS
      EVENT_MOUSE_BUTTON_RELEASE
      EVENT_MOUSE_BUTTON_PRESS
      EVENT_MOUSE_BUTTON_RELEASE
   An only double-click action on a mouse also induces four successive 
   mouse events, but:
      EVENT_MOUSE_BUTTON_PRESS
      EVENT_MOUSE_BUTTON_RELEASE
      EVENT_MOUSE_DOUBLE_CLICK
      EVENT_MOUSE_BUTTON_RELEASE

   Note:
      - If the user program retrieves  a KEY_... event, this does not clear 
      the keyboard buffer. If the keyboard buffer needs to be cleared after 
      user retrieves the event, he will need to clear it manually (see Inkey
      ).
      - Event queuing and InKey buffering are two completely independent 
      ways to test the keyboard state. They can coexist, even in two 
      competing threads without any conflict.
      - There are currently three ways to test input from the keyboard 
      using gfxlib:
            using Inkey (user can test only keys that have an ascii 
            representation),
            using MultiKey (user can query the state pressed/released of 
            any key on keyboard),
            using ScreenEvent (user can check the KEY_PRESS, KEY_RELEASE 
            and KEY_REPEAT events).

Examples
   Example of simple ScreenEvent mechanism to implement a key-pressed 
   events handling:
   (click on the window-close button [X] to exit)
   '   The main code tests events in a loop:
   '       - calls a user Sub each time a key-pressed event is retrieved
   '       - exits the loop if a window-close event is retrieved (by click on window-close button)
   '   The user Sub prints the character of the key pressed, the ascci code and the scancode.

   #include Once "fbgfx.bi"
   Using FB

   '' user callback Sub definition
   Sub printInkeyData (ByVal ascii As Long, ByVal scancode As Long)
      Print "'" & Chr(ascii) & "' (" & ascii & ")", scancode
   End Sub

   '' user main code
   Screen 12
   Dim e As Event
   Do
      If (ScreenEvent(@e)) Then
         Select Case As Const e.type
         Case EVENT_KEY_PRESS                     '' test key-pressed event
            printInkeyData(e.ascii, e.scancode)
         Case EVENT_WINDOW_CLOSE                  '' test window-close event
            Exit Do
         End Select
      End If
      Sleep 10, 1
   Loop
         

   Simple example highlighting that Event queuing and InKey buffering can 
   coexist, even in two competing threads without any conflict:
   (ESC to quit)
   '   The main code (main thread) tests Inkey in a loop.
   '   The other thread tests ScreenEvent in a loop.
   '   The ESC character allows to exit the two loops.

   #include "fbgfx.bi"
   Using FB

   Function getAscii (ByVal ascii As Long) As String
      If ((ascii>0) And (ascii<255)) Then
         Return "'" & Chr(ascii) & "'"
      Else
         Return "???"
      End If
   End Function

   Sub Thread (ByVal p As Any Ptr)
      Dim e As Event
      Do
         If (ScreenEvent(@e)) Then
            Select Case As Const e.Type
            Case EVENT_KEY_PRESS                                      '' test key-pressed event
               Print getAscii(e.ascii) &_ 
               " is pressed    (from ScreenEvent)   (other thread)"
               If (e.scancode=SC_ESCAPE) Then                        '' test ESC
                  Exit Sub
               End If
            Case EVENT_KEY_RELEASE                                    '' test key-released event
               Print getAscii(e.ascii) &_ 
               " is released   (from ScreenEvent)   (other thread)"
            Case EVENT_KEY_REPEAT                                     '' test key-repeated event
               Print getAscii(e.ascii) &_ 
               " is repeated   (from ScreenEvent)   (other thread)"
            End Select
         End If
         Sleep 10, 1
      Loop
   End Sub

   Screen 12

   Dim As String s
   Dim As Any Ptr pt
   pt = ThreadCreate(@Thread)

   Do
      s = Inkey
      If s <> "" Then                                                   '' test inkey return
         Print getAscii(s[0]) &_ 
         " is viewed     (from Inkey)         (main thread)"
      End If
      Sleep 10, 1
   Loop Until s = Chr(27)                                                '' test ESC

   ThreadWait(pt)
   Print "main and other thread completed"

   Sleep
         

   Example of mouse event handling where cursor position and buttons state 
   are stored in a Type derived of EVENT to be available at the time of 
   events other than those that normally provide them:
   (click on the window-close button [X] to exit)
   ' Memorization in (.mx, .my) of the cursor position of the mouse:
   '     - at MOUSE_MOVE event : e.mx = e.x, e.my = e.y
   ' Memorization in .mbutton of the buttons state of the mouse:
   '     - at MOUSE_BUTTON_PRESS event and MOUSE_DOUBLE_CLICK event : e.mbutton = e.mbutton Or e.button
   '     - at MOUSE_BUTTON_RELEASE event : e.mbutton = e.mbutton Xor e.button

   #include Once "fbgfx.bi"
   Using FB

   Type EVENTstore Extends Event
      mx As Long
      my As Long
      mbutton As Long
   End Type

   Screen 19
   Dim e As EVENTstore
   Do
      If ScreenEvent(@e) Then
         Select Case As Const e.Type
         Case EVENT_MOUSE_MOVE
            e.mx = e.x
            e.my = e.y
            Print Using "Mouse move:                  x=####   /   y=####      dx=####  /  dy=####      button=##";_ 
            e.x; e.y; e.dx; e.dy; e.mbutton
         Case EVENT_MOUSE_BUTTON_PRESS
            e.mbutton = e.mbutton Or e.button
            Print Using "Mouse button press:          button =##               x=####   /   y=####";_ 
            e.button; e.mx; e.my
         Case EVENT_MOUSE_BUTTON_RELEASE
            e.mbutton = e.mbutton Xor e.button
            Print Using "Mouse button release:        button =##               x=####   /   y=####";_ 
            e.button; e.mx; e.my
         Case EVENT_MOUSE_DOUBLE_CLICK
            e.mbutton = e.mbutton Or e.button
            Print Using "Mouse button double click:   button =##               x=####   /   y=####";_ 
            e.button; e.mx; e.my
         Case EVENT_MOUSE_WHEEL
            Print Using "Mouse wheel:                 wheel=  ###########      x=####   /   y=####";_ 
            e.z; e.mx; e.my
         Case EVENT_MOUSE_HWHEEL
            Print Using "Mouse hwheel:                hwheel= ###########      x=####   /   y=####";_ 
            e.z; e.mx; e.my
         Case EVENT_WINDOW_CLOSE
            Exit Do
         End Select
      End If
      Sleep 10, 1
   Loop
         

See also
   * Event
   * ScreenEvent
   * Inkey
   * MultiKey
   * GetMouse
   * Keyboard scancodes



-------------------------------------------------------- CatPgDddefines ----
Intrinsic Defines

Preprocessor symbols defined by the compiler.

Description
   Intrinsic defines are set by the compiler and may be used as any other 
   defined symbol.  Intrinsic defines often convey information about the 
   state of the compiler, either in general or at a specific point in the 
   compilation process.  Most intrinsic defines are associated with a 
   value.

Platform Information
   Defines that provide information on the system.
Version Information
   Defines that provide information on the fbc compiler version being used.
Command-line switches
   Defines that provide information with the command-line switches used 
   with fbc.
Environment Information
   Defines that provide information about the operating system environment.
Context-specific Information
   Defines that provide context information about the compilation process.
Basic-macros
   Built-in basic-macros.
Constants
   Built-in constants.

Platform Information
   __FB_WIN32__
      Defined if compiling for Windows.
   __FB_LINUX__
      Defined if compiling for Linux.
   __FB_DOS__
      Defined if compiling for DOS.
   __FB_CYGWIN__
      Defined if compiling for Cygwin.
   __FB_FREEBSD__
      Defined if compiling for FreeBSD.
   __FB_NETBSD__
      Defined if compiling for NetBSD.
   __FB_OPENBSD__
      Defined if compiling for OpenBSD.
   __FB_DARWIN__
      Defined if compiling for Darwin.
   __FB_XBOX__
      Defined if compiling for Xbox.
   __FB_BIGENDIAN__
      Defined if compiling on a system using big-endian byte-order.
   __FB_PCOS__
      Defined if compiling for a common PC OS (e.g. DOS, Windows, OS/2).
   __FB_UNIX__
      Defined if compiling for a Unix-like OS.
   __FB_64BIT__
      Defined if compiling for a 64bit target.
   __FB_ARM__
      Defined if compiling for the ARM architecture.
   __FB_PPC__
      Defined if compiling for the PowerPC architecture.
   __Fb_Riscv64__
      Defined if compiling for the 64-bit RISC-V architecture.
   __Fb_S390X__
      Defined if compiling for the s390x architecture.
   __Fb_Loongarch64__
      Defined if compiling for the 64-bit LoongArch architecture.
   __FB_X86__
      Defined if compiling for the X86 / X86_64 architecture.
   __FB_JS__
      Defined if compiling for emscripten target.
   __FB_ANDROID__
      Defined if compiling for android target.

Version Information
   __FB_VERSION__
      Defined as a string literal of the compiler version.
   __FB_VER_MAJOR__
      Defined as an integral literal of the compiler major version number.
   __FB_VER_MINOR__
      Defined as an integral literal of the compiler minor version number.
   __FB_VER_PATCH__
      Defined as an integral literal of the compiler patch number.
   __FB_MIN_VERSION__
      Macro to check for a minimum compiler version.
   __FB_BUILD_DATE__
      Defined as a string literal of the compiler build date in 
      "mm-dd-yyyy" format.
   __FB_BUILD_DATE_ISO__
      Defined as a string literal of the compiler build date in 
      "yyyy-mm-dd" format.
   __FB_SIGNATURE__ 
      Defined as a string literal of the compiler signature.
   __FB_BUILD_SHA1__ 
      Defined as a string literal of the compiler's source revision sha-1.
   __FB_BUILD_FORK_ID__ 
      Defined as a string literal of the custom defined project fork 
      identifier name.

Command-line switches
   __FB_ASM__
      Defined to either "intel" or "att" depending on -asm.
   __FB_BACKEND__
      Defined to either "gas" or "gcc" depending on -gen.
   __FB_GCC__
      True (-1) if -gen gcc is used, false (0) otherwise.
   __FB_OPTIMIZE__
      Defined to the optimization level depending on -O.
   __FB_GUI__
      True (-1) if GUI subsystem mode is active, false (0) otherwise.
   __FB_MAIN__
      Defined if compiling a module with an entry point.
   __FB_DEBUG__
      True (-1) if the "-g" switch was used, false (0) otherwise.
   __FB_ERR__
      Zero (0) if neither the "-e", "-ex" or "-exx" switches were used.
   __FB_FPMODE__
      Defined as "fast" if compiling for fast SSE math, "precise" 
      otherwise.
   __FB_FPU__
      Defined as "sse" if compiling for SSE floating point unit, or "x87" 
      for normal x87 floating-point unit.
   __FB_LANG__
      Defined to a string literal of the "-lang" dialect used.
   __FB_MT__
      True (-1) if the "-mt" switch was used, false (0) otherwise.
   __FB_OUT_DLL__
      True (-1) in a module being compiled and linked into a shared 
      library, false (0) otherwise.
   __FB_OUT_EXE__
      True (-1) in a module being compiled and linked into an executable, 
      false (0) otherwise.
   __FB_OUT_LIB__
      True (-1) in a module being compiled and linked into a static 
      library, zero (0) otherwise.
   __FB_OUT_OBJ__
      True (-1) in a module being compiled only, zero (0) otherwise.
   __FB_PROFILE__
      Set to an integer to indicate the profiling method.
   __FB_SSE__
      Defined if compiling for SSE floating point unit.
   __FB_VECTORIZE__
      Defined as the level of automatic vectorization (0 to 2)
Environment Information
   __FB_ARGC__
      Defined as an integer literal of the number of command-line arguments 
      passed to the program.
   __FB_ARGV__
      Defined as a ZString Ptr Ptr to the command line arguments passed to 
      the program.
   __DATE__
      Defined as a string literal of the compilation date in "mm-dd-yyyy" 
      format.
   __DATE_ISO__
      Defined as a string literal of the compilation date in "yyyy-mm-dd" 
      format.
   __TIME__
      Defined as a string literal of the compilation time.
   __PATH__
      Defined as a string literal of the absolute path of the module.

Context-specific Information
   __FILE__ and __FILE_NQ__
      Defined as the name of the module.
   __FUNCTION__ and __FUNCTION_NQ__
      Defined as the name of the procedure where it's used.
   __LINE__
      Defined as an integer literal of the line of the module where it's 
      used.
   __FB_OPTION_BYVAL__
      True (-1) if parameters are declared by value by default, zero (0) 
      otherwise.
   __FB_OPTION_DYNAMIC__
      True (-1) if all arrays are variable-length, zero (0) otherwise.
   __FB_OPTION_ESCAPE__
      True (-1) if string literals are processed for escape sequences, zero 
      (0) otherwise.
   __FB_OPTION_GOSUB__
      True (-1) if gosub support is enabled, zero (0) otherwise.
   __FB_OPTION_EXPLICIT__
      True (-1) if variables and objects need to be explicitly declared, 
      zero (0) otherwise.
   __FB_OPTION_PRIVATE__
      True (-1) if all procedures are private by default, zero (0) 
      otherwise.
   __FB_OPTION_PROFILE__
      True (-1) if profiling code is generated, zero (0) otherwise.

Basic-macros
   __FB_ARG_COUNT__
      Counts the number of arguments in an argument list.
   __FB_ARG_EXTRACT__
      Returns nth argument from an argument list.
   __FB_ARG_LEFTOF__
      Returns left token based on separator.
   __Fb_Arg_Listexpand__
      Expands a macro one or more time on an argument list
   __FB_ARG_RIGHTOF__
      Returns right token based on separator.
   __FB_EVAL__
      Evaluates an argument (expression) at compile time.
   __FB_IIF__
      Returns an expression depending on the result of a comparison 
      expression evaluated at compile time.
   __FB_JOIN__
      Joins two token arguments together as one.
   __Fb_Query_Symbol__
      Queries a fbc's symbol internals.
   __FB_QUOTE__
      Converts the argument to a string.
   __FB_UNIQUEID__
      Gets the identifier at the top of a stack.
   __FB_UNIQUEID_POP__
      Pops an identifier off of a stack.
   __FB_UNIQUEID_PUSH__
      Pushes a new unique identifier on to a stack.
   __FB_UNQUOTE__
      Takes a literal string and converts it back to tokens.

Constants
   False and True
      Intrinsic constants for the Boolean data type.



------------------------------------------------- ProPgIdentifierLookup ----
Identifier Look-ups in namespaces and types

When referencing to an identifier is encountered in a program, a look-up is 
performed to locate the declaration that introduced that identifier.

Preamble:

   The identifiers to look-up can be unqualified or qualified:
      - An unqualified identifier is an identifier that does not have a 
      prefix to specify what scope it comes from.
      - A qualified identifier includes a prefix to clarify the 
      interpretive scope by overriding the default scope.

Scope priority hierarchy
   Unqualified identifier look-ups verify the priority hierarchy as 
   follows:
      * [1] Current Namespace/Type.
      * [2] Base Types (by Extends), ranked from closest to furthest in 
        inheritance hierarchy.
      * [3] Parent Namespaces (by nesting), ranked from closest to 
        furthest in ancestry hierarchy (including global namespace: always 
        furthest in hierarchy).
      * [4] Imported Namespaces (by Using), without hierarchy between them 
        (regardless of their respective level of nesting).

      Unqualified identifiers for look-up can be:
         - Variable identifiers.
            => Look-up order: [1], [2], [3], [4].
         - Procedure identifiers.
            => Look-up order: [1], [2], [3], [4].
         - Type/Union identifiers.
            => Look-up order: [1], [3], [4].
         - Enum identifiers, not their field symbols alone.
            => Look-up order: [1], [3], [4].

   If a qualified identifier with a prefix referring to a namespace is used 
   instead of an unqualified identifier, the previous rules for unqualified 
   identifiers are amended as follows:
      * The look-up begins at the level of the namespace corresponding to 
        the specified prefix (as in [1]).
      * Failing that, then only namespaces imported into this namespace 
        can be candidates for the look-up (as in [4]).
      * But never the parent namespaces of this namespace nor also the 
        global namespace can be candidates (not as in [3]).
      => Look-up order: [1], [4].

   If a qualified identifier with a prefix (object-name/This or 
   Base (Member Access)) referring to a type is used instead of an 
   unqualified identifier, the previous rules for unqualified identifiers 
   are amended as follows:
      * The look-up begins at the level of the type or base type depending 
        on the specified prefix object-name/This or Base (Member Access) 
        (similarly to [1]).
      * Failing that, then only higher base types from closest to furthest 
        can be successively candidates for the look-up (as in [2]).
      * But never any namespaces, the current also excluded, can be 
        candidates (not as in [3] or [4]).
      => Look-up order: [1], [2].

Full process
   The full process simplifies the problem by dealing with it in two 
   successive phases:
      * Using the scope priority hierarchy rules above, selection of a 
        single scope among all those which are accessible by only taking 
        into account the identifier for look-up, regardless of the 
        signature supplied by the caller (if at least two scopes containing 
        this identifier have equivalent accessibility priority, then the 
        process is stopped with an ambiguity status).
      * Within the single scope retained if it exists, one final overload 
        resolution taking into account the full signature is carried out 
        (if there is no compatibility with the declared signature(s), the 
        process is stopped without testing another accessible scope).

   The problem is thus simplified to one single full overload resolution 
   within a same scope (instead of a full overload resolution within each 
   scope candidate, and then the difficult choice of the best result among 
   the scope candidates).

   The coding of a very optimized resolution process (the best of human 
   intelligence) for a procedure identifier is cumbersome, because having 
   to take into account from the start the complete signature of the called 
   procedure (identifier of the procedure + type and number of parameters + 
   calling convention + return type if it exists).
   In addition, it must be taken into account that the signature deduced 
   from the call may not necessarily be identical but just compatible with 
   certain declared ones in the scope candidates.

   Identifier look-ups for the overload non-member operators
      Currently, the look-up for the overload non-member operator 
      identifiers is simplified by the fact that the compiler always define 
      these operators in the global namespace even if the user declared 
      them in named namespaces. 
      But the global namespace is always a scope candidate when looking-up 
      for a non-member overload operator identifier from another scope, 
      because this operator identifier cannot be used with a qualifier 
      prefix but always as an unqualified identifier (seen from the 
      operator call, the global namespace is either the current namescape 
      or a parent namescape).

   Identifier look-ups for the Using commands
      The look-up for the Using command identifiers follows rules similar 
      to those of a Type.

Examples
   The following four codes test different look-ups both for one 
   unqualified and one qualified identifier of procedures defined in 
   different scope cases (from the highest to the lowest priority 
   hierarchy):
   Sub duplicateSub()
      Print "   ..duplicateSub"
   End Sub

   Namespace M
      Sub duplicateSub()
         Print "   M.duplicateSub"
      End Sub
   End Namespace

   Namespace N
      Sub duplicateSub()
         Print "   N.duplicateSub"
      End Sub
      Namespace P
         Using M
         Sub duplicateSub()
            Print "   N.P.duplicateSub"
         End Sub
         Sub test()
            Using M  '' useless, but just to demonstrate that does not increase priority level of imported namespace 
            duplicateSub()
         End Sub
      End Namespace
   End Namespace

   Print "From Namespace:"
   ' "N.P.test()" calls the unqualified identifier "duplicateSub"
   ' "N.P.duplicateSub()" calls the qualified identifier "N.P.duplicateSub"

   N.P.test()               '' "N.P.duplicateSub" expected : in (1) current namespace/type
   N.P.duplicateSub()       '' "N.P.duplicateSub" expected : in (1) current namespace/type

   Print
   Sleep

   Sub duplicateSub()
      Print "   ..duplicateSub"
   End Sub

   Namespace M
      Sub duplicateSub()
         Print "   M.duplicateSub"
      End Sub
   End Namespace

   Namespace N
      Sub duplicateSub()
         Print "   N.duplicateSub"
      End Sub
      Namespace P
         Using M
         'Sub duplicateSub()
         '    Print "   N.P.duplicateSub"
         'End Sub
         Sub test()
            Using M  '' useless, but just to demonstrate that does not increase priority level of imported namespace 
            duplicateSub()
         End Sub
      End Namespace
   End Namespace

   Print "From Namespace:"
   ' "N.P.test()" calls the unqualified identifier "duplicateSub"
   ' "N.P.duplicateSub()" calls the qualified identifier "N.P.duplicateSub"

   N.P.test()               '' "N.duplicateSub" expected : in [3] parent namespaces (by nesting)
   N.P.duplicateSub()       '' "M.duplicateSub" expected : in [4] imported namespaces (by 'Using')

   Print
   Sleep

   Sub duplicateSub()
      Print "   ..duplicateSub"
   End Sub

   Namespace M
      Sub duplicateSub()
         Print "   M.duplicateSub"
      End Sub
   End Namespace

   Namespace N
      'Sub duplicateSub()
      '    Print "   N.duplicateSub"
      'End Sub
      Namespace P
         Using M
         'Sub duplicateSub()
         '    Print "   N.P.duplicateSub"
         'End Sub
         Sub test()
            Using M  '' useless, but just to demonstrate that does not increase priority level of imported namespace 
            duplicateSub()
         End Sub
      End Namespace
   End Namespace

   Print "From Namespace:"
   ' "N.P.test()" calls the unqualified identifier "duplicateSub"
   ' "N.P.duplicateSub()" calls the qualified identifier "N.P.duplicateSub"

   N.P.test()               '' "..duplicateSub" expected : in [3] parent namespaces (by nesting)
   N.P.duplicateSub()       '' "M.duplicateSub" expected : in [4] imported namespaces (by 'Using')

   Print
   Sleep

   'Sub duplicateSub()
   '    Print "   ..duplicateSub"
   'End Sub

   Namespace M
      Sub duplicateSub()
         Print "   M.duplicateSub"
      End Sub
   End Namespace

   Namespace N
      'Sub duplicateSub()
      '    Print "   N.duplicateSub"
      'End Sub
      Namespace P
         Using M
         'Sub duplicateSub()
         '    Print "   N.P.duplicateSub"
         'End Sub
         Sub test()
            Using M  '' useless, but just to demonstrate that does not increase priority level of imported namespace 
            duplicateSub()
         End Sub
      End Namespace
   End Namespace

   Print "From Namespace:"
   ' "N.P.test()" calls the unqualified identifier "duplicateSub"
   ' "N.P.duplicateSub()" calls the qualified identifier "N.P.duplicateSub"

   N.P.test()               '' "M.duplicateSub" expected : in [4] imported namespaces (by 'Using')
   N.P.duplicateSub()       '' "M.duplicateSub" expected : in [4] imported namespaces (by 'Using')

   Print
   Sleep

   The following six codes test different look-ups both for one unqualified 
   and one qualified identifier of variables defined in different scope 
   cases (from the highest to the lowest priority hierarchy):
   Dim Shared As ZString * 32 duplicateVar = "   ..duplicateVar"

   Namespace M
      Dim As ZString *32 duplicateVar = "   M.duplicateVar"
   End Namespace

   Namespace N
      Using M
      Dim As ZString * 32 duplicateVar = "   N.duplicateVar"
      Type Parent Extends Object
         Dim As ZString * 32 duplicateVar = "   N.Parent.duplicateVar"
      End Type
      Type Child Extends Parent
         Dim As ZString * 32 duplicateVar = "   N.Child.duplicateVar"
      End Type
      Type GrandChild Extends Child
         Dim As ZString * 32 duplicateVar = "   N.GrandChild.duplicateVar"
         Declare Sub test()
      End Type
      Sub GrandChild.test()
         Using M  '' useless, but just to demonstrate that does not increase priority level of imported namespace
         Print duplicateVar
      End Sub
   End Namespace

   Print "From Type:"
   Dim As N.GrandChild gc
   ' "gc.test()" calls the unqualified identifier "duplicateVar"
   ' "Print gc.duplicateVar" calls the qualified identifier "gc.duplicateVar"

   gc.test()                '' "N.GrandChild.duplicateVar" expected : in [1] current namespace/type
   Print gc.duplicateVar    '' "N.GrandChild.duplicateVar" expected : in [1] current namespace/type

   Print
   Sleep

   Dim Shared As ZString * 32 duplicateVar = "   ..duplicateVar"

   Namespace M
      Dim As ZString *32 duplicateVar = "   M.duplicateVar"
   End Namespace

   Namespace N
      Using M
      Dim As ZString * 32 duplicateVar = "   N.duplicateVar"
      Type Parent Extends Object
         Dim As ZString * 32 duplicateVar = "   N.Parent.duplicateVar"
      End Type
      Type Child Extends Parent
         Dim As ZString * 32 duplicateVar = "   N.Child.duplicateVar"
      End Type
      Type GrandChild Extends Child
         'Dim As Zstring * 32 duplicateVar = "   N.GrandChild.duplicateVar"
         Declare Sub test()
      End Type
      Sub GrandChild.test()
         Using M  '' useless, but just to demonstrate that does not increase priority level of imported namespace
         Print duplicateVar
      End Sub
   End Namespace

   Print "From Type:"
   Dim As N.GrandChild gc
   ' "gc.test()" calls the unqualified identifier "duplicateVar"
   ' "Print gc.duplicateVar" calls the qualified identifier "gc.duplicateVar"

   gc.test()                '' "N.Child.duplicateVar" expected : in [2] base types (by 'Extends')
   Print gc.duplicateVar    '' "N.Child.duplicateVar" expected : in [2] base types (by 'Extends')

   Print
   Sleep

   Dim Shared As ZString * 32 duplicateVar = "   ..duplicateVar"

   Namespace M
      Dim As ZString *32 duplicateVar = "   M.duplicateVar"
   End Namespace

   Namespace N
      Using M
      Dim As ZString * 32 duplicateVar = "   N.duplicateVar"
      Type Parent Extends Object
         Dim As ZString * 32 duplicateVar = "   N.Parent.duplicateVar"
      End Type
      Type Child Extends Parent
         'Dim As Zstring * 32 duplicateVar = "   N.Child.duplicateVar"
      End Type
      Type GrandChild Extends Child
         'Dim As Zstring * 32 duplicateVar = "   N.GrandChild.duplicateVar"
         Declare Sub test()
      End Type
      Sub GrandChild.test()
         Using M  '' useless, but just to demonstrate that does not increase priority level of imported namespace
         Print duplicateVar
      End Sub
   End Namespace

   Print "From Type:"
   Dim As N.GrandChild gc
   ' "gc.test()" calls the unqualified identifier "duplicateVar"
   ' "Print gc.duplicateVar" calls the qualified identifier "gc.duplicateVar"

   gc.test()                '' "N.Parent.duplicateVar" expected : in [2] base types (by 'Extends')
   Print gc.duplicateVar    '' "N.Parent.duplicateVar" expected : in [2] base types (by 'Extends')

   Print
   Sleep

   Dim Shared As ZString * 32 duplicateVar = "   ..duplicateVar"

   Namespace M
      Dim As ZString *32 duplicateVar = "   M.duplicateVar"
   End Namespace

   Namespace N
      Using M
      Dim As ZString * 32 duplicateVar = "   N.duplicateVar"
      Type Parent Extends Object
         'Dim As Zstring * 32 duplicateVar = "   N.Parent.duplicateVar"
      End Type
      Type Child Extends Parent
         'Dim As Zstring * 32 duplicateVar = "   N.Child.duplicateVar"
      End Type
      Type GrandChild Extends Child
         'Dim As Zstring * 32 duplicateVar = "   N.GrandChild.duplicateVar"
         Declare Sub test()
      End Type
      Sub GrandChild.test()
         Using M  '' useless, but just to demonstrate that does not increase priority level of imported namespace
         Print duplicateVar
      End Sub
   End Namespace

   Print "From Type:"
   Dim As N.GrandChild gc
   ' "gc.test()" calls the unqualified identifier "duplicateVar"
   ' "Print gc.duplicateVar" calls the qualified identifier "gc.duplicateVar"

   gc.test()                '' "N.duplicateVar" expected : in [3] parent namespaces (by nesting)
   'Print gc.duplicateVar   '' error

   Print
   Sleep

   Dim Shared As ZString * 32 duplicateVar = "   ..duplicateVar"

   Namespace M
      Dim As ZString *32 duplicateVar = "   M.duplicateVar"
   End Namespace

   Namespace N
      Using M
      'Dim As Zstring * 32 duplicateVar = "   N.duplicateVar"
      Type Parent Extends Object
         'Dim As Zstring * 32 duplicateVar = "   N.Parent.duplicateVar"
      End Type
      Type Child Extends Parent
         'Dim As Zstring * 32 duplicateVar = "   N.Child.duplicateVar"
      End Type
      Type GrandChild Extends Child
         'Dim As Zstring * 32 duplicateVar = "   N.GrandChild.duplicateVar"
         Declare Sub test()
      End Type
      Sub GrandChild.test()
         Using M  '' useless, but just to demonstrate that does not increase priority level of imported namespace
         Print duplicateVar
      End Sub
   End Namespace

   Print "From Type:"
   Dim As N.GrandChild gc
   ' "gc.test()" calls the unqualified identifier "duplicateVar"
   ' "Print gc.duplicateVar" calls the qualified identifier "gc.duplicateVar"

   gc.test()                '' "..duplicateVar" expected : in [3] parent namespaces (by nesting)
   'Print gc.duplicateVar   '' error

   Print
   Sleep

   'Dim Shared As Zstring * 32 duplicateVar = "   ..duplicateVar"

   Namespace M
      Dim As ZString *32 duplicateVar = "   M.duplicateVar"
   End Namespace

   Namespace N
      Using M
      'Dim As Zstring * 32 duplicateVar = "   N.duplicateVar"
      Type Parent Extends Object
         'Dim As Zstring * 32 duplicateVar = "   N.Parent.duplicateVar"
      End Type
      Type Child Extends Parent
         'Dim As Zstring * 32 duplicateVar = "   N.Child.duplicateVar"
      End Type
      Type GrandChild Extends Child
         'Dim As Zstring * 32 duplicateVar = "   N.GrandChild.duplicateVar"
         Declare Sub test()
      End Type
      Sub GrandChild.test()
         Using M  '' useless, but just to demonstrate that does not increase priority level of imported namespace
         Print duplicateVar
      End Sub
   End Namespace

   Print "From Type:"
   Dim As N.GrandChild gc
   ' "gc.test()" calls the unqualified identifier "duplicateVar"
   ' "Print gc.duplicateVar" calls the qualified identifier "gc.duplicateVar"

   gc.test()                '' "M.duplicateVar" expected : in [4] imported namespaces (by 'Using')
   'Print gc.duplicateVar   '' error

   Print
   Sleep

   The following four codes test different look-ups both for one 
   unqualified and one qualified identifier of types defined in different 
   scope cases (from the highest to the lowest priority hierarchy):
   Type duplicateType
      Dim As ZString * 32 root = "   ..duplicateType"
   End Type

   Namespace M
      Type duplicateType
         Dim As ZString * 32 root = "   M.duplicateType"
      End Type
   End Namespace

   Namespace N
      Type duplicateType
         Dim As ZString * 32 root = "   N.duplicateType"
      End Type
      Namespace P
         Using M
         Type duplicateType
            Dim As ZString * 32 root = "   N.P.duplicateType"
         End Type
         Sub test()
            Using M  '' useless, but just to demonstrate that does not increase priority level of imported namespace
            Print Type<duplicateType>.root
         End Sub
      End Namespace
   End Namespace

   ' "N.P.test()" calls the unqualified identifier "duplicateType"
   ' "Print Type<N.P.duplicateType>.root" calls the qualified identifier "N.P.duplicateType"

   Print "From Namespace:"
   N.P.test()                          '' "N.P.duplicateSub" expected : in (1) current namespace/type
   Print Type<N.P.duplicateType>.root  '' "N.P.duplicateSub" expected : in (1) current namespace/type

   Print
   Sleep

   Type duplicateType
      Dim As ZString * 32 root = "   ..duplicateType"
   End Type

   Namespace M
      Type duplicateType
         Dim As ZString * 32 root = "   M.duplicateType"
      End Type
   End Namespace

   Namespace N
      Type duplicateType
         Dim As ZString * 32 root = "   N.duplicateType"
      End Type
      Namespace P
         Using M
         'Type duplicateType
         '    Dim As Zstring * 32 root = "   N.P.duplicateType"
         'End type
         Sub test()
            Using M  '' useless, but just to demonstrate that does not increase priority level of imported namespace
            Print Type<duplicateType>.root
         End Sub
      End Namespace
   End Namespace

   ' "N.P.test()" calls the unqualified identifier "duplicateType"
   ' "Print Type<N.P.duplicateType>.root" calls the qualified identifier "N.P.duplicateType"

   Print "From Namespace:"
   N.P.test()                          '' "N.duplicateSub" expected : in [3] parent namespaces (by nesting)
   Print Type<N.P.duplicateType>.root  '' "M.duplicateSub" expected : in [4] imported namespaces (by 'Using')

   Print
   Sleep

   Type duplicateType
      Dim As ZString * 32 root = "   ..duplicateType"
   End Type

   Namespace M
      Type duplicateType
         Dim As ZString * 32 root = "   M.duplicateType"
      End Type
   End Namespace

   Namespace N
      'Type duplicateType
      '    Dim As Zstring * 32 root = "   N.duplicateType"
      'End type
      Namespace P
         Using M
         'Type duplicateType
         '    Dim As Zstring * 32 root = "   N.P.duplicateType"
         'End type
         Sub test()
            Using M  '' useless, but just to demonstrate that does not increase priority level of imported namespace
            Print Type<duplicateType>.root
         End Sub
      End Namespace
   End Namespace

   ' "N.P.test()" calls the unqualified identifier "duplicateType"
   ' "Print Type<N.P.duplicateType>.root" calls the qualified identifier "N.P.duplicateType"

   Print "From Namespace:"
   N.P.test()                          '' "..duplicateSub" expected : in [3] parent namespaces (by nesting)
   Print Type<N.P.duplicateType>.root  '' "M.duplicateSub" expected : in [4] imported namespaces (by 'Using')

   Print
   Sleep

   'Type duplicateType
   '    Dim As Zstring * 32 root = "   ..duplicateType"
   'End type

   Namespace M
      Type duplicateType
         Dim As ZString * 32 root = "   M.duplicateType"
      End Type
   End Namespace

   Namespace N
      'Type duplicateType
      '    Dim As Zstring * 32 root = "   N.duplicateType"
      'End type
      Namespace P
         Using M
         'Type duplicateType
         '    Dim As Zstring * 32 root = "   N.P.duplicateType"
         'End type
         Sub test()
            Using M  '' useless, but just to demonstrate that does not increase priority level of imported namespace
            Print Type<duplicateType>.root
         End Sub
      End Namespace
   End Namespace

   ' "N.P.test()" calls the unqualified identifier "duplicateType"
   ' "Print Type<N.P.duplicateType>.root" calls the qualified identifier "N.P.duplicateType"

   Print "From Namespace:"
   N.P.test()                          '' "M.duplicateSub" expected : in [4] imported namespaces (by 'Using')
   Print Type<N.P.duplicateType>.root  '' "M.duplicateSub" expected : in [4] imported namespaces (by 'Using')

   Print
   Sleep

   The following four codes test different look-ups both for one 
   unqualified and one qualified identifier of enums defined in different 
   scope cases (from the highest to the lowest priority hierarchy):
   Dim Shared As ZString * 32 root(...) = {"   ..duplicateEnum", "   M.duplicateEnum", "   N.duplicateEnum", "   N.P.duplicateEnum"}

   Enum duplicateEnum
      nb = 0
   End Enum

   Namespace M
      Enum duplicateEnum
         nb = 1
      End Enum
   End Namespace

   Namespace N
      Enum duplicateEnum
         nb = 2
      End Enum
      Namespace P
         Using M
         Enum duplicateEnum
            nb = 3
         End Enum
         Sub test()
            Using M  '' useless, but just to demonstrate that does not increase priority level of imported namespace
            Print root(duplicateEnum.nb)
         End Sub
      End Namespace
   End Namespace

   ' "N.P.test()" calls the unqualified identifier "duplicateEnum"
   ' "Print root(N.P.duplicateEnum.nb)" calls the qualified identifier "N.P.duplicateEnum"

   Print "From Namespace:"
   N.P.test()                        '' "N.P.duplicateEnum" expected : in (1) current namespace/type
   Print root(N.P.duplicateEnum.nb)  '' "N.P.duplicateEnum" expected : in (1) current namespace/type

   Print
   Sleep

   Dim Shared As ZString * 32 root(...) = {"   ..duplicateEnum", "   M.duplicateEnum", "   N.duplicateEnum", "   N.P.duplicateEnum"}

   Enum duplicateEnum
      nb = 0
   End Enum

   Namespace M
      Enum duplicateEnum
         nb = 1
      End Enum
   End Namespace

   Namespace N
      Enum duplicateEnum
         nb = 2
      End Enum
      Namespace P
         Using M
         'Enum duplicateEnum
         '    nb = 3
         'End Enum
         Sub test()
            Using M  '' useless, but just to demonstrate that does not increase priority level of imported namespace
            Print root(duplicateEnum.nb)
         End Sub
      End Namespace
   End Namespace

   ' "N.P.test()" calls the unqualified identifier "duplicateEnum"
   ' "Print root(N.P.duplicateEnum.nb)" calls the qualified identifier "N.P.duplicateEnum"

   Print "From Namespace:"
   N.P.test()                        '' "N.duplicateEnum" expected : in [3] parent namespaces (by nesting)
   Print root(N.P.duplicateEnum.nb)  '' "M.duplicateEnum" expected : in [4] imported namespaces (by 'Using')

   Print
   Sleep

   Dim Shared As ZString * 32 root(...) = {"   ..duplicateEnum", "   M.duplicateEnum", "   N.duplicateEnum", "   N.P.duplicateEnum"}

   Enum duplicateEnum
      nb = 0
   End Enum

   Namespace M
      Enum duplicateEnum
         nb = 1
      End Enum
   End Namespace

   Namespace N
      'Enum duplicateEnum
      '    nb = 2
      'End Enum
      Namespace P
         Using M
         'Enum duplicateEnum
         '    nb = 3
         'End Enum
         Sub test()
            Using M  '' useless, but just to demonstrate that does not increase priority level of imported namespace
            Print root(duplicateEnum.nb)
         End Sub
      End Namespace
   End Namespace

   ' "N.P.test()" calls the unqualified identifier "duplicateEnum"
   ' "Print root(N.P.duplicateEnum.nb)" calls the qualified identifier "N.P.duplicateEnum"

   Print "From Namespace:"
   N.P.test()                        '' "..duplicateEnum" expected : in [3] parent namespaces (by nesting)
   Print root(N.P.duplicateEnum.nb)  '' "M.duplicateEnum" expected : in [4] imported namespaces (by 'Using')

   Print
   Sleep

   Dim Shared As ZString * 32 root(...) = {"   ..duplicateEnum", "   M.duplicateEnum", "   N.duplicateEnum", "   N.P.duplicateEnum"}

   'Enum duplicateEnum
   '    nb = 0
   'End Enum

   Namespace M
      Enum duplicateEnum
         nb = 1
      End Enum
   End Namespace

   Namespace N
      'Enum duplicateEnum
      '    nb = 2
      'End Enum
      Namespace P
         Using M
         'Enum duplicateEnum
         '    nb = 3
         'End Enum
         Sub test()
            Using M  '' useless, but just to demonstrate that does not increase priority level of imported namespace
            Print root(duplicateEnum.nb)
         End Sub
      End Namespace
   End Namespace

   ' "N.P.test()" calls the unqualified identifier "duplicateEnum"
   ' "Print root(N.P.duplicateEnum.nb)" calls the qualified identifier "N.P.duplicateEnum"

   Print "From Namespace:"
   N.P.test()                        '' "M.duplicateEnum" expected : in [4] imported namespaces (by 'Using')
   Print root(N.P.duplicateEnum.nb)  '' "M.duplicateEnum" expected : in [4] imported namespaces (by 'Using')

   Print
   Sleep

Version
   * Since fbc 1.09.0.
   * Before fbc 1.09.0, the priority hierarchy was poorly managed with 
     inconsistencies.

See also
   * Identifier Rules




============================================================================
    Technical Articles

-------------------------------------------------------------- KeyPgAsm ----
Asm

Code block that allows the use of architecture-specific instructions.

Syntax
   Asm
      architecture-dependent instructions
   End Asm

      Or

   Asm architecture-dependent instructions

Description
   The Asm block is used to insert specific machine-code instructions in a 
   program in order to perform operations that cannot be carried out using 
   the features of the language or to hand-optimize performance-sensitive 
   sections of code.

   The current FreeBASIC compiler currently only produces code for Intel 
   80x86-based machines; however, in the future, the compiler might be 
   ported to a platform which does not support the same instruction set.  
   Therefore, Asm blocks should only be used when necessary, and a 
   FreeBASIC-only alternative should be provided if possible.

   The return value of a function may be set by using the Function keyword 
   within brackets as shown in the example below.

   Asm block comments have the same syntax as usual FreeBASIC Comments  - 
   use FreeBASIC-like " ' " comments, not " ; " as usual in assembly code. 

   x86 Specific:

      Syntax
         The syntax of the inline assembler is a simplified form of Intel 
         syntax.  Intel syntax is used by the majority of x86 assemblers, 
         such as MASM, TASM, NASM, YASM and FASM. In general, the 
         destination of an instruction is placed first, followed by the 
         source. Variables and functions defined by a program may be 
         referenced in an Asm block.  The assembler used by FreeBASIC is 
         GAS, using the .intel_syntax noprefix directive, and Asm blocks 
         are passed through unmodified, except for the substitution of 
         local variable names for stack frame references, and commenting 
         removal.

         Instruction syntax is mostly the same as FASM uses, one important 
         difference is that GAS requires size settings to be followed by 
         the word "ptr".

   ' Assuming "n" is a FB global or local ULONG variable
   mov  eax, [n]        ' OK: size is apparent from eax
   inc  [n]             ' Not OK: size is not given
   inc  dword [n]       ' Not OK: size given, but still not accepted by GAS
   inc  dword Ptr [n]   ' OK: "ptr" is needed by GAS here

      Register Preservation
         When an Asm block is opened, the registers ebx, esi, and edi are 
         pushed to the stack, when the block is closed, these registers are 
         popped back from the stack.  This is because these registers are 
         required to be preserved by most or all OS's using the x86 CPU.  
         You can therefore use these registers without explicitly 
         preserving them yourself. You should not change esp and ebp, since 
         they are usually used to address local variables. 
         Note: Inside a Naked procedure, there is no such register 
         preservation.

      Register Names
         The names of the registers for the x86 architecture are written as 
         follows in an Asm block:
         * 4-byte integer registers: eax, ebx, ecx, edx, ebp, esp, edi, 
           esi
         * 2-byte integer registers: ax, bx, cx, dx, bp, sp, di, si (low 
           words of 4-byte e- registers)
         * 1-byte integer registers: al, ah, bl, bh, cl, ch, dl, dh (low 
           and high bytes of 2-byte -x registers)
         * Floating-point registers: st(0), st(1), st(2), st(3), st(4), 
           st(5), st(6), st(7)
         * MMX registers (aliased onto floating-point registers): mm0, mm1
           , mm2, mm3, mm4, mm5, mm6, mm7
         * SSE registers: xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7

      Instruction Set
         See these external references:
         * Original Intel 80386 manual from 1986
         * Latest Intel Pentium 4 manuals
         * NASM x86 Instruction Reference (Please note that NASM is not 
           the assembler used by FreeBASIC, but this page provides a good 
           overview of x86 instructions)

      Unsafe instructions
         Note that the FreeBASIC compiler produces 32-bit protected-mode 
         code for the x86 which usually runs in an unprivileged user level; 
         therefore, privileged and sensitive instructions will assemble 
         fine, but possibly won't work correctly or cause a runtime 
         "General Protection Fault", "Illegal instruction", or SIGILL 
         error. The following are the privileged and sensitive instructions 
         as of the Intel Pentium 4 and Xeon:
         * cli *1
         * clts
         * hlt
         * in *1
         * ins *1
         * int *1               
         * into *1               
         * invd
         * invlpg
         * lgdt
         * lidt
         * lldt
         * lmsw
         * ltr
         * mov to/from CRn, DRn, TRn
         * out *1
         * outs *1
         * rdmsr
         * rdpmc *2
         * rdtsc *2
         * sti *1
         * str
         * wbinvd
         * wrmsr
         * all SSE2 and higher instructions *2

          *1: sensitive to IOPL, fine in DOS 
          *2: sensitive to permission bits in CR4, see below

   The privileged instructions will work "correctly" in DOS when running on 
   a Ring 0 DPMI kernel, like the (non-default) Ring 0 version of CWSDPMI, 
   WDOSX or D3X, nevertheless most of them are not really useful and 
   dangerous when executed from DPMI code. RDTSC (Read Time Stamp Counter) 
   has been shown to be allowed by most, or all OS'es.

   However the usefulness of RDTSC has been diminished with the advent of 
   multi-core and hibernating CPUs. SSE2 and higher instructions are 
   disabled "by default" after CPU initialization, Windows and Linux 
   usually do enable them, in DOS it is business of the DPMI host: HDPMI32 
   will enable them, CWSDPMI won't. The INT instruction is usable in the 
   DOS version/target only, note that it works slightly differently from 
   real mode DOS, see also FaqDOS.

   The segment registers (cs, ds, es, fs, gs) should not be changed from an 
   Asm block, except in certain cases with the DOS port (note that they do 
   NOT work the same way as in real-mode DOS, see also FaqDOS). The 
   operating system or DPMI host is responsible for memory management; the 
   meaning of segments (selectors) in protected mode is very different from 
   real-mode memory addressing.

   Note that those "unsafe" instructions are not guaranteed to raise a 
   "visible" crash even when ran with insufficient privilege - the OS or 
   DPMI host can decide to "emulate" them, either functionally (reading 
   from some CRx works under HDPMI32), or "dummy" (nothing happens, 
   instruction will pass silently, like a NOP).

Example
   '' This is an example for the x86 architecture.
   Function AddFive(ByVal num As Long) As Long
      Asm
         mov eax, [num]
         Add eax, 5
         mov [Function], eax
      End Asm
   End Function

   Dim i As Long = 4

   Print "4 + 5 ="; AddFive(i)

   4 + 5 = 9

   FreeBASIC's Assembler is AS / GAS, the assembler of GCC, so an external 
   program. Some quirks apply:
      * The error lines  returned by FBC for Asm blocks are not related 
        the FB source file. As FBC simply displays the errors returned by 
        AS , the lines are related to the assembly file. To make FreeBASIC 
        preserve them, the compiler must be invoked with the -R option 
        ("don't delete ASM files").
      * The label names are case sensitive inside Asm blocks.

Dialect Differences
   * Not available in the -lang qb dialect unless referenced with the 
     alias __Asm.

Differences from QB
   * New to FreeBASIC

See also
   * Function
   * Naked



--------------------------------------------------------- ProPgCruntime ----
C Standard Library Functions

This is a list of function prototypes in the standard C library in 
alphabetical order and a list of prototypes grouped by functionality. 

Alphabetical List
Buffer Manipulation
Character Classification and Conversion
Data Conversion
Directory Manipulation
File Manipulation
Stream I/O
Low level I/O
Mathematics
Memory Allocation
Process Control
Searching and Sorting
String Manipulation
Time

Description
   The Comments column contains a very brief description of the use of the 
   function. The list is not complete, however it provides information on 
   the major functions in the C Runtime Library. It should, at the very 
   least, indicate what functions are available in the standard C library 
   allow you to do more investigation on your own.  Some of the C library 
   functions documented elsewhere may not be available in FreeBASIC.  Check 
   the appropriate include file for more information. 

   Note: The following prototypes are not the official FreeBASIC prototypes 
   (see the include files), however, they will give you enough information 
   to properly use the functions. 

   The Include File column contains the name of the file which you must 
   include, using the #include directive at the beginning of your program. 
   If you don't include the appropriate include file, the program either 
   will not compile, or it will compile apparently correctly but give 
   incorrect results when run.  All of the C Runtime headers are located in 
   the crt directory; for example, if the specified header is math.bi, use 
   #include "crt/math.bi" or #include "crt\math.bi", our just #include 
   "crt.bi" including all the others.

   The Prototype column contains the following information: 
      * The name of the function; 
      * The parameters required for the function in parenthesis, together 
        with the data-type of the parameters; 
      * The data-type of the value returned by the function. 

   For example atoi(a as zstring ptr) as integer means that the function 
   atoi returns a value of type integer and requires a character zstring 
   ptr as its argument. 

   Note: In order to make calling the C runtime functions very easy, any 
   string type argument may be directly passed to a procedure referring to 
   a parameter declared as 'zstring ptr'. The compiler performs itself an 
   automatic conversion (without warning message) between any string type 
   argument and the 'zstring ptr' type parameter.

Alphabetical List

      +--------+----------------------------------------------------------------------------+------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
      |Name    |Prototype (with parameters)                                                 |Include File|Comments                                                                                                                                                                                                      |
      |abs_    |abs_(n as integer) as integer                                               |stdlib.bi   |Returns the absolute value (i.e. positive value)                                                                                                                                                              |
      |acos_   |acos_(a as double) as double                                                |math.bi     |Returns the inverse cosine (angle in radians)                                                                                                                                                                 |
      |asin_   |asin_(a as double) as double                                                |math.bi     |Returns the inverse sine (angle in radians)                                                                                                                                                                   |
      |atan_   |atan_(a as double) as double                                                |math.bi     |Returns the inverse tan (angle in radians)                                                                                                                                                                    |
      |atan2_  |atan2_(y as double, x as double) as double                                  |math.bi     |Returns the inverse tan (pass the opposite as y and the adjacent as x)                                                                                                                                        |
      |atoi    |atoi(s as zstring ptr) as integer                                           |stdlib.bi   |Converts a character zstring of digits to a number of type integer.                                                                                                                                           |
      |atof    |atof(s as zstring ptr) as double                                            |stdlib.bi   |Converts a character zstring of digits to a number of type double.                                                                                                                                            |
      |calloc  |calloc(NumElts as integer, EltSiz as integer) as any ptr                    |stdlib.bi   |Allocates memory. Returns a pointer to a buffer for an array having NumElts elements, each of size EltSiz bytes.                                                                                              |
      |ceil    |ceil(d as double) as double                                                 |math.bi     |Returns the nearest whole number above the value passed.                                                                                                                                                      |
      |clearerr|clearerr(s as FILE ptr)                                                     |stdio.bi    |Clears the error indicators on a file stream (read or write).                                                                                                                                                 |
      |cos_    |cos_(ar as double) as double                                                |math.bi     |Returns the cosine of an angle measured in radians.                                                                                                                                                           |
      |cosh    |cosh(x as double) as double                                                 |math.bi     |Returns the hyperbolic cosine of an angle measured in radians.                                                                                                                                                |
      |div     |div(num as integer, denom as integer) as div_t                              |stdlib.bi   |Returns the quotient and remainder of a division as a structure of type div_t.                                                                                                                                |
      |ecvt    |ecvt(x as double) as zstring ptr                                            |math.bi     |Converts a number to a zstring.                                                                                                                                                                               |
      |exit_   |exit_(status as integer)                                                    |stdlib.bi   |Exits a program. It will flush file buffers and closes all opened files, and run any functions called by atexit().                                                                                            |
      |exp_    |exp_(a as double) as double                                                 |math.bi     |Returns the value of e raised to the power of the argument (Inverse to natural logarithm).                                                                                                                    |
      |fabs    |fabs(d as double) as double                                                 |math.bi     |Returns the absolute value (i.e. positive value) of type double.                                                                                                                                              |
      |fclose  |fclose(s as FILE ptr) as FILE ptr                                           |stdio.bi    |Closes a file. Returns 0 if successful otherwise EOF.                                                                                                                                                         |
      |feof    |feof(s as FILE ptr) as integer                                              |stdio.bi    |Returns value of end-of-file indicator . (0 if not eof). Indicator will clear itself but can be reset by clearerr().                                                                                          |
      |ferror  |ferror(s as FILE ptr) as integer                                            |stdio.bi    |Returns error indicator for a stream (0 if no error). Error indicator is reset by clearerr() or rewind().                                                                                                     |
      |fflush  |fflush(s as FILE ptr) as integer                                            |stdio.bi    |Flushes (i.e. deletes) a stream (use stdin to flush the stream from the keyboard). Returns 0 if successful.                                                                                                   |
      |fgetc   |fgetc(s as FILE ptr) as integer                                             |stdio.bi    |Single character input (in ASCII) from passed stream (stdin for keyboard).                                                                                                                                    |
      |fgetpos |fgetpos(s as FILE ptr, c as fpos_t ptr) as integer                          |stdio.bi    |Saves the position of the file pointer on stream s at the location pointed to by c.                                                                                                                           |
      |fgets   |fgets(b as zstring ptr, n as integer, s as FILE ptr) as zstring ptr         |stdio.bi    |From the stream s reads up to n-1 characters to buffer b.                                                                                                                                                     |
      |floor   |floor(d as double) as double                                                |math.bi     |Returns the nearest whole number below the value passed.                                                                                                                                                      |
      |fmod    |fmod(x as double, y as double) as double                                    |math.bi     |Calculates the remainder of x divided by y.                                                                                                                                                                   |
      |fopen   |fopen(file as zstring ptr, mode as zstring ptr) as FILE ptr                 |stdio.bi    |Opens a file. Pass the DOS name of the file and a code to indicate whether for reading, writing, or appending. Codes are r for read, w for write, + for read and write, a for append and b to indicate binary.|
      |fprintf |fprintf(s as FILE ptr, fmt as zstring ptr, ...) as integer                  |stdio.bi    |Prints on stream s as many items as there are single % signs in fmt that have matching arguments in the list.                                                                                                 |
      |fputc   |fputc(c as integer, s as FILE ptr) as integer                               |stdio.bi    |Outputs the single character c to the stream s.                                                                                                                                                               |
      |fputs   |fputs(b as zstring ptr, s as FILE ptr) as integer                           |stdio.bi    |Sends the character stream in b to stream s, returns 0 if the operation fails.                                                                                                                                |
      |fread   |fread(buf as any ptr, b as size_t, c as size_t, s as FILE ptr) as integer   |stdio.bi    |Reads the number c items of data of size b bytes from file s to the buffer buf. Returns the number of data items actually read.                                                                               |
      |free    |free(p as any ptr)                                                          |stdlib.bi   |Frees the memory allocation for a pointer p to enable this memory to be used.                                                                                                                                 |
      |freopen |freopen(file as zstring ptr, mode as zstring ptr, s as FILE ptr) as FILE ptr|stdio.bi    |Opens a file for redirecting a stream. e.g. freopen("myfile", "w", stdout) will redirect the standard output to the opened "myfile".                                                                          |
      |frexp   |frexp(x as double, p as integer ptr) as double                              |math.bi     |Calculates a value m so that x equals m times 2 to some power. p is a pointer to m.                                                                                                                           |
      |fscanf  |fscanf(s as FILE ptr, fmt as zstring ptr, ...) as integer                   |stdio.bi    |Reads from stream s as many items as there are % signs in fmt with corresponding listed pointers.                                                                                                             |
      |fseek   |fseek(s as FILE ptr, offset as integer, origin as integer) as integer       |stdio.bi    |Locates a file pointer. With origin 0, 1 or 2 for the beginning, offset bytes into and at the end of the stream.                                                                                              |
      |fsetpos |fsetpos(s as FILE ptr, p as fpos_t ptr) as integer                          |stdio.bi    |Sets the file pointer for the stream s to the value pointed to by p.                                                                                                                                          |
      |ftell   |ftell(s as FILE ptr) as long                                                |stdio.bi    |Locates the position of the file pointer for the stream s.                                                                                                                                                    |
      |fwrite  |fwrite(buf as any ptr, b as integer, c as integer, s as FILE ptr) as integer|stdio.bi    |Writes the number c items of data of size b bytes from the buffer buf to the file s. Returns the number of data items actually written.                                                                       |
      |getc    |getc(s as FILE ptr) as integer                                              |stdio.bi    |Macro for single character input (in ASCII) from passed stream. (stdin for keyboard)                                                                                                                          |
      |getchar |getchar() as integer                                                        |stdio.bi    |Single character input from the standard input                                                                                                                                                                |
      |gets    |gets(b as zstring ptr) as zstring ptr                                       |stdio.bi    |Reads a stream of characters from the standard input until it meets \n or EOF.                                                                                                                                |
      |hypot   |hypot(x as double, y as double) as double                                   |math.bi     |Calculates the hypotenuse from the sides x and y.                                                                                                                                                             |
      |isalnum |isalnum(c as integer) as integer                                            |ctype.bi    |Returns a non zero value if character c is alphabetic or a digit.                                                                                                                                             |
      |isalpha |isalpha(c as integer) as integer                                            |ctype.bi    |Returns a non zero value if character c is alphabetic.                                                                                                                                                        |
      |iscntrl |iscntrl(c as integer) as integer                                            |ctype.bi    |Returns a non zero value if character c is a control character.                                                                                                                                               |
      |isdigit |isdigit(c as integer) as integer                                            |ctype.bi    |Returns a non zero value if character c is a digit.                                                                                                                                                           |
      |isgraph |isgraph(c as integer) as integer                                            |ctype.bi    |Returns a non zero value if character c is alphabetic.                                                                                                                                                        |
      |islower |islower(c as integer) as integer                                            |ctype.bi    |Returns a non-zero value if character c is a lower case character.                                                                                                                                            |
      |isprint |isprint(c as integer) as integer                                            |ctype.bi    |Returns a non zero value if character c is printable.                                                                                                                                                         |
      |ispunct |ispunct(c as integer) as integer                                            |ctype.bi    |Returns a non zero value if character c is a punctuation character.                                                                                                                                           |
      |isspace |isspace(c as integer) as integer                                            |ctype.bi    |Returns a non zero value if character c denotes a space.                                                                                                                                                      |
      |isupper |isupper(c as integer) as integer                                            |ctype.bi    |Returns a non-zero value if character c is an upper case character.                                                                                                                                           |
      |isxdigit|isxdigit(c as integer) as integer                                           |ctype.bi    |Returns a non-zero value if character c is a hex digit (0 to F or f).                                                                                                                                         |
      |ldexp   |ldexp(x as double, n as integer) as double                                  |math.bi     |Returns the product of x and 2 to the power n.                                                                                                                                                                |
      |ldiv    |ldiv(num as long, denom as long) as ldiv_t                                  |stdlib.bi   |Returns the quotient and remainder of a division as a structure of type ldiv_t.                                                                                                                               |
      |log_    |log_(a as double) as double                                                 |math.bi     |Returns the natural logarithm of the argument.                                                                                                                                                                |
      |log10   |log10(a as double) as double                                                |math.bi     |Returns the logarithm to the base 10 of the argument.                                                                                                                                                         |
      |malloc  |malloc(bytes as integer) as any ptr                                         |stdlib.bi   |Allocates memory. Returns a pointer to a buffer comprising storage for the specified size.                                                                                                                    |
      |modf    |modf(d as double, p as double ptr) as double                                |math.bi     |Returns the fractional part of a floating point number d. p points to the integral part expressed as a float.                                                                                                 |
      |perror  |perror(mess as zstring ptr)                                                 |stdio.bi    |Prints on the stream stderr a message passed as the argument.                                                                                                                                                 |
      |pow     |pow(x as double, y as double) as double                                     |math.bi     |Returns x to the power y.                                                                                                                                                                                     |
      |pow10   |pow10(x as double) as double                                                |math.bi     |Returns 10 to the power x (inverse function to log10()).                                                                                                                                                      |
      |printf  |printf(fmt as zstring ptr, ...) as integer                                  |stdio.bi    |Prints on standard output as many items as there are single % signs in fmt with matching arguments in the list.                                                                                               |
      |putc    |putc(c as integer, s as FILE ptr) as integer                                |stdio.bi    |Macro to output the single character c to the stream s.                                                                                                                                                       |
      |putchar |putchar(c as integer) as integer                                            |stdio.bi    |Macro to output the single character c to the standard output.                                                                                                                                                |
      |puts    |puts(b as zstring ptr) as integer                                           |stdio.bi    |Sends the character stream in b to the standard output, returns 0 if operation fails.                                                                                                                         |
      |rand    |rand() as integer                                                           |stdlib.bi   |Returns a pseudo random number. A seed is required. The seed is set with srand.                                                                                                                               |
      |realloc |realloc(p as any ptr, newsize as size_t) as any ptr                         |stdlib.bi   |Allocates memory. Returns a pointer to a buffer for a change in size of object pointed to by p.                                                                                                               |
      |rewind  |rewind(s as FILE ptr)                                                       |stdio.bi    |Clears the error indicators on a file stream (read or write). Necessary before reading an amended file.                                                                                                       |
      |scanf   |scanf(fmt as zstring ptr, ...) as integer                                   |stdio.bi    |Reads from standard input as many items as there are % signs in fmt with corresponding listed pointers.                                                                                                       |
      |sin_    |sin_(ar as double) as double                                                |math.bi     |Returns the sine of an angle measured in radians.                                                                                                                                                             |
      |sinh    |sinh(x as double) as double                                                 |math.bi     |Returns the hyperbolic sine of an angle measured in radians.                                                                                                                                                  |
      |sprintf |sprintf(p as zstring ptr, fmt as zstring ptr, ...) as integer               |stdio.bi    |Prints on zstring p as many items as there are single % signs in fmt that have matching arguments in the list.                                                                                                |
      |sqrt    |sqrt(a as double) as double                                                 |math.bi     |Returns the square root of the value passed. Domain error if value is negative.                                                                                                                               |
      |srand   |srand(seed as uinteger)                                                     |stdlib.bi   |Sets the seed for a random number. A possible seed is the current time.                                                                                                                                       |
      |sscanf  |sscanf(b as zstring ptr, fmt as zstring ptr, ...) as integer                |stdio.bi    |Reads from buffer b as many items as there are % signs in fmt with corresponding listed pointers.                                                                                                             |
      |strcat  |strcat(s1 as zstring ptr, s2 as zstring ptr) as zstring ptr                 |string.bi   |Concatenates (appends) zstring s2 to s1.                                                                                                                                                                      |
      |strchr  |strchr(s as zstring ptr, c as integer) as zstring ptr                       |string.bi   |Returns a pointer to the first occurrence of c in s or NULL if it fails to find one.                                                                                                                          |
      |strcmp  |strcmp(s1 as zstring ptr, s2 as zstring ptr) as integer                     |string.bi   |Compares zstring s2 to s1. Returns 0 or signed difference in ASCII values of first non matching character.                                                                                                    |
      |strcpy  |strcpy(s1 as zstring ptr, s2 as zstring ptr) as zstring ptr                 |string.bi   |Copies s2 into s1.                                                                                                                                                                                            |
      |strcspn |strcspn(s1 as zstring ptr, s2 as zstring ptr) as integer                    |string.bi   |Returns the number of characters in s1 encountered before meeting any of the characters in s2.                                                                                                                |
      |strerror|strerror(n as integer) as zstring ptr                                       |string.bi   |Returns a pointer to a system error message corresponding to the passed error number.                                                                                                                         |
      |strlen  |strlen(s as zstring ptr) as integer                                         |string.bi   |Returns the number of bytes in the null terminated zstring pointed to by s (does not count null).                                                                                                             |
      |strncat |strncat(s1 as zstring ptr, s2 as zstring ptr, n as integer) as zstring ptr  |string.bi   |Concatenates (appends) n bytes from zstring s2 to s1.                                                                                                                                                         |
      |strncmp |strncmp(s1 as zstring ptr, s2 as any ptr, n as integer) as integer          |string.bi   |Compares n bytes of zstring s2 to the same of s1. Returns 0 or signed difference in ASCII values of first non matching character.                                                                             |
      |strncpy |strncpy(s1 as zstring ptr, s2 as zstring ptr, n as integer) as zstring ptr  |string.bi   |Copies n bytes from s2 into s1.                                                                                                                                                                               |
      |strpbrk |strpbrk(s1 as zstring ptr, s2 as zstring ptr) as zstring ptr                |string.bi   |Returns a pointer to the first character encountered in s1 that is also in s2.                                                                                                                                |
      |strrchr |strrchr(s as zstring ptr, c as integer) as zstring ptr                      |string.bi   |Returns a pointer to the last occurrence of c in s or NULL if it fails to find one.                                                                                                                           |
      |strspn  |strspn(s1 as zstring ptr, s2 as zstring ptr) as integer                     |string.bi   |Returns the number of characters in s1 encountered before meeting a character which is not in s2.                                                                                                             |
      |strstr  |strstr(s1 as zstring ptr, s2 as zstring ptr) as zstring ptr                 |string.bi   |Finds the location of the zstring s2 in s1 and returns a pointer to its leading character.                                                                                                                    |
      |strtod  |strtod(s as zstring ptr, p as zstring ptr) as double                        |stdlib.bi   |Converts a zstring to double, provided the zstring is written in the form of a number.                                                                                                                        |
      |strtok  |strtok(s1 as zstring ptr, s2 as zstring ptr) as zstring ptr                 |string.bi   |Returns pointers to successive tokens utilizing the zstring s1. Tokens regarded as separators are listed in s2.                                                                                               |
      |system  |system(command as zstring ptr) as integer                                   |stdlib.bi   |Executes, from within a program, a command addressed to the operating system written as a zstring (e.g. DIR on Windows and DOS and LS on Linux).                                                              |
      |tan_    |tan_(ar as double) as double                                                |math.bi     |Returns the tangent of an angle measured in radians.                                                                                                                                                          |
      |tanh    |tanh(x as double) as double                                                 |math.bi     |Returns the hyperbolic tangent of an angle measured in radians.                                                                                                                                               |
      |tolower |tolower(c as integer) as integer                                            |ctype.bi    |Converts a character from upper case to lower case (uses ASCII code).                                                                                                                                         |
      |toupper |toupper(c as integer) as integer                                            |ctype.bi    |Converts a character from lower case to upper case (uses ASCII code).                                                                                                                                         |
      |ungetc  |ungetc(c as integer, s as FILE ptr) as integer                              |stdio.bi    |Pushes a character c back into the stream s, returns EOF if unsuccessful. Do not push more than one character.                                                                                                |
      +--------+----------------------------------------------------------------------------+------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

Buffer Manipulation

   #include "crt/string.bi"

      +----------------------------------------------------------------+--------------------------------------------------+
      |Prototype (with parameters)                                     |Comments                                          |
      |memchr(s as any ptr, c as integer, n as size_t) as any ptr      |Search for a character in a buffer.               |
      |memcmp(s1 as any ptr, s2 as any ptr, n as size_t) as integer    |Compare two buffers.                              |
      |memcpy(dest as any ptr, src as any ptr, n as size_t) as any ptr |Copy one buffer into another .                    |
      |memmove(dest as any ptr, src as any ptr, n as size_t) as any ptr|Move a number of bytes from one buffer lo another.|
      |memset(s as any ptr, c as integer, n as size_t) as any ptr      |Set all bytes of a buffer to a given character.   |
      +----------------------------------------------------------------+--------------------------------------------------+

Character Classification and Conversion

   #include "crt/ctype.bi"

      +---------------------------------+-------------------------------------+
      |Prototype (with parameters)      |Comments                             |
      |isalnum(c as integer) as integer |True if c is alphanumeric.           |
      |isalpha(c as integer) as integer |True if c is a letter.               |
      |isascii(c as integer) as integer |True if c is ASCII .                 |
      |iscntrl(c as integer) as integer |True if c is a control character.    |
      |isdigit(c as integer) as integer |True if c is a decimal digit.        |
      |isgraph(c as integer) as integer |True if c is a graphical character.  |
      |islower(c as integer) as integer |True if c is a lowercase letter.     |
      |isprint(c as integer) as integer |True if c is a printable character.  |
      |ispunct(c as integer) as integer |True if c is a punctuation character.|
      |isspace(c as integer) as integer |True if c is a space character.      |
      |isupper(c as integer) as integer |True if c is an uppercase letter.    |
      |isxdigit(c as integer) as integer|True if c is a hexadecimal digit.    |
      |toascii(c as integer) as integer |Convert c to ASCII .                 |
      |tolower(c as integer) as integer |Convert c to lowercase.              |
      |toupper(c as integer) as integer |Convert c to uppercase.              |
      +---------------------------------+-------------------------------------+

Data Conversion

   #include "crt/stdlib.bi"

      +---------------------------------------------------------------------------------+--------------------------------------------------------+
      |Prototype (with parameters)                                                      |Comments                                                |
      |atof(string1 as zstring ptr) as double                                           |Convert zstring to floating point value.                |
      |atoi(string1 as zstring ptr) as integer                                          |Convert zstring to an integer value.                    |
      |atol(string1 as zstring ptr) as integer                                          |Convert zstring to a long integer value.                |
      |itoa(value as integer, zstring as zstring ptr, radix as integer) as zstring ptr  |Convert an integer value to a zstring using given radix.|
      |ltoa(value as long, zstring as zstring ptr, radix as integer) as zstring ptr     |Convert long integer to zstring in a given radix.       |
      |strtod(string1 as zstring ptr, endptr as zstring ptr) as double                  |Convert zstring to a floating point value.              |
      |strtol(string1 as zstring ptr, endptr as zstring ptr, radix as integer) as long  |Convert zstring to a long integer using a given radix.  |
      |strtoul(string1 as zstring ptr, endptr as zstring ptr, radix as integer) as ulong|Convert zstring to unsigned long.                       |
      +---------------------------------------------------------------------------------+--------------------------------------------------------+

Directory Manipulation

   #include "crt/io.bi"

      +----------------------------------------------------------------+------------------------------------------+
      |Prototype (with parameters)                                     |Comments                                  |
      |_chdir(path as zstring ptr) as integer                          |Change current directory to given path.   |
      |_getcwd(path as zstring ptr, numchars as integer) as zstring ptr|Returns name of current working directory.|
      |_mkdir(path as zstring ptr) as integer                          |Create a directory using given path name. |
      |_rmdir(path as zstring ptr) as integer                          |Delete a specified directory.             |
      +----------------------------------------------------------------+------------------------------------------+

File Manipulation

   #include "crt/sys/stat.bi"
   #include "crt/io.bi"

      +------------------------------------------------------------------+------------------------------------------+
      |Prototype (with parameters)                                       |Comments                                  |
      |chmod(path as zstring ptr, pmode as integer) as integer           |Change permission settings of a file.     |
      |fstat(handle as integer, buffer as type stat ptr) as integer      |Get file status information.              |
      |remove(path as zstring ptr) as integer                            |Delete a named file.                      |
      |rename_(oldname as zstring ptr, newname as zstring ptr) as integer|rename a file.                            |
      |stat(path as zstring ptr, buffer as type stat ptr) as integer     |Get file status information of named file.|
      |umask(pmode as uinteger) as uinteger                              |Set file permission mask.                 |
      +------------------------------------------------------------------+------------------------------------------+

Stream I/O

   #include "crt/stdio.bi"

      +------------------------------------------------------------------------------------------------------------+-----------------------------------------------------------------+
      |Prototype (with parameters)                                                                                 |Comments                                                         |
      |clearerr(file_pointer as FILE ptr)                                                                          |Clear error indicator of stream,                                 |
      |fclose(file_pointer as FILE ptr) as integer                                                                 |Close a file,                                                    |
      |feof(file_pointer as FILE ptr) as integer                                                                   |Check if end of file occurred on a stream.                       |
      |ferror(file_pointer as FILE ptr) as integer                                                                 |Check if any error occurred during file I/0.                     |
      |fflush(file_pointer as FILE ptr) as integer                                                                 |Write out (flush) buffer to file.                                |
      |fgetc(file_pointer as FILE ptr) as integer                                                                  |Get a character from a stream.                                   |
      |fgetpos(file_pointer as FILE ptr, fpos_t current_pos) as integer                                            |Get the current position in a stream.                            |
      |fgets(string1 as zstring ptr, maxchar as integer, file_pointer as FILE ptr) as zstring ptr                  |Read a zstring from a file.                                      |
      |fopen(filename as zstring ptr, access_mode as zstring ptr) as FILE ptr                                      |Open a file for buffered I/0.                                    |
      |fprintf(file_pointer as FILE ptr, format_string as zstring ptr, args) as integer                            |Write formatted output to a file,                                |
      |fputc(c as integer, file_pointer as FILE ptr) as integer                                                    |Write a character to a stream.                                   |
      |fputchar(c as integer) as integer                                                                           |Write a character to stdout.                                     |
      |fputs(string1 as zstring ptr, file_pointer as FILE ptr) as integer                                          |Write a zstring to a stream.                                     |
      |fread(buffer as zstring ptr, size as size_t count as size_t, file_pointer as FILE ptr) as size_t            |Read unformatted data from a stream into a buffer.               |
      |freopen(filename as zstring ptr, access as zstring ptr mode, file_pointer as FILE ptr) as FILE ptr          |Reassign a file pointer to a different file.                     |
      |fscanf(file_pointer as FILE ptr, format as zstring ptr zstring, args) as integer                            |Read formatted input from a stream.                              |
      |fseek(file_pointer as FILE ptr, offset as long, origin as integer) as integer                               |Set current position in file to a new location.                  |
      |fsetpos(file_pointer as FILE ptr, current_pos as fpos_t) as integer                                         |Set current position in file to a new location.                  |
      |ftell(file_pointer as FILE ptr) as long                                                                     |Get current location in file.                                    |
      |fwrite(buffer as zstring ptr, size as size_t, count as size_t file_pointer as FILE ptr) as size_t           |Write unformatted data from a buffer to a stream.                |
      |getc(file_pointer as FILE ptr) as integer                                                                   |Read a character from a stream.                                  |
      |getchar() as integer                                                                                        |Read a character from stdin.                                     |
      |gets(buffer as zstring ptr) as zstring ptr                                                                  |Read a line from stdin into a buffer.                            |
      |printf(format as zstring ptr _string, args) as integer                                                      |Write formatted output to stdout.                                |
      |putc(c as integer, file_pointer as FILE ptr) as integer                                                     |Write a character to a stream.                                   |
      |putchar(c as integer) as integer                                                                            |Write a character to stdout.                                     |
      |puts(string1 as zstring ptr) as integer                                                                     |Write a zstring to stdout.                                       |
      |rewind(file_pointer as FILE ptr)                                                                            |Rewind a file.                                                   |
      |scanf(format_string as zstring ptr, args) as integer                                                        |Read formatted input from stdin.                                 |
      |setbuf(file_pointer as FILE ptr, buffer as zstring ptr)                                                     |Set up a new buffer for the stream.                              |
      |setvbuf(file_pointer as FILE ptr, buffer as zstring ptr, buf_type as integer, buf as size_t size) as integer|Set up new buffer and control the level of buffering on a stream.|
      |sprintf(string1 as zstring ptr, format_string as zstring ptr, args) as integer                              |Write formatted output to a zstring.                             |
      |sscanf(buffer as zstring ptr, format_string as zstring ptr, args) as integer                                |Read formatted input from a zstring.                             |
      |tmpfile() as FILE ptr                                                                                       |Open a temporary file.                                           |
      |tmpnam(file_name as zstring ptr) as zstring ptr                                                             |Get temporary file name.                                         |
      |ungetc(c as integer, file_pointer as FILE ptr) as integer                                                   |Push back character into stream' s buffer                        |
      +------------------------------------------------------------------------------------------------------------+-----------------------------------------------------------------+

Low level I/O

   #include "crt/io.bi"

   So far Win32 only, connects to MSVCRT.DLL (headers missing for other 
   platforms)

      +------------------------------------------------------------------------------+----------------------------------------------------+
      |Prototype (with parameters)                                                   |Comments                                            |
      |_close(handle as integer) as integer                                          |Close a file opened for unbuffered I/O.             |
      |_creat(filename as zstring ptr, pmode as integer) as integer                  |Create a new file with specified permission setting.|
      |_eof(handle as integer) as integer                                            |Check for end of file.                              |
      |_lseek(handle as integer, offset as long, origin as integer) as long          |Go to a specific position in a file.                |
      |_open(filename as zstring ptr, oflag as integer, pmode as uinteger) as integer|Open a file for low-level I/O.                      |
      |_read(handle as integer, buffer as zstring ptr, length as uinteger) as integer|Read binary data from a file into a buffer.         |
      |_write(handle as integer, buffer as zstring ptr, count as uinteger) as integer|Write binary data from a buffer to a file.          |
      +------------------------------------------------------------------------------+----------------------------------------------------+

Mathematics

   #include "crt/math.bi"

      +---------------------------------------------------+----------------------------------------------------------+
      |Prototype (with parameters)                        |Comments                                                  |
      |abs_(n as integer) as integer                      |Get absolute value of an integer.                         |
      |acos_(x as double) as double                       |Compute arc cosine of x.                                  |
      |asin_(x as double) as double                       |Compute arc sine of x.                                    |
      |atan_(x as double) as double                       |Compute arc tangent of x.                                 |
      |atan2_(y as double, x as double) as double         |Compute arc tangent of y/x.                               |
      |ceil(x as double) as double                        |Get smallest integral value that exceeds x.               |
      |cos_(x as double) as double                        |Compute cosine of angle in radians.                       |
      |cosh(x as double) as double                        |Compute the hyperbolic cosine of x.                       |
      |div(number as integer, denom as integer) as div_t  |Divide one integer by another.                            |
      |exp_(x as double) as double                        |Compute exponential of x.                                 |
      |fabs(x as double) as double                        |Compute absolute value of x.                              |
      |floor(x as double) as double                       |Get largest integral value less than x.                   |
      |fmod(x as double, y as double) as double           |Divide x by y with integral quotient and return remainder.|
      |frexp(x as double, expptr as integer ptr) as double|Breaks down x into mantissa and exponent of no.           |
      |labs(n as long) as long                            |Find absolute value of long integer n.                    |
      |ldexp(x as double, exp as integer) as double       |Reconstructs x out of mantissa and exponent of two.       |
      |ldiv(number as long, denom as long) as ldiv_t      |Divide one long integer by another.                       |
      |log_(x as double) as double                        |Compute log(x).                                           |
      |log10(x as double) as double                       |Compute log to the base 10 of x.                          |
      |modf(x as double, intptr as double ptr) as double  |Breaks x into fractional and integer parts.               |
      |pow(x as double, y as double) as double            |Compute x raised to the power y.                          |
      |rand() as integer                                  |Get a random integer between 0 and 32767.                 |
      |random(max_num as integer) as integer              |Get a random integer between 0 and max_num.               |
      |randomize()                                        |Set a random seed for the random number generator.        |
      |sin_(x as double) as double                        |Compute sine of angle in radians.                         |
      |sinh(x as double) as double                        |Compute the hyperbolic sine of x.                         |
      |sqrt(x as double) as double                        |Compute the square root of x.                             |
      |srand(seed as uinteger)                            |Set a new seed for the random number generator (rand).    |
      |tan_(x as double) as double                        |Compute tangent of angle in radians.                      |
      |tanh(x as double) as double                        |Compute the hyperbolic tangent of x.                      |
      +---------------------------------------------------+----------------------------------------------------------+

Memory Allocation

   #include "crt/stdlib.bi"

      +-------------------------------------------------------------+-------------------------------------------------------+
      |Prototype (with parameters)                                  |Comments                                               |
      |calloc(num as size_t elems, elem_size as size_t) as any ptr  |Allocate an array and initialise all elements to zero .|
      |free(mem_address as any ptr)                                 |Free a block of memory.                                |
      |malloc(num as size_t bytes) as any ptr                       |Allocate a block of memory.                            |
      |realloc(mem_address as any ptr, newsize as size_t) as any ptr|Reallocate (adjust size) a block of memory.            |
      +-------------------------------------------------------------+-------------------------------------------------------+

Process Control

   #include "crt/stdlib.bi"

      +------------------------------------------------------------------------------------------+-------------------------------------------------------+
      |Prototype (with parameters)                                                               |Comments                                               |
      |abort()                                                                                   |Abort a process.                                       |
      |execl(path as zstring ptr, arg0 as zstring ptr, arg1 as zstring ptr,..., NULL) as integer |Launch a child process (pass command line).            |
      |execlp(path as zstring ptr, arg0 as zstring ptr, arg1 as zstring ptr,..., NULL) as integer|Launch child (use PATH, pass command line).            |
      |execv(path as zstring ptr, argv as zstring ptr) as integer                                |Launch child (pass argument vector).                   |
      |execvp(path as zstring ptr, argv as zstring ptr) as integer                               |Launch child (use PATH, pass argument vector).         |
      |exit_(status as integer)                                                                  |Terminate process after flushing all buffers.          |
      |getenv(varname as zstring ptr) as zstring ptr                                             |Get definition of environment variable,                |
      |perror(string1 as zstring ptr)                                                            |Print error message corresponding to last system error.|
      |putenv(envstring as zstring ptr) as integer                                               |Insert new definition into environment table.          |
      |raise(signum as integer) as integer                                                       |Generate a C signal (exception).                       |
      |system_(string1 as zstring ptr) as integer                                                | Execute a resident operating system command.          |
      +------------------------------------------------------------------------------------------+-------------------------------------------------------+

Searching and Sorting

   #include "crt/stdlib.bi"
            Note: The compare callback function required by bsearch and 
            qsort must be declared as cdecl. It must return a value <0 if 
            its first argument should be located before the second one in 
            the sorted array, >0 if the first argument should be located 
            after the second one, and zero if their relative positions are 
            indifferent (equal values).  

      +-------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+
      |Prototype (with parameters)                                                                                                                            |Comments                                     |
      |bsearch(key as any ptr, base as any ptr, num as size_t, width as size_t, compare as function(elem1 as any ptr, elem2 as any ptr) as integer) as any ptr|Perform binary search.                       |
      |qsort(base as any ptr, num as size_t, width as size_t, compare as function(elem1 as any ptr, elem2 as any ptr) as integer)                             |Use the quicksort algorithm to sort an array.|
      +-------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+

String Manipulation

   #include "crt/string.bi"

      +-----------------------------------------------------------------------------------+----------------------------------------------------------+
      |Prototype (with parameters)                                                        |Comments                                                  |
      |stpcpy(dest as zstring ptr, src as zstring ptr) as zstring ptr                     |Copy one zstring into another.                            |
      |strcmp(string1 as zstring ptr, string2 as zstring ptr) as integer                  |Compare string1 and string2 to determine alphabetic order.|
      |strcpy(string1 as zstring ptr, string2 as zstring ptr) as zstring ptr              |Copy string2 to string1.                                  |
      |strerror(errnum as integer) as zstring ptr                                         |Get error message corresponding to specified error number.|
      |strlen(string1 as zstring ptr) as integer                                          |Determine the length of a zstring.                        |
      |strncat(string1 as zstring ptr, string2 as zstring ptr, n as size_t) as zstring ptr|Append n characters from string2 to string1.              |
      |strncmp(string1 as zstring ptr, string2 as zstring ptr, n as size_t) as integer    |Compare first n characters of two strings.                |
      |strncpy(string1 as zstring ptr, string2 as zstring ptr, n as size_t) as zstring ptr|Copy first n characters of string2 to string1.            |
      |strnset(string1 as zstring ptr, c as integer, size _t n) as zstring ptr            |Set first n characters of zstring to c.                   |
      |strrchr(string1 as zstring ptr, c as integer) as zstring ptr                       |Find last occurrence of character c in zstring.           |
      +-----------------------------------------------------------------------------------+----------------------------------------------------------+

Time

   #include "crt/time.bi"

      +----------------------------------------------+-------------------------------------------------------------+
      |Prototype (with parameters)                   |Comments                                                     |
      |asctime(time as type tm ptr) as zstring ptr   |Convert time from type tm to zstring.                        |
      |clock() as clock_t                            |Get elapsed processor time in clock ticks.                   |
      |ctime(time as time_t ptr) as zstring ptr      |Convert binary time to zstring.                              |
      |difftime(time_t time2, time_t time1) as double|Compute the difference between two times in seconds.         |
      |gmtime(time as time_t ptr) as type tm ptr     |Get Greenwich Mean Time (GMT) in a tm structure.             |
      |localtime(time as time_t ptr) as type tm ptr  |Get the local time in a tm structure.                        |
      |time_(timeptr as time_t ptr) as time_t        |Get current time as seconds elapsed since 0 hours GMT 1/1/70.|
      +----------------------------------------------+-------------------------------------------------------------+

See also
   * #include



----------------------------------------------------------- ProPgFileIO ----
File I/O with FreeBASIC

In FreeBASIC, there are 4 possible ways to perform file I/O:

1. Using the built-in BASIC commands like Open , Get, Put, and Close. This 
way is mostly portable across all platforms supported by FreeBASIC. Open 
files are identified by "file numbers", that are specific to FreeBASIC and 
can't be passed into functions from below.

2. Using the C stream I/O functions like fopen, fread, ftell, fclose (see 
Stream I/O in C Standard Library Functions) of the C library FreeBASIC 
relies on. This is slightly faster than and adds a few features beyond 
method above, and still well portable. Open files are identified by file 
pointers, as in the C language, again unique to this access method.  The 
FileAttr function can be used to return a stream I/O pointer from a file 
number as in 1. above.

3. Using the C low-level I/O functions like _open, _read, _write, _close 
(see Low Level I/O in C Standard Library Functions). Those functions should 
be portable, but so far headers are available for Win32 only, so code using 
them will not compile to any other platform by now.

4. Talk directly to the OS kernel (DOS: use DOS and DPMI INT's , Win32: use 
API calls like CreateFile, WriteFile). This is no longer portable. Files 
are identified by handles generated by and specific to the OS kernel.

This example shows methods 1. and 2. described above:

Example
   '==== File I/O example / 2018-05-18 ====

   Dim As String fileName = "test_123.tmp"
   Dim As ULong buffer(0 To 99) '100 x 4 bytes
   Dim As Integer numItems, result

   Print !"\n==== Using the C Runtime (CRT) file I/O ====\n"

   #include Once "crt/stdio.bi"

   Dim As FILE Ptr filePtr

   'open in binary writing mode
   filePtr = fopen(fileName, "wb")
   If filePtr <> 0 Then
      'write 75 x 4 = 300 bytes
      numItems = fwrite(@buffer(0), SizeOf(buffer(0)), 75, filePtr)
      Print "Number of bytes written: " & Str(numItems * SizeOf(buffer(0)))
      Print "Number of items written: " & Str(numItems)
      fclose(filePtr)
   Else
      Print "Failed to open " & fileName & " for writing"
   End If

   'open in binary reading mode
   filePtr = fopen(fileName, "rb")
   If filePtr <> 0 Then
      'skip the first 25 items
      If fseek(filePtr, SizeOf(buffer(0)) * 25, SEEK_SET) <> 0 Then
         Print "Failed to seek (set file stream position)"
      End If
      'try to read the next 100 items
      numItems = fread(@buffer(0), SizeOf(buffer(0)), 100, filePtr)
      Print "Number of bytes read: " & Str(numItems * SizeOf(buffer(0)))
      Print "Number of items read: " & Str(numItems)
      fclose(filePtr)
   Else
      Print "Failed to open " & fileName & " for reading"
   End If

   result = remove(fileName) 'delete file
   If result = 0 Then Print "Removed: " & fileName

   Print !"\n==== Using the FreeBASIC file I/O ====\n"

   Dim As Long fileNum
   Dim As Integer numBytes

   fileNum = FreeFile
   'open in binary writing mode
   If Open(fileName, For Binary, Access Write, As fileNum) = 0 Then
      'write 75 x 4 = 300 bytes
      result = Put(fileNum, , buffer(0), 75) 'No @buffer(0)
      numBytes = Seek(fileNum) - 1 'FreeBASIC file position is 1-based
      Print "Number of bytes written: " & Str(numBytes)
      Print "Number of items written: " & Str(numBytes \ SizeOf(buffer(0)))
      Close(fileNum)
   Else
      Print "Failed to open " & fileName & " for writing"
   End If

   'open in binary reading mode
   If Open(fileName, For Binary, Access Read, As fileNum) = 0 Then
      'skip the first 25 items
      Seek fileNum, 25 * SizeOf(buffer(0)) + 1 'Note: +1 & seek(...) not allowed
      'try to read the next 100 items
      result = Get(fileNum, , buffer(0), 100, numBytes)
      Print "Number of bytes read: " & Str(numBytes)
      Print "Number of items read: " & Str(numBytes \ SizeOf(buffer(0)))
      Close(fileNum)
   Else
      Print "Failed to open " & fileName & " for reading"
   End If

   result = Kill(fileName) 'delete file
   If result = 0 Then Print "Killed: " & fileName

   Print !"\n==== End ====\n"

 

See also
   * File I/O Functions
   * C Standard Library Functions
   * Get (File I/O Command)



---------------------------------------------------- ProPgDynamicMemory ----
Dynamic memory management with FreeBASIC

Managing Dynamic Memory (Allocation / Deallocation) with FreeBASIC

Preamble:

   FreeBASIC supports three basic types of memory allocation:
      - Static allocation occurs for static and global variables: Memory is 
      allocated once when the program runs and persists throughout the life 
      of the program.
      - Stack allocation occurs for procedure parameters and local 
      variables: Memory is allocated when the corresponding block is 
      entered, and released when the block is left, as many times as 
      necessary.
      - Dynamic allocation is the subject of this page.

   Static allocation and stack allocation have two things in common:
      - The size of the variable must be known at compile time.
      - Memory allocation and deallocation occur automatically (when the 
      variable is instantiated then destroyed). The user can not anticipate 
      the destruction of such a variable.

   Most of the time, that is fine. However, there are situations where one 
   or other of these constraints cause problems (when the memory needed 
   depends on user input, the sizing can only be determined during 
   run-time).

   If the size of everything must be declared at compile time, the best is 
   try to estimate the maximum size of the variables needed and hope this 
   will be enough.
   This is a bad solution for at least third reasons:
      - First, it leads to wasting memory if it is not fully used.
      - Second, most normal variables are allocated in a part of the memory 
      called the stack. The amount of stack memory for a program is usually 
      quite low (1 MB or 2 MB by default). If exceeding this number, the 
      stack overflow will occur, and the program will abort.
      - Third, and most importantly, this can lead to artificial 
      limitations and / or overflows. What happens if the required memory 
      becomes greater than the reserved memory (stopping the program, 
      emitting message to user, ...).

   Fortunately, these problems are easily solved through the dynamic 
   allocation of memory. Dynamic memory allocation is a way of running 
   programs to request memory from the operating system when needed. This 
   memory does not come from the program's limited stack memory, but it is 
   rather allocated from a much larger memory pool managed by the operating 
   system called heap. On modern machines, the heap can have a size of 
   several gigabytes.

Keywords for dynamic memory allocation
   There are two sets of keyword for dynamic allocation / deallocation:
      - Allocate / CAllocate / Reallocate / Deallocate: for raw memory 
      allocation then deallocation, for simple pre-defined types or buffers 
      (as numeric pre-defined types, user buffer, ...).
      - New / Delete: for memory allocation + construction then destruction 
      + deallocation, for object type (as var-len strings, UDTs, ...).

   Mixing keywords between these two sets is very strongly discouraged when 
   managing a same memory block.

Dynamic memory allocation management by using Allocate / Callocate / 
Reallocate / Deallocate
   For each keyword, see the detailed syntax, precise description and 
   examples in the individual documentation pages.

   Additional functionalities and tips for use:
      - Allocate / CAllocate / Reallocate allows to know if memory 
      allocation is successful (otherwise a null pointer is returned).
      - Even if the allocated memory size is requested for 0 Byte, a non 
      null pointer is returned and its value should be used to then release 
      the allocation (except for Reallocate(pointer, 0) which behaves 
      similar to Deallocate).
      - For memory deallocation, Deallocate can be called on any type of 
      pointer (with the right value anyway).
      - If the user absolutely wants to use this type of allocation for an 
      object (for example to be able to do reallocation), it's up to him to 
      manually call if necessary the constructor and the destructor (by 
      using member access operator) at the right way.
      - After deallocation, the pointer value becomes invalid (pointing to 
      an invalid memory address), and its reuse (for dereferencing or 
      calling Deallocate again) will result in undefined behavior.

Dynamic memory allocation management by using New / Delete
   For each keyword, see the detailed syntax, precise description and 
   examples in the individual documentation pages.

   Additional functionalities and tips for use:
      - Before, New did not signal if memory allocation was successful 
      (program hangs). Problem solved from fbc rev 1.06, by returning a 
      null pointer if New fails.
      - Even if the allocated memory size is requested for 0 Byte (New 
      predefined_datatype[0]), a non null pointer is returned and its value 
      should be used to then release the allocation.
      - For object destruction and memory deallocation, Delete must be 
      called on a proper typed pointer (otherwise the object destructor 
      will not be called or miscalled, and that may result in a memory leak 
      or even a crash with Delete[]).
      - The user can also use this type of allocation for a simple 
      pre-defined types (except for the fix-len strings), but this does not 
      functionally add anything, except a simpler usage syntax for 
      allocation.
      - After destruction + deallocation, the pointer value becomes invalid 
      (pointing to an invalid memory address), and its reuse (for 
      dereferencing or calling Delete again) will result in undefined 
      behavior.
      - If used, the special Placement New (using memory already allocated) 
      induces only object construction, so use Delete is forbidden (to 
      avoid double request of deallocation). If necessary, the only 
      destruction of the object must be manually do by user (calling the 
      destructor by using member access operator).

Variant by using Redim / Erase
   FreeBASIC also supports dynamic arrays (variable-length arrays).
   The memory used by a dynamic array to store its elements is allocated at 
   run-time in the heap. Dynamic arrays can contain simple types as well as 
   complex objects.
   By using ReDim, the user does not need to call the constructor / 
   destructor because ReDim does this automatically when adding / removing 
   element. Erase then destroys all the remaining elements to completely 
   free the memory allocated to them.

Use cases by comparing 4 methods
   Usage example on a set of objects, by comparing 4 methods:
      - 3 then 4 objects: CAllocate, Reallocate, Deallocate, (+ 
      .constructor + .destructor).
      - 3 objects: New, Delete.
      - 3 objects: Placement New, (+ .destructor).
      - 3 then 4 objects: ReDim, Erase.
   Type UDT
      Dim As String S = "FreeBASIC"              '' induce an implicit constructor and destructor
   End Type

   ' 3 then 4 objects: Callocate, Reallocate, Deallocate, (+ .constructor + .destructor)
   Dim As UDT Ptr p1 = CAllocate(3, SizeOf(UDT))  '' allocate cleared memory for 3 elements (string descriptors cleared,
                                       ''     but maybe useless because of the constructor's call right behind)
   For I As Integer = 0 To 2
      p1[I].Constructor()                        '' call the constructor on each element
   Next I
   For I As Integer = 0 To 2
      p1[I].S &= Str(I)                          '' add the element number to the string of each element
   Next I
   For I As Integer = 0 To 2
      Print "'" & p1[I].S & "'",                 '' print each element string
   Next I
   Print
   p1 = Reallocate(p1, 4 * SizeOf(UDT))           '' reallocate memory for one additional element
   Clear p1[3], 0, 3 * SizeOf(Integer)            '' clear the descriptor of the additional element,
                                       ''     but maybe useless because of the constructor's call right behind
   p1[3].Constructor()                            '' call the constructor on the additional element
   p1[3].S &= Str(3)                              '' add the element number to the string of the additional element
   For I As Integer = 0 To 3
      Print "'" & p1[I].S & "'",                 '' print each element string
   Next I
   Print
   For I As Integer = 0 To 3
      p1[I].Destructor()                         '' call the destructor on each element
   Next I
   Deallocate(p1)                                 '' deallocate the memory
   Print

   ' 3 objects: New, Delete
   Dim As UDT Ptr p2 = New UDT[3]                 '' allocate memory and construct 3 elements
   For I As Integer = 0 To 2
      p2[I].S &= Str(I)                          '' add the element number to the string of each element
   Next I
   For I As Integer = 0 To 2
      Print "'" & p2[I].S & "'",                 '' print each element string
   Next I
   Print
   Delete [] p2                                   '' destroy the 3 element and deallocate the memory
   Print

   ' 3 objects: Placement New, (+ .destructor)
   ReDim As Byte array(0 To 3 * SizeOf(UDT) - 1)  '' allocate buffer for 3 elements
   Dim As Any Ptr p = @array(0)
   Dim As UDT Ptr p3 = New(p) UDT[3]              '' only construct the 3 elements in the buffer (placement New)
   For I As Integer = 0 To 2
      p3[I].S &= Str(I)                          '' add the element number to the string of each element
   Next I
   For I As Integer = 0 To 2
      Print "'" & p3[I].S & "'",                 '' print each element string
   Next I
   Print
   For I As Integer = 0 To 2
      p3[I].Destructor()                         '' call the destructor on each element
   Next I
   Erase array                                    '' deallocate the buffer
   Print

   ' 3 then 4 objects: Redim, Erase
   ReDim As UDT p4(0 To 2)                        '' define a dynamic array of 3 elements
   For I As Integer = 0 To 2
      p4(I).S &= Str(I)                          '' add the element number to the string of each element
   Next I
   For I As Integer = 0 To 2
      Print "'" & p4(I).S & "'",                 '' print each element string
   Next I
   Print
   ReDim Preserve p4(0 To 3)                      '' resize the dynamic array for one additional element
   p4(3).S &= Str(3)                              '' add the element number to the string of the additional element
   For I As Integer = 0 To 3
      Print "'" & p4(I).S & "'",                 '' print each element string
   Next I
   Print
   Erase p4                                       '' erase the dynamic array
   Print

   Sleep
         
 Output:

   'FreeBASIC0'  'FreeBASIC1'  'FreeBASIC2'
   'FreeBASIC0'  'FreeBASIC1'  'FreeBASIC2'  'FreeBASIC3'

   'FreeBASIC0'  'FreeBASIC1'  'FreeBASIC2'

   'FreeBASIC0'  'FreeBASIC1'  'FreeBASIC2'

   'FreeBASIC0'  'FreeBASIC1'  'FreeBASIC2'
   'FreeBASIC0'  'FreeBASIC1'  'FreeBASIC2'  'FreeBASIC3'
   			

Specific dynamic image buffer allocation by using Imagecreate / 
Imagedestroy
   ImageCreate allocates and initializes storage for an image.
   The resulting image buffer can be used in drawing procedures while in 
   any screen mode, and across mode changes,  as long as the color depth of 
   the image buffer matches that of the graphics screen.
   ImageDestroy destroys and deallocates storage for an image.

See also
   * New and Delete
   * Variable-length Arrays
   * Dynamic Object and Data Lifetime



----------------------------------------------- ProPgRecursionIteration ----
Replace Recursion with Iteration

How to replace any recursion with simple iteration, or unlimited iteration 
with its own stack.

Preamble:

   Iteration and recursion are two very useful ways to program, especially 
   to perform a certain number of times a certain script, and thus allow 
   optimization of the code. If iteration is relatively easy to understand, 
   recursion is a concept not necessarily obvious at the beginning.
   When speaking of a recursive procedure (subroutine or function), we 
   refer to a syntactic characteristic: the procedure, in its own 
   definition, refers to itself (it calls itself).
   But when talking about recursive process, linear or tree, we are 
   interested in the process flow, not in the syntax of the procedure's 
   writing.
   Thus, a procedure can have a recursive definition but correspond to an 
   iterative process.

   Some treatments are naturally implemented as a recursive algorithm 
   (although this is not always the most optimal solution).
   The main problem of the recursive approach is that it consumes 
   potentially a lot of space on the execution stack: from a certain level 
   of "depth" of recursion, the space allocated for the execution stack of 
   the thread is exhausted, and causes an error of type "stack overflow".
   Repeatedly calling the same procedure can also make the execution 
   slower, although this may make the code easier.
   To increase the speed of execution, simple recursive algorithms can be 
   recreated in little more complicated iterative algorithms using loops 
   that execute much faster.

   What is the use of recursion if it increases the execution time and 
   memory space compared to an iterative solution?
   There are still cases where it is not possible to do otherwise, where 
   iterative translation does not exist or, where it exists, is much 
   heavier to implement (requiring for example a dynamic storage capacity 
   to substitute for the execution stack).

   Table of Contents
1. Recursion and iteration definition
2. Problem of replacing recursion with iteration
3. Replace tail recursion with simple iteration
4. Replace non-tail recursion with more complex iteration

1. Recursion and iteration definition
   Recursion and iteration both repeatedly execute the instruction set:
      - Recursion occurs when an instruction in a procedure calls the 
      procedure itself repeatedly.
      - Iteration occurs when a loop executes repeatedly until the control 
      condition becomes false.

   The main difference between recursion and iteration is that recursion is 
   a process always applied to a procedure, while iteration is applied to a 
   set of instructions to execute repeatedly.

   Definition of Recursion
      FreeBASIC allows a procedure to call itself in its code. This means 
      that the procedure definition has a procedure call to itself.
      The set of local variables and parameters used by the procedure are 
      newly created each time the procedure is called and are stored at the 
      top of the execution stack.
      But every time a procedure calls itself, it does not create a new 
      copy of that procedure.
      The recursive procedure does not significantly reduce the size of the 
      code and does not even improve the memory usage, but it does a little 
      bit compared to iteration.

      To end recursion, a condition must be tested to force the return of 
      the procedure without giving a recursive call to itself.
      The absence of a test of a condition in the definition of a recursive 
      procedure would leave the procedure in infinite recursion once 
      called.

      Note: When the parameters of a recursive procedure are passed by 
      reference, take care to work with local variables when the code body 
      needs to modify their values.

      Simple example with a recursive function which returns the factorial 
      of the integer:
         The code body of the recursive function is defined by using the 
         recursive definition of the factorial function:
            Case (n = 0) : factorial(0) = 1
            Case (n > 0) : factorial(n) = n * factorial(n-1)

         The first line allows to determine the end condition: If (n = 0) 
         Then Return 1
         The second line allows to determine the statement syntax which 
         calls the function itself: Return n * factorial(n - 1)

         Full code:
   Function recursiveFactorial (ByVal n As Integer) As Integer
      If (n = 0) Then                           '' end condition
         Return 1
      Else                                      '' recursion loop
         Return n * recursiveFactorial(n - 1)  '' recursive call
      End If
   End Function
               

   Definition of Iteration
      Iteration is a process of repeatedly executing a set of instructions 
      until the iteration condition becomes false.
      The iteration block includes the initialization, the comparison, the 
      execution of the instructions to be iterated and finally the update 
      of the control variable.
      Once the control variable is updated, it is compared again and the 
      process is repeated until the condition in the iteration is false.
      Iteration blocks are "for" loop, "while" loop, ...

      The iteration block does not use the execution stack to store the 
      variables at each cycle. Therefore, the execution of the iteration 
      block is faster than the recursion block.
      In addition, iteration does not have the overhead of repeated 
      procedure calls that also make its execution faster than a recursion.
      The iteration is complete when the control condition becomes false.

      Simple example with a iterative function which returns the factorial 
      of the integer:
         The code body of the iterative function is defined by using the 
         iterative definition of the factorial function:
            Case (n = 0) : factorial(0) = 1
            Case (n > 0) : factorial(n) = (1) * ..... * (n - 2) * (n - 1) * 
            (n)

         The first line allows to determine the cumulative variable 
         initialization: result = 1
         The second line allows to determine the statement syntax which 
         accumulates: result = result * I

         Full code:
   Function iterativeFactorial (ByVal n As Integer) As Integer
      Dim As Integer result = 1  '' variable initialization
      For I As Integer = 1 To n  '' iteration loop
         result = result * I    '' iterative accumulation
      Next I
      Return result
   End Function
               

Back to top

2. Problem of replacing recursion with iteration
   Whatever the problem to be solved, there is the choice between the 
   writing of an iterative procedure and that of a recursive procedure.
   If the problem has a natural recursive structure, then the recursive 
   program is a simple adaptation of the chosen structure. This is the case 
   of the factorial functions (seen above) for example.
   The recursive approach, however, has drawbacks: some languages â€‹â€‹do 
   not allow recursion (like the machine language!), and a recursive 
   procedure is often expensive in memory (for execution stack) as in 
   execution time.

   These disadvantages can be overcome by transforming the recursive 
   procedure, line by line, into an iterative procedure: it is always 
   possible.
   Replace a recursion with an iteration allows to suppress the limitation 
   on the number of cycles due to the execution stack size available.
   But for an iteration with its own storage stack, the time spent to calls 
   to the procedures for pushing and pulling stack data is generally 
   greater than the one for passing the parameters of a recursive procedure 
   at each calling cycle.

   The complexity of the iterative procedure obtained by such a 
   transformation depends on the structure of the recursive procedure:
      - For some form of recursive procedure (see below the tail 
      recursion), the transformation into an iterative procedure is very 
      simple by means of just defining local variables corresponding to the 
      parameters of the recursive procedure (passed arguments).
      - At opposite for other forms of recursive procedure (non-tail 
      recursions), the use of a user storage stack in the iterative 
      procedure is necessary to save the context, as the recursive calls do 
      (values â€‹â€‹of the passed arguments at each call):
         - when executing a recursive procedure, each recursive call leads 
         to push the context on execution stack,
         - when the condition of stopping recursion occurs, the different 
         contexts are progressively popped from execution stack to continue 
         executing the procedure.

Back to top

3. Replace tail recursion with simple iteration
   The recursive procedure is a tail recursive procedure if the only 
   recursive call is at the end of the recursion and is therefore not 
   followed by any other statement:
      - For a recursive subroutine, the only recursive call is at the end 
      of the recursion.
      - For a recursive function, the only recursive call is at the end of 
      the recursion and consists in taking into account the return of the 
      function without any other additional operation on it.

   A tail recursive procedure is easy to transform into an iterative 
   procedure.
   The principle is that if the recursive call is the last instruction of a 
   procedure, it is not necessary to keep on the execution stack the 
   context of the current call, since it is not necessary to return to it:
      - It suffices to replace the parameters by their new values, and 
      resume execution at the beginning of the procedure.
      - The recursion is thus transformed into iteration, so that there is 
      no longer any risk of causing an overflow of the execution stack.

   Some non-tail recursive procedures can be transformed into tail 
   recursive procedures, sometimes with a little more complex code, but 
   even before they are subsequently transformed into iterative procedures, 
   these tail recursive procedures often already gain in memory usage and 
   execution time.

   Example with the simple "factorial" recursive function:
      Non-tail recursive form (already presented above):
   Function recursiveFactorial (ByVal n As Integer) As Integer
      If (n = 0) Then                           '' end condition
         Return 1
      Else                                      '' recursion loop
         Return n * recursiveFactorial(n - 1)  '' recursive call
      End If
   End Function
            
This function has a non-tail recursive form because even though the 
recursive call is at the end of the function, this recursive call is not 
the last instruction of the function because one has to multiplied again by 
n when recursiveFactorial(n - 1) is got.
         This calculation is done when popping context from execution 
         stack.

      It is quite easy to transform this function so that the recursion is 
      a tail recursion.
      To achieve this, it is necessary to add a new parameter to the 
      function: the result parameter which will serve as accumulator:
   Function tailRecursiveFactorial (ByVal n As Integer, ByVal result As Integer = 1) As Integer
      If (n = 0) Then                                       '' end condition
         Return result
      Else                                                  '' recursion loop
         Return tailRecursiveFactorial(n - 1, result * n)  '' tail recursive call
      End If
   End Function
            
This time, the calculation is done when pushing context on execution stack.

      Tail recursion is more explicit by calculating n - 1 and result * n 
      just before the recursive call:
   Function explicitTailRecursiveFactorial (ByVal n As Integer, ByVal result As Integer = 1) As Integer
      If (n = 0) Then                                       '' end condition
         Return result
      Else                                                  '' recursion loop
         result = result * n
         n = n - 1
         Return explicitTailRecursiveFactorial(n, result)  '' tail recursive call
      End If
   End Function
            

      Now it is sufficient to resume execution at the beginning of the 
      procedure by a Goto begin instead of the function call, to obtain an 
      iterative function:
   Function translationToIterativeFactorial (ByVal n As Integer, ByVal result As Integer = 1) As Integer
      begin:
      If (n = 0) Then          '' end condition
         Return result
      Else                     '' iteration loop
         result = result * n  '' iterative accumulation
         n = n - 1
         Goto begin           '' iterative jump
      End If
   End Function
            

      Finally it is better to avoid the If ... Goto ... End If instructions 
      by using for example a While ... Wend block instead, and the added 
      result parameter can be transformed into a local variable:
   Function  betterTranslationToIterativeFactorial (ByVal n As Integer) As Integer
      Dim As Integer result = 1
      While Not (n = 0)        '' end condition of iterative loop
         result = result * n  '' iterative accumulation
         n = n - 1
      Wend
      Return result
   End Function
            

   Similar transformation steps for the simple "reverse string" recursive 
   function following:
   Function recursiveReverse (ByVal s As String) As String
      If (s = "") Then                                     '' end condition
         Return s
      Else                                                 '' recursion loop
         Return recursiveReverse(Mid(s, 2)) & Left(s, 1)  '' recursive call
      End If
   End Function
         

   Function tailRecursiveReverse (ByVal s As String, ByVal cumul As String = "") As String
      If (s = "") Then                                                '' end condition
         Return cumul
      Else                                                            '' recursion loop
         Return tailRecursiveReverse(Mid(s, 2), Left(s, 1) & cumul)  '' tail recursive call
      End If
   End Function
         
Note: As the & operator (string concatenation) is not a symmetric operator 
((a & b) <> (b & a), while (x * y) = (y * x) like previously), the two 
operand order must to be reversed when pushing context on execution stack 
instead of before when popping context from execution stack.
   Function explicitTailRecursiveReverse (ByVal s As String, ByVal cumul As String = "") As String
      If (s = "") Then                                   '' end condition
         Return cumul
      Else                                               '' recursion loop
         cumul = Left(s, 1) & cumul
         s = Mid(s, 2)
         Return explicitTailRecursiveReverse(s, cumul)  '' tail recursive call
      End If
   End Function
         

   Function translationToIterativeReverse (ByVal s As String, ByVal cumul As String = "") As String
      begin:
      If (s = "") Then                '' end condition
         Return cumul
      Else                            '' iteration loop
         cumul = Left(s, 1) & cumul  '' iterative accumulation
         s = Mid(s, 2)
         Goto begin                  '' iterative jump
      End If
   End Function
         

   Function betterTranslationToIterativeReverse (ByVal s As String) As String
      Dim As String cumul = ""
      While Not (s = "")              '' end condition of iterative loop
         cumul = Left(s, 1) & cumul  '' iterative accumulation
         s = Mid(s, 2)
      Wend
      Return cumul
   End Function
         

   As less simple example, the "Fibonacci series" non-tail recursive 
   function:
      Sometimes, the transformation to a tail recursive function is less 
      obvious.
      The code body of the recursive function is defined by using the 
      recursive definition of the Fibonacci series:
         Case (n = 0) : F(0) = 0
         Case (n = 1) : F(1) = 1
         Case (n > 1) : F(n) = F(n-1) + F(n-2)

      The first two lines allow to determine the end condition: If n = 0 Or 
      n = 1 Then Return n
      The third line allows to determine the statement syntax which calls 
      the function itself: Return F(n - 1) + F(n - 2)

      Non-tail recursive form code:
   Function recursiveFibonacci (ByVal n As UInteger) As LongInt
      If n = 0 Or n = 1 Then                                            '' end condition
         Return n
      Else                                                              '' recursion loop
         Return recursiveFibonacci(n - 1) + recursiveFibonacci(n - 2)  '' recursive call
      End If
   End Function
            

      The execution time duration for the highest values becomes no more 
      negligible.
      Indeed, to compute F(n), there are 2^(n-1) calls: about one milliard 
      for n=31.

      Try to make the recursive algorithm linear, using a recursive 
      function which have 2 other parameters corresponding to the previous 
      value and the last value of the series, let f(n, a, b).
      We obtain:
         Case (n = 1): a = F(0) = 0, b = F(1) = 1
         Case (n-1): a = F(n-2), b = F(n-1)
         Case (n): F(n-1) = b, F(n) = F(n-1) + F(n-2) = a + b

      Consequently, for this new function f(n, a, b), the recursive call 
      becomes f(n-1, b, a+b), and there are only (n-1) calls.

      Tail recursive form code:
   Function tailRecursiveFibonacci (ByVal n As UInteger, ByVal a As UInteger = 0, ByVal b As UInteger = 1) As LongInt
      If n <= 1 Then                                      '' end condition
         Return b * n
      Else                                                '' recursion loop
         Return tailRecursiveFibonacci(n - 1, b, a + b)  '' tail recursive call
      End If
   End Function
            

      Then, similar transformations as previously in order to obtain the 
      iterative form:
   Function explicitTailRecursiveFibonacci (ByVal n As UInteger, ByVal a As UInteger = 0, ByVal b As UInteger = 1) As LongInt
      If n <= 1 Then                                      '' end condition
         Return b * n
      Else                                                '' recursion loop
         n = n - 1
         Swap a, b
         b = b + a
         Return explicitTailRecursiveFibonacci(n, a, b)  '' tail recursive call
      End If
   End Function
            

   Function translationToIterativeFibonacci (ByVal n As UInteger, ByVal a As UInteger = 0, ByVal b As UInteger = 1) As LongInt
      begin:
      If n <= 1 Then    '' end condition
         Return b * n
      Else              '' iteration loopp
         n = n - 1
         Swap a, b
         b = b + a
         Goto begin    '' iterative jump
      End If
   End Function
            

   Function betterTranslationToIterativeFibonacci (ByVal n As UInteger) As LongInt
      Dim As UInteger a = 0, b = 1
      While Not (n <= 1)  '' end condition of iterative loop
         n = n - 1
         Swap a, b
         b = b + a
      Wend
      Return b * n
   End Function
            

Back to top

4. Replace non-tail recursion with more complex iteration
   The recursive procedure is a non-tail recursive procedure if there is at 
   least one recursive call followed by at least one instruction.
   A non-tail recursion cannot be normally transformed into a simple 
   iteration, or it could have been transformed already into tail 
   recursion.

   To avoid limitation due to the execution stack size, a non-tail 
   recursive algorithm can always (more or less easily) be replaced by an 
   iterative algorithm, by pushing the parameters that would normally be 
   passed to the recursive procedure onto an own storage stack.
   In fact, the execution stack is replaced by a user stack (less limited 
   in size).

   In the following examples, the below user stack macro (compatible with 
   any datatype) is used:
   '' save as file: "DynamicUserStackTypeCreateMacro.bi"

   #macro DynamicUserStackTypeCreate(typename, datatype)

      Type typename
         Public:
            Declare Constructor ()                       '' pre-allocating user stack memory
            Declare Property push (ByRef i As datatype)  '' pushing on the user stack
            Declare Property pop () ByRef As datatype    '' popping from the user stack
            Declare Property used () As Integer          '' outputting number of used elements in the user stack
            Declare Property allocated () As Integer     '' outputting number of allocated elements in the user stack
            Declare Destructor ()                        '' deallocating user stack memory
         Private:
            Dim As datatype ae (Any)  '' array of elements
            Dim As Integer nue        '' number of used elements
            Dim As Integer nae        '' number of allocated elements
            Dim As Integer nae0       '' minimum number of allocated elements
      End Type

      Constructor typename ()
         This.nae0 = 2^Int(Log(1024 * 1024 / SizeOf(datatype)) / Log(2) + 1) '' only a power of 2 (1 MB < stack memory < 2 MB here)
         This.nue = 0
         This.nae = This.nae0
         ReDim This.ae(This.nae - 1)                                         '' pre-allocating user stack memory
      End Constructor

      Property typename.push (ByRef i As datatype)  '' pushing on the user stack
         This.nue += 1
         If This.nue > This.nae0 And This.nae < This.nue * 2 Then
            This.nae *= 2
            ReDim Preserve This.ae(This.nae - 1)  '' allocating user stack memory for double used elements at least
         End If
         This.ae(This.nue - 1) = i
      End Property

      Property typename.pop () ByRef As datatype  '' popping from the user stack
         If This.nue > 0 Then
            Property = This.ae(This.nue - 1)
            This.nue -= 1
            If This.nue > This.nae0 And This.nae > This.nue * 2 Then
               This.nae \= 2
               ReDim Preserve This.ae(This.nae - 1)  '' allocating user stack memory for double used elements at more
            End If
         Else
            Static As datatype d
            Dim As datatype d0
            d = d0
            Property = d
            AssertWarn(This.nue > 0)  '' warning if popping while empty user stack and debug mode (-g compiler option)
         End If
      End Property

      Property typename.used () As Integer  '' outputting number of used elements in the user stack
         Property = This.nue
      End Property

      Property typename.allocated () As Integer  '' outputting number of allocated elements in the user stack
         Property = This.nae
      End Property

      Destructor typename  '' deallocating user stack memory
         This.nue = 0
         This.nae = 0
         Erase This.ae  '' deallocating user stack memory
      End Destructor

   #endmacro
         

   Translation Quite Simple from Final Recursive Procedure (non-tail) to 
   Iterative Procedure
      A non-tail recursive procedure is final when the recursive call(s) 
      is(are) placed at the end of executed code (no executable instruction 
      line after and between for several recursive calls).

      In the 3 following examples, the transformation of a recursive 
      procedure into an iterative procedure is quite simple because the 
      recursive calls are always at the end of executed code block, and 
      without order constraints:
         - Make the procedure parameters (and the return value for a 
         function) as local ones.
         - Push the initial parameter values in the user stack.
         - Enter in a While ... Wend loop to empty the user stack:
            - Pull the variables from the user stack.
            - Process the variables similarly to the recursive procedure 
            body.
            - Accumulate the "return" variable for a recursive function 
            (the final value will be returned at function body end).
            - Replace the recursive calls by pushing the corresponding 
            variables on the user stack.

      First example (for console window): Computation of the combination 
      coefficients nCp (binomial coefficients calculation) and display of 
      the Pascal's triangle:
         The first function recursiveCombination is the recursive form (not 
         a tail recursion because there are two recursive calls with 
         summation in the last active statement).
         The second function translationToIterativeCombinationStack is the 
         iterative form using an own stack.

         In the two functions, a similar structure is conserved to 
         enlighten the conversion method.
         From recursive function to iterative stacking function:
            - Ahead, declaration of 1 local variable for the accumulator.
            - Pushing the two initial parameters values in the user stack.
            - Entering in the While ... Wend loop to empty the user stack.
            - Pulling parameters from the user stack.
            - Return 1 is replaced by cumul = cumul + 1.
            - Return recursiveCombination(n - 1, p) + 
            recursiveCombination(n - 1, p - 1) is replaced by S.push = n - 
            1 : S.push = p and S.push = n - 1 : S.push = p - 1.

   Function recursiveCombination (ByVal n As UInteger, ByVal p As UInteger) As LongInt
      If p = 0 Or p = n Then
         Return 1
      Else
         Return recursiveCombination(n - 1, p) + recursiveCombination(n - 1, p - 1)
      End If
   End Function

   '---------------------------------------------------------------------------

   #include "DynamicUserStackTypeCreateMacro.bi"
   DynamicUserStackTypeCreate(DynamicUserStackTypeForUinteger, UInteger)

   Function translationToIterativeCombinationStack (ByVal n As UInteger, ByVal p As UInteger) As LongInt
      Dim cumul As LongInt = 0
      Dim As DynamicUserStackTypeForUinteger S
      S.push = n : S.push = p
      While S.used > 0
         p = S.pop : n = S.pop
         If p = 0 Or p = n Then
            cumul = cumul + 1
         Else
            S.push = n - 1 : S.push = p
            S.push = n - 1 : S.push = p - 1
         End If
      Wend
      Return cumul
   End Function

   '---------------------------------------------------------------------------

   Sub Display(ByVal Combination As Function (ByVal n As UInteger, ByVal p As UInteger) As LongInt, ByVal n As Integer)
      For I As UInteger = 0 To n
         For J As UInteger = 0 To I
            Locate , 6 * J + 3 * (n - I) + 3
            Print Combination(I, J);
         Next J
         Print
      Next I
   End Sub

   '---------------------------------------------------------------------------

   Print " recursion:";
   Display(@recursiveCombination, 12)

   Print
   Print
   Print " iteration with own storage stack:";
   Display(@translationToIterativeCombinationStack, 12)

   Sleep
            

      Second example (for graphics window), using a non-tail recursive 
      subroutine (recursive drawing of circles):
         Similar transformation steps:
   Sub recursiveCircle (ByVal x As Integer, ByVal y As Integer, ByVal r As Integer)
      Circle (x, y), r
      If r > 16 Then
         recursiveCircle(x + r / 2, y, r / 2)
         recursiveCircle(x - r / 2, y, r / 2)
         recursiveCircle(x, y + r / 2, r / 2)
         recursiveCircle(x, y - r / 2, r / 2)
      End If
   End Sub

   '---------------------------------------------------------------------------

   #include "DynamicUserStackTypeCreateMacro.bi"
   DynamicUserStackTypeCreate(DynamicUserStackTypeForInteger, Integer)

   Sub recursiveToIterativeCircleStack (ByVal x As Integer, ByVal y As Integer, ByVal r As Integer)
      Dim As DynamicUserStackTypeForInteger S
      S.push = x : S.push = y : S.push = r
      Do While S.used > 0
         r = S.pop : y = S.pop : x = S.pop
         Circle (x, y), r
         If r > 16 Then
            S.push = x + r / 2 : S.push = y : S.push = r / 2
            S.push = x - r / 2 : S.push = y : S.push = r / 2
            S.push = x : S.push = y + r / 2 : S.push = r / 2
            S.push = x : S.push = y - r / 2 : S.push = r / 2
         End If
      Loop
   End Sub

   '---------------------------------------------------------------------------

   Screen 12

   Locate 2, 2
   Print "recursion:"
   recursiveCircle(160, 160, 150)

   Locate 10, 47
   Print "iteration with own storage stack:"
   recursiveToIterativeCircleStack(480, 320, 150)

   Sleep
               

      Third example (for console window), using a non-tail recursive 
      subroutine (Quick Sort algorithm):
         Similar transformation steps:
   Dim Shared As UByte t(99)

   Sub recursiveQuicksort (ByVal L As Integer, ByVal R As Integer)
      Dim As Integer pivot = L, I = L, J = R
      Do
         If t(I) >= t(J) Then
            Swap t(I), t(J)
            pivot = L + R - pivot
         End If
         If pivot = L Then
            J = J - 1
         Else
            I = I + 1
         End If
      Loop Until I = J
      If L < I - 1 Then
         recursiveQuicksort(L, I - 1)
      End If
      If R > J + 1 Then
         recursiveQuicksort(J + 1, R)
      End If
   End Sub

   #include "DynamicUserStackTypeCreateMacro.bi"
   DynamicUserStackTypeCreate(DynamicUserStackTypeForInteger, Integer)

   Sub translationToIteraticeQuicksortStack (ByVal L As Integer, ByVal R As Integer)
      Dim As DynamicUserStackTypeForInteger S
      S.push = L : S.push = R
      While S.used > 0
         R = S.pop : L = S.pop
         Dim As Integer pivot = L, I = L, J = R
         Do
            If t(I) >= t(J) Then
               Swap t(I), t(J)
               pivot = L + R - pivot
            End If
            If pivot = L Then
               J = J - 1
            Else
               I = I + 1
            End If
         Loop Until I = J
         If L < I - 1 Then
            S.push = L : S.push = I - 1
         End If
         If R > J + 1 Then
            S.push = J + 1 : S.push = R
         End If
      Wend
   End Sub

   Randomize
   For I As Integer = LBound(t) To UBound(t)
      t(i) = Int(Rnd * 256)
   Next I
   Print "raw memory:"
   For K As Integer = LBound(t) To UBound(t)
      Print Using "####"; t(K);
   Next K
   Print

   recursiveQuicksort(LBound(t), UBound(t))

   Print "sorted memory by recursion:"
   For K As Integer = LBound(t) To UBound(t)
      Print Using "####"; t(K);
   Next K
   Print
   Print

   Randomize
   For I As Integer = LBound(t) To UBound(t)
      t(i) = Int(Rnd * 256)
   Next I
   Print "raw memory:"
   For K As Integer = LBound(t) To UBound(t)
      Print Using "####"; t(K);
   Next K
   Print

   translationToIteraticeQuicksortStack(LBound(t), UBound(t))

   Print "sorted memory by iteration with stack:"
   For K As Integer = LBound(t) To UBound(t)
      Print Using "####"; t(K);
   Next K
   Print

   Sleep
               

   Translation Little More Complex from Non-Final Recursive Procedure to 
   Iterative Procedure
      For theses examples, the transformation of the non-final recursive 
      procedure into an iterative procedure is a little more complex 
      because the recursive call(s) is(are) not placed at the end of 
      executed code.

      The general method used hereafter is to first transform original 
      recursive procedure into a "final" recursive procedure where the 
      recursive call(s) is(are) now placed at the end of executed code 
      block (no executable instruction line between or after).

      First example (for console window), using a non-tail recursive 
      subroutine (tower of Hanoi algorithm):
         For this example, the two recursive calls are at the end of 
         executed code block but separated by an instruction line and there 
         is an order constraint.
         In the two functions, a similar structure is conserved to 
         enlighten the conversion method.
         From recursive function to iterative stacking function:
            - The first step consists in removing the instruction line 
            between the two recursive calls by adding its equivalent at top 
            of the recursive code body (2 parameters are added to the 
            procedure to pass the corresponding useful data).
            - Then the process of translation to iterative form is similar 
            to the previous examples (using a own storage stack) but 
            reversing the order of the 2 recursive calls when pushing on 
            the storage stack.

   Sub recursiveHanoi (ByVal n As Integer, ByVal departure As String, ByVal middle As String, ByVal arrival As String)
      If n > 0 Then
         recursiveHanoi(n - 1, departure, arrival, middle)
         Print "  move one disk from " & departure & " to " & arrival
         recursiveHanoi(n -1 , middle, departure, arrival)
      End If
   End Sub

   Sub finalRecursiveHanoi (ByVal n As Integer, ByVal departure As String, ByVal middle As String, ByVal arrival As String, ByVal dep As String = "", ByVal arr As String = "")
      If dep <> "" Then Print "  move one disk from " & dep & " to " & arr
      If n > 0 Then
         finalRecursiveHanoi(n - 1, departure, arrival, middle, "")
         finalRecursiveHanoi(n - 1, middle, departure, arrival, departure, arrival)
      End If
   End Sub

   #include "DynamicUserStackTypeCreateMacro.bi"
   DynamicUserStackTypeCreate(DynamicUserStackTypeForString, String)

   Sub translationToIterativeHanoi (ByVal n As Integer, ByVal departure As String, ByVal middle As String, ByVal arrival As String)
      Dim As String dep = "", arr = ""
      Dim As DynamicUserStackTypeForString S
      S.push = Str(n) : S.push = departure : S.push = middle : S.push = arrival : S.push = dep : S.push = arr
      While S.used > 0
         arr = S.pop : dep = S.pop : arrival = S.pop : middle = S.pop : departure = S.pop : n = Val(S.pop)
         If dep <> "" Then Print "  move one disk from " & dep & " to " & arr
         If n > 0 Then
            S.push = Str(n - 1) : S.push = middle : S.push = departure : S.push = arrival : S.push = departure : S.push = arrival
            S.push = Str(n - 1) : S.push = departure : S.push = arrival : S.push = middle : S.push = "" : S.push = ""
         End If
      Wend
   End Sub

   Print "recursive tower of Hanoi:"
   recursiveHanoi(3, "A", "B", "C")
   Print

   Print "final recursive tower of Hanoi:"
   finalRecursiveHanoi(3, "A", "B", "C")
   Print

   Print "iterative tower of Hanoi:"
   translationToIterativeHanoi(3, "A", "B", "C")
   Print

   Sleep
            

      Second example (for console window), using a non-tail recursive 
      subroutine (counting-down from n, then re-counting up to n):
         For this example, the recursive call is followed by an instruction 
         line before the end of executed code block.
         In the two functions, a similar structure is conserved to 
         enlighten the conversion method.
         From recursive function to iterative stacking function:
            - The first step consists in replacing the instruction line at 
            the end of executed code block by a new recursive call (a 
            parameter is added to the procedure to pass the corresponding 
            useful data).
            - An equivalent instruction line is added at top of the 
            recursive code body (using the passed data), executed in this 
            case instead of the normal code.
            - Then the process of translation to iterative form is similar 
            to the previous example (using a own storage stack) and 
            reversing the order of the 2 recursive calls when pushing on 
            the storage stack.

   Sub recursiveCount (ByVal n As Integer)
      If n >= 0 Then
         Print n & " ";
         If n = 0 Then Print
         recursiveCount(n - 1)
         Print n & " ";
      End If
   End Sub

   Sub finalRecursiveCount (ByVal n As Integer, ByVal recount As String = "")
      If recount <> "" Then
         Print recount & " ";
      Else
         If n >= 0 Then
            Print n & " ";
            If n = 0 Then Print
            finalRecursiveCount(n - 1, "")
            finalRecursiveCount(n - 1, Str(n))
         End If
      End If
   End Sub

   #include "DynamicUserStackTypeCreateMacro.bi"
   DynamicUserStackTypeCreate(DynamicUserStackTypeForString, String)

   Sub translationToIterativeCount (ByVal n As Integer)
      Dim As String recount = ""
      Dim As DynamicUserStackTypeForString S
      S.push = Str(n) : S.push = recount
      While S.used > 0
         recount = S.pop : n = Val(S.pop)
         If recount <> "" Then
            Print recount & " ";
         Else
            If n >= 0 Then
               Print n & " ";
               If n = 0 Then Print
               S.push = Str(n - 1) : S.push = Str(n)
               S.push = Str(n - 1) : S.push = ""
            End If
         End If
      Wend
   End Sub

   Print "recursive counting-down then re-counting up:"
   recursiveCount(9)
   Print
   Print

   Print "final recursive counting-down then re-counting up:"
   finalRecursiveCount(9)
   Print
   Print

   Print "iterative counting-down then re-counting up:"
   translationToIterativeCount(9)
   Print
   Print

   Sleep
            

   Translation from Other Non-Obvious Recursive Procedure to Iterative 
   Procedure
      Two other cases of translation from recursion to iteration are 
      presented here by means of simple examples:
         - For mutual recursion.
         - For nested recursion.

      Two functions are said to be mutually recursive if the first calls 
      the second, and in turn the second calls the first.
      A recursive function is said nested if an argument passed to the 
      function refers to the function itself.

      Example using mutual recursive functions ('even()' and 'odd()' 
      functions):
         From mutual recursive procedures to iterative stacking procedures 
         (for the general case):
            - The first step consists in transforming the recursive 
            procedures into "final" recursive procedures.
            - Then, the method is similar than that already described, with 
            besides an additional parameter (an index) which is also pushed 
            on the user stack in order to select the right code body to 
            execute when pulling data from the stack.
            - Therefore, each iterative procedure contains the translation 
            (for stacking) of all code bodies from the recursive 
            procedures.

         In this following examples, the simple mutual recursive functions 
         are here processed as in the general case (other very simple 
         iterative solutions exist):
   Declare Function recursiveIsEven(ByVal n As Integer) As Boolean
   Declare Function recursiveIsOdd(ByVal n As Integer) As Boolean

   Function recursiveIsEven(ByVal n As Integer) As Boolean
      If n = 0 Then
         Return True
      Else
         Return recursiveIsOdd(n - 1)
      End If
   End Function

   Function recursiveIsOdd(ByVal n As Integer) As Boolean
      If n = 0 Then
         Return False
      Else
         Return recursiveIsEven(n - 1)
      End If
   End Function

   #include "DynamicUserStackTypeCreateMacro.bi"
   DynamicUserStackTypeCreate(DynamicUserStackTypeForInteger, Integer)

   Function iterativeIsEven(ByVal n As Integer) As Boolean
      Dim As Integer i = 1
      Dim As DynamicUserStackTypeForInteger S
      S.push = n : S.push = i
      While S.used > 0
         i = S.pop : n = S.pop
         If i = 1 Then
            If n = 0 Then
               Return True
            Else
               S.push = n - 1 : S.push = 2
            End If
         ElseIf i = 2 Then
            If n = 0 Then
               Return False
            Else
               S.push = n - 1 : S.push = 1
            End If
         End If
      Wend
   End Function

   Function iterativeIsOdd(ByVal n As Integer) As Boolean
      Dim As Integer i = 2
      Dim As DynamicUserStackTypeForInteger S
      S.push = n : S.push = i
      While S.used > 0
         i = S.pop : n = S.pop
         If i = 1 Then
            If n = 0 Then
               Return True
            Else
               S.push = n - 1 : S.push = 2
            End If
         ElseIf i = 2 Then
            If n = 0 Then
               Return False
            Else
               S.push = n - 1 : S.push = 1
            End If
         End If
      Wend
   End Function

   Print recursiveIsEven(16), recursiveIsOdd(16)
   Print recursiveIsEven(17), recursiveIsOdd(17)
   Print

   Print iterativeIsEven(16), iterativeIsOdd(16)
   Print iterativeIsEven(17), iterativeIsOdd(17)
   Print

   Sleep
               

      Example using nested recursive function ('Ackermann()' function):
         From nested recursive function to iterative stacking function:
            - Use 2 independent storage stacks, one for the first parameter 
            m and another for the second parameter n of the function, 
            because of the nested call on one parameter.
            - Return expression is transformed into a pushing the 
            expression on the stack dedicated to the parameter where the 
            nesting call is.
            - Therefore a Return of data popping from the same stack is 
            added at code end.

   Function recursiveAckermann (ByVal m As Integer, ByVal n As Integer) As Integer
      If m = 0 Then
         Return n + 1
      Else
         If n = 0 Then
            Return recursiveAckermann(m - 1, 1)
         Else
            Return recursiveAckermann(m - 1, recursiveAckermann(m, n - 1))
         End If
      End If
   End Function

   #include "DynamicUserStackTypeCreateMacro.bi"
   DynamicUserStackTypeCreate(DynamicUserStackTypeForInteger, Integer)

   Function iterativeAckermann (ByVal m As Integer, ByVal n As Integer) As Integer
      Dim As DynamicUserStackTypeForInteger Sm, Sn
      Sm.push = m : Sn.push = n
      While Sm.used > 0
         m = Sm.pop : n = Sn.pop
         If m = 0 Then
            Sn.push = n + 1                                      ' Return n + 1 (and because of nested call)
         Else
            If n = 0 Then
               Sm.push = m - 1 : Sn.push = 1                    ' Return Ackermann(m - 1, 1)
            Else
               Sm.push = m - 1 : Sm.push = m : Sn.push = n - 1  ' Return Ackermann(m - 1, Ackermann(m, n - 1))
            End If
         End If
      Wend
      Return Sn.pop                                                ' (because of Sn.push = n + 1)
   End Function

   Print recursiveAckermann(3, 0), recursiveAckermann(3, 1), recursiveAckermann(3, 2), recursiveAckermann(3, 3), recursiveAckermann(3, 4)
   Print iterativeAckermann(3, 0), iterativeAckermann(3, 1), iterativeAckermann(3, 2), iterativeAckermann(3, 3), iterativeAckermann(3, 4)

   Sleep
            

Back to top

See also
   * Recursion



------------------------------------------------------- ProPgObjectRtti ----
OBJECT built-in and RTTI info

How the OBJECT built-in implements the capacity of inheritance polymorphism 
and the Run-Time Type Information for identification.

Preamble:

   The Object built-in type provides to all types derived (using the Extends
   declaration):
      - The ability to redefine a method (using the Abstract / Virtual 
      keywords) in a derived-type (sub-type) inheriting from a base-type 
      (super-type). It is then possible to call the method of an object 
      without worrying about its intrinsic type: it is the inheritance 
      polymorphism (sub-type polymorphism).
      - The capacity of determining the real type of an object at run-time, 
      which can be different of its at compile-time. The operator 
      Is (Run-Time Type Information) uses it to check if an object is 
      compatible to a type derived from its compile-time type, because RTTI 
      provides not only the run-time typename of the object but also all 
      names of its different base-types, up to the Object built-in type.

   Table of Contents
1. Mechanism under the hood for inheritance polymorphism and RTTI info
2. Inheritance polymorphism mechanism demonstrated by both true operating and faithful emulation
3. Demangle typenames from RTTI info

1. Mechanism under the hood for inheritance polymorphism and RTTI info
   The abstract/virtual member procedures are implemented using virtual 
   procedure tables (vtbl). vtbl is, simply explained, a table of static 
   procedures pointers.
   The compiler fills a vtbl for each polymorphic type, i.e. a type 
   defining at least an abstract/virtual procedure or a type derived from 
   the former.
   vtbl contains entries for all abstract/virtual procedures available in 
   the type, including the abstract/virtual procedures defined in upper 
   level of inheritance hierarchy (for abstract procedure not still 
   implemented, a null pointer is set in the vtbl).

   Each vtbl contains the correct addresses of procedures for each 
   abstract/virtual procedure in corresponding type. Here correct means the 
   address of the corresponding procedure of the most derived-type that 
   defines/overrides that procedure:
      - When the type is instantiated, the instance will contain a pointer 
      (vptr) to the virtual procedure table (vtbl) of the instantiated 
      type.
      - When an object of a derived-type is referenced within a 
      pointer/reference of base-type, then abstract/virtual procedure 
      feature really performs. The call of an abstract/virtual procedure is 
      somehow translated at run-time and the corresponding procedure from 
      the virtual procedure table of the type of underlying object (not of 
      the pointer/reference type) is chosen.
      - Thus, what procedure is called depends on what the real type of 
      object the pointer/reference points to, which can't be known at 
      compile-time, that is why the abstract/virtual procedure call is 
      decided at run-time.

   Therefore, the abstract/virtual procedure call (by means of a pointer or 
   a reference) is not an ordinary call and has a little performance 
   overhead, which may turn into a huge if we have numerous calls.
   The abstract/virtual procedure call is converted by compiler to 
   something else by using the proper vtbl addressed by the vptr value 
   (located at offset 0 in the instance data):
      Let be 'method1()', 'method2()', 'method3()' the first three abstract 
      or virtual member procedures declared in an inheritance type 
      structure, and 'pt' a based pointer to a derived object:
         pt->method1()
         pt->method2()
         pt->method3()
      are about translated by the compiler into respectively:
         Cptr(Sub (Byref As typename), Cptr(Any Ptr Ptr Ptr, 
         pt)[0][0])(*pt)
         Cptr(Sub (Byref As typename), Cptr(Any Ptr Ptr Ptr, 
         pt)[0][1])(*pt)
         Cptr(Sub (Byref As typename), Cptr(Any Ptr Ptr Ptr, 
         pt)[0][2])(*pt)
            - The first indirection [0] allows to access to the value of 
            the vptr from the address of the instance. This value 
            correspond to the address of the vtbl.
            - The second indirection [0] or [1] or [2] allows to access in 
            the vtbl to the static address of the virtual procedures 
            'method1()' or 'method2()' or 'method3()' respectively (in the 
            declaration order of the abstract or virtual procedures of the 
            Type structure).

   For the vptr value setting:
      - The compiler generates some extra code in the constructor of each 
      type (from the base-type up to the instantiated type), which it adds 
      before the user code. Even if the user does not define a constructor, 
      the compiler generates a default one, and the initialization of vptr 
      is there (from the vtbl address of the base-type up to the one of the 
      instantiated type). So each time an object of a polymorphic type is 
      created, vptr is correctly initialized and finally points to the vtbl 
      of that instantiated type.
      - At the end, when the object is destructed, the destructors are 
      called in the reverse order (from the instantiated type up to the 
      base-type). The compiler also generates some extra code in the 
      destructor of each type, which it adds before the user code. Even if 
      the user does not define a destructor, the compiler generates a 
      default one, and the de-initialization of vptr is there (from the 
      vtbl address of the instantiated type up to the one of the 
      base-type).
      - This initialization/de-initialization of the vptr value by step is 
      mandatory so that the user code in each constructor/destructor can 
      call the polymorphic procedures at the correct type level during the 
      successive steps of construction/destruction.

   The built-in Object type also provides the RTTI (Run-Time Type 
   Information) capacity for all types derived from it using the Extends 
   declaration:
      - The RTTI capacity allows to determine the real type of an object at 
      run-time, which can be different of its at compile-time.
      - The operator Is (rtti) uses it to check if an object is compatible 
      to a type derived from its compile-time type, because RTTI provides 
      not only the real runtime type-name of the object but also all 
      type-names of its base types, up to the Object built-in type.
      - Nevertheless these type-names stored by RTTI (referenced by a 
      specific pointer in the vtbl) are mangled names inaccessible directly 
      from a FreeBASIC keyword.

   How are chained the entities: object instance, vptr, vtbl (vtable), and 
   RTTI info:
      - Instance -> Vptr -> Vtbl -> RTTI info chaining:
         - For any type derived (directly or indirectly) from the Object 
         built-in type, a hidden pointer vptr is added at beginning 
         (located at offset 0) of its data fields (own or inherited). This 
         vptr points to the virtual table vtbl of the considered type.
         - The vtbl contains the list of the addresses of all 
         abstract/virtual procedures (from the offset 0). The vtbl also 
         contains (located at offset -1) a pointer to the Run Time Type 
         Information (RTTI) info block of the considered type.
         - The RTTI info block contains (located at offset +1) a pointer to 
         the mangled-typename of the considered type (ascii characters). 
         The RTTI info block also contains (located at offset +2) a pointer 
         to the RTTI info block of its Base. All RTTI info blocks for 
         up-hierarchy are so chained.

      - Instance -> Vptr -> Vtbl -> RTTI info diagram:

   '                                      vtbl (vtable)
   '                                  .-------------------.
   '                              [-2]|   reserved (0)    |               RTTI info                Mangled Typename
   '                                  |-------------------|       .-----------------------.       .---------------.
   '         Instance of UDT      [-1]| Ptr to RTTI info  |--->[0]|     reserved (0)      |       |Typename string|
   '      .-------------------.       |-------------------|       |-----------------------|       |     with      |
   '   [0]| vptr: Ptr to vtbl |--->[0]|Ptr to virt proc #1|   [+1]|Ptr to Mangled Typename|--->[0]| length (ASCII)|
   '      |-------------------|       |-------------------|       |-----------------------|       |       &       |
   '      |UDT member field #a|   [+1]|Ptr to virt proc #2|   [+2]| Ptr to Base RTTI info |---.   |  name (ASCII) |
   '      |-------------------|       |-------------------|       |_______________________|   |   |      for      |
   '      |UDT member field #b|   [+2]|Ptr to virt proc #3|   ________________________________|   |each component |
   '      |-------------------|       :- - - - - - - - - -:  |                                    |_______________|
   '      |UDT member field #c|       :                   :  |             Base RTTI info
   '      :- - - - - - - - - -:       :                   :  |       .----------------------------.
   '      :                   :       |___________________|  '--->[0]|        reserved (0)        |
   '      :                   :                                      |----------------------------|
   '      |___________________|                                  [+1]|Ptr to Mangled Base Typename|--->
   '                                                                 |----------------------------|
   '                                                             [+2]| Ptr to Base.Base RTTI info |---.
   '                                                                 |____________________________|   |
   '                                                                                                  |
   '                                                                                                  V
   			

Back to top

2. Inheritance polymorphism mechanism demonstrated by both true operating 
and faithful emulation
   In the below proposed example, the polymorphic part is broken down to 
   better bring out all the elements necessary for the mechanics of 
   polymorphism.

   Example of inheritance polymorphism, true operating: 'Animal type 
   collection'
      The generic base-type chosen is any 'animal' (abstraction).
      The specialized derived-types are a 'dog', a 'cat', and a 'bird' 
      (each defining a non-static string member containing its type-name).
      The abstract procedures declared in the generic base-type, and which 
      must be defined in each specialized derived-type, are:
         - 'addr_override_fct()': returns the instance address,
         - 'speak_override_fct()': returns the way of speaking,
         - 'type_override_sub()': prints the type-name (from a string 
         member with initialyzer).

      * 'animal' type declaration (generic base-type):
            - Three public abstract procedures ('addr_override_fct()', 
            'speak_override_fct()', 'type_override_sub()') are declared 
            (but without any body defining them).
            - This base-type is non-instantiable, because containing an 
            abstract procedure at least.

   'Base-type animal:
   	Type animal Extends Object
   		Public:
   			Declare Abstract Function addr_override_fct () As animal Ptr
   			Declare Abstract Function speak_override_fct () As String
   			Declare Abstract Sub type_override_sub ()
   	End Type
   				

      * 'dog', 'cat', 'bird' types declarations (specialized 
        derived-types):
            - For each derived-type, the three same public procedures (
            'addr_override_fct()', 'speak_override_fct()', 
            'type_override_sub()') are declared virtual, and their bodies 
            are specialized for each derived-type.
            - For each derived-type, a non-static string member initialized 
            with its type-name.
            - Each derived-type is instantiable, because implementing all 
            abstract procedures declared in its base.

   'Derived-type dog:
   	Type dog Extends animal
   		Public:
   			Declare Virtual Function addr_override_fct () As animal Ptr Override
   			Declare Virtual Function speak_override_fct () As String Override
   			Declare Virtual Sub type_override_sub () Override
   		Private:
   			Dim As String animal_type = "dog"
   	End Type
   				


   'Derived-type cat:
   	Type cat Extends animal
   		Public:
   			Declare Virtual Function addr_override_fct () As animal Ptr Override
   			Declare Virtual Function speak_override_fct () As String Override
   			Declare Virtual Sub type_override_sub () Override
   		Private:
   			Dim As String animal_type = "cat"
   	End Type
   				


   'Derived-type bird:
   	Type bird Extends animal
   		Public:
   			Declare Virtual Function addr_override_fct () As animal Ptr Override
   			Declare Virtual Function speak_override_fct () As String Override
   			Declare Virtual Sub type_override_sub () Override
   		Private:
   			Dim As String animal_type = "bird"
   	End Type
   				

      * Full code of example:
            - To be able to trigger polymorphism, a base-type pointer array 
            ('animal_list') is declared then initialized with instances of 
            different derived-types (a dog, a cat, a bird), in order to 
            constitute a collection of objects from different types (but 
            all having a common base-type).
            - So, the same compiled code line, put in a loop (iterator 'I'
            ), processes all instances from different types (
            'animal_list(I)->addr_override_fct()', 'animal_list(I)->
            speak_override_fct()', 'animal_list(I)->type_override_sub()'), 
            because the polymorphism mechanic allows to call each 
            specialized procedure at run-time. 
   'Base-type animal:
      Type animal Extends Object
         Public:
            Declare Abstract Function addr_override_fct () As animal Ptr
            Declare Abstract Function speak_override_fct () As String
            Declare Abstract Sub type_override_sub ()
      End Type

   'Derived-type dog:
      Type dog Extends animal
         Public:
            Declare Virtual Function addr_override_fct () As animal Ptr Override
            Declare Virtual Function speak_override_fct () As String Override
            Declare Virtual Sub type_override_sub () Override
         Private:
            Dim As String animal_type = "dog"
      End Type
      
      'override_sub procedures for dog object:
         Virtual Function dog.addr_override_fct () As animal Ptr
            Return @This
         End Function
         Virtual Function dog.speak_override_fct () As String
            Return "Woof!"
         End Function
         Virtual Sub dog.type_override_sub ()
            Print This.animal_type
         End Sub

   'Derived-type cat:
      Type cat Extends animal
         Public:
            Declare Virtual Function addr_override_fct () As animal Ptr Override
            Declare Virtual Function speak_override_fct () As String Override
            Declare Virtual Sub type_override_sub () Override
         Private:
            Dim As String animal_type = "cat"
      End Type
      
      'override_sub mehods for cat object:
         Virtual Function cat.addr_override_fct () As animal Ptr
            Return @This
         End Function
         Virtual Function cat.speak_override_fct () As String
            Return "Meow!"
         End Function
         Virtual Sub cat.type_override_sub ()
            Print This.animal_type
         End Sub

   'Derived-type bird:
      Type bird Extends animal
         Public:
            Declare Virtual Function addr_override_fct () As animal Ptr Override
            Declare Virtual Function speak_override_fct () As String Override
            Declare Virtual Sub type_override_sub () Override
         Private:
            Dim As String animal_type = "bird"
      End Type
      
      'override_sub mehods for bird object:
         Virtual Function bird.addr_override_fct () As animal Ptr
            Return @This
         End Function
         Virtual Function bird.speak_override_fct () As String
            Return "Cheep!"
         End Function
         Virtual Sub bird.type_override_sub ()
            Print This.animal_type
         End Sub

   'Create a dog and cat and bird dynamic instances referred through an animal pointer list:
      Dim As dog Ptr p_my_dog = New dog
      Dim As cat Ptr p_my_cat = New cat
      Dim As bird Ptr p_my_bird = New bird
      Dim As animal Ptr animal_list (1 To ...) = {p_my_dog, p_my_cat, p_my_bird}

   'Have the animals speak and eat:
      Print "INHERITANCE POLYMORPHISM", "@object", "speak", "type"
      Print "   true operating"
      For I As Integer = LBound(animal_list) To UBound(animal_list)
         Print "      animal #" & I & ":",
         Print animal_list(I)->addr_override_fct(),   'real polymorphism
         Print animal_list(I)->speak_override_fct(),  'real polymorphism
         animal_list(I)->type_override_sub()          'real polymorphism
      Next I

   Sleep

   Delete p_my_dog
   Delete p_my_cat
   Delete p_my_bird
               
Ouput:

   INHERITANCE POLYMORPHISM    @Object       speak         Type
      True operating
   	  animal #1:            11479616      Woof!         dog
   	  animal #2:            11479688      Meow!         cat
   	  animal #3:            11479760      Cheep!        bird
   					

   Example of polymorphism emulation very close to real operating of 
   'Animal type collection'
      This following emulation of sub-type polymorphism is very close to 
      the real operating:
         - A static procedure pointer table 'callback_table()' is defined 
         for each derived-type to emulate the vtbl (an instance reference 
         will be passed as first parameter to each static procedure to 
         emulate the hidden 'This' reference passed to any non-static 
         member procedure).

   'Derived-type dog:
   	Type dog Extends animal
   		Private:
   			Static As Any Ptr callback_table(0 To 2)
   		Public:
   			Declare Static Function addr_callback_fct (ByRef As dog) As animal Ptr
   			Declare Static Function speak_callback_fct (ByRef As dog) As String
   			Declare Static Sub type_callback_sub (ByRef As dog)
   			Declare Constructor ()
   		Private:
   			Dim As String animal_type = "dog"
   	End Type
   	Static As Any Ptr dog.callback_table(0 To 2) = {@dog.addr_callback_fct, @dog.speak_callback_fct, @dog.type_callback_sub}
   			


   'Derived-type cat:
   	Type cat Extends animal
   		Private:
   			Static As Any Ptr callback_table(0 To 2)
   		Public:
   			Declare Static Function addr_callback_fct (ByRef As cat) As animal Ptr
   			Declare Static Function speak_callback_fct (ByRef As cat) As String
   			Declare Static Sub type_callback_sub (ByRef As cat)
   			Declare Constructor ()
   		Private:
   			Dim As String animal_type = "cat"
   	End Type
   	Static As Any Ptr cat.callback_table(0 To 2) = {@cat.addr_callback_fct, @cat.speak_callback_fct, @cat.type_callback_sub}
   			


   'Derived-type bird:
   	Type bird Extends animal
   		Private:
   			Static As Any Ptr callback_table(0 To 2)
   		Public:
   			Declare Static Function addr_callback_fct (ByRef As bird) As animal Ptr
   			Declare Static Function speak_callback_fct (ByRef As bird) As String
   			Declare Static Sub type_callback_sub (ByRef As bird)
   			Declare Constructor ()
   		Private:
   			Dim As String animal_type = "bird"
   	End Type
   	Static As Any Ptr bird.callback_table(0 To 2) = {@bird.addr_callback_fct, @bird.speak_callback_fct, @bird.type_callback_sub}
   			

         - At the base-type level, a non static pointer 'callback_ptr' is 
         allocated for any derived-type instance to emulate the vptr (its 
         value, initialized by the constructor, will depend on what 
         derived-type is constructed: address of the following described 
         table).
         - At the base-type level, each abstract procedure is replaced by a 
         member procedure calling the proper derived procedure through the 
         'callback_ptr' / 'callback_table(I)' ('I' being the index inside 
         the table corresponding to this procedure).

   'Base-type animal:
   	Type animal
   		Protected:
   			Dim As Any Ptr Ptr callback_ptr
   		Public:
   			Declare Function addr_callback_fct () As animal Ptr
   			Declare Function speak_callback_fct () As String
   			Declare Sub type_callback_sub ()
   	End Type

   	Function animal.addr_callback_fct () As animal Ptr
   		Return CPtr(Function (ByRef As animal) As animal Ptr, This.callback_ptr[0])(This)
   	End Function
   	Function animal.speak_callback_fct () As String
   		Return CPtr(Function (ByRef As animal) As String, This.callback_ptr[1])(This)
   	End Function
   	Sub animal.type_callback_sub ()
   		CPtr(Sub (ByRef As animal), This.callback_ptr[2])(This)
   	End Sub
   			

      * Full code of emulation:
   ' Emulation of polymorphism is very close to the real operating:
   ' - a non static pointer is allocated for any derived-type instance to emulate the vptr
   '   (its value will depend on what derived-type is constructed: address of the following table)
   ' - a static procedure pointer table is defined for each derived type to emulate the vtable
   '   (an instance reference is passed as first parameter to each static procedure to emulate the hidden 'This' reference passed to any non-static member procedure)

   'Base-type animal:
      Type animal
         Protected:
            Dim As Any Ptr Ptr callback_ptr
         Public:
            Declare Function addr_callback_fct () As animal Ptr
            Declare Function speak_callback_fct () As String
            Declare Sub type_callback_sub ()
      End Type

      Function animal.addr_callback_fct () As animal Ptr
         Return CPtr(Function (ByRef As animal) As animal Ptr, This.callback_ptr[0])(This)
      End Function
      Function animal.speak_callback_fct () As String
         Return CPtr(Function (ByRef As animal) As String, This.callback_ptr[1])(This)
      End Function
      Sub animal.type_callback_sub ()
         CPtr(Sub (ByRef As animal), This.callback_ptr[2])(This)
      End Sub

   'Derived-type dog:
      Type dog Extends animal
         Private:
            Static As Any Ptr callback_table(0 To 2)
         Public:
            Declare Static Function addr_callback_fct (ByRef As dog) As animal Ptr
            Declare Static Function speak_callback_fct (ByRef As dog) As String
            Declare Static Sub type_callback_sub (ByRef As dog)
            Declare Constructor ()
         Private:
            Dim As String animal_type = "dog"
      End Type
      Static As Any Ptr dog.callback_table(0 To 2) = {@dog.addr_callback_fct, @dog.speak_callback_fct, @dog.type_callback_sub}

   'callback_sub methods + constructor for dog object:
      Static Function dog.addr_callback_fct (ByRef d As dog) As animal Ptr
         Return @d
      End Function
      Static Function dog.speak_callback_fct (ByRef d As dog) As String
         Return "Woof!"
      End Function
      Static Sub dog.type_callback_sub (ByRef d As dog)
         Print d.animal_type
      End Sub
      Constructor dog ()
         This.callback_ptr = @callback_table(0)
      End Constructor

   'Derived-type cat:
      Type cat Extends animal
         Private:
            Static As Any Ptr callback_table(0 To 2)
         Public:
            Declare Static Function addr_callback_fct (ByRef As cat) As animal Ptr
            Declare Static Function speak_callback_fct (ByRef As cat) As String
            Declare Static Sub type_callback_sub (ByRef As cat)
            Declare Constructor ()
         Private:
            Dim As String animal_type = "cat"
      End Type
      Static As Any Ptr cat.callback_table(0 To 2) = {@cat.addr_callback_fct, @cat.speak_callback_fct, @cat.type_callback_sub}

   'callback_sub mehods + constructor for cat object:
      Static Function cat.addr_callback_fct (ByRef c As cat) As animal Ptr
         Return @c
      End Function
      Static Function cat.speak_callback_fct (ByRef c As cat) As String
         Return "Meow!"
      End Function
      Static Sub cat.type_callback_sub (ByRef c As cat)
         Print c.animal_type
      End Sub
      Constructor cat ()
         This.callback_ptr = @callback_table(0)
      End Constructor

   'Derived-type bird:
      Type bird Extends animal
         Private:
            Static As Any Ptr callback_table(0 To 2)
         Public:
            Declare Static Function addr_callback_fct (ByRef As bird) As animal Ptr
            Declare Static Function speak_callback_fct (ByRef As bird) As String
            Declare Static Sub type_callback_sub (ByRef As bird)
            Declare Constructor ()
         Private:
            Dim As String animal_type = "bird"
      End Type
      Static As Any Ptr bird.callback_table(0 To 2) = {@bird.addr_callback_fct, @bird.speak_callback_fct, @bird.type_callback_sub}

   'callback_sub mehods + constructor for bird object:
      Static Function bird.addr_callback_fct (ByRef b As bird) As animal Ptr
         Return @b
      End Function
      Static Function bird.speak_callback_fct (ByRef b As bird) As String
         Return "Cheep!"
      End Function
      Static Sub bird.type_callback_sub (ByRef b As bird)
         Print b.animal_type
      End Sub
      Constructor bird ()
         This.callback_ptr = @callback_table(0)
      End Constructor

   'Create a dog and cat and bird dynamic instances referred through an animal pointer list:
      Dim As dog Ptr p_my_dog = New dog
      Dim As cat Ptr p_my_cat = New cat
      Dim As bird Ptr p_my_bird = New bird
      Dim As animal Ptr animal_list (1 To ...) = {p_my_dog, p_my_cat, p_my_bird}

   'Have the animals speak and eat:
      Print "SUB-TYPE POLYMORPHISM", "@object", "speak", "type"
      Print "   by emulation"
      For I As Integer = LBound(animal_list) To UBound(animal_list)
         Print "      animal #" & I & ":",
         Print animal_list(I)->addr_callback_fct(),   'emulated polymorphism
         Print animal_list(I)->speak_callback_fct(),  'emulated polymorphism
         animal_list(I)->type_callback_sub()          'emulated polymorphism
      Next I

   Sleep

   Delete p_my_dog
   Delete p_my_cat
   Delete p_my_bird
               
Output:

   Sub-Type POLYMORPHISM       @Object       speak         Type
      by emulation
   	  animal #1:            12462656      Woof!         dog
   	  animal #2:            12462728      Meow!         cat
   	  animal #3:            12462800      Cheep!        bird
   					

   Same example, with both real code and emulation code of 'Animal type 
   collection'
      The real code and emulation code are nested in a single code for 
      easier comparison:
   ' Emulated polymorphism (with explicit callback member procedures)
   ' and
   ' True polymorphism (with abstract/virtual member procedures),
   ' both in an inheritance structure.

   'Base-type animal:
      Type animal Extends Object  'Extends Object' useful for true polymorphism only
      ' for true polymorphism:
         Public:
            Declare Abstract Function addr_override_fct () As animal Ptr
            Declare Abstract Function speak_override_fct () As String
            Declare Abstract Sub type_override_sub ()
      ' for polymorphism emulation:
         Protected:
            Dim As Any Ptr Ptr callback_ptr
         Public:
            Declare Function addr_callback_fct () As animal Ptr
            Declare Function speak_callback_fct () As String
            Declare Sub type_callback_sub ()
      End Type

      ' for polymorphism emulation:
         Function animal.addr_callback_fct () As animal Ptr
            Return CPtr(Function (ByRef As animal) As animal Ptr, This.callback_ptr[0])(This)
         End Function
         Function animal.speak_callback_fct () As String
            Return CPtr(Function (ByRef As animal) As String, This.callback_ptr[1])(This)
         End Function
         Sub animal.type_callback_sub ()
            CPtr(Sub (ByRef As animal), This.callback_ptr[2])(This)
         End Sub

   'Derived-type dog:
      Type dog Extends animal
      ' for true polymorphism:
         Public:
            Declare Virtual Function addr_override_fct () As animal Ptr Override
            Declare Virtual Function speak_override_fct () As String Override
            Declare Virtual Sub type_override_sub () Override
      ' for polymorphism emulation:
         Private:
            Static As Any Ptr callback_table(0 To 2)
         Public:
            Declare Static Function addr_callback_fct (ByRef As dog) As animal Ptr
            Declare Static Function speak_callback_fct (ByRef As dog) As String
            Declare Static Sub type_callback_sub (ByRef As dog)
            Declare Constructor ()
      ' for all:
         Private:
            Dim As String animal_type = "dog"
      End Type

      ' for true polymorphism:
         ' override_sub methods for dog object:
            Virtual Function dog.addr_override_fct () As animal Ptr
               Return @This
            End Function
            Virtual Function dog.speak_override_fct () As String
               Return "Woof!"
            End Function
            Virtual Sub dog.type_override_sub ()
               Print This.animal_type
            End Sub

      ' for polymorphism emulation:
         Static As Any Ptr dog.callback_table(0 To 2) = {@dog.addr_callback_fct, @dog.speak_callback_fct, @dog.type_callback_sub}
         'callback_sub methods + constructor for dog object:
            Static Function dog.addr_callback_fct (ByRef d As dog) As animal Ptr
               Return @d
            End Function
            Static Function dog.speak_callback_fct (ByRef d As dog) As String
               Return "Woof!"
            End Function
            Static Sub dog.type_callback_sub (ByRef d As dog)
               Print d.animal_type
            End Sub
            Constructor dog ()
               This.callback_ptr = @callback_table(0)
            End Constructor

   'Derived-type cat:
      Type cat Extends animal
      ' for true polymorphism:
         Public:
            Declare Virtual Function addr_override_fct () As animal Ptr Override
            Declare Virtual Function speak_override_fct () As String Override
            Declare Virtual Sub type_override_sub () Override
      ' for polymorphism emulation:
         Private:
            Static As Any Ptr callback_table(0 To 2)
         Public:
            Declare Static Function addr_callback_fct (ByRef As cat) As animal Ptr
            Declare Static Function speak_callback_fct (ByRef As cat) As String
            Declare Static Sub type_callback_sub (ByRef As cat)
            Declare Constructor ()
      ' for all:
         Private:
            Dim As String animal_type = "cat"
      End Type

      ' for true polymorphism:
         ' override_sub mehods for cat object:
            Virtual Function cat.addr_override_fct () As animal Ptr
               Return @This
            End Function
            Virtual Function cat.speak_override_fct () As String
               Return "Meow!"
            End Function
            Virtual Sub cat.type_override_sub ()
               Print This.animal_type
            End Sub

      ' for polymorphism emulation:
         Static As Any Ptr cat.callback_table(0 To 2) = {@cat.addr_callback_fct, @cat.speak_callback_fct, @cat.type_callback_sub}
         ' callback_sub mehods + constructor for cat object:
            Static Function cat.addr_callback_fct (ByRef c As cat) As animal Ptr
               Return @c
            End Function
            Static Function cat.speak_callback_fct (ByRef c As cat) As String
               Return "Meow!"
            End Function
            Static Sub cat.type_callback_sub (ByRef c As cat)
               Print c.animal_type
            End Sub
            Constructor cat ()
               This.callback_ptr = @callback_table(0)
            End Constructor

   'Derived-type bird:
      Type bird Extends animal
      ' for true polymorphism:
         Public:
            Declare Virtual Function addr_override_fct () As animal Ptr Override
            Declare Virtual Function speak_override_fct () As String Override
            Declare Virtual Sub type_override_sub () Override
      ' for polymorphism emulation:
         Private:
            Static As Any Ptr callback_table(0 To 2)
         Public:
            Declare Static Function addr_callback_fct (ByRef As bird) As animal Ptr
            Declare Static Function speak_callback_fct (ByRef As bird) As String
            Declare Static Sub type_callback_sub (ByRef As bird)
            Declare Constructor ()
      ' for all:
         Private:
            Dim As String animal_type = "bird"
      End Type

      ' for true polymorphism:
         ' override_sub mehods for bird object:
            Virtual Function bird.addr_override_fct () As animal Ptr
               Return @This
            End Function
            Virtual Function bird.speak_override_fct () As String
               Return "Cheep!"
            End Function
            Virtual Sub bird.type_override_sub ()
               Print This.animal_type
            End Sub

      ' for polymorphism emulation:
         Static As Any Ptr bird.callback_table(0 To 2) = {@bird.addr_callback_fct, @bird.speak_callback_fct, @bird.type_callback_sub}
         ' callback_sub mehods + constructor for bird object:
            Static Function bird.addr_callback_fct (ByRef b As bird) As animal Ptr
               Return @b
            End Function
            Static Function bird.speak_callback_fct (ByRef b As bird) As String
               Return "Cheep!"
            End Function
            Static Sub bird.type_callback_sub (ByRef b As bird)
               Print b.animal_type
            End Sub
            Constructor bird ()
               This.callback_ptr = @callback_table(0)
            End Constructor

   'Create a dog and cat and bird dynamic instances referred through an animal pointer list:
      Dim As dog Ptr p_my_dog = New dog
      Dim As cat Ptr p_my_cat = New cat
      Dim As bird Ptr p_my_bird = New bird
      Dim As animal Ptr animal_list (1 To ...) = {p_my_dog, p_my_cat, p_my_bird}

   'Have the animals speak and eat:
      Print "SUB-TYPE POLYMORPHISM", "@object", "speak", "type"
      For I As Integer = LBound(animal_list) To UBound(animal_list)
         Print "   animal #" & I & ":"
         ' for override_sub:
            Print "      true operating:",
            Print animal_list(I)->addr_override_fct(),   'real polymorphism
            Print animal_list(I)->speak_override_fct(),  'real polymorphism
            animal_list(I)->type_override_sub()          'real polymorphism
         ' for polymorphism emulation:
            Print "      by emulation:",
            Print animal_list(I)->addr_callback_fct(),   'emulated polymorphism
            Print animal_list(I)->speak_callback_fct(),  'emulated polymorphism
            animal_list(I)->type_callback_sub()          'emulated polymorphism
      Next I

   Sleep

   Delete p_my_dog
   Delete p_my_cat
   Delete p_my_bird
            
Output:

   Sub-Type POLYMORPHISM       @Object       speak         Type
      animal #1:
   	  True operating:       11217472      Woof!         dog
   	  by emulation:         11217472      Woof!         dog
      animal #2:
   	  True operating:       11217552      Meow!         cat
   	  by emulation:         11217552      Meow!         cat
      animal #3:
   	  True operating:       11217632      Cheep!        bird
   	  by emulation:         11217632      Cheep!        bird
   				

Back to top

3. Demangle typenames from RTTI info
   Extraction of the mangled typename from the RTTI info:
      - From the instance address, the RTTI info pointer of the type of the 
      instance is accessed through a double indirection (with offsets: 
      [0][-1]).
      - The RTTI info pointer chaining described above allows to access 
      RTTI info of the selected type in the inheritance hierarchy (up to 
      the Object built-in type). This is done by means of an iteration on 
      the pointer indirection (with offset: [+2]).
      - Then the selected mangled typename is accessed (final indirection 
      with offset: [+1])

   Function 'mangledTypeNameFromRTTI()' to extract the mangled typenames:

   Function mangledTypeNameFromRTTI (ByVal po As Object Ptr, ByVal baseIndex As Integer = 0) As String
   	' Function to get any mangled-typename in the inheritance up hierarchy
   	' of the type of an instance (address: 'po') compatible with the built-in 'Object'
   	'
   	' ('baseIndex =  0' to get the mangled-typename of the instance)
   	' ('baseIndex = -1' to get the base mangled-typename of the instance, or "" if not existing)
   	' ('baseIndex = -2' to get the base.base mangled-typename of the instance, or "" if not existing)
   	' (.....)
   	'
   		Dim As String s
   		Dim As ZString Ptr pz
   		Dim As Any Ptr p = CPtr(Any Ptr Ptr Ptr, po)[0][-1]  ' Ptr to RTTI info
   		For I As Integer = baseIndex To -1
   			p = CPtr(Any Ptr Ptr, p)[2]                  ' Ptr to Base RTTI info of previous RTTI info
   			If p = 0 Then Return s
   		Next I
   		pz = CPtr(Any Ptr Ptr, p)[1]                         ' Ptr to mangled-typename
   		s = *pz
   		Return s
   End Function
   		

   Example of mangled typenames extraction from RTTI info, for an 
   inheritance structure (three derived level) declared inside a namespace 
   block:
   Namespace oop
      Type parent Extends Object
      End Type

      Type child Extends parent
      End Type

      Type grandchild Extends child
      End Type
   End Namespace

   Function mangledTypeNameFromRTTI (ByVal po As Object Ptr, ByVal baseIndex As Integer = 0) As String
      ' Function to get any mangled-typename in the inheritance up hierarchy
      ' of the type of an instance (address: 'po') compatible with the built-in 'Object'
      '
      ' ('baseIndex =  0' to get the mangled-typename of the instance)
      ' ('baseIndex = -1' to get the base mangled-typename of the instance, or "" if not existing)
      ' ('baseIndex = -2' to get the base.base mangled-typename of the instance, or "" if not existing)
      ' (.....)
      '
         Dim As String s
         Dim As ZString Ptr pz
         Dim As Any Ptr p = CPtr(Any Ptr Ptr Ptr, po)[0][-1]  ' Ptr to RTTI info
         For I As Integer = baseIndex To -1
            p = CPtr(Any Ptr Ptr, p)[2]                      ' Ptr to Base RTTI info of previous RTTI info
            If p = 0 Then Return s
         Next I
         pz = CPtr(Any Ptr Ptr, p)[1]                         ' Ptr to mangled-typename
         s = *pz
         Return s
   End Function

   Dim As Object Ptr p = New oop.grandchild

   Print "Mangled typenames list, from RTTI info:"
   Print "  " & mangledTypeNameFromRTTI(p, 0)
   Print "  " & mangledTypeNameFromRTTI(p, -1)
   Print "  " & mangledTypeNameFromRTTI(p, -2)
   Print "  " & mangledTypeNameFromRTTI(p, -3)
   Delete p

   Sleep
         
Output:

   Mangled typenames list, from RTTI info:
     N3OOP10GRANDCHILDE
     N3OOP5CHILDE
     N3OOP6PARENTE
     6Object
   			

   Implementation of the mangled typenames
      From the above output, the mangling process on typenames can be 
      highlighted with the following formatting:
         N3OOP10GRANDCHILDE
         (for 'oop.grandchild')

         N3OOP5CHILDE
         (for 'oop.child')

         N3OOP6PARENTE
         (for 'oop.parent')

         6Object
         (for 'Object')

      Details on the the mangling process on typenames in the RTTI info:
         - The mangled typename is a Zstring (ended by the null character).
         - Each component (one dot as separator) of the full typename 
         (converted to uppercase) is preceded by its number of characters 
         encoded in ASCII itself (based on length-prefixed strings).
         - When the type is inside at least one namespace, the mangled 
         typename string begins with an additional "N" and ends with an 
         additional "E".
            (prefix "N" and suffix "E" from Nested-name ... Ending)

   Extract the typenames (demangled) from RTTI info
      The previous function ('mangledTypeNameFromRTTI()') can be now 
      completed with a demangling process.

      Function 'typeNameFromRTTI()' to extract the demangled typenames:

   Function typeNameFromRTTI (ByVal po As Object Ptr, ByVal baseIndex As Integer = 0) As String
   	' Function to get any typename in the inheritance up hierarchy
   	' of the type of an instance (address: 'po') compatible with the built-in 'Object'
   	'
   	' ('baseIndex =  0' to get the typename of the instance)
   	' ('baseIndex = -1' to get the base.typename of the instance, or "" if not existing)
   	' ('baseIndex = -2' to get the base.base.typename of the instance, or "" if not existing)
   	' (.....)
   	'
   		Dim As String s
   		Dim As ZString Ptr pz
   		Dim As Any Ptr p = CPtr(Any Ptr Ptr Ptr, po)[0][-1]     ' Ptr to RTTI info
   		For I As Integer = baseIndex To -1
   			p = CPtr(Any Ptr Ptr, p)[2]                     ' Ptr to Base RTTI info of previous RTTI info
   			If p = 0 Then Return s
   		Next I
   		pz = CPtr(Any Ptr Ptr, p)[1]                            ' Ptr to mangled-typename
   		Do
   			Do While (*pz)[0] > Asc("9") OrElse (*pz)[0] < Asc("0")
   				If (*pz)[0] = 0 Then Return s
   				pz += 1
   			Loop
   			Dim As Integer N = Val(*pz)
   			Do
   				pz += 1
   			Loop Until (*pz)[0] > Asc("9") OrElse (*pz)[0] < Asc("0")
   			If s <> "" Then s &= "."
   			s &= Left(*pz, N)
   			pz += N
   		Loop
   End Function
   			

      Previous example completed with the above function:
   Namespace oop
      Type parent Extends Object
      End Type

      Type child Extends parent
      End Type

      Type grandchild Extends child
      End Type
   End Namespace

   Function mangledTypeNameFromRTTI (ByVal po As Object Ptr, ByVal baseIndex As Integer = 0) As String
      ' Function to get any mangled-typename in the inheritance up hierarchy
      ' of the type of an instance (address: 'po') compatible with the built-in 'Object'
      '
      ' ('baseIndex =  0' to get the mangled-typename of the instance)
      ' ('baseIndex = -1' to get the base mangled-typename of the instance, or "" if not existing)
      ' ('baseIndex = -2' to get the base.base mangled-typename of the instance, or "" if not existing)
      ' (.....)
      '
         Dim As String s
         Dim As ZString Ptr pz
         Dim As Any Ptr p = CPtr(Any Ptr Ptr Ptr, po)[0][-1]  ' Ptr to RTTI info
         For I As Integer = baseIndex To -1
            p = CPtr(Any Ptr Ptr, p)[2]                      ' Ptr to Base RTTI info of previous RTTI info
            If p = 0 Then Return s
         Next I
         pz = CPtr(Any Ptr Ptr, p)[1]                         ' Ptr to mangled-typename
         s = *pz
         Return s
   End Function

   Function typeNameFromRTTI (ByVal po As Object Ptr, ByVal baseIndex As Integer = 0) As String
      ' Function to get any typename in the inheritance up hierarchy
      ' of the type of an instance (address: 'po') compatible with the built-in 'Object'
      '
      ' ('baseIndex =  0' to get the typename of the instance)
      ' ('baseIndex = -1' to get the base.typename of the instance, or "" if not existing)
      ' ('baseIndex = -2' to get the base.base.typename of the instance, or "" if not existing)
      ' (.....)
      '
         Dim As String s
         Dim As ZString Ptr pz
         Dim As Any Ptr p = CPtr(Any Ptr Ptr Ptr, po)[0][-1]          ' Ptr to RTTI info
         For I As Integer = baseIndex To -1
            p = CPtr(Any Ptr Ptr, p)[2]                              ' Ptr to Base RTTI info of previous RTTI info
            If p = 0 Then Return s
         Next I
         pz = CPtr(Any Ptr Ptr, p)[1]                                 ' Ptr to mangled-typename
         Do
            Do While (*pz)[0] > Asc("9") OrElse (*pz)[0] < Asc("0")
               If (*pz)[0] = 0 Then Return s
               pz += 1
            Loop
            Dim As Integer N = Val(*pz)
            Do
               pz += 1
            Loop Until (*pz)[0] > Asc("9") OrElse (*pz)[0] < Asc("0")
            If s <> "" Then s &= "."
            s &= Left(*pz, N)
            pz += N
         Loop
   End Function

   Dim As Object Ptr p = New oop.grandchild

   Print "Mangled typenames list, from RTTI info:"
   Print "  " & mangledTypeNameFromRTTI(p, 0)
   Print "  " & mangledTypeNameFromRTTI(p, -1)
   Print "  " & mangledTypeNameFromRTTI(p, -2)
   Print "  " & mangledTypeNameFromRTTI(p, -3)
   Print
   Print "Typenames (demangled) list, from RTTI info:"
   Print "  " & typeNameFromRTTI(p, 0)
   Print "  " & typeNameFromRTTI(p, -1)
   Print "  " & typeNameFromRTTI(p, -2)
   Print "  " & typeNameFromRTTI(p, -3)
   Delete p

   Sleep
            
Output:

   Mangled typenames list, from RTTI info:
     N3OOP10GRANDCHILDE
     N3OOP5CHILDE
     N3OOP6PARENTE
     6Object

   Typenames (demangled) list, from RTTI info:
     OOP.GRANDCHILD
     OOP.CHILD
     OOP.PARENT
     Object
   				

   Extract at once the Typename (demangled) and all those of its base-types 
   hierarchy, from RTTI info
      Simply by calling the previous function in a loop with a decreasing 
      parameter 'baseIndex' (from the value 0) and to stop it as soon as an 
      empty string is returned. Finaly by returning a string containing the 
      different typenames with a hierarchic separator between each.

      Function 'typeNameHierarchyFromRTTI()' to extract the Typename 
      (demangled) and all those of its base-types hierarchy:

   Function typeNameHierarchyFromRTTI (ByVal po As Object Ptr) As String
   	' Function to get the typename inheritance up hierarchy
   	' of the type of an instance (address: po) compatible with the built-in 'Object'
   	'
   		Dim As String s = TypeNameFromRTTI(po)
   		Dim As Integer i = -1
   		Do
   			Dim As String s0 = typeNameFromRTTI(po, i)
   			If s0 = "" Then Exit Do
   			s &= "->" & s0
   			i -= 1
   		Loop
   		Return s
   End Function
   			

      Previous example again completed with the above function:
   Namespace oop
      Type parent Extends Object
      End Type

      Type child Extends parent
      End Type

      Type grandchild Extends child
      End Type
   End Namespace

   Function mangledTypeNameFromRTTI (ByVal po As Object Ptr, ByVal baseIndex As Integer = 0) As String
      ' Function to get any mangled-typename in the inheritance up hierarchy
      ' of the type of an instance (address: 'po') compatible with the built-in 'Object'
      '
      ' ('baseIndex =  0' to get the mangled-typename of the instance)
      ' ('baseIndex = -1' to get the base mangled-typename of the instance, or "" if not existing)
      ' ('baseIndex = -2' to get the base.base mangled-typename of the instance, or "" if not existing)
      ' (.....)
      '
         Dim As String s
         Dim As ZString Ptr pz
         Dim As Any Ptr p = CPtr(Any Ptr Ptr Ptr, po)[0][-1]  ' Ptr to RTTI info
         For I As Integer = baseIndex To -1
            p = CPtr(Any Ptr Ptr, p)[2]                      ' Ptr to Base RTTI info of previous RTTI info
            If p = 0 Then Return s
         Next I
         pz = CPtr(Any Ptr Ptr, p)[1]                         ' Ptr to mangled-typename
         s = *pz
         Return s
   End Function

   Function typeNameFromRTTI (ByVal po As Object Ptr, ByVal baseIndex As Integer = 0) As String
      ' Function to get any typename in the inheritance up hierarchy
      ' of the type of an instance (address: 'po') compatible with the built-in 'Object'
      '
      ' ('baseIndex =  0' to get the typename of the instance)
      ' ('baseIndex = -1' to get the base.typename of the instance, or "" if not existing)
      ' ('baseIndex = -2' to get the base.base.typename of the instance, or "" if not existing)
      ' (.....)
      '
         Dim As String s
         Dim As ZString Ptr pz
         Dim As Any Ptr p = CPtr(Any Ptr Ptr Ptr, po)[0][-1]          ' Ptr to RTTI info
         For I As Integer = baseIndex To -1
            p = CPtr(Any Ptr Ptr, p)[2]                              ' Ptr to Base RTTI info of previous RTTI info
            If p = 0 Then Return s
         Next I
         pz = CPtr(Any Ptr Ptr, p)[1]                                 ' Ptr to mangled-typename
         Do
            Do While (*pz)[0] > Asc("9") OrElse (*pz)[0] < Asc("0")
               If (*pz)[0] = 0 Then Return s
               pz += 1
            Loop
            Dim As Integer N = Val(*pz)
            Do
               pz += 1
            Loop Until (*pz)[0] > Asc("9") OrElse (*pz)[0] < Asc("0")
            If s <> "" Then s &= "."
            s &= Left(*pz, N)
            pz += N
         Loop
   End Function

   Function typeNameHierarchyFromRTTI (ByVal po As Object Ptr) As String
      ' Function to get the typename inheritance up hierarchy
      ' of the type of an instance (address: po) compatible with the built-in 'Object'
      '
         Dim As String s = TypeNameFromRTTI(po)
         Dim As Integer i = -1
         Do
            Dim As String s0 = typeNameFromRTTI(po, i)
            If s0 = "" Then Exit Do
            s &= "->" & s0
            i -= 1
         Loop
         Return s
   End Function

   Dim As Object Ptr p = New oop.grandchild

   Print "Mangled typenames list, from RTTI info:"
   Print "  " & mangledTypeNameFromRTTI(p, 0)
   Print "  " & mangledTypeNameFromRTTI(p, -1)
   Print "  " & mangledTypeNameFromRTTI(p, -2)
   Print "  " & mangledTypeNameFromRTTI(p, -3)
   Print
   Print "Typenames (demangled) list, from RTTI info:"
   Print "  " & typeNameFromRTTI(p, 0)
   Print "  " & typeNameFromRTTI(p, -1)
   Print "  " & typeNameFromRTTI(p, -2)
   Print "  " & typeNameFromRTTI(p, -3)
   Print
   Print "Typename (demangled) and all those of its base-types hierarchy, from RTTI info:"
   Print "  " & typeNameHierarchyFromRTTI(p)
   Delete p

   Sleep
            
Output:

   Mangled typenames list, from RTTI info:
     N3OOP10GRANDCHILDE
     N3OOP5CHILDE
     N3OOP6PARENTE
     6Object

   Typenames (demangled) list, from RTTI info:
     OOP.GRANDCHILD
     OOP.CHILD
     OOP.PARENT
     Object

   Typename (demangled) And all those of its Base-types hierarchy, from RTTI info:
     OOP.GRANDCHILD->OOP.CHILD->OOP.PARENT->Object
   				

   Compare the typename (demangled) extracted from RTTI info to a string 
   variable
      As the various steps of demangling, the successive elements of the 
      typname extracted from the RTTI info are compared with those of the 
      chain provided (as soon as an element is different, "false" is 
      returned immediately).

      Function 'typeNameEqualFromRTTI()' to compared the typename 
      (demangled) extracted from RTTI info to a string variable:

   Function typeNameEqualFromRTTI (ByVal po As Object Ptr, ByRef typeName As String) As Boolean
   	' Function to get true if the instance typename (address: po) is the same than the passed string
   	'
   		Dim As String t = UCase(typeName)
   		Dim As ZString Ptr pz = CPtr(Any Ptr Ptr Ptr Ptr, po)[0][-1][1] ' Ptr to Mangled Typename
   		Dim As Integer i = 1
   		Do
   			Do While (*pz)[0] > Asc("9") OrElse (*pz)[0] < Asc("0")
   				If (*pz)[0] = 0 Then Return True
   				pz += 1
   			Loop
   			Dim As Integer N = Val(*pz)
   			Do
   				pz += 1
   			Loop Until (*pz)[0] > Asc("9") OrElse (*pz)[0] < Asc("0")
   			If i > 1 Then
   				If Mid(t, i, 1) <> "." Then Return False Else i += 1
   			End If
   			If Mid(t, i, N) <> Left(*pz, N) Then Return False Else pz += N : i += N
   		Loop
   End Function
   			

      Previous example finally completed with the above function:
   Namespace oop
      Type parent Extends Object
      End Type

      Type child Extends parent
      End Type

      Type grandchild Extends child
      End Type
   End Namespace

   Function mangledTypeNameFromRTTI (ByVal po As Object Ptr, ByVal baseIndex As Integer = 0) As String
      ' Function to get any mangled-typename in the inheritance up hierarchy
      ' of the type of an instance (address: 'po') compatible with the built-in 'Object'
      '
      ' ('baseIndex =  0' to get the mangled-typename of the instance)
      ' ('baseIndex = -1' to get the base mangled-typename of the instance, or "" if not existing)
      ' ('baseIndex = -2' to get the base.base mangled-typename of the instance, or "" if not existing)
      ' (.....)
      '
         Dim As String s
         Dim As ZString Ptr pz
         Dim As Any Ptr p = CPtr(Any Ptr Ptr Ptr, po)[0][-1]  ' Ptr to RTTI info
         For I As Integer = baseIndex To -1
            p = CPtr(Any Ptr Ptr, p)[2]                      ' Ptr to Base RTTI info of previous RTTI info
            If p = 0 Then Return s
         Next I
         pz = CPtr(Any Ptr Ptr, p)[1]                         ' Ptr to mangled-typename
         s = *pz
         Return s
   End Function

   Function typeNameFromRTTI (ByVal po As Object Ptr, ByVal baseIndex As Integer = 0) As String
      ' Function to get any typename in the inheritance up hierarchy
      ' of the type of an instance (address: 'po') compatible with the built-in 'Object'
      '
      ' ('baseIndex =  0' to get the typename of the instance)
      ' ('baseIndex = -1' to get the base.typename of the instance, or "" if not existing)
      ' ('baseIndex = -2' to get the base.base.typename of the instance, or "" if not existing)
      ' (.....)
      '
         Dim As String s
         Dim As ZString Ptr pz
         Dim As Any Ptr p = CPtr(Any Ptr Ptr Ptr, po)[0][-1]          ' Ptr to RTTI info
         For I As Integer = baseIndex To -1
            p = CPtr(Any Ptr Ptr, p)[2]                              ' Ptr to Base RTTI info of previous RTTI info
            If p = 0 Then Return s
         Next I
         pz = CPtr(Any Ptr Ptr, p)[1]                                 ' Ptr to mangled-typename
         Do
            Do While (*pz)[0] > Asc("9") OrElse (*pz)[0] < Asc("0")
               If (*pz)[0] = 0 Then Return s
               pz += 1
            Loop
            Dim As Integer N = Val(*pz)
            Do
               pz += 1
            Loop Until (*pz)[0] > Asc("9") OrElse (*pz)[0] < Asc("0")
            If s <> "" Then s &= "."
            s &= Left(*pz, N)
            pz += N
         Loop
   End Function

   Function typeNameHierarchyFromRTTI (ByVal po As Object Ptr) As String
      ' Function to get the typename inheritance up hierarchy
      ' of the type of an instance (address: po) compatible with the built-in 'Object'
      '
         Dim As String s = TypeNameFromRTTI(po)
         Dim As Integer i = -1
         Do
            Dim As String s0 = typeNameFromRTTI(po, i)
            If s0 = "" Then Exit Do
            s &= "->" & s0
            i -= 1
         Loop
         Return s
   End Function

   Function typeNameEqualFromRTTI (ByVal po As Object Ptr, ByRef typeName As String) As Boolean
      ' Function to get true if the instance typename (address: po) is the same than the passed string
      '
         Dim As String t = UCase(typeName)
         Dim As ZString Ptr pz = CPtr(Any Ptr Ptr Ptr Ptr, po)[0][-1][1] ' Ptr to Mangled Typename
         Dim As Integer i = 1
         Do
            Do While (*pz)[0] > Asc("9") OrElse (*pz)[0] < Asc("0")
               If (*pz)[0] = 0 Then Return True
               pz += 1
            Loop
            Dim As Integer N = Val(*pz)
            Do
               pz += 1
            Loop Until (*pz)[0] > Asc("9") OrElse (*pz)[0] < Asc("0")
            If i > 1 Then
               If Mid(t, i, 1) <> "." Then Return False Else i += 1
            End If
            If Mid(t, i, N) <> Left(*pz, N) Then Return False Else pz += N : i += N
         Loop
   End Function

   Dim As Object Ptr p = New oop.grandchild

   Print "Mangled typenames list, from RTTI info:"
   Print "  " & mangledTypeNameFromRTTI(p, 0)
   Print "  " & mangledTypeNameFromRTTI(p, -1)
   Print "  " & mangledTypeNameFromRTTI(p, -2)
   Print "  " & mangledTypeNameFromRTTI(p, -3)
   Print
   Print "Typenames (demangled) list, from RTTI info:"
   Print "  " & typeNameFromRTTI(p, 0)
   Print "  " & typeNameFromRTTI(p, -1)
   Print "  " & typeNameFromRTTI(p, -2)
   Print "  " & typeNameFromRTTI(p, -3)
   Print
   Print "Typename (demangled) and all those of its base-types hierarchy, from RTTI info:"
   Print "  " & typeNameHierarchyFromRTTI(p)
   Delete p
   Print
   p = New oop.child
   Print "Is the typename of an oop.child instance the same as ""child""?"
   Print "  " & typeNameEqualFromRTTI(p, "child")
   Print "Is the typename of an oop.child instance the same as ""oop.child""?"
   Print "  " & typeNameEqualFromRTTI(p, "oop.child")
   Print "Is the typename of an oop.child instance the same as ""oop.grandchild""?"
   Print "  " & typeNameEqualFromRTTI(p, "oop.grandchild")
   Print "Is the typename of an oop.child instance the same as ""oop.parent""?"
   Print "  " & typeNameEqualFromRTTI(p, "oop.parent")
   Delete p

   Sleep
            
Output:

   Mangled typenames list, from RTTI info:
     N3OOP10GRANDCHILDE
     N3OOP5CHILDE
     N3OOP6PARENTE
     6Object

   Typenames (demangled) list, from RTTI info:
     OOP.GRANDCHILD
     OOP.CHILD
     OOP.PARENT
     Object

   Typename (demangled) And all those of its Base-types hierarchy, from RTTI info:
     OOP.GRANDCHILD->OOP.CHILD->OOP.PARENT->Object

   Is the typename of an oop.child instance the same As "child"?
     False
   Is the typename of an oop.child instance the same As "oop.child"?
     True
   Is the typename of an oop.child instance the same As "oop.grandchild"?
     False
   Is the typename of an oop.child instance the same As "oop.parent"?
     False
   				

Back to top

See also
   * Composition, Aggregation, Inheritance
   * Inheritance Polymorphism



--------------------------------------------------- ProPgDataExecutable ----
Embed and Access binary Data in Executable

How to embed binary data into an executable file at compile time, and access
 it from program code.
(based from forum posts of caseih and coderJeff)

This article describes a way to include binary data in a compiled program, 
and how to access them.

Principle
   The (G)LD linker (included in the FreeBASIC distribution) can process 
   binary data in a file, by turning them into an object file. This object 
   file exports symbols that can be accessed from the program code to read 
   the data.
   The linker will so build two byte symbols based on the file name 
   provided:
      - a symbol for the beginning of the data block (the first data byte),
      - another symbol for the end of the data block (just after the last 
      data byte).
   By compiling the user program with the object file, the addresses of 
   these byte symbols allow to get pointers to the beginning and end of the 
   data.

   Note: It may be advantageous to apply this principle for example to an 
   audio data file which can thus be included in the executable file. Both 
   a pointer to the start of the audio data and the size of the audio data 
   can be passed to any audio player function.

Example
   Simple example to only demonstrate the principle (tested on linux/win 
   32/64-bit gas/gas64/gcc).
   This example uses as binary data the ASCII code bytes of a text inserted 
   in a hello.txt text file:
      hello.txt text file for example:

   Hello!
   Welcome To the forum.
   			

      Invoke the LD linker manually to turn the hello.txt text file into an 
      hello.o object file exporting symbols:
         ...\ld -r -b binary -o hello.o hello.txt

      Two byte symbols are exported from the hello.o object file:
         - on Windows 32-bit:
               binary_hello_txt_start : beginning of the data block (the 
               first data byte)
               binary_hello_txt_end : end of the data block (just after the 
               last data byte)
         - otherwise:
               _binary_hello_txt_start : beginning of the data block (the 
               first data byte)
               _binary_hello_txt_end : end of the data block (just after 
               the last data byte)

      Include the hello.o object file in the command-line when compiling 
      the following program (which prints the ASCII code bytes embedded in 
      the executable):
   Extern "C"
      #if defined(__FB_WIN32__) And Not defined(__FB_64BIT__)
         Extern hello_txt_start Alias "binary_hello_txt_start" As Const Byte
         Extern hello_txt_end Alias "binary_hello_txt_end" As Const Byte
      #else
         Extern hello_txt_start Alias "_binary_hello_txt_start" As Const Byte
         Extern hello_txt_end Alias "_binary_hello_txt_end" As Const Byte
      #endif
   End Extern

   Dim hello_ptr As Const Byte Const Ptr = @hello_txt_start
   Dim hello_length As Const UInteger = @hello_txt_end - @hello_txt_start

   For i As UInteger = 0 To hello_length - 1
      Print Chr(hello_ptr[i]);
   Next
   Print

   Sleep
            

See also
   * Executables
   * fbc command-line



----------------------------------------------------- ProPgUseNewDelete ----
Use Implicit / Overload New([]) and Delete([]) Operators with Inheritance Polymorphism

How to use the implicit or overload New and Delete operators and their New[]
 and Delete[] array-versions, with inheritance polymorphism (sub-type 
polymorphism), and how workaround some unexpected or unsuitable behaviors.

Preamble:

   Some definitions and introductions to start with.

   Different operators New and Delete (may be confusion in the user mind 
   despite the documentation that distinguishes them from each other 
   through different pages)

      Implicit New/Delete operator (inaccessible by user):
         - It is a static function/sub that only allocates/frees memory (it 
         is not very different from Allocate/Deallocate).
      Overload New/Delete operator (defined by user):
         - It is a member operator (static function/sub) that can overload 
         the 'Implicit New/Delete operator' only for user-defined types.
         - So the user can define its own dynamic memory 
         allocation/deallocation process part (the following/previous 
         process part for implicit object construction/destruction can not 
         be modified).

      New Expression operator:
         - It starts by using the 'Implicit/Overload New operator' (the 
         implicit, or the overload if exists) to allocate memory.
         - Then it invokes the constructor for the right type of object. If 
         that object contains any other objects (either embedded or as base 
         types) those constructors as invoked as well.
         - So the final result is memory allocated and object constructed.
      Delete Statement operator:
         - It starts by invoking the destructor for the right type of 
         object. If that object contains any other objects (either embedded 
         or as base types) those destructors as invoked as well.
         - Then it uses the 'Implicit/Overload Delete operator' (the 
         implicit, or the overload if exists) to deallocate memory.
         - So the final result is object destroyed and memory freed.

      Placement New Operator:
         - It constructs an object at a specified memory address (already 
         allocated by another process).
         - Consequently there is no 'Placement Delete operator'.
         - It the object has a destructor (implicit or explicit), the user 
         can call it with syntax as for a member method by using member 
         access operator.

      Similar definition for 'Implicit/overload New[]/Delete[] operators', 
      'New[] expression operator' and 'Delete[] statement operator', 
      'Placement New[] operator', which are only the (one-dimensional) 
      array-versions of the previous operators (there is 
      construction/destruction loop on the array elements).

   Inheritance Polymorphism (ability of calling from the base type the 
   member procedures of derived-types without worrying about the real type 
   of the processed objects)

      Thanks to the 'abstract'/'virtual' procedures, one can write a code 
      using only the base type that will automatically call the 
      derived-type procedures.
      It is then possible to call the procedure of an object without 
      worrying about its intrinsic type.

      By using the same procedure name for several different types, the 
      polymorphism allows a much more generic programming (abstraction).
      The coder does not have to know, when calling a base procedure, the 
      precise type of object on which the procedure will apply. He just 
      needs to know that this type will implement the procedure.

      Thus, a base-typed pointer (or reference), pointing to an instance of 
      a derived-type, can be used to manipulate such an object.
      Considering a collection of objects whose instantiate types are 
      derived-types from a base type, then all these objects can be 
      manipulated in an uniform way by considering them as objects of the 
      base type.

   Content of the following (6 parts and their associated examples)

      6 main parts by increasing difficulty:
Preamble
1. Use Implicit New and Delete operators with inheritance polymorphism (sub-type polymorphism)
2. Use Placement New operator with inheritance polymorphism (sub-type polymorphism)
3. Use Implicit New[] and Delete[] operators with inheritance polymorphism (sub-type polymorphism)
4. Use Placement New[] operator with inheritance polymorphism (sub-type polymorphism)
5. Use Overload New and Delete operators with inheritance polymorphism (sub-type polymorphism)
6. Use Overload New[] and Delete[] operators with inheritance polymorphism (sub-type polymorphism)
Conclusion

      6 associated examples:
         Starting from the same common body of polymorphism by inheritance 
         (polymorphism by sub-type):
            - Structure hierarchy: Animal as base Type, Cat and Dog as 
            derived Types.
            - Member data: string ('name') in Animal, string ('favorite') 
            in Cat and in Dog.
            - Procedure fields: abstract/virtual subs 'Init()', 
            abstract/virtual functions 'get_attributes()', virtual 
            destructors 'Destructor()'.
            - Base constructor is protected and base copy-constructor is 
            private, in order to disallow any construction or 
            copy-construction for base object.
            - 4 objects constructed: 2 instances of Cat, 2 instances of 
            Dog.
         Then, other member procedures are added according to the part to 
         be processed, and to the unexpected or unsuitable behaviors to be 
         workarounded.

1. Use Implicit New and Delete operators with inheritance polymorphism 
(sub-type polymorphism)
   A collection of base-typed pointers in an array (base-typed Ptr array), 
   where each pointer addresses a single derived object of any derived 
   type.
   No New/Delete operator overload.

   This is the starting point of the study (simple case of polymorphism).
   No unexpected or unsuitable behavior.

   No unsuitable or unexpected behavior
      Although the Implicit Delete operator is static, everything works 
      fine when calling the static Delete statement on a base-typed 
      pointer:
         - The object is completely destroyed (derived part and base part) 
         thanks to the virtual destructor in each derived type which 
         overrides that of the base type.
         - Then, the total memory is well deallocated even by calling the 
         Implicit Delete operator of the base type, because this process 
         only uses the value of the pointer provided.

   Example
   ' Code for using implicit 'New'/'Delete' operators from base-typed pointer array in polymorphic inheritance context

   Type Animal Extends Object
      Public:
         Declare Abstract Sub Init(ByRef _name As String, ByRef _favorite As String)
         Declare Abstract Function get_attributes() As String
         Declare Virtual Destructor()
      Protected:
         Dim As String Name
         Declare Constructor()
      Private:
         Declare Constructor(ByRef _a As Animal)
   End Type

   Destructor Animal ()
      Print "Animal destructor: ", "object address: " & @This
   End Destructor

   Constructor Animal ()
      Print "Animal constructor: ", "object address: " & @This
   End Constructor

   Type Cat Extends Animal
      Public:
         Declare Constructor()
         Declare Virtual Sub Init(ByRef _name As String, ByRef _favorite As String)
         Declare Virtual Function get_attributes() As String
         Declare Virtual Destructor()
      Private:
         Dim As String favorite
   End Type

   Constructor Cat ()
      Print "  Cat constructor: ", "  object address: " & @This
   End Constructor

   Sub Cat.Init(ByRef _name As String, ByRef _favorite As String = "")
      This.Name = _name
      This.favorite = _favorite
   End Sub

   Function Cat.get_attributes() As String
      Return This.Name & ": Cat, Meow, " & This.favorite
   End Function

   Destructor Cat()
      Print "  Cat destructor: ", "  object address: " & @This
   End Destructor

   Type Dog Extends Animal
      Public:
         Declare Constructor()
         Declare Virtual Sub Init(ByRef _name As String, ByRef _favorite As String)
         Declare Virtual Function get_attributes() As String
         Declare Virtual Destructor()
      Private:
         Dim As String favorite
   End Type

   Constructor Dog()
      Print "  Dog constructor: ", "  object address: " & @This
   End Constructor

   Sub Dog.Init(ByRef _name As String, ByRef _favorite As String)
      This.Name = _name
      This.favorite = _favorite
   End Sub

   Function Dog.get_attributes() As String
      Return This.Name & ": Dog, Woof, " & This.favorite
   End Function

   Destructor Dog()
      Print "  Dog destructor: ", "  object address: " & @This
   End Destructor

   '------------------------------------------------------------------------------

   Dim As Animal Ptr pa(0 To ...) = {New Cat(), New Cat(), New Dog(), New Dog()}

   pa(0)->Init("Tiger", "Salmon")
   pa(1)->Init("Kitty", "Sardine")
   pa(2)->Init("Buddy", "Lamb")
   pa(3)->Init("Molly", "Beef")

   For I As Integer = LBound(pa) To UBound(pa)
      Print "    " & pa(I)->get_attributes()
   Next I

   For I As Integer = LBound(pa) To UBound(pa)
      Delete pa(I)
   Next I

   Sleep

			Output (64-bit):

   Animal Constructor:         Object address: 16455952
     Cat Constructor:            Object address: 16455952
   Animal Constructor:         Object address: 16473360
     Cat Constructor:            Object address: 16473360
   Animal Constructor:         Object address: 16473424
     Dog Constructor:            Object address: 16473424
   Animal Constructor:         Object address: 16473488
     Dog Constructor:            Object address: 16473488
   	Tiger: Cat, Meow, Salmon
   	Kitty: Cat, Meow, Sardine
   	Buddy: Dog, Woof, Lamb
   	Molly: Dog, Woof, Beef
     Cat Destructor:             Object address: 16455952
   Animal Destructor:          Object address: 16455952
     Cat Destructor:             Object address: 16473360
   Animal Destructor:          Object address: 16473360
     Dog Destructor:             Object address: 16473424
   Animal Destructor:          Object address: 16473424
     Dog Destructor:             Object address: 16473488
   Animal Destructor:          Object address: 16473488

Back to top

2. Use Placement New operator with inheritance polymorphism (sub-type 
polymorphism)
   A collection of base-typed pointers in an array (base-typed Ptr array), 
   where each pointer addresses a single derived object of any derived 
   type.
   The memory allocation/deallocation is done by another process 
   (Allocate/Deallocate).

   From the previous example
      For the memory allocation and object construction:
         replace:
   Dim As Animal Ptr pa(0 To ...) = {New Cat(), New Cat(), New Dog(), New Dog()}

			with:
   Dim As Any Ptr pc1 = Allocate(SizeOf(Cat))
   Dim As Any Ptr pc2 = Allocate(SizeOf(Cat))
   Dim As Any Ptr pd1 = Allocate(SizeOf(Dog))
   Dim As Any Ptr pd2 = Allocate(SizeOf(Dog))

   Dim As Animal Ptr pa(0 To ...) = {New(pc1) Cat(), New(pc2) Cat(), New(pd1) Dog(), New(pd2) Dog()}

			
      For the object destruction and memory deallocation:
         replace:
   For I As Integer = LBound(pa) To UBound(pa)
      Delete pa(I)
   Next I

			with:
   For I As Integer = LBound(pa) To UBound(pa)
      pa(I)->Destructor()
   Next I

   Deallocate(pc1)
   Deallocate(pc2)
   Deallocate(pd1)
   Deallocate(pd2)

Back to top

3. Use Implicit New[] and Delete[] operators with inheritance polymorphism 
(sub-type polymorphism)
   A collection of base-typed pointers in an array (base-typed Ptr array), 
   where each pointer is a buffer pointer allowing to address several 
   derived object of a same derived type.
   No New[]/Delete[] operator overload.

   One unsuitable behavior and one unexpected behavior are encountered
      The calculation of the right address of any derived object is 
      generally false (because it takes into account as object size the one 
      corresponding to the pointer type and not the real object type), 
      except obviously for the first object:
         - To access to the right address of any derived object (when 
         derived type contains one data field at least) in the array buffer 
         constructed by the Implicit New[] operator, and from a base-typed 
         pointer, a solution consists in overloading the '[]' operator, 
         with a virtual '[]' operator in each derived type which overrides 
         that (abstract) of the base type.
         - Finally, to well call the overload '[]' operator (and not the 
         implicit '[]' operator), it must be called on a dereferenced 
         pointer (and not on the rough pointer that would called the 
         implicit '[]' operator).
         - If 'p' is the base-typed pointer, the right expression is 
         '(*p)[n]' and not 'p[n]'.
         - Warning: to calculate the right address of the nth derived 
         object, the virtual '[]' operator is always called on the '*p' 
         reference corresponding to the first object of the array buffer, 
         so a correct overriding of the operator assumes that this first 
         object of the array buffer is always a valid derived object (not 
         destroyed for example).
      The static Delete[] statement does not allow to retrieve the real 
      run-time type of the object:
         - So the calculation of the address of each object to destroy (if 
         it is necessary) is generally false (because it takes into account 
         as object size the one corresponding to the pointer type and not 
         the real object type), except obviously for the first object.
         - However, the total memory would be well deallocated even by 
         calling the Implicit Delete[] operator of the base type, because 
         this process only uses the value of the pointer provided.
         - The safest is to use a virtual launcher for the Delete[] 
         statement in each derived type which overrides that (abstract) of 
         the base type, and in this case (as by calling the Delete[] 
         statement on a derived type pointer), this is not mandatory of 
         defining a virtual destructor but remains still recommended.
         - In the following example, the called virtual launcher is 
         'DeleteSB_launcher()'.

   Example
   ' Code for using implicit 'New[]'/'Delete[]' operators from base-typed pointer array in polymorphic inheritance context
   '    Added member procedures to workaround unsuitable or unexpected behaviors:
   '       - Abstract/Virtual 'Operator []()' to access to the right address of any derived object from a base-typed pointer
   '       - Abstract/Virtual 'DeleteSB_launcher()' to destroy the right objects from a base-typed pointer

   Type Animal Extends Object
      Public:
         Declare Abstract Sub Init(ByRef _name As String, ByRef _favorite As String)
         Declare Abstract Function get_attributes() As String
         Declare Virtual Destructor()
         Declare Abstract Operator [](ByVal _n As Integer) ByRef As Animal
         Declare Abstract Sub DeleteSB_launcher()
      Protected:
         Dim As String Name
         Declare Constructor()
      Private:
         Declare Constructor(ByRef _a As Animal)
   End Type

   Destructor Animal ()
      Print "Animal destructor: ", "object address: " & @This
   End Destructor

   Constructor Animal ()
      Print "Animal constructor: ", "object address: " & @This
   End Constructor

   Type Cat Extends Animal
      Public:
         Declare Constructor()
         Declare Virtual Sub Init(ByRef _name As String, ByRef _favorite As String)
         Declare Virtual Function get_attributes() As String
         Declare Virtual Destructor()
         Declare Virtual Operator [](ByVal _n As Integer) ByRef As Cat
         Declare Virtual Sub DeleteSB_launcher()
      Private:
         Dim As String favorite
   End Type

   Constructor Cat()
      Print "  Cat constructor: ", "  object address: " & @This
   End Constructor

   Sub Cat.Init(ByRef _name As String, ByRef _favorite As String = "")
      This.Name = _name
      This.favorite = _favorite
   End Sub

   Function Cat.get_attributes() As String
      Return This.Name & ": Cat, Meow, " & This.favorite
   End Function

   Destructor Cat()
      Print "  Cat destructor: ", "  object address: " & @This
   End Destructor

   Operator Cat.[](ByVal _n As Integer) ByRef As Cat
      Return (@This)[_n]
   End Operator

   Sub Cat.DeleteSB_launcher()
      Delete[] @This
   End Sub

   Type Dog Extends Animal
      Public:
         Declare Constructor()
         Declare Virtual Sub Init(ByRef _name As String, ByRef _favorite As String)
         Declare Virtual Function get_attributes() As String
         Declare Virtual Destructor()
         Declare Virtual Operator [](ByVal _n As Integer) ByRef As Dog
         Declare Virtual Sub DeleteSB_launcher()
      Private:
         Dim As String favorite
   End Type

   Constructor Dog()
      Print "  Dog constructor: ", "  object address: " & @This
   End Constructor

   Sub Dog.Init(ByRef _name As String, ByRef _favorite As String)
      This.Name = _name
      This.favorite = _favorite
   End Sub

   Function Dog.get_attributes() As String
      Return This.Name & ": Dog, Woof, " & This.favorite
   End Function

   Destructor Dog()
     Print "  Dog destructor: ", "  object address: " & @This
   End Destructor

   Operator Dog.[](ByVal _n As Integer) ByRef As Dog
      Return (@This)[_n]
   End Operator

   Sub Dog.DeleteSB_launcher()
      Delete[] @This
   End Sub

   '------------------------------------------------------------------------------

   Dim As Animal Ptr pa(0 To ...) = {New Cat[2], New Dog[2]}

   'pa(0)[0].Init("Tiger", "Salmon")   '' does not work
   'pa(0)[1].Init("Kitty", "Sardine")  '' does not work
   'pa(1)[0].Init("Buddy", "Lamb")     '' does not work
   'pa(1)[1].Init("Molly", "Beef")     '' does not work
   (*pa(0))[0].Init("Tiger", "Salmon")
   (*pa(0))[1].Init("Kitty", "Sardine")
   (*pa(1))[0].Init("Buddy", "Lamb")
   (*pa(1))[1].Init("Molly", "Beef")

   For I As Integer = LBound(pa) To UBound(pa)
      For J As Integer = 0 To 1
   '        Print "    " & pa(I)[J].get_attributes()  '' does not work
         Print "    " & (*pa(I))[J].get_attributes()
      Next J
   Next I

   For I As Integer = LBound(pa) To UBound(pa)
   '    Delete[] pa(I)  '' does not work
      pa(I)->DeleteSB_launcher()
   Next I

   Sleep

			Output (64-bit):

   Animal Constructor:         Object address: 7101688
     Cat Constructor:            Object address: 7101688
   Animal Constructor:         Object address: 7101744
     Cat Constructor:            Object address: 7101744
   Animal Constructor:         Object address: 7101816
     Dog Constructor:            Object address: 7101816
   Animal Constructor:         Object address: 7101872
     Dog Constructor:            Object address: 7101872
   	Tiger: Cat, Meow, Salmon
   	Kitty: Cat, Meow, Sardine
   	Buddy: Dog, Woof, Lamb
   	Molly: Dog, Woof, Beef
     Cat Destructor:             Object address: 7101744
   Animal Destructor:          Object address: 7101744
     Cat Destructor:             Object address: 7101688
   Animal Destructor:          Object address: 7101688
     Dog Destructor:             Object address: 7101872
   Animal Destructor:          Object address: 7101872
     Dog Destructor:             Object address: 7101816
   Animal Destructor:          Object address: 7101816

Back to top

4. Use Placement New[] operator with inheritance polymorphism (sub-type 
polymorphism)
   A collection of base-typed pointers in an array (base-typed Ptr array), 
   where each pointer is a buffer pointer allowing to address several 
   derived object of a same derived type.
   The memory allocation/deallocation is done by another process 
   (Allocate/Deallocate).

   From the previous example
      For the memory allocation and object construction:
         replace:
   Dim As Animal Ptr pa(0 To ...) = {New Cat[2], New Dog[2]}

			with:
   Dim As Any Ptr pc = Allocate(2 * SizeOf(Cat))
   Dim As Any Ptr pd = Allocate(2 * SizeOf(Dog))

   Dim As Animal Ptr pa(0 To ...) = {New(pc) Cat[2], New(pd) Dog[2]}

			
      For the object destruction and memory deallocation:
         replace:
   For I As Integer = LBound(pa) To UBound(pa)
   '    Delete[] pa(I)  '' does not work
      pa(I)->DeleteSB_launcher()
   Next I

			with:
   For I As Integer = LBound(pa) To UBound(pa)
      For J As Integer = 1 To 0 Step -1  '' reverse order for destruction is mandatory
                                 ''    (see warning on '[]' operator usage)
   '        pa(I)[J]. Destructor()   '' does not work
         (*pa(I))[J].Destructor()
      Next J
   Next I

   Deallocate(pc)
   Deallocate(pd)

			Warning when using the virtual operator '[]' in a context of inheritance 
polymorphism (sub-type polymorphism):
            - To calculate the correct address of the nth derived object in 
            a buffer, from a base-typed pointer 'p', a virtual operator 
            '[]' can be used to return (using: 'Return (@This)[n]') a 
            reference to this nth derived object.
            - This virtual operator '[]' is always called on the same 
            reference ('*p') corresponding to the first object of the 
            buffer (operator called by: '(*p)[n]').
            - So, a correct overriding of this operator (to calculate the 
            correct address of the nth derived object) assumes that the 
            first object in the buffer is always a valid derived object 
            (not destroyed for example).
            - This is why the destruction loop of the objects of the buffer 
            (by: '(*p)[n].Destructor()'), in case of 'Placement New[]' 
            usage as above, must always be done in the reverse order (end 
            with the first object of the buffer).

Back to top

5. Use Overload New and Delete operators with inheritance polymorphism 
(sub-type polymorphism)
   A collection of base-typed pointers in an array (base-typed Ptr array), 
   where each pointer addresses a single derived object of any derived 
   type.
   New/Delete operators overloaded.

   One unexpected behavior is encountered
      The static Delete statement does not allow to retrieve the real 
      run-time type of the object:
         - So, the user code of the overload Delete operator of the derived 
         type is not executed because the Delete operator of the base type 
         is called instead.
         - The safest is to use a virtual launcher for the Delete statement 
         in each derived type which overrides that (abstract) of the base 
         type, and in this case (as by calling the Delete statement on a 
         derived type pointer), this is not mandatory of defining a virtual 
         destructor but remains still recommended.
         - In the following example, the called virtual launcher is 
         'Delete_launcher()'.

   Example
   ' Code for using overload 'New'/'Delete' operators from base-typed pointer array in polymorphic inheritance context
   '    Added member procedure to workaround unexpected behavior:
   '       - Abstract/Virtual 'Delete_launcher()' to call the overload Delete operator of the derived type from a base-typed pointer

   Type Animal Extends Object
      Public:
         Declare Abstract Sub Init(ByRef _name As String, ByRef _favorite As String)
         Declare Abstract Function get_attributes() As String
         Declare Virtual Destructor()
         Declare Abstract Sub Delete_launcher()
      Protected:
         Dim As String Name
         Declare Constructor()
      Private:
         Declare Constructor(ByRef _a As Animal)
   End Type

   Destructor Animal ()
      Print "  Animal destructor: ", "  object address: " & @This
   End Destructor

   Constructor Animal ()
      Print "  Animal constructor: ", "  object address: " & @This
   End Constructor

   Type Cat Extends Animal
      Public:
         Declare Constructor()
         Declare Virtual Sub Init(ByRef _name As String, ByRef _favorite As String)
         Declare Virtual Function get_attributes() As String
         Declare Virtual Destructor()
         Declare Operator New(ByVal size As UInteger) As Any Ptr
         Declare Operator Delete(ByVal buf As Any Ptr)
         Declare Virtual Sub Delete_launcher()
      Private:
         Dim As String favorite
   End Type

   Constructor Cat ()
      Print "    Cat constructor: ", "    object address: " & @This
   End Constructor

   Sub Cat.Init(ByRef _name As String, ByRef _favorite As String = "")
      This.Name = _name
      This.favorite = _favorite
   End Sub

   Function Cat.get_attributes() As String
      Return This.Name & ": Cat, Meow, " & This.favorite
   End Function

   Destructor Cat()
      Print "    Cat destructor: ", "    object address: " & @This
   End Destructor

   Operator Cat.New(ByVal size As UInteger) As Any Ptr
      Dim As Any Ptr p = CAllocate(size)
      Print "Cat New operator: ", "buffer address: " & p
      Return p
   End Operator

   Operator Cat.Delete(ByVal buf As Any Ptr)
      Print "Cat Delete operator: ", "object address: " & buf
      Deallocate(buf)
   End Operator

   Sub Cat.Delete_launcher()
      Delete @This
   End Sub

   Type Dog Extends Animal
      Public:
         Declare Constructor()
         Declare Virtual Sub Init(ByRef _name As String, ByRef _favorite As String)
         Declare Virtual Function get_attributes() As String
         Declare Virtual Destructor()
         Declare Operator New(ByVal size As UInteger) As Any Ptr
         Declare Operator Delete(ByVal buf As Any Ptr)
         Declare Virtual Sub Delete_launcher()
      Private:
         Dim As String favorite
   End Type

   Constructor Dog()
      Print "    Dog constructor: ", "    object address: " & @This
   End Constructor

   Sub Dog.Init(ByRef _name As String, ByRef _favorite As String)
      This.Name = _name
      This.favorite = _favorite
   End Sub

   Function Dog.get_attributes() As String
      Return This.Name & ": Dog, Woof, " & This.favorite
   End Function

   Destructor Dog()
      Print "    Dog destructor: ", "    object address: " & @This
   End Destructor

   Operator Dog.New(ByVal size As UInteger) As Any Ptr
      Dim As Any Ptr p = CAllocate(size)
      Print "Dog New operator: ", "buffer address: " & p
      Return p
   End Operator

   Operator Dog.Delete(ByVal buf As Any Ptr)
      Print "Dog Delete operator: ", "buffer address: " & buf
      Deallocate(buf)
   End Operator

   Sub Dog.Delete_launcher()
      Delete @This
   End Sub

   '------------------------------------------------------------------------------

   Dim As Animal Ptr pa(0 To ...) = {New Cat(), New Cat(), New Dog(), New Dog()}

   pa(0)->Init("Tiger", "Salmon")
   pa(1)->Init("Kitty", "Sardine")
   pa(2)->Init("Buddy", "Lamb")
   pa(3)->Init("Molly", "Beef")

   For I As Integer = LBound(pa) To UBound(pa)
      Print "      " & pa(I)->get_attributes()
   Next I

   For I As Integer = LBound(pa) To UBound(pa)
   '    Delete pa(I)  '' does not work
      pa(I)->Delete_launcher()
   Next I

   Sleep

			Output (64-bit):

   Cat New Operator:           buffer address: 13900048
     Animal Constructor:         Object address: 13900048
   	Cat Constructor:            Object address: 13900048
   Cat New Operator:           buffer address: 13917456
     Animal Constructor:         Object address: 13917456
   	Cat Constructor:            Object address: 13917456
   Dog New Operator:           buffer address: 13917520
     Animal Constructor:         Object address: 13917520
   	Dog Constructor:            Object address: 13917520
   Dog New Operator:           buffer address: 13917584
     Animal Constructor:         Object address: 13917584
   	Dog Constructor:            Object address: 13917584
   	  Tiger: Cat, Meow, Salmon
   	  Kitty: Cat, Meow, Sardine
   	  Buddy: Dog, Woof, Lamb
   	  Molly: Dog, Woof, Beef
   	Cat Destructor:             Object address: 13900048
     Animal Destructor:          Object address: 13900048
   Cat Delete Operator:        Object address: 13900048
   	Cat Destructor:             Object address: 13917456
     Animal Destructor:          Object address: 13917456
   Cat Delete Operator:        Object address: 13917456
   	Dog Destructor:             Object address: 13917520
     Animal Destructor:          Object address: 13917520
   Dog Delete Operator:        buffer address: 13917520
   	Dog Destructor:             Object address: 13917584
     Animal Destructor:          Object address: 13917584
   Dog Delete Operator:        buffer address: 13917584

Back to top

6. Use Overload New[] and Delete[] operators with inheritance polymorphism 
(sub-type polymorphism)
   A collection of base-typed pointers in an array (base-typed Ptr array), 
   where each pointer is a buffer pointer allowing to address several 
   derived object of a same derived type.
   New[]/Delete[] operators overloaded.

   One unsuitable behavior and one unexpected behavior are encountered
      The calculation of the right address of any derived object is 
      generally false (because it takes into account as object size the one 
      corresponding to the pointer type and not the real object type), 
      except obviously for the first object:
         - To access to the right address of any derived object (when 
         derived type contains one data field at least) in the array buffer 
         constructed by the Overload New[] operator, and from a base-typed 
         pointer, a solution consists in overloading the '[]' operator, 
         with a virtual '[]' operator in each derived type which overrides 
         that (abstract) of the base type.
         - To well call the overload '[]' operator (and not the implicit 
         '[]' operator), it must be called on a dereferenced pointer (and 
         not on the rough pointer that would called the implicit '[]' 
         operator).
         - If 'p' is the base-typed pointer, the right expression is 
         '(*p)[n]' and not 'p[n]'.
         - Warning: to calculate the right address of the nth derived 
         object, the virtual '[]' operator is always called on the '*p' 
         reference corresponding to the first object of the array buffer, 
         so a correct overriding of the operator assumes that this first 
         object of the array buffer is always a valid derived object (not 
         destroyed for example).
      The static Delete[] statement does not allow to retrieve the real 
      run-time type of the object:
         - So the calculation of the address of each object to destroy (if 
         it is necessary) is generally false (because it takes into account 
         as object size the one corresponding to the pointer type and not 
         the real object type), except obviously for the first object.
         - Also, the user code of the overload Delete[] operator of the 
         derived type is not executed because the Delete[] operator of the 
         base type is called instead.
         - The safest for these two consequences is to always use a virtual 
         launcher for the Delete[] statement in each derived type which 
         overrides that (abstract) of the base type, and in this case (as 
         by calling the Delete[] statement on a derived type pointer), this 
         is not mandatory of defining a virtual destructor but remains 
         still recommended.
         - In the following example, the called virtual launcher is 
         'DeleteSB_launcher()'.

   Example
   ' Code for using overload 'New[]'/'Delete[]' operators from base-typed pointer array in polymorphic inheritance context
   '    Added member procedures to workaround unsuitable or unexpected behaviors:
   '       - Abstract/Virtual 'Operator []()' to access to the right address of any derived object from a base-typed pointer
   '       - Abstract/Virtual 'DeleteSB_launcher()' to destroy the right objects from a base-typed pointer, and to call the overload Delete[] operator of the derived type from a base-typed pointer

   Type Animal Extends Object
      Public:
         Declare Abstract Sub Init(ByRef _name As String, ByRef _favorite As String)
         Declare Abstract Function get_attributes() As String
         Declare Virtual Destructor()
         Declare Abstract Operator [](ByVal _n As Integer) ByRef As Animal
         Declare Abstract Sub DeleteSB_launcher()
      Protected:
         Dim As String Name
         Declare Constructor()
      Private:
         Declare Constructor(ByRef _a As Animal)
   End Type

   Destructor Animal ()
      Print "  Animal destructor: ", "  object address: " & @This
   End Destructor

   Constructor Animal ()
      Print "  Animal constructor: ", "  object address: " & @This
   End Constructor

   Type Cat Extends Animal
      Public:
         Declare Constructor()
         Declare Virtual Sub Init(ByRef _name As String, ByRef _favorite As String)
         Declare Virtual Function get_attributes() As String
         Declare Virtual Destructor()
         Declare Virtual Operator [](ByVal _n As Integer) ByRef As Cat
         Declare Operator New[](ByVal size As UInteger) As Any Ptr
         Declare Operator Delete[](ByVal buf As Any Ptr)
         Declare Virtual Sub DeleteSB_launcher()
      Private:
         Dim As String favorite
   End Type

   Constructor Cat()
      Print "    Cat constructor: ", "    object address: " & @This
   End Constructor

   Sub Cat.Init(ByRef _name As String, ByRef _favorite As String = "")
      This.Name = _name
      This.favorite = _favorite
   End Sub

   Function Cat.get_attributes() As String
      Return This.Name & ": Cat, Meow, " & This.favorite
   End Function

   Destructor Cat()
      Print "    Cat destructor: ", "    object address: " & @This
   End Destructor

   Operator Cat.[](ByVal _n As Integer) ByRef As Cat
      Return (@This)[_n]
   End Operator

   Operator Cat.New[](ByVal size As UInteger) As Any Ptr
      Dim As Any Ptr p = CAllocate(size)
      Print "Cat New[] operator: ", "buffer address: " & p
      Return p
   End Operator

   Operator Cat.Delete[](ByVal buf As Any Ptr)
      Print "Cat Delete[] operator: ", "buffer address: " & buf
      Deallocate(buf)
   End Operator

   Sub Cat.DeleteSB_launcher()
      Delete[] @This
   End Sub

   Type Dog Extends Animal
      Public:
         Declare Constructor()
         Declare Virtual Sub Init(ByRef _name As String, ByRef _favorite As String)
         Declare Virtual Function get_attributes() As String
         Declare Virtual Destructor()
         Declare Virtual Operator [](ByVal _n As Integer) ByRef As Dog
         Declare Operator New[](ByVal size As UInteger) As Any Ptr
         Declare Operator Delete[](ByVal buf As Any Ptr)
         Declare Virtual Sub DeleteSB_launcher()
      Private:
         Dim As String favorite
   End Type

   Constructor Dog()
      Print "    Dog constructor: ", "    object address: " & @This
   End Constructor

   Sub Dog.Init(ByRef _name As String, ByRef _favorite As String)
      This.Name = _name
      This.favorite = _favorite
   End Sub

   Function Dog.get_attributes() As String
      Return This.Name & ": Dog, Woof, " & This.favorite
   End Function

   Destructor Dog()
     Print "    Dog destructor: ", "    object address: " & @This
   End Destructor

   Operator Dog.[](ByVal _n As Integer) ByRef As Dog
      Return (@This)[_n]
   End Operator

   Operator Dog.New[](ByVal size As UInteger) As Any Ptr
      Dim As Any Ptr p = CAllocate(size)
      Print "Dog New[] operator: ", "buffer address: " & p
      Return p
   End Operator

   Operator Dog.Delete[](ByVal buf As Any Ptr)
      Print "Dog Delete[] operator: ", "buffer address: " & buf
      Deallocate(buf)
   End Operator

   Sub Dog.DeleteSB_launcher()
      Delete[] @This
   End Sub

   '------------------------------------------------------------------------------

   Dim As Animal Ptr pa(0 To ...) = {New Cat[2], New Dog[2]}

   'pa(0)[0].Init("Tiger", "Salmon")   '' does not work
   'pa(0)[1].Init("Kitty", "Sardine")  '' does not work
   'pa(1)[0].Init("Buddy", "Lamb")     '' does not work
   'pa(1)[1].Init("Molly", "Beef")     '' does not work
   (*pa(0))[0].Init("Tiger", "Salmon")
   (*pa(0))[1].Init("Kitty", "Sardine")
   (*pa(1))[0].Init("Buddy", "Lamb")
   (*pa(1))[1].Init("Molly", "Beef")

   For I As Integer = LBound(pa) To UBound(pa)
      For J As Integer = 0 To 1
   '        Print "      " & pa(I)[J].get_attributes()  '' does not work
         Print "      " & (*pa(I))[J].get_attributes()
      Next J
   Next I

   For I As Integer = LBound(pa) To UBound(pa)
   '    Delete[] pa(I)  '' does not work
      pa(I)->DeleteSB_launcher()
   Next I

   Sleep

			Output (64-bit):

   Cat New[] Operator:         buffer address: 17128688
     Animal Constructor:         Object address: 17128696
   	Cat Constructor:            Object address: 17128696
     Animal Constructor:         Object address: 17128752
   	Cat Constructor:            Object address: 17128752
   Dog New[] Operator:         buffer address: 17128816
     Animal Constructor:         Object address: 17128824
   	Dog Constructor:            Object address: 17128824
     Animal Constructor:         Object address: 17128880
   	Dog Constructor:            Object address: 17128880
   	  Tiger: Cat, Meow, Salmon
   	  Kitty: Cat, Meow, Sardine
   	  Buddy: Dog, Woof, Lamb
   	  Molly: Dog, Woof, Beef
   	Cat Destructor:             Object address: 17128752
     Animal Destructor:          Object address: 17128752
   	Cat Destructor:             Object address: 17128696
     Animal Destructor:          Object address: 17128696
   Cat Delete[] Operator:      buffer address: 17128688
   	Dog Destructor:             Object address: 17128880
     Animal Destructor:          Object address: 17128880
   	Dog Destructor:             Object address: 17128824
     Animal Destructor:          Object address: 17128824
   Dog Delete[] Operator:      buffer address: 17128816

				Note:
               - As the derived type has a destructor, an extra uinteger is 
               allocated by the New[] operator at the head of the memory 
               buffer, in order to store the number of elements as part of 
               the allocation, so that the Delete[] operator can determine 
               the count of destructors to call.
               - This is why the memory buffer address is different from 
               the first object address in the memory buffer.

Back to top

Conclusion:

   To be compatible at the same time with any usage (simple/array-version, 
   implicit/overload) of the New([])/Delete([]) operators in an inheritance 
   polymorphism (sub-type polymorphism), 3 member procedures must be added 
   to workaround unsuitable or unexpected behaviors:
      - Abstract/Virtual 'Operator []()' to access to the right address of 
      any derived object from a base-typed pointer.
      - Abstract/Virtual 'Delete_launcher()' to call the overload Delete 
      operator of the derived type from a base-typed pointer.
      - Abstract/Virtual 'DeleteSB_launcher()' to destroy the objects at 
      the right addresses from a base-typed pointer, and to call the 
      overload Delete[] operator of the derived type from a base-typed 
      pointer.

      'Virtual' declarations and bodies of the added member procedures in 
      each derived type, but only 'abstract' declarations in the base type:
   Type base_type Extends Object
      Declare Abstract Operator [](ByVal n As Integer) ByRef As base_type
      Declare Abstract Sub Delete_launcher()
      Declare Abstract Sub DeleteSB_launcher()
   End Type

   '------------------------------------------------------------------------

   Type derived_type Extends base_type
      Declare Virtual Operator [](ByVal n As Integer) ByRef As derived_type
      Declare Virtual Sub Delete_launcher()
      Declare Virtual Sub DeleteSB_launcher()
   End Type

   Operator derived_type.[](ByVal n As Integer) ByRef As derived_type
      Return (@This)[n]
   End Operator

   Sub derived_type.Delete_launcher()
      Delete @This
   End Sub

   Sub derived_type.DeleteSB_launcher()
      Delete[] @This
   End Sub

			Note:
            - For the virtual '[]' operator in the derived type, declaring 
            returning by derived-typed reference is not mandatory (just for 
            aesthetics by using the covariance). Returning by base-typed 
            reference is sufficient.
            - The important thing is the derived operator body which uses a 
            derived-typed pointer indexing, allowing to return a 
            based-typed reference but rightly pointing to the derived 
            object.

   Abstract
      - The New([]) expression returns a typed pointer corresponding to the 
      called type (a derived type in our case), but the principle of 
      inheritance polymorphism (sub-type polymorphism) is precisely to 
      immediately up-cast this derived type to a base type.
      - Using a base-typed pointer to a derived object buffer does not 
      generally allows to correctly index the different addresses of the 
      derived objects (except if all member data fields are in the base 
      type only).
      - The Implicit/Overload operators New([]) or Delete([]) are all 
      static because their only role is to allocate or free memory, and at 
      that time the object does not exist yet or no longer exists. So this 
      is the Implicit/Overload Delete([]) operator of the base type which 
      is called instead of the one of the derived type.
      - Thus, to nevertheless use all these New([])/Delete([]) 
      functionalities correctly without derogating from the exclusive usage 
      of base-typed pointers, it is necessary to use a solution as 
      developed above (adding one virtual overload operator and two virtual 
      procedures).

Back to top

See also
   * New and Delete
   * Inheritance Polymorphism



----------------------------------------------------- ProPgEmulateTlsTp ----
Emulate a TLS (Thread Local Storage) and a TP (Thread Pooling) feature

How emulate a kind of TLS (Thread Local Storage) and a kind of TP (Thread 
Pooling) feature with FreeBASIC.

Preamble:

   TLS (Thread Local Storage)
      Static variables are normally shared across all the threads. If we 
      modify a static variable, it is visible so modified to all the 
      threads.
      Unlike normal static variable, if we create a TLS static variable, 
      every thread must have its own copy of the variable (but with the 
      same access name), i.e. any change to the variable is local to the 
      thread (locally stored).
      This allows to create a thread-safe procedure, because each call to 
      this procedure gets its own copy of the same declared static 
      variables.
      In normal procedure with static variables, the content of that 
      variables can be updated by multiple threads, but with TLS, we can 
      think of these as static data but local to each thread.

      TLS data is similar to static data, but the only difference is that 
      TLS data are unique to each thread.

   TP (Thread Pooling)
      A thread pool is a set of threads that can be used to run tasks based 
      on user needs.
      The thread pool is accessible via a Type structure.

      Creating a new thread is an expensive act in terms of resources, both 
      from a processor (CPU) point of view and from a memory point of view.
      Also, in the event that a program requires the execution of many 
      tasks, the creation and deletion of a thread for each of them would 
      greatly penalize the performance of the application.
      Therefore, it would be interesting to be able to share the creation 
      of threads so that a thread that has finished executing a task is 
      available for the execution of a future task.

1. How emulate a kind of TLS (Thread Local Storage) feature with FreeBASIC
      The principle of this TLS emulation for FreeBASIC is to use a static 
      array for each requested TLS variable, where each thread has its own 
      unique index (hidden) to access the array element.
      This unique index relating to the thread is deduced from the thread 
      handle value:
            - With fbc version >= 1.08, the thread handle value is simply 
            returned from the 'Threadself()' function calling (new 
            function) from any thread.
            - With fbc version < 1.08, the code is more twisted:
                  - The thread handle value is only accessible from the 
                  'ThreadCreate()' return in the parent (or main) thread 
                  when creating it.
                  - There is no way to properly emulate the 'Threadself()' 
                  function, but only by a twisted method.
                  - In the example below (for fbc version < 1.08), a 
                  'Threadself()' function (returning by reference) value is 
                  initialized before each use by the thread (with its own 
                  thread handle), and all of this (initialization + use) 
                  protected by a mutex as for its corresponding 
                  'ThreadCreate()'.

      In the below example, the TLS static variable is an integer which is 
      used in a single and generic counting procedure ('counter()') with 
      none passed parameter). This counting procedure is called by each 
      thread (thus each thread counts independently of each other but by 
      calling the same single counting procedure).
      A single macro allows to define any TLS variable (except array) of 
      any type.

      * Code with preprocessor conditional directives depending on fbc 
        version:
   #include Once "crt/string.bi"

   #if __FB_VERSION__ < "1.08"
      ' Emulation of the function Threadself() of FreeBASIC
      ' Before each use, the thread must refresh this function value with its own thread handle,
      ' and all of this (refreshing + use) protected by a mutex.
      Function ThreadSelf () ByRef As Any Ptr
         Static As Any Ptr handle
         Return handle
      End Function
   #else
      #include Once "fbthread.bi"
   #endif

   #macro CreateTLSdatatypeVariableFunction (variable_function_name, variable_datatype)
   ' Creation of a "variable_function_name" function to emulate a static datatype variable (not an array),
   ' with a value depending on the thread using it.
      Namespace TLS
         Function variable_function_name (ByVal cd As Boolean = True) ByRef As variable_datatype
         ' Function emulating (creation/access/destruction) a static datatype variable with value depending on thread using it:
            ' If calling without parameter (or with 'True') parameter, this allows to [create and] access the static datatype variable.
            ' If calling with the 'False' parameter, this allows to destroy the static datatype variable.
            Dim As Integer bound = 0
            Static As Any Ptr TLSindex(bound)
            Static As variable_datatype TLSdata(bound)
            Dim As Any Ptr Threadhandle = ThreadSelf()
            Dim As Integer index = 0
            For I As Integer = 1 To UBound(TLSindex)  ' search existing TLS variable (existing array element) for the running thread
               If TLSindex(I) = Threadhandle Then
                  index = I
                  Exit For
               End If
            Next I
            If index = 0 And cd = True Then  ' create a new TLS variable (new array element) for a new thread
               index = UBound(TLSindex) + 1
               ReDim Preserve TLSindex(index)
               TLSindex(index) = Threadhandle
               ReDim Preserve TLSdata(index)
            ElseIf index > 0 And cd = False Then  ' destroy a TLS variable (array element) and compact the array
               If index < UBound(TLSindex) Then  ' reorder the array elements
                  memmove(@TLSindex(index), @TLSindex(index + 1), (UBound(TLSindex) - index) * SizeOf(Any Ptr))
                  Dim As variable_datatype Ptr p = Allocate(SizeOf(variable_datatype))  ' for compatibility to object with destructor
                  memmove(p, @TLSdata(index), SizeOf(variable_datatype))                ' for compatibility to object with destructor
                  memmove(@TLSdata(index), @TLSdata(index + 1), (UBound(TLSdata) - index) * SizeOf(variable_datatype))
                  memmove(@TLSdata(UBound(TLSdata)), p, SizeOf(variable_datatype))      ' for compatibility to object with destructor
                  Deallocate(p)                                                         ' for compatibility to object with destructor
               End If
               ReDim Preserve TLSindex(UBound(TLSindex) - 1)
               ReDim Preserve TLSdata(UBound(TLSdata) - 1)
               index = 0
            End If
            Return TLSdata(index)
         End Function
      End Namespace
   #endmacro

   '------------------------------------------------------------------------------

   Type threadData
      Dim As Any Ptr handle
      Dim As String prefix
      Dim As String suffix
      Dim As Double tempo
      #if __FB_VERSION__ < "1.08"
         Static As Any Ptr mutex
      #endif
   End Type
   #if __FB_VERSION__ < "1.08"
      Dim As Any Ptr threadData.mutex
   #endif

   CreateTLSdatatypeVariableFunction (count, Integer)  ' create a TLS static integer function

   Function counter() As Integer  ' definition of a generic counter with counting depending on thread calling it
      TLS.count() += 1            ' increment the TLS static integer
      Return TLS.count()          ' return the TLS static integer
   End Function

   Sub Thread(ByVal p As Any Ptr)
      Dim As threadData Ptr ptd = p
      Dim As UInteger c
      Do
         #if __FB_VERSION__ < "1.08"
            MutexLock(threadData.mutex)
            ThreadSelf() = ptd->handle
         #endif
            c = counter()
         #if __FB_VERSION__ < "1.08"
            MutexUnlock(threadData.mutex)
         #endif
         Print ptd->prefix & c & ptd->suffix & " ";  ' single print with concatenated string avoids using a mutex
         Sleep ptd->tempo, 1
      Loop Until c = 12
      #if __FB_VERSION__ < "1.08"
         MutexLock(threadData.mutex)
         ThreadSelf() = ptd->handle
      #endif
      TLS.count(False)  ' destroy the TLS static integer
      #if __FB_VERSION__ < "1.08"
         MutexUnlock(threadData.mutex)
      #endif
   End Sub

   '------------------------------------------------------------------------------

   Print "|x| : counting from thread a"
   Print "(x) : counting from thread b"
   Print "[x] : counting from thread c"
   Print

   #if __FB_VERSION__ < "1.08"
      threadData.mutex = MutexCreate()
   #endif

   Dim As threadData mtlsa
   mtlsa.prefix = "|"
   mtlsa.suffix = "|"
   mtlsa.tempo = 100
   #if __FB_VERSION__ < "1.08"
      MutexLock(threadData.mutex)
   #endif
   mtlsa.handle = ThreadCreate(@Thread, @mtlsa)
   #if __FB_VERSION__ < "1.08"
      MutexUnlock(threadData.mutex)
   #endif

   Dim As threadData mtlsb
   mtlsb.prefix = "("
   mtlsb.suffix = ")"
   mtlsb.tempo = 150
   #if __FB_VERSION__ < "1.08"
      MutexLock(threadData.mutex)
   #endif
   mtlsb.handle = ThreadCreate(@Thread, @mtlsb)
   #if __FB_VERSION__ < "1.08"
      MutexUnlock(threadData.mutex)
   #endif

   Dim As threadData mtlsc
   mtlsc.prefix = "["
   mtlsc.suffix = "]"
   mtlsc.tempo = 250
   #if __FB_VERSION__ < "1.08"
      MutexLock(threadData.mutex)
   #endif
   mtlsc.handle = ThreadCreate(@Thread, @mtlsc)
   #if __FB_VERSION__ < "1.08"
      MutexUnlock(threadData.mutex)
   #endif

   ThreadWait(mtlsa.handle)
   ThreadWait(mtlsb.handle)
   ThreadWait(mtlsc.handle)
   #if __FB_VERSION__ < "1.08"
      MutexDestroy(threadData.mutex)
   #endif

   Print
   Print
   Print "end of threads"

   Sleep
               
Output example

   |x| : counting from thread a
   (x) : counting from thread b
   [x] : counting from thread c

   |1| (1) [1] |2| (2) |3| [2] (3) |4| |5| (4) [3] |6| (5) |7| [4] (6) |8| |9| (7) [5] |10| (8) |11| |12| (9) [6] (10) [7] (11) (12) [8] [9] [10] [11] [12]

   End of threads
   					

2. How emulate a kind of TP (Thread Pooling) feature with FreeBASIC
      The objective of thread pooling is to pool the threads in order to 
      avoid untimely creation or deletion of threads, and thus allow their 
      reuse.
      So when a task needs to be executed, it will be more resource 
      efficient to check if the thread pool contains an available thread.
      If so, it will be used while the task is running, and then freed when 
      the task is completed.
      If there is no thread available, a new thread can be created, and at 
      the end of the task, the thread would be in turn available in the 
      pool of threads.

      Two Type structures are first proposed below:
            * ThreadInitThenMultiStart.
            * ThreadPooling.
         These two structures make it possible to use one thread per 
         instance created, and to chain on this dedicated thread the 
         execution of user procedures one after the other, but without the 
         thread stopping between each:
               - The 'ThreadInitThenMultiStart' structure requires a manual 
               start after initialization (and manual wait for completion) 
               for each user procedure to be executed in sequence in the 
               thread.
               - The 'ThreadPooling' structure allows to register a 
               sequence of user thread procedure submissions in a queue, 
               while at same time the user procedures start to be executed 
               in the thread without waiting (a last registered wait 
               command is enough to test for full sequence completion).
         By creating and using several instances, these two structures make 
         it possible to execute sequences of user procedures in several 
         threads, therefore executed in parallel (temporally).

      A last structure is finally proposed:
            * ThreadDispatching.
         This last structure is an over-structure of the ThreadPooling 
         structure, dispatching user thread procedures over a given max 
         number of secondary threads.

      These 3 different structures are then compared from the point of 
      view:
            * Execution time gain (between them).
            * Time wasted when running a user task (among themselves and 
in relation to other methods).

      * ThreadInitThenMultiStart Type:
            * Principle:
                  The 'ThreadInitThenMultiStart' Type below operationally 
                  provides to user 3 (4 actually) main public methods (plus 
                  a constructor and a destructor), and internally uses 9 
                  private data members plus 1 private subroutine (static) 
                  member.

                  The public methods are:
                     - ThreadInit : Initialize the instance with the 
                     parameters of the requested user procedure to be 
                     executed in a thread.
                     - ThreadStart : Start the user procedure execution in 
                     the thread (2 overload methods).
                     - ThreadWait : Wait for the completion of the user 
                     procedure in the thread.

                  By creating several instances each associated with a 
                  thread, we can obtain a kind of thread pooling feature.
                  The 'ThreadInitThenMultiStart' Type does not manage any 
                  pending thread queue.
                  It is up to the user to choose an existing instance or to 
                  create a new instance with which to run his thread 
                  procedure.

            * Description:
                  Each user procedure (to be executed in a thread) must be 
                  available under the following function signature:
                     Function userproc (Byval puserdata As Any Ptr) As 
                     String
                  in order to be compatible with the parameters of the 
                  'ThreadInit' method:
                     Declare Sub ThreadInit (Byval pThread As Function 
                     (Byval As Any Ptr) As String, Byval p As Any Ptr = 0)
                  and perform the instance ('t') initialization by:
                     t.ThreadInit(@userproc [, puserdata])

                  The other methods are called on the instance ('t'):
                     t.ThreadStart() or t.ThreadStart(puserdata)
                     t.ThreadWait()

                  The different methods must be called respecting the order 
                  of the following sequence:
                     ThreadInit, [user code,] ThreadStart, [user code,] 
                     ThreadWait, [user code,] ThreadStart, [user code,] 
                     ThreadWait, [user code,] .....

                  After any 'ThreadStart'...'ThreadWait' sequence, a new 
                  user thread procedure can be initialized by calling the 
                  'ThreadInit' method again on the same instance.
                  On the other hand, 'ThreadStart'...'ThreadWait' sequences 
                  can also be chained on different instances already 
                  initialized.
                  If using several instances (so several threads), the 
                  ordered sequences on each instance can be interlaced 
                  between instances because calling methods on different 
                  instances.
                  The overload method 'ThreadStart(Byval p As Any Ptr)' 
                  allows to start the user thread procedure by specifying a 
                  new parameter value, without having to call 'ThreadInit' 
                  first. The overload method 'ThreadStart()' starts the 
                  user thread procedure without modifying the parameter 
                  value.

                  The 'ThreadWait' method returns a 'As String' Type (by 
                  value), like the user thread function is declared (a 
                  string variable return allows to also pass a numeric 
                  value).

                  This user data return from the user function is accessed 
                  through the 'ThreadWait' return. It is always safe 
                  (because in this case, the user thread function has been 
                  always fully executed).
                  If the user doesn't want to use the return value of his 
                  thread function (to be used like for a subroutine):
                     - He ends his user thread function with Return "" for 
                     example.
                     - He calls 'ThreadWait' as a subroutine and not as a 
                     function (not accessing the value potentially returned 
                     by 'ThreadWait').
                  If the user want to use an existing thread subroutine, he 
                  can define a wrapper function (with an "any pointer" as 
                  parameter, calling the thread subroutine, and returning a 
                  string), and pass this function to 'ThreadInit'.

                  Warning: The information supplied to the user thread 
                  procedure via the passed pointer (by 'ThreadInit' or 
                  'ThreadStart') should not be changed between 
                  'ThreadStart' and 'ThreadWait' due to the time 
                  uncertainty on the real call of the user thread procedure 
                  in this interval.

            * Under the hood:
                  In fact, each instance is associated with an internal 
                  thread that runs continuously in a loop as soon as a 
                  first initialization ('ThreadInit') has taken place. This 
                  internal thread runs the private subroutine (static) 
                  member.
                  It is this private subroutine (static) member that will 
                  call (on a 'ThreadStart') the user procedure to be 
                  executed, like a classic function call. The value 
                  returned by the user function is stored to be 
                  subsequently returned to the user through the returned 
                  value by 'ThreadWait'.

                  So, for each new 'ThreadInitThenMultiStart' instance, an 
                  internal thread is started on the first 'ThreadInit' 
                  method (calling the 'ThreadCreate' FreeBASIC keyword), 
                  then the user thread procedure is started on the 
                  'ThreadStart' method request.
                  As each initialized instance is associated with a running 
                  internal thread, using local scopes or dynamic instances 
                  allow to stop internal threads that are no longer used.

                  In the 'ThreadInitThenMultiStart' Type, an additional 
                  property 'ThreadState' is available to returns (in a 
                  Ubyte) the current internal state of the process.
                  This property allows to sample at any time the state of 
                  the internal thread.
                  This property can also be used during the debugging phase 
                  (allowing in addition to identify the case of blocking in 
                  the user thread procedure running).

                  ThreadState flags:
                     0 -> disabled (internal thread stopped, waiting for 
                     'ThreadInit')
                     1 -> available (waiting for 'ThreadStart' or another 
                     'ThreadInit')
                     2 -> busy (user thread procedure running)
                     4 -> completing (user thread procedure completed, but 
                     waiting for 'ThreadWait')
                     (possible Ubyte values : 0, 1, 2, 4)

                  Internally, the Type uses 3 mutexes (by self locking and 
                  mutual unlocking) to ensure the ordered sequence of 
                  methods called as defined above and wait for the end of 
                  the user thread function or for a new user thread 
                  function to call.
                  So, no waiting loop is used in the methods coding but 
                  only mutexes locking/unlocking requests, so that the 
                  halted thread (on a mutex to be locked) has its execution 
                  suspended and does not consume any CPU time until the 
                  mutex is unlocked.
                  The constructor is responsible for creating and locking 
                  the 3 mutexes, while the destructor stops the thread (if 
                  it exists) then destroys the 3 mutexes.

                  Note: An advised user can stop the internal thread 
                  (linked to instance 't') by using the non-breaking 
                  sequence: t.Destructor() : t.Constructor(). Then a 
                  t.ThreadInit(...) is necessary to start a new internal 
                  thread.

            * Example:
                  Chronology of the user code:
                     - A single 'ThreadInitThenMultiStart' instance is 
                     created in order to use a single thread.
                     - The instance is initialized ('ThreadInit') with a 
                     first user thread function: 'UserThreadS' (internal 
                     thread creation by using the 'ThreadCreate' FreeBASIC 
                     keyword).
                     - A sequence of 9 'ThreadStart...ThreadWait' is 
                     requested for this first user thread function, used 
                     like a thread subroutine.
                     - The same instance is reinitialized ('ThreadInit') 
                     with a second user thread function: 'UserThreadF' (the 
                     previous pending thread will be reused).
                     - A sequence of 9 'ThreadStart...ThreadWait' is also 
                     requested for this second user thread function, used 
                     like a thread function.

                  Full code with the 'ThreadInitThenMultiStart' Type:
   Type ThreadInitThenMultiStartData
      Dim As Function(ByVal p As Any Ptr) As String _pThread
      Dim As Any Ptr _p
      Dim As Any Ptr _mutex1
      Dim As Any Ptr _mutex2
      Dim As Any Ptr _mutex3
      Dim As Any Ptr _pt
      Dim As Byte _end
      Dim As String _returnF
      Dim As UByte _state
   End Type

   Type ThreadInitThenMultiStart
      Public:
         Declare Constructor()
         Declare Sub ThreadInit(ByVal pThread As Function(ByVal As Any Ptr) As String, ByVal p As Any Ptr = 0)
         Declare Sub ThreadStart()
         Declare Sub ThreadStart(ByVal p As Any Ptr)
         Declare Function ThreadWait() As String

         Declare Property ThreadState() As UByte

         Declare Destructor()
      Private:
         Dim As ThreadInitThenMultiStartData Ptr _pdata
         Declare Static Sub _Thread(ByVal p As Any Ptr)
         Declare Constructor(ByRef t As ThreadInitThenMultiStart)
         Declare Operator Let(ByRef t As ThreadInitThenMultiStart)
   End Type

   Constructor ThreadInitThenMultiStart()
      This._pdata = New ThreadInitThenMultiStartData
      With *This._pdata
         ._mutex1 = MutexCreate()
         MutexLock(._mutex1)
         ._mutex2 = MutexCreate()
         MutexLock(._mutex2)
         ._mutex3 = MutexCreate()
         MutexLock(._mutex3)
      End With
   End Constructor

   Sub ThreadInitThenMultiStart.ThreadInit(ByVal pThread As Function(ByVal As Any Ptr) As String, ByVal p As Any Ptr = 0)
      With *This._pdata
         ._pThread = pThread
         ._p = p
         If ._pt = 0 Then
            ._pt= ThreadCreate(@ThreadInitThenMultiStart._Thread, This._pdata)
            MutexUnlock(._mutex3)
            ._state = 1
         End If
      End With
   End Sub

   Sub ThreadInitThenMultiStart.ThreadStart()
      With *This._pdata
         MutexLock(._mutex3)
         MutexUnlock(._mutex1)
      End With
   End Sub

   Sub ThreadInitThenMultiStart.ThreadStart(ByVal p As Any Ptr)
      With *This._pdata
         MutexLock(._mutex3)
         ._p = p
         MutexUnlock(._mutex1)
      End With
   End Sub

   Function ThreadInitThenMultiStart.ThreadWait() As String
      With *This._pdata
         MutexLock(._mutex2)
         MutexUnlock(._mutex3)
         ._state = 1
         Return ._returnF
      End With
   End Function

   Property ThreadInitThenMultiStart.ThreadState() As UByte
      Return This._pdata->_state
   End Property

   Sub ThreadInitThenMultiStart._Thread(ByVal p As Any Ptr)
      Dim As ThreadInitThenMultiStartData Ptr pdata = p
      With *pdata
         Do
            MutexLock(._mutex1)
            If ._end = 1 Then Exit Sub
            ._state = 2
            ._returnF = ._pThread(._p)
            ._state = 4
            MutexUnlock(._mutex2)
         Loop
      End With
   End Sub

   Destructor ThreadInitThenMultiStart()
      With *This._pdata
         If ._pt > 0 Then
            ._end = 1
            MutexUnlock(._mutex1)
            ..ThreadWait(._pt)
         End If
         MutexDestroy(._mutex1)
         MutexDestroy(._mutex2)
         MutexDestroy(._mutex3)
      End With
      Delete This._pdata
   End Destructor

   '---------------------------------------------------

   Function UserThreadS(ByVal p As Any Ptr) As String
      Dim As UInteger Ptr pui = p
      Print *pui * *pui
      Return ""
   End Function

   Function UserThreadF(ByVal p As Any Ptr) As String
      Dim As UInteger Ptr pui = p
      Dim As UInteger c = (*pui) * (*pui)
      Return Str(c)
   End Function

   Dim As ThreadInitThenMultiStart t

   Print "First user function executed like a thread subroutine:"
   t.ThreadInit(@UserThreadS)  '' initializes the user thread function (used as subroutine)
   For I As UInteger = 1 To 9
      Print I & "^2 = ";
      t.ThreadStart(@I)       '' starts the user thread procedure code body
      t.ThreadWait()          '' waits for the user thread procedure code end
   Next I
   Print

   Print "Second user function executed like a thread function:"
   t.ThreadInit(@UserThreadF)  '' initializes the user thread function (used as function)
   For I As UInteger = 1 To 9
      Print I & "^2 = ";
      t.ThreadStart(@I)       '' starts the user thread procedure code body
      Print t.ThreadWait()    '' waits for the user thread procedure code end and prints result
   Next I
   Print

   Sleep
                        
Output:

   First user Function executed like a thread subroutine:
   1^2 = 1
   2^2 = 4
   3^2 = 9
   4^2 = 16
   5^2 = 25
   6^2 = 36
   7^2 = 49
   8^2 = 64
   9^2 = 81

   Second user Function executed like a thread Function:
   1^2 = 1
   2^2 = 4
   3^2 = 9
   4^2 = 16
   5^2 = 25
   6^2 = 36
   7^2 = 49
   8^2 = 64
   9^2 = 81
   								

      * ThreadPooling Type:
            * Principle:
                  The 'ThreadPooling' Type below operationally provides to 
                  user 2 (3 actually) main public methods (plus a 
                  constructor and a destructor), and internally uses 11 
                  private data members plus 1 private subroutine (static) 
                  member.

                  The public methods are:
                     - PoolingSubmit : Enter a user thread procedure in the 
                     queue.
                     - PoolingWait : Wait for full emptying of the queue 
                     (with last user procedure executed).

                  By creating several instances each associated with a 
                  thread, we can obtain a kind of thread pooling feature.
                  The 'ThreadPooling' Type manages a pending thread queue 
                  by instance (so, by thread).
                  It is up to the user to choose an existing instance or to 
                  create a new instance with which to run his thread 
                  procedure sequence.

                  On each 'ThreadPooling' Type instance, the submitted user 
                  thread procedures are immediately entered in a queue 
                  specific to the instance.
                  These buffered user thread procedures are sequentially as 
                  soon as possible executed in the thread dedicated to the 
                  instance.

            * Description:
                  Each user procedure (to be executed in a thread) must be 
                  available under the following function signature:
                  Function userproc (Byval puserdata As Any Ptr) As String
                  in order to be compatible with the parameters of the 
                  'PoolingSubmit()' method:
                  Declare Sub PoolingSubmit (Byval pThread As Function 
                  (Byval As Any Ptr) As String, Byval p As Any Ptr = 0)
                  and perform the instance ('t') submission in the queue 
                  by:
                  t.PoolingSubmit(@userproc [, puserdata])

                  The other method is called on the instance ('t'):
                  t.PoolingWait() or t.PoolingWait(returndata())

                  The different methods must be called respecting the order 
                  of the following sequence:
                  PoolingSubmit, [user code,] [PoolingSubmit, [user code,] 
                  [PoolingSubmit, [user code, ...]] PoolingWait, [user 
                  code,] ...

                  After any 'PoolingSubmit'...'PoolingWait' sequence, a new 
                  user thread procedure sequence can be submitted by 
                  calling another 'PoolingSubmit'...'PoolingWait' sequence 
                  again on the same instance.
                  On the other hand, 'PoolingSubmit'...'PoolingWait' 
                  sequences can also be chained on different instances 
                  already initialized.
                  If using several instances (so several threads), the 
                  ordered sequences on each instance can be interlaced 
                  between instances because calling methods on different 
                  instances.

                  The 'PoolingWait(returndata())' method fills in a String 
                  array with the user thread function returns (a string 
                  variable return allows to also pass a numeric value).
                  These user data returns from the user functions is 
                  accessed through the argument of 
                  'PoolingWait(returndata())' method. It is always safe 
                  (because in this case, the user thread functions has been 
                  always fully executed).
                  If the user doesn't want to use the return values of his 
                  thread functions (to be used like for subroutines):
                     - He ends his user thread functions with Return "" for 
                     example.
                     - He calls the 'PoolingWait()' method without 
                     parameter.
                  If the user want to use an existing thread subroutine, he 
                  can define a wrapper function (with an "any pointer" as 
                  parameter, calling the thread subroutine, and returning a 
                  string), and pass this function to 'PoolingSubmit()'.

                  Warning: The information supplied to the user thread 
                  procedure via the passed pointer (by 'PoolingSubmit') 
                  should not be changed between 'PoolingSubmit' and 
                  'PoolingWait' due to the time uncertainty on the real 
                  call of the user thread procedure in this interval.

            * Under the hood:
                  In fact, each instance is associated with an internal 
                  thread that runs continuously in a loop as soon as the 
                  instance is constructed. This internal thread runs the 
                  private subroutine (static) member.
                  It is this private subroutine (static) member that will 
                  call the user procedures of the sequence to be executed, 
                  like classic function calls. The value returned by each 
                  user function is stored in an internal string array to be 
                  finally returned to the user through the argument of 
                  'PoolingWait(returndata())'.

                  So, for each new 'ThreadPooling' instance, an internal 
                  thread is started by the constructor, then each user 
                  thread procedure is started on each dequeuing of the 
                  registered submissions.
                  As each initialized instance is associated with a running 
                  internal thread, using local scopes or dynamic instances 
                  allow to stop internal threads that are no longer used.

                  In the 'ThreadPooling' Type, an additional property 
                  'PoolingState' is available to returns (in a Ubyte) the 
                  current internal state of the process.
                  This property allows to sample at any time the state of 
                  the internal thread.
                  This property can also be used during the debugging phase 
                  (allowing in addition to identify the case of blocking in 
                  the user thread procedure running).

                  PoolingState flags:
                     0 -> User thread procedures sequence execution 
                     completed (after 'PoolingWait' acknowledge or new 
                     instance creation)
                     1 -> Beginning of user thread procedure sequence 
                     submitted but no still executing (after first 
                     'PoolingSubmit')
                     2 -> User thread procedure running
                     4 -> User thread procedure sequence execution pending 
                     (for 'PoolingWait' acknowledge or new user thread 
                     procedure submission)
                     8 -> User thread procedure submission queue not empty
                     (possible Ubyte values : 0, 1, 2, 4, 9, 10)

                  An overload method 'PoolingWait(values() As String)' is 
                  added.
                  'PoolingWait(values()' As String) fills out a 
                  user-supplied dynamic array with the return value 
                  sequence from the latest user thread functions (then 
                  internally clear these same supplied return data).
                  The other overload method 'PoolingWait()' (without passed 
                  parameter) also clears the internal return values.

                  'ThreadPooling' Type allows to manage kind of "FIFOs" 
                  (First In First Out) via dynamic arrays:
                     - Arrays are filled in as user submissions (from the 
                     main thread).
                     - Arrays are automatically emptied on the fly by the 
                     secondary thread which executes their requests as and 
                     when.
                     - So, the inputs and outputs of the "FIFOs" are 
                     therefore asynchronous with an optimized throughput on 
                     each side.

                  With 'ThreadPooling' the execution time of a 
                  'PoolingSubmit' method in the main thread, corresponds 
                  only to the time spent to register the user procedure 
                  submission.

                  It is necessary to be able to do (for the 'PoolingSubmit'
                  , 'PoolingWait' and 'Destructeur' methods, all in 
                  competition with '_Thread' subroutine) atomic mutex 
                  unlockings, which is not possible with simple mutexlocks 
                  / mutexunlocks.
                  This therefore requires the use of conditional variables 
                  (condwait / condsignal).

                  The constructor is responsible for creating the 2 
                  conditional variables and the associated mutex, while the 
                  destructor stops the thread then destroys the 2 
                  conditional variables and the associated mutex.

            * Example:
                  Chronology of the user code:
                     - A single 'ThreadPooling' instance is created in 
                     order to use a single thread.
                     - A first sequence (a) of 3 'PoolingSubmit' is 
                     requested for the first three user thread functions, 
                     ended by a 'PoolingWait' without parameter.
                     - A second sequence (b) of 3 'PoolingSubmit' is 
                     requested for the last three user thread functions, 
                     ended by a 'PoolingWait' with a dynamic string array 
                     as argument (so, only the returns from the last three 
                     user thread functions will fill out in the dynamic 
                     string array).

                  Full code with the 'ThreadPooling' Type:
   #include Once "crt/string.bi"

   Type ThreadPoolingData
      Dim As Function(ByVal p As Any Ptr) As String _pThread0
      Dim As Any Ptr _p0
      Dim As Function(ByVal p As Any Ptr) As String _pThread(Any)
      Dim As Any Ptr _p(Any)
      Dim As Any Ptr _mutex
      Dim As Any Ptr _cond1
      Dim As Any Ptr _cond2
      Dim As Any Ptr _pt
      Dim As Byte _end
      Dim As String _returnF(Any)
      Dim As UByte _state
   End Type

   Type ThreadPooling
      Public:
         Declare Constructor()
         Declare Sub PoolingSubmit(ByVal pThread As Function(ByVal As Any Ptr) As String, ByVal p As Any Ptr = 0)
         Declare Sub PoolingWait()
         Declare Sub PoolingWait(values() As String)

         Declare Property PoolingState() As UByte

         Declare Destructor()
      Private:
         Dim As ThreadPoolingData Ptr _pdata
         Declare Static Sub _Thread(ByVal p As Any Ptr)
         Declare Constructor(ByRef t As ThreadPooling)
         Declare Operator Let(ByRef t As ThreadPooling)
   End Type

   Constructor ThreadPooling()
      This._pdata = New ThreadPoolingData
      With *This._pdata
         ReDim ._pThread(0)
         ReDim ._p(0)
         ReDim ._returnF(0)
         ._mutex = MutexCreate()
         ._cond1 = CondCreate()
         ._cond2 = CondCreate()
         ._pt= ThreadCreate(@ThreadPooling._Thread, This._pdata)
      End With
   End Constructor

   Sub ThreadPooling.PoolingSubmit(ByVal pThread As Function(ByVal As Any Ptr) As String, ByVal p As Any Ptr = 0)
      With *This._pdata
         MutexLock(._mutex)
         ReDim Preserve ._pThread(UBound(._pThread) + 1)
         ._pThread(UBound(._pThread)) = pThread
         ReDim Preserve ._p(UBound(._p) + 1)
         ._p(UBound(._p)) = p
         CondSignal(._cond2)
         ._state = 1
         MutexUnlock(._mutex)
      End With
   End Sub

   Sub ThreadPooling.PoolingWait()
      With *This._pdata
         MutexLock(._mutex)
         While (._state And 11) > 0
            CondWait(._Cond1, ._mutex)
         Wend
         ReDim ._returnF(0)
         ._state = 0
         MutexUnlock(._mutex)
      End With
   End Sub

   Sub ThreadPooling.PoolingWait(values() As String)
      With *This._pdata
         MutexLock(._mutex)
         While (._state And 11) > 0
            CondWait(._Cond1, ._mutex)
         Wend
         If UBound(._returnF) > 0 Then
            ReDim values(1 To UBound(._returnF))
            For I As Integer = 1 To UBound(._returnF)
               values(I) = ._returnF(I)
            Next I
            ReDim ._returnF(0)
         Else
            Erase values
         End If
         ._state = 0
         MutexUnlock(._mutex)
      End With
   End Sub

   Property ThreadPooling.PoolingState() As UByte
      With *This._pdata
         If UBound(._p) > 0 Then
            Return 8 + ._state
         Else
            Return ._state
         End If
      End With
   End Property

   Sub ThreadPooling._Thread(ByVal p As Any Ptr)
      Dim As ThreadPoolingData Ptr pdata = p
      With *pdata
         Do
            MutexLock(._mutex)
            If UBound(._pThread) = 0 Then
               ._state = 4
               CondSignal(._cond1)
               While UBound(._pThread) = 0
                  If ._end = 1 Then Exit Sub
                  CondWait(._cond2, ._mutex)
               Wend
            End If
            ._pThread0 = ._pThread(1)
            ._p0 = ._p(1)
            If UBound(._pThread) > 1 Then
               memmove(@._pThread(1), @._pThread(2), (UBound(._pThread) - 1) * SizeOf(._pThread))
               memmove(@._p(1), @._p(2), (UBound(._p) - 1) * SizeOf(._p))
            End If
            ReDim Preserve ._pThread(UBound(._pThread) - 1)
            ReDim Preserve ._p(UBound(._p) - 1)
            MutexUnlock(._mutex)
            ReDim Preserve ._ReturnF(UBound(._returnF) + 1)
            ._state = 2
            ._returnF(UBound(._returnF)) = ._pThread0(._p0)
         Loop
      End With
   End Sub

   Destructor ThreadPooling()
      With *This._pdata
         MutexLock(._mutex)
         ._end = 1
         CondSignal(._cond2)
         MutexUnlock(._mutex)
         ..ThreadWait(._pt)
         MutexDestroy(._mutex)
         CondDestroy(._cond1)
         CondDestroy(._cond2)
      End With
      Delete This._pdata
   End Destructor

   '---------------------------------------------------

   Sub Prnt (ByRef s As String, ByVal p As Any Ptr)
      Dim As String Ptr ps = p
      If ps > 0 Then Print *ps;
      For I As Integer = 1 To 10
         Print s;
         Sleep 100, 1
      Next I
   End Sub

   Function UserCode1 (ByVal p As Any Ptr) As String
      Prnt("1", p)
      Return "UserCode #1"
   End Function

   Function UserCode2 (ByVal p As Any Ptr) As String
      Prnt("2", p)
      Return "UserCode #2"
   End Function

   Function UserCode3 (ByVal p As Any Ptr) As String
      Prnt("3", p)
      Return "UserCode #3"
   End Function

   Function UserCode4 (ByVal p As Any Ptr) As String
      Prnt("4", p)
      Return "UserCode #4"
   End Function

   Function UserCode5 (ByVal p As Any Ptr) As String
      Prnt("5", p)
      Return "UserCode #5"
   End Function

   Function UserCode6 (ByVal p As Any Ptr) As String
      Prnt("6", p)
      Return "UserCode #6"
   End Function

   Dim As String sa = "  Sequence #a: "
   Dim As String sb = "  Sequence #b: "
   Dim As String s()

   Dim As ThreadPooling t

   t.PoolingSubmit(@UserCode1, @sa)
   t.PoolingSubmit(@UserCode2)
   t.PoolingSubmit(@UserCode3)
   Print " Sequence #a of 3 user thread functions fully submitted "
   t.PoolingWait()
   Print
   Print " Sequence #a completed"
   Print

   t.PoolingSubmit(@UserCode4, @sb)
   t.PoolingSubmit(@UserCode5)
   t.PoolingSubmit(@UserCode6)
   Print " Sequence #b of 3 user thread functions fully submitted "
   t.PoolingWait(s())
   Print
   Print " Sequence #b completed"
   Print

   Print " List of returned values from sequence #b only"
   For I As Integer = LBound(s) To UBound(s)
      Print "  " & I & ": " & s(I)
   Next I
   Print

   Sleep
                        
Output example

    Sequence #a of 3 user thread functions fully submitted
     Sequence #a: 111111111122222222223333333333
    Sequence #a completed

    Sequence #b of 3 user thread functions fully submitted
     Sequence #b: 444444444455555555556666666666
    Sequence #b completed

    List of returned values from sequence #b only
     1: UserCode #4
     2: UserCode #5
     3: UserCode #6
   								
Note: If the first user thread procedure of each sequence starts very 
quickly, the acknowledgement message of each sequence of 3 submissions may 
appear inserted after the beginning of the text printed by the first user 
procedure of the sequence.
                        That is not the case here.

      * ThreadDispatching Type, over-structure of ThreadPooling Type, 
        dispatching user thread procedures over a given max number of 
        secondary threads:
            * Principle:
                  The maximum number of secondary threads that can be used 
                  is fixed when constructing the 'ThreadDispatching' 
                  instance (1 secondary thread by default), and also the 
                  minimum number of initialized secondary threads (0 
                  secondary thread by default).
                  'ThreadDispatching' manages an internal dynamic array of 
                  pointers to 'ThreadPooling' instances.

                  If a secondary thread is available (already existing 
                  instance of 'ThreadPooling' pending), it is used to 
                  submit the user thread procedure.
                  Otherwise, a new secondary thread is created (new 
                  instance of 'ThreadPooling' created) by respecting the 
                  number of secondary threads allowed.
                  As long as all potential secondary threads are already in 
                  use, each new user thread procedure is distributed evenly 
                  over them.

            * Description:
                  Methods:
                     - Constructor : Construct a 'ThreadDispatching' 
                     instance and set the maximum number of usable 
                     secondary threads (1 by default) and set the minimum 
                     number of initialized secondary thread (0 by default).
                     - DispatchingSubmit : Enter a user thread procedure in 
                     the queue of the "best" secondary thread among the 
                     usable ones.
                     - DispatchingWait : Wait for the complete emptying of 
                     the queues of all secondary threads used (with all 
                     last user procedures executed).
                     - DispatchingThread : Return the number of internal 
                     threads really started.
                     - Destructor : Stop and complete the secondary threads 
                     used.

                  In the 'ThreadDispatching' Type, an additional sub 
                  'DispatchingState(state() As Ubyte)' is available to 
                  returns (in a Ubyte array) the current state of each 
                  internal thread started.
                  This sub allows to sample at any time the state of the 
                  internal threads started.
                  This sub can also be used during the debugging phase 
                  (allowing in addition to identify the case of blocking in 
                  the user thread procedure running).

                  DispatchingState flags (a Ubyte for each internal thread 
                  started):
                     0 -> User thread procedures sequence execution 
                     completed (after 'DispatchingWait' acknowledge or new 
                     instance creation)
                     1 -> Beginning of user thread procedure sequence 
                     submitted but no still executing (after first 
                     'DispatchingSubmit')
                     2 -> User thread procedure running
                     4 -> User thread procedure sequence execution pending 
                     (for 'DispatchingWait' acknowledge or new user thread 
                     procedure submission)
                     8 -> User thread procedure submission queue not empty
                     (possible Ubyte values : 0, 1, 2, 4, 9, 10)

                  The 'DispatchingWait(returndata())' method fills in a 
                  String array with the user thread function returns (a 
                  string variable return allows to also pass a numeric 
                  value). In the array, the user thread function returns 
                  are grouped by internal threads really used, in the order 
                  they were started.
                  These user data returns from the user functions is 
                  accessed through the argument of 
                  'DispatchingWait(returndata())' method. It is always safe 
                  (because in this case, the user thread functions has been 
                  always fully executed).
                  If the user doesn't want to use the return values of his 
                  thread functions (to be used like for subroutines):
                     - He ends his user thread functions with Return "" for 
                     example.
                     - He calls the 'DispatchingWait()' method without 
                     parameter.
                  If the user want to use an existing thread subroutine, he 
                  can define a wrapper function (with an "any pointer" as 
                  parameter, calling the thread subroutine, and returning a 
                  string), and pass this function to 'DispatchingSubmit()'.

            * Example:
                  Example of use of 'ThreadDispatching' (whatever the 
                  allowed number of secondary threads, the submission 
                  sequence syntax is always the same):
   #include Once "crt/string.bi"

   Type ThreadPoolingData
      Dim As Function(ByVal p As Any Ptr) As String _pThread0
      Dim As Any Ptr _p0
      Dim As Function(ByVal p As Any Ptr) As String _pThread(Any)
      Dim As Any Ptr _p(Any)
      Dim As Any Ptr _mutex
      Dim As Any Ptr _cond1
      Dim As Any Ptr _cond2
      Dim As Any Ptr _pt
      Dim As Byte _end
      Dim As String _returnF(Any)
      Dim As UByte _state
   End Type

   Type ThreadPooling
      Public:
         Declare Constructor()
         Declare Sub PoolingSubmit(ByVal pThread As Function(ByVal As Any Ptr) As String, ByVal p As Any Ptr = 0)
         Declare Sub PoolingWait()
         Declare Sub PoolingWait(values() As String)

         Declare Property PoolingState() As UByte

         Declare Destructor()
      Private:
         Dim As ThreadPoolingData Ptr _pdata
         Declare Static Sub _Thread(ByVal p As Any Ptr)
         Declare Constructor(ByRef t As ThreadPooling)
         Declare Operator Let(ByRef t As ThreadPooling)
   End Type

   Constructor ThreadPooling()
      This._pdata = New ThreadPoolingData
      With *This._pdata
         ReDim ._pThread(0)
         ReDim ._p(0)
         ReDim ._returnF(0)
         ._mutex = MutexCreate()
         ._cond1 = CondCreate()
         ._cond2 = CondCreate()
         ._pt= ThreadCreate(@ThreadPooling._Thread, This._pdata)
      End With
   End Constructor

   Sub ThreadPooling.PoolingSubmit(ByVal pThread As Function(ByVal As Any Ptr) As String, ByVal p As Any Ptr = 0)
      With *This._pdata
         MutexLock(._mutex)
         ReDim Preserve ._pThread(UBound(._pThread) + 1)
         ._pThread(UBound(._pThread)) = pThread
         ReDim Preserve ._p(UBound(._p) + 1)
         ._p(UBound(._p)) = p
         CondSignal(._cond2)
         ._state = 1
         MutexUnlock(._mutex)
      End With
   End Sub

   Sub ThreadPooling.PoolingWait()
      With *This._pdata
         MutexLock(._mutex)
         While (._state And 11) > 0
            CondWait(._Cond1, ._mutex)
         Wend
         ReDim ._returnF(0)
         ._state = 0
         MutexUnlock(._mutex)
      End With
   End Sub

   Sub ThreadPooling.PoolingWait(values() As String)
      With *This._pdata
         MutexLock(._mutex)
         While (._state And 11) > 0
            CondWait(._Cond1, ._mutex)
         Wend
         If UBound(._returnF) > 0 Then
            ReDim values(1 To UBound(._returnF))
            For I As Integer = 1 To UBound(._returnF)
               values(I) = ._returnF(I)
            Next I
            ReDim ._returnF(0)
         Else
            Erase values
         End If
         ._state = 0
         MutexUnlock(._mutex)
      End With
   End Sub

   Property ThreadPooling.PoolingState() As UByte
      With *This._pdata
         If UBound(._p) > 0 Then
            Return 8 + ._state
         Else
            Return ._state
         End If
      End With
   End Property

   Sub ThreadPooling._Thread(ByVal p As Any Ptr)
      Dim As ThreadPoolingData Ptr pdata = p
      With *pdata
         Do
            MutexLock(._mutex)
            If UBound(._pThread) = 0 Then
               ._state = 4
               CondSignal(._cond1)
               While UBound(._pThread) = 0
                  If ._end = 1 Then Exit Sub
                  CondWait(._cond2, ._mutex)
               Wend
            End If
            ._pThread0 = ._pThread(1)
            ._p0 = ._p(1)
            If UBound(._pThread) > 1 Then
               memmove(@._pThread(1), @._pThread(2), (UBound(._pThread) - 1) * SizeOf(._pThread))
               memmove(@._p(1), @._p(2), (UBound(._p) - 1) * SizeOf(._p))
            End If
            ReDim Preserve ._pThread(UBound(._pThread) - 1)
            ReDim Preserve ._p(UBound(._p) - 1)
            MutexUnlock(._mutex)
            ReDim Preserve ._ReturnF(UBound(._returnF) + 1)
            ._state = 2
            ._returnF(UBound(._returnF)) = ._pThread0(._p0)
         Loop
      End With
   End Sub

   Destructor ThreadPooling()
      With *This._pdata
         MutexLock(._mutex)
         ._end = 1
         CondSignal(._cond2)
         MutexUnlock(._mutex)
         ..ThreadWait(._pt)
         MutexDestroy(._mutex)
         CondDestroy(._cond1)
         CondDestroy(._cond2)
      End With
      Delete This._pdata
   End Destructor

   '---------------------------------------------------

   Type ThreadDispatching
      Public:
         Declare Constructor(ByVal nbMaxSecondaryThread As Integer = 1, ByVal nbMinSecondaryThread As Integer = 0)
         Declare Sub DispatchingSubmit(ByVal pThread As Function(ByVal As Any Ptr) As String, ByVal p As Any Ptr = 0)
         Declare Sub DispatchingWait()
         Declare Sub DispatchingWait(values() As String)

         Declare Property DispatchingThread() As Integer
         Declare Sub DispatchingState(state() As UByte)

         Declare Destructor()
      Private:
         Dim As Integer _nbmst
         Dim As Integer _dstnb
         Dim As ThreadPooling Ptr _tp(Any)
         Declare Constructor(ByRef t As ThreadDispatching)
         Declare Operator Let(ByRef t As ThreadDispatching)
   End Type

   Constructor ThreadDispatching(ByVal nbMaxSecondaryThread As Integer = 1, ByVal nbMinSecondaryThread As Integer = 0)
      This._nbmst = nbMaxSecondaryThread
      If nbMinSecondaryThread > nbMaxSecondaryThread Then
         nbMinSecondaryThread = nbMaxSecondaryThread
      End If
      If nbMinSecondaryThread > 0 Then
         ReDim This._tp(nbMinSecondaryThread - 1)
         For I As Integer = 0 To nbMinSecondaryThread - 1
            This._tp(I) = New ThreadPooling
         Next I
      End If
   End Constructor

   Sub ThreadDispatching.DispatchingSubmit(ByVal pThread As Function(ByVal As Any Ptr) As String, ByVal p As Any Ptr = 0)
      For I As Integer = 0 To UBound(This._tp)
         If (This._tp(I)->PoolingState And 11) = 0 Then
            This._tp(I)->PoolingSubmit(pThread, p)
            Exit Sub
         End If
      Next I
      If UBound(This._tp) < This._nbmst - 1 Then
         ReDim Preserve This._tp(UBound(This._tp) + 1)
         This._tp(UBound(This._tp)) = New ThreadPooling
         This._tp(UBound(This._tp))->PoolingSubmit(pThread, p)
      ElseIf UBound(This._tp) >= 0 Then
         This._tp(This._dstnb)->PoolingSubmit(pThread, p)
         This._dstnb = (This._dstnb + 1) Mod This._nbmst
      End If
   End Sub

   Sub ThreadDispatching.DispatchingWait()
      For I As Integer = 0 To UBound(This._tp)
         This._tp(I)->PoolingWait()
      Next I
   End Sub

   Sub ThreadDispatching.DispatchingWait(values() As String)
      Dim As String s()
      For I As Integer = 0 To UBound(This._tp)
         This._tp(I)->PoolingWait(s())
         If UBound(s) >= 1 Then
            If UBound(values) = -1 Then
               ReDim Preserve values(1 To UBound(values) + UBound(s) + 1)
            Else
               ReDim Preserve values(1 To UBound(values) + UBound(s))
            End If
            For I As Integer = 1 To UBound(s)
               values(UBound(values) - UBound(s) + I) = s(I)
            Next I
         End If
      Next I
   End Sub

   Property ThreadDispatching.DispatchingThread() As Integer
      Return UBound(This._tp) + 1
   End Property

   Sub ThreadDispatching.DispatchingState(state() As UByte)
      If UBound(This._tp) >= 0 Then
         ReDim state(1 To UBound(This._tp) + 1)
         For I As Integer = 0 To UBound(This._tp)
            state(I + 1) = This._tp(I)->PoolingState
         Next I
      End If
   End Sub

   Destructor ThreadDispatching()
      For I As Integer = 0 To UBound(This._tp)
         Delete This._tp(I)
      Next I
   End Destructor

   '---------------------------------------------------

   Sub Prnt (ByRef s As String, ByVal p As Any Ptr)
      Dim As String Ptr ps = p
      If ps > 0 Then Print *ps;
      For I As Integer = 1 To 10
         Print s;
         Sleep 100, 1
      Next I
   End Sub

   Function UserCode1 (ByVal p As Any Ptr) As String
      Prnt("1", p)
      Return "UserCode #1"
   End Function

   Function UserCode2 (ByVal p As Any Ptr) As String
      Prnt("2", p)
      Return "UserCode #2"
   End Function

   Function UserCode3 (ByVal p As Any Ptr) As String
      Prnt("3", p)
      Return "UserCode #3"
   End Function

   Function UserCode4 (ByVal p As Any Ptr) As String
      Prnt("4", p)
      Return "UserCode #4"
   End Function

   Function UserCode5 (ByVal p As Any Ptr) As String
      Prnt("5", p)
      Return "UserCode #5"
   End Function

   Function UserCode6 (ByVal p As Any Ptr) As String
      Prnt("6", p)
      Return "UserCode #6"
   End Function

   Sub SubmitSequence(ByRef t As ThreadDispatching, ByVal ps As String Ptr)
      t.DispatchingSubmit(@UserCode1, ps)
      t.DispatchingSubmit(@UserCode2)
      t.DispatchingSubmit(@UserCode3)
      t.DispatchingSubmit(@UserCode4)
      t.DispatchingSubmit(@UserCode5)
      t.DispatchingSubmit(@UserCode6)
   End Sub  

   Dim As String sa = "  Sequence #a: "
   Dim As String sb = "  Sequence #b: "
   Dim As String sc = "  Sequence #c: "
   Dim As String sd = "  Sequence #d: "
   Dim As String se = "  Sequence #e: "
   Dim As String sf = "  Sequence #f: "
   Dim As String s()

   Dim As ThreadDispatching t1, t2 = 2, t3 = 3, t4 = 4, t5 = 5, t6 = 6

   Print " Sequence #a of 6 user thread functions dispatched over 1 secondary thread:"
   SubmitSequence(t1, @sa)
   t1.DispatchingWait()
   Print
   Print

   Print " Sequence #b of 6 user thread functions dispatched over 2 secondary threads:"
   SubmitSequence(t2, @sb)
   t2.DispatchingWait()
   Print
   Print

   Print " Sequence #c of 6 user thread functions dispatched over 3 secondary threads:"
   SubmitSequence(t3, @sc)
   t3.DispatchingWait()
   Print
   Print

   Print " Sequence #d of 6 user thread functions dispatched over 4 secondary threads:"
   SubmitSequence(t4, @sd)
   t4.DispatchingWait()
   Print
   Print

   Print " Sequence #e of 6 user thread functions dispatched over 5 secondary threads:"
   SubmitSequence(t5, @se)
   t5.DispatchingWait()
   Print
   Print

   Print " Sequence #f of 6 user thread functions dispatched over 6 secondary threads:"
   SubmitSequence(t6, @sf)
   t6.DispatchingWait(s())
   Print

   Print "  List of returned values from sequence #f:"
   For I As Integer = LBound(s) To UBound(s)
      Print "   " & I & ": " & s(I)
   Next I

   Sleep
                        
Output example:

    Sequence #a of 6 user thread functions dispatched over 1 secondary thread:
     Sequence #a: 111111111122222222223333333333444444444455555555556666666666

    Sequence #b of 6 user thread functions dispatched over 2 secondary threads:
     Sequence #b: 122112121212122112213434344343344343344356566565565656565665

    Sequence #c of 6 user thread functions dispatched over 3 secondary threads:
     Sequence #c: 123123312321213132321231213321465654546465546546456654654564

    Sequence #d of 6 user thread functions dispatched over 4 secondary threads:
     Sequence #d: 134243211234432114322341413241233124413256655656566556655656

    Sequence #e of 6 user thread functions dispatched over 5 secondary threads:
     Sequence #e: 134255243141235325415143215234342511524343521251346666666666

    Sequence #f of 6 user thread functions dispatched over 6 secondary threads:
     Sequence #f: 534126216354456132241365563142421365316524245613361245365421
     List of returned values from sequence #f:
      1: UserCode #1
      2: UserCode #2
      3: UserCode #3
      4: UserCode #4
      5: UserCode #5
      6: UserCode #6
   								

      * Execution time gain checking with ThreadInitThenMultiStart, 
        ThreadPooling, and ThreadDispatching Types:
            * Execution time gain checking with different multi-threading 
              configurations:
                  A user task is defined:
                     - Display 64 characters (2*32) on the screen, each 
                     separated by an identical time achieved by a [For ... 
                     Next] loop (no Sleep keyword so as not to free up CPU 
                     resources).
                     - For 'ThreadInitThenMultiStart' and 'ThreadPooling': 
                     Depending on the number of threads chosen 
                     1/2/4/8/16/32, this same user task is split in 
                     1/2/4/8/16/32 sub-tasks, each being executed on a 
                     thread.
                     - For 'ThreadDispatching': 32 sub-tasks are always 
                     used and the distribution of these sub-tasks over the 
                     available threads (max = 1/2/4/8/16/32) is automatic.

                  Full code with the 'ThreadInitThenMultiStart', 
                  'ThreadPooling', and 'ThreadDispatching' Types:
   Type ThreadInitThenMultiStartData
      Dim As Function(ByVal p As Any Ptr) As String _pThread
      Dim As Any Ptr _p
      Dim As Any Ptr _mutex1
      Dim As Any Ptr _mutex2
      Dim As Any Ptr _mutex3
      Dim As Any Ptr _pt
      Dim As Byte _end
      Dim As String _returnF
      Dim As UByte _state
   End Type

   Type ThreadInitThenMultiStart
      Public:
         Declare Constructor()
         Declare Sub ThreadInit(ByVal pThread As Function(ByVal As Any Ptr) As String, ByVal p As Any Ptr = 0)
         Declare Sub ThreadStart()
         Declare Sub ThreadStart(ByVal p As Any Ptr)
         Declare Function ThreadWait() As String

         Declare Property ThreadState() As UByte

         Declare Destructor()
      Private:
         Dim As ThreadInitThenMultiStartData Ptr _pdata
         Declare Static Sub _Thread(ByVal p As Any Ptr)
         Declare Constructor(ByRef t As ThreadInitThenMultiStart)
         Declare Operator Let(ByRef t As ThreadInitThenMultiStart)
   End Type

   Constructor ThreadInitThenMultiStart()
      This._pdata = New ThreadInitThenMultiStartData
      With *This._pdata
         ._mutex1 = MutexCreate()
         MutexLock(._mutex1)
         ._mutex2 = MutexCreate()
         MutexLock(._mutex2)
         ._mutex3 = MutexCreate()
         MutexLock(._mutex3)
      End With
   End Constructor

   Sub ThreadInitThenMultiStart.ThreadInit(ByVal pThread As Function(ByVal As Any Ptr) As String, ByVal p As Any Ptr = 0)
      With *This._pdata
         ._pThread = pThread
         ._p = p
         If ._pt = 0 Then
            ._pt= ThreadCreate(@ThreadInitThenMultiStart._Thread, This._pdata)
            MutexUnlock(._mutex3)
            ._state = 1
         End If
      End With
   End Sub

   Sub ThreadInitThenMultiStart.ThreadStart()
      With *This._pdata
         MutexLock(._mutex3)
         MutexUnlock(._mutex1)
      End With
   End Sub

   Sub ThreadInitThenMultiStart.ThreadStart(ByVal p As Any Ptr)
      With *This._pdata
         MutexLock(._mutex3)
         ._p = p
         MutexUnlock(._mutex1)
      End With
   End Sub

   Function ThreadInitThenMultiStart.ThreadWait() As String
      With *This._pdata
         MutexLock(._mutex2)
         MutexUnlock(._mutex3)
         ._state = 1
         Return ._returnF
      End With
   End Function

   Property ThreadInitThenMultiStart.ThreadState() As UByte
      Return This._pdata->_state
   End Property

   Sub ThreadInitThenMultiStart._Thread(ByVal p As Any Ptr)
      Dim As ThreadInitThenMultiStartData Ptr pdata = p
      With *pdata
         Do
            MutexLock(._mutex1)
            If ._end = 1 Then Exit Sub
            ._state = 2
            ._returnF = ._pThread(._p)
            ._state = 4
            MutexUnlock(._mutex2)
         Loop
      End With
   End Sub

   Destructor ThreadInitThenMultiStart()
      With *This._pdata
         If ._pt > 0 Then
            ._end = 1
            MutexUnlock(._mutex1)
            ..ThreadWait(._pt)
         End If
         MutexDestroy(._mutex1)
         MutexDestroy(._mutex2)
         MutexDestroy(._mutex3)
      End With
      Delete This._pdata
   End Destructor

   '---------------------------------------------------

   #include Once "crt/string.bi"

   Type ThreadPoolingData
      Dim As Function(ByVal p As Any Ptr) As String _pThread0
      Dim As Any Ptr _p0
      Dim As Function(ByVal p As Any Ptr) As String _pThread(Any)
      Dim As Any Ptr _p(Any)
      Dim As Any Ptr _mutex
      Dim As Any Ptr _cond1
      Dim As Any Ptr _cond2
      Dim As Any Ptr _pt
      Dim As Byte _end
      Dim As String _returnF(Any)
      Dim As UByte _state
   End Type

   Type ThreadPooling
      Public:
         Declare Constructor()
         Declare Sub PoolingSubmit(ByVal pThread As Function(ByVal As Any Ptr) As String, ByVal p As Any Ptr = 0)
         Declare Sub PoolingWait()
         Declare Sub PoolingWait(values() As String)

         Declare Property PoolingState() As UByte

         Declare Destructor()
      Private:
         Dim As ThreadPoolingData Ptr _pdata
         Declare Static Sub _Thread(ByVal p As Any Ptr)
         Declare Constructor(ByRef t As ThreadPooling)
         Declare Operator Let(ByRef t As ThreadPooling)
   End Type

   Constructor ThreadPooling()
      This._pdata = New ThreadPoolingData
      With *This._pdata
         ReDim ._pThread(0)
         ReDim ._p(0)
         ReDim ._returnF(0)
         ._mutex = MutexCreate()
         ._cond1 = CondCreate()
         ._cond2 = CondCreate()
         ._pt= ThreadCreate(@ThreadPooling._Thread, This._pdata)
      End With
   End Constructor

   Sub ThreadPooling.PoolingSubmit(ByVal pThread As Function(ByVal As Any Ptr) As String, ByVal p As Any Ptr = 0)
      With *This._pdata
         MutexLock(._mutex)
         ReDim Preserve ._pThread(UBound(._pThread) + 1)
         ._pThread(UBound(._pThread)) = pThread
         ReDim Preserve ._p(UBound(._p) + 1)
         ._p(UBound(._p)) = p
         CondSignal(._cond2)
         ._state = 1
         MutexUnlock(._mutex)
      End With
   End Sub

   Sub ThreadPooling.PoolingWait()
      With *This._pdata
         MutexLock(._mutex)
         While (._state And 11) > 0
            CondWait(._Cond1, ._mutex)
         Wend
         ReDim ._returnF(0)
         ._state = 0
         MutexUnlock(._mutex)
      End With
   End Sub

   Sub ThreadPooling.PoolingWait(values() As String)
      With *This._pdata
         MutexLock(._mutex)
         While (._state And 11) > 0
            CondWait(._Cond1, ._mutex)
         Wend
         If UBound(._returnF) > 0 Then
            ReDim values(1 To UBound(._returnF))
            For I As Integer = 1 To UBound(._returnF)
               values(I) = ._returnF(I)
            Next I
            ReDim ._returnF(0)
         Else
            Erase values
         End If
         ._state = 0
         MutexUnlock(._mutex)
      End With
   End Sub

   Property ThreadPooling.PoolingState() As UByte
      With *This._pdata
         If UBound(._p) > 0 Then
            Return 8 + ._state
         Else
            Return ._state
         End If
      End With
   End Property

   Sub ThreadPooling._Thread(ByVal p As Any Ptr)
      Dim As ThreadPoolingData Ptr pdata = p
      With *pdata
         Do
            MutexLock(._mutex)
            If UBound(._pThread) = 0 Then
               ._state = 4
               CondSignal(._cond1)
               While UBound(._pThread) = 0
                  If ._end = 1 Then Exit Sub
                  CondWait(._cond2, ._mutex)
               Wend
            End If
            ._pThread0 = ._pThread(1)
            ._p0 = ._p(1)
            If UBound(._pThread) > 1 Then
               memmove(@._pThread(1), @._pThread(2), (UBound(._pThread) - 1) * SizeOf(._pThread))
               memmove(@._p(1), @._p(2), (UBound(._p) - 1) * SizeOf(._p))
            End If
            ReDim Preserve ._pThread(UBound(._pThread) - 1)
            ReDim Preserve ._p(UBound(._p) - 1)
            MutexUnlock(._mutex)
            ReDim Preserve ._ReturnF(UBound(._returnF) + 1)
            ._state = 2
            ._returnF(UBound(._returnF)) = ._pThread0(._p0)
         Loop
      End With
   End Sub

   Destructor ThreadPooling()
      With *This._pdata
         MutexLock(._mutex)
         ._end = 1
         CondSignal(._cond2)
         MutexUnlock(._mutex)
         ..ThreadWait(._pt)
         MutexDestroy(._mutex)
         CondDestroy(._cond1)
         CondDestroy(._cond2)
      End With
      Delete This._pdata
   End Destructor

   '---------------------------------------------------

   Type ThreadDispatching
      Public:
         Declare Constructor(ByVal nbMaxSecondaryThread As Integer = 1, ByVal nbMinSecondaryThread As Integer = 0)
         Declare Sub DispatchingSubmit(ByVal pThread As Function(ByVal As Any Ptr) As String, ByVal p As Any Ptr = 0)
         Declare Sub DispatchingWait()
         Declare Sub DispatchingWait(values() As String)

         Declare Property DispatchingThread() As Integer
         Declare Sub DispatchingState(state() As UByte)

         Declare Destructor()
      Private:
         Dim As Integer _nbmst
         Dim As Integer _dstnb
         Dim As ThreadPooling Ptr _tp(Any)
         Declare Constructor(ByRef t As ThreadDispatching)
         Declare Operator Let(ByRef t As ThreadDispatching)
   End Type

   Constructor ThreadDispatching(ByVal nbMaxSecondaryThread As Integer = 1, ByVal nbMinSecondaryThread As Integer = 0)
      This._nbmst = nbMaxSecondaryThread
      If nbMinSecondaryThread > nbMaxSecondaryThread Then
         nbMinSecondaryThread = nbMaxSecondaryThread
      End If
      If nbMinSecondaryThread > 0 Then
         ReDim This._tp(nbMinSecondaryThread - 1)
         For I As Integer = 0 To nbMinSecondaryThread - 1
            This._tp(I) = New ThreadPooling
         Next I
      End If
   End Constructor

   Sub ThreadDispatching.DispatchingSubmit(ByVal pThread As Function(ByVal As Any Ptr) As String, ByVal p As Any Ptr = 0)
      For I As Integer = 0 To UBound(This._tp)
         If (This._tp(I)->PoolingState And 11) = 0 Then
            This._tp(I)->PoolingSubmit(pThread, p)
            Exit Sub
         End If
      Next I
      If UBound(This._tp) < This._nbmst - 1 Then
         ReDim Preserve This._tp(UBound(This._tp) + 1)
         This._tp(UBound(This._tp)) = New ThreadPooling
         This._tp(UBound(This._tp))->PoolingSubmit(pThread, p)
      ElseIf UBound(This._tp) >= 0 Then
         This._tp(This._dstnb)->PoolingSubmit(pThread, p)
         This._dstnb = (This._dstnb + 1) Mod This._nbmst
      End If
   End Sub

   Sub ThreadDispatching.DispatchingWait()
      For I As Integer = 0 To UBound(This._tp)
         This._tp(I)->PoolingWait()
      Next I
   End Sub

   Sub ThreadDispatching.DispatchingWait(values() As String)
      Dim As String s()
      For I As Integer = 0 To UBound(This._tp)
         This._tp(I)->PoolingWait(s())
         If UBound(s) >= 1 Then
            If UBound(values) = -1 Then
               ReDim Preserve values(1 To UBound(values) + UBound(s) + 1)
            Else
               ReDim Preserve values(1 To UBound(values) + UBound(s))
            End If
            For I As Integer = 1 To UBound(s)
               values(UBound(values) - UBound(s) + I) = s(I)
            Next I
         End If
      Next I
   End Sub

   Property ThreadDispatching.DispatchingThread() As Integer
      Return UBound(This._tp) + 1
   End Property

   Sub ThreadDispatching.DispatchingState(state() As UByte)
      If UBound(This._tp) >= 0 Then
         ReDim state(1 To UBound(This._tp) + 1)
         For I As Integer = 0 To UBound(This._tp)
            state(I + 1) = This._tp(I)->PoolingState
         Next I
      End If
   End Sub

   Destructor ThreadDispatching()
      For I As Integer = 0 To UBound(This._tp)
         Delete This._tp(I)
      Next I
   End Destructor

   '---------------------------------------------------

   Dim Shared As Double array(1 To 800000)  '' only used by the [For...Next] waiting loop in UserCode()

   Function UserCode (ByVal p As Any Ptr) As String
      Dim As String Ptr ps = p
      For I As Integer = 1 To 2
         Print *ps;
         For J As Integer = 1 To 800000
            array(J) = Tan(J) * Atn(J) * Exp(J) * Log(J)  '' [For...Next] waiting loop not freeing any CPU resource
         Next J
      Next I
      Return ""
   End Function

   Dim As String s(0 To 31)
   For I As Integer = 0 To 15
      s(I) = Str(Hex(I))
   Next I
   For I As Integer = 16 To 31
      s(I) = Chr(55 + I)
   Next I

   '---------------------------------------------------

   #macro ThreadInitThenMultiStartSequence(nbThread)
   Scope
      ReDim As ThreadInitThenMultiStart ts(nbThread - 1)
      Print "   ";
      Dim As Double t = Timer
      For I As Integer = 0 To 32 - nbThread Step nbThread
         For J As Integer = 0 To nbThread - 1
            ts(J).ThreadInit(@UserCode, @s(I + J))
            ts(J).ThreadStart()
         Next J
         For J As Integer = 0 To nbThread - 1
            ts(J).ThreadWait()
         Next J
      Next I
      t = Timer - t
      Print Using " : ####.## s"; t
   End Scope
   #endmacro

   #macro ThreadPoolingSequence(nbThread)
   Scope
      ReDim As ThreadPooling tp(nbThread - 1)
      Print "   ";
      Dim As Double t = Timer
      For I As Integer = 0 To 32 - nbThread Step nbThread
         For J As Integer = 0 To nbThread - 1
            tp(J).PoolingSubmit(@UserCode, @s(I + J))
         Next J
      Next I
      For I As Integer = 0 To nbThread - 1
         tp(I).PoolingWait()
      Next I
      t = Timer - t
      Print Using " : ####.## s"; t
   End Scope
   #endmacro

   #macro ThreadDispatchingSequence(nbThreadmax)
   Scope
      Dim As ThreadDispatching td##nbThreadmax = nbThreadmax
      Print "   ";
      Dim As Double t = Timer
      For I As Integer = 0 To 31
         td##nbThreadmax.DispatchingSubmit(@UserCode, @s(I))
      Next I
      td##nbThreadmax.DispatchingWait()
      t = Timer - t
      Print Using " : ####.## s"; t
   End Scope
   #endmacro
      
   '---------------------------------------------------

   Print "'ThreadInitThenMultiStart' with 1 secondary thread:"
   ThreadInitThenMultiStartSequence(1)

   Print "'ThreadPooling' with 1 secondary thread:"
   ThreadPoolingSequence(1)

   Print "'ThreadDispatching' with 1 secondary thread max:"
   ThreadDispatchingSequence(1)
   Print

   '---------------------------------------------------

   Print "'ThreadInitThenMultiStart' with 2 secondary threads:"
   ThreadInitThenMultiStartSequence(2)

   Print "'ThreadPooling' with 2 secondary threads:"
   ThreadPoolingSequence(2)

   Print "'ThreadDispatching' with 2 secondary threads max:"
   ThreadDispatchingSequence(2)
   Print

   '---------------------------------------------------

   Print "'ThreadInitThenMultiStart' with 4 secondary threads:"
   ThreadInitThenMultiStartSequence(4)

   Print "'ThreadPooling' with 4 secondary threads:"
   ThreadPoolingSequence(4)

   Print "'ThreadDispatching' with 4 secondary threads max:"
   ThreadDispatchingSequence(4)
   Print

   '---------------------------------------------------

   Print "'ThreadInitThenMultiStart' with 8 secondary threads:"
   ThreadInitThenMultiStartSequence(8)

   Print "'ThreadPooling' with 8 secondary threads:"
   ThreadPoolingSequence(8)

   Print "'ThreadDispatching' with 8 secondary threads max:"
   ThreadDispatchingSequence(8)
   Print

   '---------------------------------------------------

   Print "'ThreadInitThenMultiStart' with 16 secondary threads:"
   ThreadInitThenMultiStartSequence(16)

   Print "'ThreadPooling' with 16 secondary threads:"
   ThreadPoolingSequence(16)

   Print "'ThreadDispatching' with 16 secondary threads max:"
   ThreadDispatchingSequence(16)
   Print

   '---------------------------------------------------

   Print "'ThreadInitThenMultiStart' with 32 secondary threads:"
   ThreadInitThenMultiStartSequence(32)

   Print "'ThreadPooling' with 32 secondary threads:"
   ThreadPoolingSequence(32)

   Print "'ThreadDispatching' with 32 secondary threads max:"
   ThreadDispatchingSequence(32)
   Print

   Sleep
                        
Output example:

   'ThreadInitThenMultiStart' with 1 secondary thread:
      00112233445566778899AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSSTTUUVV :    5.40 s
   'ThreadPooling' with 1 secondary thread:
      00112233445566778899AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSSTTUUVV :    5.39 s
   'ThreadDispatching' with 1 secondary thread max:
      00112233445566778899AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSSTTUUVV :    5.42 s

   'ThreadInitThenMultiStart' with 2 secondary threads:
      01012323454567768998ABABCDCDEFEFGHGHIJJIKLKLMNNMOPOPQRRQSTSTUVVU :    2.88 s
   'ThreadPooling' with 2 secondary threads:
      01012323455476769898BAABCDCDFEFEHGHGJIJILKLKNMNMPOPORQRQTSTSVUVU :    2.83 s
   'ThreadDispatching' with 2 secondary threads max:
      01103232545476769898BABADCDCFEFHEGHJGJILILKNKNMPMPORORQTQTSVSVUU :    2.96 s

   'ThreadInitThenMultiStart' with 4 secondary threads:
      012312304576645789ABA98BCEDFCEFDGIHJGIJHLKMNNLKMOQPRPOQRSTVUTSUV :    1.72 s
   'ThreadPooling' with 4 secondary threads:
      012313204576457689AB89ABCDFECFDEGJHIGJHINKLMNKMLROPQROQPVSUTVSUT :    1.71 s
   'ThreadDispatching' with 4 secondary threads max:
      012320316475674A5B89AB98EFDCEFDCIJHGIJHMGNLKMNLKQRPORQPOVTUSVTUS :    1.76 s

   'ThreadInitThenMultiStart' with 8 secondary threads:
      01324567706415328B9ACDEFBE8D9CAFGHIJKNMLGNLMKHIJOQRPSVUTVOQRUTPS :    1.19 s
   'ThreadPooling' with 8 secondary threads:
      01234567032415678BAEC9DF8BEA9CDFGJIHLMKNGJIHLMKNORQTPSUVORTPQSUV :    1.05 s
   'ThreadDispatching' with 8 secondary threads max:
      0123456776415032FE9CABD8FE9ACB8DNMIHKJLGMNIHKGLJVUQPSTORVUQPSOTR :    1.09 s

   'ThreadInitThenMultiStart' with 16 secondary threads:
      013A4567892BCDEF1A2B7903C8465DEFGHIJKNMLPOQRSTVULJGKNMIRHTSOPUQV :    1.14 s
   'ThreadPooling' with 16 secondary threads:
      0124356789ABCDEF512A04D639E7B8CKJNGILHFQTPMOURSGJNQHLTKIVORPUMSV :    1.10 s
   'ThreadDispatching' with 16 secondary threads max:
      0123456B897ACDEFFEDA798031C56B42TPOGJQNUKVMSILRHJQGTUOPKLMINSVHR :    1.11 s

   'ThreadInitThenMultiStart' with 32 secondary threads:
      01243675AB89ECFDGHIJKLMNOPQ146RSTGVBA3IEFJTSNM5082CDHU7KLO9RQPVU :    1.06 s
   'ThreadPooling' with 32 secondary threads:
      0I32456789ABCDEFHG1JKLMNOPRSQTVUN7260534FKBEGIHCD98A1OJLQTSRUPVM :    1.07 s
   'ThreadDispatching' with 32 secondary threads max:
      012345A7896BCDFGE4C89D76B5A0321EGHIJKLMNOQRUVPSTFLKHMIJNOTSPVUQR :    1.07 s
Note: From a certain number of threads used, the gain in execution time 
becomes more or less constant (even slightly decreasing), which corresponds 
roughly to the number of threads the used CPU really has (8 in the case 
above).

               'ThreadInitThenMultiStart' and 'ThreadPooling':
                  From fbc 1.10.0, and in order to have a single structure 
                  (for 'ThreadInitThenMultiStart' or 'ThreadPooling'), the 
                  additional Type of data ('ThreadInitThenMultiStartData' 
                  or 'ThreadPoolingData') can be nested as is in its main 
                  Type, just above the declaration of its pointer.

               'ThreadDispatching' versus 'ThreadPooling':
                  - The 'ThreadDispatching' Type allows to best and 
                  automatically distribute user tasks over a given number 
                  of secondary threads.
                  - But if the user wants complete control of the 
                  distribution per secondary thread, he can instead use a 
                  'ThreadPooling' array with the desired number of 
                  secondary threads as the size.

               'ThreadInitThenMultiStart' / 'ThreadPooling' / 
               'ThreadDispatching', and CPU time with pending secondary 
               threads (waiting for user tasks):
                  Once a secondary thread is created and initialized (by 
                  creating an instance of 'ThreadInitThenMultiStart'+
                  'ThreadInit' or 'ThreadPooling' or 'ThreadDispatching)', 
                  it no longer consumes CPU time as long as it is pending 
                  (waiting for a user task):
                     - This is because the thread code of 
                     'ThreadInitThenMultiStart._Thread()' is in the 
                     'MutexLock(pThis->_mutex1)' state and it will only 
                     wake after a 'MutexUnlock(This._mutex1)' triggered by 
                     a user task submission from 
                     'ThreadInitThenMultiStart.ThreadStart()'.
                     - This is because the thread code of 
                     'ThreadPooling._Thread()' is in the 
                     'CondWait(pThis->_cond2, pThis->_mutex)' state and it 
                     will only wake after a 'CondSignal(This._cond2)' 
                     triggered by a user task submission from 
                     'ThreadPooling.PoolingSubmit()'.

                  So the only interest of the 2nd optional parameter of the 
                  'ThreadDispatching' constructor which allows to set the 
                  minimum number of secondary threads (0 by default) is 
                  only to start these secondary threads at the earliest at 
                  the time of the instance construction, in order to have 
                  greater responsiveness at the time of the first user task 
                  submissions.

      * Time wasted when running a user task either by procedure calling 
        method, by elementary threading method, or by various thread 
        pooling methods:
            Creating a new thread is a costly act in terms of resources, 
            both from a processor (CPU) and memory point of view.
            Also, if a program requires the execution of many tasks, the 
            creation and deletion of a thread for each of them would 
            strongly penalize the performance of the application.
            It would therefore be interesting to be able to share the 
            creation of threads so that a thread that has finished 
            executing a task is available for the execution of a future 
            task.

            The objective of thread pooling (ThreadInitThenMultiStart, 
            ThreadPooling, ThreadDispatching methods) is to pool threads in 
            order to avoid the untimely creation or deletion of threads, 
            and thus allow their reuse.

            Test code to evaluate the different times wasted depending on 
            the feature used:
   Type ThreadInitThenMultiStart
      Public:
         Declare Constructor()
         Declare Sub ThreadInit(ByVal pThread As Function(ByVal As Any Ptr) As String, ByVal p As Any Ptr = 0)
         Declare Sub ThreadStart()
         Declare Sub ThreadStart(ByVal p As Any Ptr)
         Declare Function ThreadWait() As String

         Declare Property ThreadState() As UByte

         Declare Destructor()
      Private:
         Dim As Function(ByVal p As Any Ptr) As String _pThread
         Dim As Any Ptr _p
         Dim As Any Ptr _mutex1
         Dim As Any Ptr _mutex2
         Dim As Any Ptr _mutex3
         Dim As Any Ptr _pt
         Dim As Byte _end
         Dim As String _returnF
         Dim As UByte _state
         Declare Static Sub _Thread(ByVal p As Any Ptr)
   End Type

   Constructor ThreadInitThenMultiStart()
      This._mutex1 = MutexCreate()
      MutexLock(This._mutex1)
      This._mutex2 = MutexCreate()
      MutexLock(This._mutex2)
      This._mutex3 = MutexCreate()
      MutexLock(This._mutex3)
   End Constructor

   Sub ThreadInitThenMultiStart.ThreadInit(ByVal pThread As Function(ByVal As Any Ptr) As String, ByVal p As Any Ptr = 0)
      This._pThread = pThread
      This._p = p
      If This._pt = 0 Then
         This._pt= ThreadCreate(@ThreadInitThenMultiStart._Thread, @This)
         MutexUnlock(This._mutex3)
         This._state = 1
      End If
   End Sub

   Sub ThreadInitThenMultiStart.ThreadStart()
      MutexLock(This._mutex3)
      MutexUnlock(This._mutex1)
   End Sub

   Sub ThreadInitThenMultiStart.ThreadStart(ByVal p As Any Ptr)
      MutexLock(This._mutex3)
      This._p = p
      MutexUnlock(This._mutex1)
   End Sub

   Function ThreadInitThenMultiStart.ThreadWait() As String
      MutexLock(This._mutex2)
      MutexUnlock(This._mutex3)
      This._state = 1
      Return This._returnF
   End Function

   Property ThreadInitThenMultiStart.ThreadState() As UByte
      Return This._state
   End Property

   Sub ThreadInitThenMultiStart._Thread(ByVal p As Any Ptr)
      Dim As ThreadInitThenMultiStart Ptr pThis = p
      Do
         MutexLock(pThis->_mutex1)
         If pThis->_end = 1 Then Exit Sub
         pThis->_state = 2
         pThis->_returnF = pThis->_pThread(pThis->_p)
         pThis->_state = 4
         MutexUnlock(pThis->_mutex2)
      Loop
   End Sub

   Destructor ThreadInitThenMultiStart()
      If This._pt > 0 Then
         This._end = 1
         MutexUnlock(This._mutex1)
         .ThreadWait(This._pt)
      End If
      MutexDestroy(This._mutex1)
      MutexDestroy(This._mutex2)
      MutexDestroy(This._mutex3)
   End Destructor

   '---------------------------------------------------

   #include Once "crt/string.bi"
   Type ThreadPooling
      Public:
         Declare Constructor()
         Declare Sub PoolingSubmit(ByVal pThread As Function(ByVal As Any Ptr) As String, ByVal p As Any Ptr = 0)
         Declare Sub PoolingWait()
         Declare Sub PoolingWait(values() As String)

         Declare Property PoolingState() As UByte

         Declare Destructor()
      Private:
         Dim As Function(ByVal p As Any Ptr) As String _pThread0
         Dim As Any Ptr _p0
         Dim As Function(ByVal p As Any Ptr) As String _pThread(Any)
         Dim As Any Ptr _p(Any)
         Dim As Any Ptr _mutex
         Dim As Any Ptr _cond1
         Dim As Any Ptr _cond2
         Dim As Any Ptr _pt
         Dim As Byte _end
         Dim As String _returnF(Any)
         Dim As UByte _state
         Declare Static Sub _Thread(ByVal p As Any Ptr)
   End Type

   Constructor ThreadPooling()
      ReDim This._pThread(0)
      ReDim This._p(0)
      ReDim This._returnF(0)
      This._mutex = MutexCreate()
      This._cond1 = CondCreate()
      This._cond2 = CondCreate()
      This._pt= ThreadCreate(@ThreadPooling._Thread, @This)
   End Constructor

   Sub ThreadPooling.PoolingSubmit(ByVal pThread As Function(ByVal As Any Ptr) As String, ByVal p As Any Ptr = 0)
      MutexLock(This._mutex)
      ReDim Preserve This._pThread(UBound(This._pThread) + 1)
      This._pThread(UBound(This._pThread)) = pThread
      ReDim Preserve This._p(UBound(This._p) + 1)
      This._p(UBound(This._p)) = p
      CondSignal(This._cond2)
      This._state = 1
      MutexUnlock(This._mutex)
   End Sub

   Sub ThreadPooling.PoolingWait()
      MutexLock(This._mutex)
      While (This._state And 11) > 0
         CondWait(This._Cond1, This._mutex)
      Wend
      ReDim This._returnF(0)
      This._state = 0
      MutexUnlock(This._mutex)
   End Sub

   Sub ThreadPooling.PoolingWait(values() As String)
      MutexLock(This._mutex)
      While (This._state And 11) > 0
         CondWait(This._Cond1, This._mutex)
      Wend
      If UBound(This._returnF) > 0 Then
         ReDim values(1 To UBound(This._returnF))
         For I As Integer = 1 To UBound(This._returnF)
            values(I) = This._returnF(I)
         Next I
         ReDim This._returnF(0)
      Else
         Erase values
      End If
      This._state = 0
      MutexUnlock(This._mutex)
   End Sub

   Property ThreadPooling.PoolingState() As UByte
      If UBound(This._p) > 0 Then
         Return 8 + This._state
      Else
         Return This._state
      End If
   End Property

   Sub ThreadPooling._Thread(ByVal p As Any Ptr)
      Dim As ThreadPooling Ptr pThis = p
      Do
         MutexLock(pThis->_mutex)
         If UBound(pThis->_pThread) = 0 Then
            pThis->_state = 4
            CondSignal(pThis->_cond1)
            While UBound(pThis->_pThread) = 0
               CondWait(pThis->_cond2, pThis->_mutex)
               If pThis->_end = 1 Then Exit Sub
            Wend
         End If
         pThis->_pThread0 = pThis->_pThread(1)
         pThis->_p0 = pThis->_p(1)
         If UBound(pThis->_pThread) > 1 Then
            memmove(@pThis->_pThread(1), @pThis->_pThread(2), (UBound(pThis->_pThread) - 1) * SizeOf(pThis->_pThread))
            memmove(@pThis->_p(1), @pThis->_p(2), (UBound(pThis->_p) - 1) * SizeOf(pThis->_p))
         End If
         'ReDim Preserve pThis->_pThread(UBound(pThis->_pThread) - 1)  '' bug in current fbc version 1.20
         With *pThis                                                   '' workaround for the bug
            ReDim Preserve ._pThread(UBound(pThis->_pThread) - 1)     '' workaround for the bug
         End With                                                      '' workaround for the bug
         ReDim Preserve pThis->_p(UBound(pThis->_p) - 1)
         MutexUnlock(pThis->_mutex)
         ReDim Preserve pThis->_ReturnF(UBound(pThis->_returnF) + 1)
         pThis->_state = 2
         pThis->_returnF(UBound(pThis->_returnF)) = pThis->_pThread0(pThis->_p0)
      Loop
   End Sub

   Destructor ThreadPooling()
      MutexLock(This._mutex)
      This._end = 1
      CondSignal(This._cond2)
      MutexUnlock(This._mutex)
      .ThreadWait(This._pt)
      MutexDestroy(This._mutex)
      CondDestroy(This._cond1)
      CondDestroy(This._cond2)
   End Destructor

   '---------------------------------------------------

   Type ThreadDispatching
      Public:
         Declare Constructor(ByVal nbMaxSecondaryThread As Integer = 1, ByVal nbMinSecondaryThread As Integer = 0)
         Declare Sub DispatchingSubmit(ByVal pThread As Function(ByVal As Any Ptr) As String, ByVal p As Any Ptr = 0)
         Declare Sub DispatchingWait()
         Declare Sub DispatchingWait(values() As String)

         Declare Property DispatchingThread() As Integer
         Declare Sub DispatchingState(state() As UByte)

         Declare Destructor()
      Private:
         Dim As Integer _nbmst
         Dim As Integer _dstnb
         Dim As ThreadPooling Ptr _tp(Any)
   End Type

   Constructor ThreadDispatching(ByVal nbMaxSecondaryThread As Integer = 1, ByVal nbMinSecondaryThread As Integer = 0)
      This._nbmst = nbMaxSecondaryThread
      If nbMinSecondaryThread > nbMaxSecondaryThread Then
         nbMinSecondaryThread = nbMaxSecondaryThread
      End If
      If nbMinSecondaryThread > 0 Then
         ReDim This._tp(nbMinSecondaryThread - 1)
         For I As Integer = 0 To nbMinSecondaryThread - 1
            This._tp(I) = New ThreadPooling
         Next I
      End If
   End Constructor

   Sub ThreadDispatching.DispatchingSubmit(ByVal pThread As Function(ByVal As Any Ptr) As String, ByVal p As Any Ptr = 0)
      For I As Integer = 0 To UBound(This._tp)
         If (This._tp(I)->PoolingState And 11) = 0 Then
            This._tp(I)->PoolingSubmit(pThread, p)
            Exit Sub
         End If
      Next I
      If UBound(This._tp) < This._nbmst - 1 Then
         ReDim Preserve This._tp(UBound(This._tp) + 1)
         This._tp(UBound(This._tp)) = New ThreadPooling
         This._tp(UBound(This._tp))->PoolingSubmit(pThread, p)
      ElseIf UBound(This._tp) >= 0 Then
         This._tp(This._dstnb)->PoolingSubmit(pThread, p)
         This._dstnb = (This._dstnb + 1) Mod This._nbmst
      End If
   End Sub

   Sub ThreadDispatching.DispatchingWait()
      For I As Integer = 0 To UBound(This._tp)
         This._tp(I)->PoolingWait()
      Next I
   End Sub

   Sub ThreadDispatching.DispatchingWait(values() As String)
      Dim As String s()
      For I As Integer = 0 To UBound(This._tp)
         This._tp(I)->PoolingWait(s())
         If UBound(s) >= 1 Then
            If UBound(values) = -1 Then
               ReDim Preserve values(1 To UBound(values) + UBound(s) + 1)
            Else
               ReDim Preserve values(1 To UBound(values) + UBound(s))
            End If
            For I As Integer = 1 To UBound(s)
               values(UBound(values) - UBound(s) + I) = s(I)
            Next I
         End If
      Next I
   End Sub

   Property ThreadDispatching.DispatchingThread() As Integer
      Return UBound(This._tp) + 1
   End Property

   Sub ThreadDispatching.DispatchingState(state() As UByte)
      If UBound(This._tp) >= 0 Then
         ReDim state(1 To UBound(This._tp) + 1)
         For I As Integer = 0 To UBound(This._tp)
            state(I + 1) = This._tp(I)->PoolingState
         Next I
      End If
   End Sub

   Destructor ThreadDispatching()
      For I As Integer = 0 To UBound(This._tp)
         Delete This._tp(I)
      Next I
   End Destructor

   '---------------------------------------------------

   Sub s(ByVal p As Any Ptr)
      '' user task
   End Sub

   Function f(ByVal p As Any Ptr) As String
      '' user task
      Return ""
   End Function

   '---------------------------------------------------
   'Time wasted when running a user task either by procedure calling or by various threading methods
   Print "Mean time wasted when running a user task :"
   Print "   either by procedure calling method,"
   Print "   or by various threading methods."
   Print

   Scope
      Dim As Double t = Timer
      For I As Integer = 1 To 1000000
         s(0)
      Next I
      t = Timer - t
      Print Using "      - Using procedure calling method        : ###.###### ms"; t / 1000
      Print
   End Scope

   Scope
      Dim As Any Ptr P
      Dim As Double t = Timer
      For I As Integer = 1 To 1000
         p = ThreadCreate(@s)
         ThreadWait(p)
      Next I
      t = Timer - t
      Print Using "      - Using elementary threading method     : ###.###### ms"; t
      Print
   End Scope

   Scope
      Dim As ThreadInitThenMultiStart ts
      Dim As Double t = Timer
      ts.ThreadInit(@f)
      For I As Integer = 1 To 10000
         ts.ThreadStart()
         ts.ThreadWait()
      Next I
      t = Timer - t
      Print Using "      - Using ThreadInitThenMultiStart method : ###.###### ms"; t / 10
   End Scope

   Scope
      Dim As ThreadPooling tp
      Dim As Double t = Timer
      For I As Integer = 1 To 10000
         tp.PoolingSubmit(@f)
      Next I
      tp.PoolingWait()
      t = Timer - t
      Print Using "      - Using ThreadPooling method            : ###.###### ms"; t / 10
   End Scope

   Scope
      Dim As ThreadDispatching td
      Dim As Double t = Timer
      For I As Integer = 1 To 10000
         td.DispatchingSubmit(@f)
      Next I
      td.DispatchingWait()
      t = Timer - t
      Print Using "      - Using ThreadDispatching method        : ###.###### ms"; t / 10
   End Scope

   Print
   Sleep
                  
Output:

   Mean Time wasted when running a user task :
      either by procedure calling method,
      Or by various threading methods.

   	  - Using procedure calling method        :   0.000033 ms

   	  - Using elementary threading method     :   0.146337 ms

   	  - Using ThreadInitThenMultiStart method :   0.007382 ms
   	  - Using ThreadPooling method            :   0.006873 ms
   	  - Using ThreadDispatching method        :   0.007066 ms
   						

            The above results with my PC show that a thread pooling method 
            allows to gain about 140 Âµs by user task compared to a 
            elementary threading method, but it remains about 7 Âµs to 
            compare to 0.03 Âµs for a simple calling method.

See also
   * Multi-Threading Overview
   * Threads
   * Mutual Exclusion
   * Conditional Variables
   * Critical Sections
   * Critical Sections FAQ



---------------------------------------------------- CommunityTutorials ----
Community Tutorials

Tutorials submitted by the FreeBASIC community:
 Getting Started
   *Getting Started with FreeBASIC by SJ Zero
   *Using libraries in FreeBASIC by SJ Zero
   *Using the Mouse in FreeBASIC by MystikShadows
   *Get Information into your program by TekRat
   *Using Dynamic Arrays in FreeBASIC by SephKnows
   *Beginners Guide to Types as Objects (Part 1) by YetiFoot
   *Beginners Guide to Types as Objects (Part 2) by YetiFoot
   *Introduction to Variable Scope by rdc
   *Introduction to Arrays by rdc
   *Introduction to the Type Def by rdc
   *New To Programming? by The FB Community
   *Compiling a BIG QB program by Antoni

Game Programming
   * How to Program a Game: Lesson 1 by Lachie Dazdarian
   * Managing A High Score Table by Lachie Dazdarian

Flow Control Statements
   *The IF Statement by rdc
   *The Select Case Statement by rdc

Pre Processor
   *Conditional Compilation And You by AetherFox

Memory Management
   *Introduction to Pointers by rdc
   *Pointers, Data Types and Memory by rdc
   *The Pointer Data Type by rdc
   *Using Linked Lists by Parker
   *Dynamic Arrays in Types by rdc

  Intermediate Techniques
   *Introduction to Function Overloading in FreeBASIC by :stylin:

Mathematics
   *Different ways angles are measured by RandyKeeling
   *A Brief Introduction To Trigonometry by RandyKeeling

Windows API
   *Introduction to Message-Based Programming by rdc

Libraries
   *Interfacing with C by UtenNavn
   *SDL_NET by Paragon
   *Using FreeBASIC Built Libraries with GCC by Jeff Marshall

Object Oriented Programming
   *Introduction to the Extended Type by rdc
   *Simulating Polymorphism by rdc
   *OOP in non-OOP languages by KevinWhitefoot
   *Const Qualifiers and You by notthecheatr

FBgfx
   *Creating and Understanding Your FBgfx Img and Font Buffer by The FB 
     Community



----------------------------------------------------------- CodeLibrary ----
Community Code Library

 FreeBASIC Code, Games, and Libraries.  Written in FreeBASIC, by FreeBASIC 
Community Members.

Code Editors & IDEs 
   FBEdit, an IDE for FB by KetilO (Win32)
   Tiko Editor, an IDE for FB by Paul Squires (Win32,Win64)
   VISG GUI Builder (WIN) by mrhx
   List of FreeBASIC IDEs/Editors on the forum

Graphics Code
   Demos
   Animated Clouds by Zamaster
   Island Generation by rdc
   Plasma Generation by Zamaster
   Tree Generation by Zamaster

   Graphics Functions and Primitives
   AntiAliased Bezier Curves by Acetoline
   Antialiased Circles by Acetoline
   Ellipse Renderer by Pritchard
   Catmull-rom Splines by relsoft	Bezier vs Catmull-rom by relsoft
   Accurate Image Scaler by KristopherWindsor
   Spline Curve by Zamaster
   Rotozoom by Dr_D

   Colors and Palettes
   24bit to 16bit color width by Eternal_Pain
   HSV Color Space by Antoni

   Formats
   fbpng library by yetifoot
   FBImage static Win/Lin 32/64-bit by by D.J.Peters

   Animation
   ASCII Animation Example by Pritchard
   Chain-Like Animation Tutorial by Lachie Dazdarian

Sound Code
   Mic Input using FMod by mambazo
   Using the PC Speaker by several
   Wave synthesizer by Zamaster

Math Code
   FBMath by jdebord
   A* Pathfinding by dumbledore
   Fraction Library by Zamaster
   Big Number Wrapper by Yetifoot
   BCD arithmetics by srvaldez
   10Byte extended float by srvaldez, included in FB examples
   CRC Calculation by Fragmeister

   Physics simulation
   Atom smash simulation by coderjeff
   2d rigid body library by coderjeff
   Irrlicht wrapper + Newton Intergrated by SiskinEDGE

Text/Parser Code
   Expression Parser by yetifoot
   Turing Machine by Zamaster
   Roman Numeral to Integer Conversion by stylin
   Unicode console calender, by zippy and voodooattack
   FB source to  highlighted HTML by Kristopher Windsor
   Portable help (not .chm) viewer by coderjeff
   Lisp interpreter by coderjeff

   Cryptography
   MARS encryption by Zamaster
   AES Encryption/Decryption by Zamaster
   DES/LUCIFER Encryption/Decryption by Zamaster
   MD5 Calculator by DOS386
   Tiger Hash by Mindless

FreeBASIC Games
   FreeBASIC Games Directory by Lachie Dazdarian

   Featured Games:
   Kingdoms by Piptol
   Lynn's Legacy by cha0s and Josiah Tobin
   Relativity by Lithium
   Star Cage by Lachie Dazdarian
   100 Line Tetris by Deleter
   Any PNG or JPEG as a Jigsaw Puzzle by Mysoft

GUI Code
   In Game GUI by coderJeff
   Zine GUI by VonGodric
   WX GUI example by ciw1973
   KwikGUI (WIN/LIN/DOS) by Vincent DeCampo
   FB_GUI by BasicScience

Networking- Web Code
   FB Web Server (Win) by parakeet
   FB Server side scripting (uses the server above) by fishhf
   ChiSock portable sockets library by cha0s

I/O Code
   Text Input by Pritchard & sir_mud
   ConLib Console library with PCopy by cha0s
   Lock Mouse to Grid Positions by Pritchard

   Serial Port
   Drive a Parallax servo controller by phishguy
   Modbus device finder by Antoni
   Serial port terminal program by Antoni

OS Specific Code

   Windows
   ServiceFB (Win) by zerospeed
   FBWinPrint 1.0 by vdecampo
   In memory dialogs by MichaelW
   Talking program usin Win Voice API, by coder guy 
   Using GfxLib in Windows API by MichaelW 
   Print a bitmap file by MichaelW
   ShellExecute wrapper by RayBritton
   FBWiki to chm format converter by coderjeff
   FB ODBC library by KaraK
   Get a file from an URL by Sisophon

   Linux
   Printing on Linux by coderJeff
   Using GfxLib on Gtk by caseih

   DOS
   Detect system codepage by DrV
   Calling an Interrupt requiring a pointer by DrV
   Access BTRIEVE files by mjs
   "GetDiskFreeSpaceEx" Check for disk total/free space on FAT32 by DOS386
   DPMI host detection version/capabilities by DrV

Data structures and special-purpose UDTs
   Boolean Type by Imortis
   Safe FBstring Type by stylin
   FreeBASIC Memory Leak Detector by DrV & Others
   Auto-deallocating 'Smart' Pointers by stylin
   UDTs for Properties by Pritchard

Miscellaneous Code
   FreeBASIC Extended Library
   FB  CAD by owen
   FBstd C++ Lib Port (W.I.P.) by stylin
   Testly by zerospeed
   Portable way to add a resource to a program  by voodooattack
   CPU Identification by MichaelW
   Cpu Cycle counter for benchmarking of code by MichaelW
   Use of the FBGfx built-in LZW routines by Lillo
   Using FB dll's in RapidQ programs by JohnK

Community Websites/Links
   External Library Documentation
   Sourceforge
   FreeBASIC Games Directory

This is a place to post worthy projects/code snippets for FreeBASIC, in 
their relative categories.  To add a page, link to either its wiki page, 
website, or thread on the FreeBASIC Forums.  State the project name and who 
it's by.  Sections may be broken down into their own separate pages some 
time in the future.  Note:  Due to FB being in Beta stage of development, 
earlier coded projects may need to be reconfigured or recompiled to work on 
later versions of FreeBASIC.





============================================================================
  EXTERNAL LIBRARIES INDEX
  ------------------------



============================================================================
    Graphical/test-based user interfaces

------------------------------------------------------------ ExtLibcgui ----
CGUI

Library for making GUIs in a simple way.

Website: http://cgui.sourceforge.net/index.html, http://www.allegro.cc/resou
rce/Libraries/GUI/CGUI
Platforms supported: Win32, Linux
Headers to include: cgui.bi
Header version: 2.0.4
Example Usage: yes, in examples/GUI/CGUI/

   


---------------------------------------------------------- ExtLibcurses ----
Curses

Standardized console user interface library

Website: http://pdcurses.sourceforge.net/ and http://www.gnu.org/software/nc
urses/
Platforms supported: DOS, Win32, Linux
Headers to include: curses.bi
Header versions: pdcurses 3.4, ncurses 5.9
Note: On Win32 systems pdcurses is used, on Linux it uses the standard 
ncurses library.
Examples: yes, in examples/console/curses/

Example
   #include Once "curses.bi"

   initscr()
   cbreak()
   noecho()
   start_color()

   '' The default pair 0 will have the console's default colors

   '' Set pair 1 to be white/blue
   init_pair(1, COLOR_WHITE, COLOR_BLUE)

   '' Select pair 1, so from now on output will be white text on blue background
   attrset(COLOR_PAIR(1))

   printw(!"Hello, world!\n")

   '' Reset to pair 0
   attrset(COLOR_PAIR(0))

   '' Sleep
   printw(!"Waiting for keypress...\n")
   getch()

   endwin()

   


------------------------------------------------------------- ExtLibgtk ----
GTK+, The GIMP ToolKit

Cross-platform Graphical User Interface library

Website: http://www.gtk.org
Platforms supported: Win32, Linux
Headers to include: gtk/gtk.bi
Example Usage: yes, in examples/GUI/GTK+/
Header version: 2.24.27, 3.14.10

By default, gtk/gtk.bi will use the GTK+ 2 API.
Define __USE_GTK3__ before including gtk/gtk.bi to use GTK+ 3.

Example
   #include Once "gtk/gtk.bi"

   Dim Shared As GtkWidget Ptr win

   Private Sub on_clicked cdecl(ByVal button As GtkButton Ptr, ByVal userdata As gpointer)
      Static As Integer clickcount = 0
      clickcount += 1
      gtk_window_set_title(GTK_WINDOW(win), "clicked " & clickcount & " times")
   End Sub

   gtk_init(NULL, NULL)

   win = gtk_window_new(GTK_WINDOW_TOPLEVEL)
   gtk_window_set_title(GTK_WINDOW(win), "A small GTK+ example")
   gtk_window_set_default_size(GTK_WINDOW(win), 300, 200)
   gtk_container_set_border_width(GTK_CONTAINER(win), 20)

   g_signal_connect(G_OBJECT(win), "destroy", G_CALLBACK(@gtk_main_quit), NULL)

   Dim As GtkWidget Ptr button = gtk_button_new_with_label("Click me!")
   gtk_container_add(GTK_CONTAINER(win), button)

   g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(@on_clicked), NULL)

   gtk_widget_show_all(win)

   gtk_main()



------------------------------------------------------------- ExtLibIUP ----
IUP

Portable toolkit for building graphical user interfaces.

Website: http://www.tecgraf.puc-rio.br/iup/
Platforms supported: Win32, Linux
Headers to include: IUP/iup.bi
Header version: 3.13
Example Usage: yes, in examples/GUI/IUP/



------------------------------------------------------------- ExtLibwxc ----
wx-c, C Interface for WxWidgets

Cross-platform Graphical User Interface library

Website: http://wxnet.sourceforge.net/
Platforms supported: Win32, Linux
Headers to include: wx-c/wx.bi
Header version: 0.9.0.2
Example Usage: yes, in examples/GUI/wx-c/



--------------------------------------------------------- ExtLibwindows ----
Windows API

Standard API for all Windows Systems, used for example for creating Windows 
GUIs (forms and controls), socket programming, inter-process communication, 
and so much more.

Website: http://msdn.microsoft.com/en-us/library/ee663300.aspx
Platforms supported: Win32, Linux (using WINE)
Headers to include: windows.bi
Examples: yes, in examples/win32/



------------------------------------------------------------- ExtLibX11 ----
X11

The X Windowing System is widely used on Linux as the layer that 
coordinates drawing to the screen by providing windows. It also delivers 
events such as mouse and keyboard input from the kernel to applications. It 
is designed to run as a server that can be contacted through a specific 
protocol. The client's side of the protocol is implemented by libraries 
such as the old Xlib or the more modern XCB. Applications can use these to 
create windows and draw to them. However, typically most developers will 
choose to use a GUI library such as GTK+ (which has an X11 backend) 
instead.

Website: http://www.x.org/, http://xcb.freedesktop.org/
Platforms supported: Linux
Headers to include: X11/*.bi




============================================================================
    Graphics

--------------------------------------------------------- ExtLiballegro ----
Allegro

Game programming library

Website: http://alleg.sourceforge.net/index.html
Platforms supported: Win32, Linux, DOS
Headers to include: allegro.bi (Allegro 4) or allegro5/allegro.bi (Allegro 
5)
Header version: 4.4.2, 5.0.11
Example Usage: yes, in examples/graphics/Allegro/



------------------------------------------------------------ ExtLibDUGL ----
DUGL

Graphics and game programming library

Website: http://dugl.50webs.com
Platforms supported: DOS
Headers to include: DUGL.BI (not yet included with FB, see link below)
Example of usage: see link below
Note: use DUGL 1.13 or newer (see link below), older version have a bug and 
do crash when used with FB

See forum thread: http://www.freebasic.net/forum/viewtopic.php?t=11046

   


------------------------------------------------------------ ExtLibcaca ----
caca

A colour ASCII art library.

Website: http://libcaca.zoy.org/
Platforms supported: Win32, Linux, DOS
Headers to include: caca.bi (new API) or caca0.bi (old API)
Header version: libcaca-0.99.beta19
Example Usage: yes, in examples/console/caca/

   


----------------------------------------------------------- ExtLibcairo ----
Cairo

2D graphics library with support for multiple output devices. It can be 
used to draw on multiple different surfaces, such as the FB graphics 
window, in-memory pixel buffers, a GTK+ widget or a Win32 window or device 
context.

Website: http://www.cairographics.org
Platforms supported: Win32, Linux
Headers to include: cairo/cairo.bi
Header version: 1.14.2
Examples: yes, in examples/graphics/cairo/

Example
   '' Example showing cairo being used to draw into the FB graphics window
   #include Once "cairo/cairo.bi"

   Const SCREEN_W = 400
   Const SCREEN_H = 300

   ScreenRes SCREEN_W, SCREEN_H, 32

   '' Create a cairo drawing context, using the FB screen as surface.
   Var surface = cairo_image_surface_create_for_data(ScreenPtr(), CAIRO_FORMAT_ARGB32, SCREEN_W, SCREEN_H, SCREEN_W * SizeOf(ULong))

   Var c = cairo_create(surface)

   ScreenLock()

   '' Draw the entire context white.
   cairo_set_source_rgba(c, 1, 1, 1, 1)
   cairo_paint(c)

   '' Draw a red line
   cairo_set_line_width(c, 1)
   cairo_set_source_rgba(c, 1, 0, 0, 1)
   cairo_move_to(c, 0, 0)
   cairo_line_to(c, SCREEN_W - 1, SCREEN_H - 1)
   cairo_stroke(c)

   ScreenUnlock()

   Sleep

   '' Clean up the cairo context
   cairo_destroy(c)

 last reviewed: MrSwiss, 2018-05-05 -- changed: SizeOf(Integer) to SizeOf
(ULong) reason: 32/64 compatibility 

---------------------------------------------------------- ExtLibdislin ----
DisLin

Library of subroutines and functions that display data graphically.

Website: http://www.mps.mpg.de/dislin/
Platforms supported: Win32, Linux
Headers to include: dislin.bi
Header version: from 2005



-------------------------------------------------------- ExtLibfreeglut ----
Free alternative to the OpenGL Utility Toolkit

Just like GLUT, freeglut is a helper library that can be used to create Open
GL applications. It allows easy creation of windows with OpenGL drawing 
contexts and callback-based input event handling.

Website: http://freeglut.sourceforge.net/
Platforms supported: Win32, Linux
Headers to include: GL/freeglut.bi
Header version: 3.0.0



------------------------------------------------------- ExtLibfreeimage ----
FreeImage

FreeImage is an Open Source library project for developers who would like 
to support popular graphics image formats like PNG, BMP, JPEG, TIFF and 
others as needed by today's multimedia applications. FreeImage is easy to 
use, fast, multithreading safe, compatible with all 32-bit versions of 
Windows, and cross-platform (works both with Linux and Mac OS X).

Website: http://freeimage.sourceforge.net/
Platforms supported: Win32, Linux
Headers to include: FreeImage.bi
Header version: 3.15.1
Example included: yes, in examples/files/FreeImage

Example
Here follows an example of using FreeImage in FreeBASIC.  If using Windows 
you will require freeimage.dll which is available from the FreeImage site.

   '' Code example for loading all common image types using FreeImage.
   '' The example loads an image passed as a command line argument.

   '' The function FI_Load returns a null pointer (0) if there was an error during
   '' loading.  Otherwise it returns a 32-bit PUT compatible buffer.

   #include "FreeImage.bi"
   #include "crt.bi"
   #include "fbgfx.bi"

   Function FI_Load(filename As String) As Any Ptr
      If Len(filename) = 0 Then
         Return NULL
      End If

      '' Find out the image format
      Dim As FREE_IMAGE_FORMAT form = FreeImage_GetFileType(StrPtr(filename), 0)
      If form = FIF_UNKNOWN Then
         form = FreeImage_GetFIFFromFilename(StrPtr(filename))
      End If

      '' Exit if unknown
      If form = FIF_UNKNOWN Then
         Return NULL
      End If

      '' Always load jpegs accurately
      Dim As UInteger flags = 0
      If form = FIF_JPEG Then
         flags = JPEG_ACCURATE
      End If

      '' Load the image into memory
      Dim As FIBITMAP Ptr image = FreeImage_Load(form, StrPtr(filename), flags)
      If image = NULL Then
         '' FreeImage failed to read in the image
         Return NULL
      End If

      '' Flip the image so it matches FB's coordinate system
      FreeImage_FlipVertical(image)

      '' Convert to 32 bits per pixel
      Dim As FIBITMAP Ptr image32 = FreeImage_ConvertTo32Bits(image)

      '' Get the image's size
      Dim As UInteger w = FreeImage_GetWidth(image)
      Dim As UInteger h = FreeImage_GetHeight(image)

      '' Create an FB image of the same size
      Dim As fb.Image Ptr sprite = ImageCreate(w, h)

      Dim As Byte Ptr target = CPtr(Byte Ptr, sprite + 1)
      Dim As Integer target_pitch = sprite->pitch

      Dim As Any Ptr source = FreeImage_GetBits(image32)
      Dim As Integer source_pitch = FreeImage_GetPitch(image32)

      '' And copy over the pixels, row by row
      For y As Integer = 0 To (h - 1)
         memcpy(target + (y * target_pitch), _
               source + (y * source_pitch), _
               w * 4)
      Next

      FreeImage_Unload(image32)
      FreeImage_Unload(image)

      Return sprite
   End Function

   ScreenRes 640, 480, 32

   Dim As String filename = Command(1)

   Dim As Any Ptr image = FI_Load(filename)
   If image <> 0 Then
      Put (0, 0), image
      ImageDestroy(image)
   Else
      Print "Problem while loading file : " & filename
   End If

   Sleep



------------------------------------------------------- ExtLibfreetype2 ----
Freetype2

A Free, High-Quality, and Portable Font Engine

Website: http://www.freetype.org
Platforms supported: Win32, Linux
Headers to include: freetype2/freetype.bi
Header version: 2.5.5
Examples: yes, in examples/graphics/FreeType/

Example
   '' Example of rendering a char using freetype

   #include "freetype2/freetype.bi"

   #ifdef __FB_LINUX__
   Const TTF_FONT = "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf"
   #else
   Const TTF_FONT = "Vera.ttf"
   #endif

   Dim As FT_Library library
   If (FT_Init_FreeType(@library) <> 0) Then
      Print "FT_Init_FreeType() failed" : Sleep : End 1
   End If

   ''
   '' Load a font and render an '@' character on to a bitmap
   ''

   Dim As FT_Face face
   If (FT_New_Face(library, TTF_FONT, 0, @face) <> 0) Then
      Print "FT_New_Face() failed (font file '" & TTF_FONT & "' not found?)" : Sleep : End 1
   End If

   If (FT_Set_Pixel_Sizes(face, 0, 200) <> 0) Then
      Print "FT_Set_Pixel_Sizes() failed" : Sleep : End 1
   End If

   If (FT_Load_Char(face, Asc("@"), FT_LOAD_DEFAULT) <> 0) Then
      Print "FT_Load_Char() failed" : Sleep : End 1
   End If

   If (FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL) <> 0) Then
      Print "FT_Render_Glyph() failed" : Sleep : End 1
   End If

   ''
   '' Draw the rendered bitmap
   ''

   ScreenRes 320, 200, 32

   Dim As FT_Bitmap Ptr bitmap = @face->glyph->bitmap

   For y As Integer = 0 To (bitmap->rows - 1)
      For x As Integer = 0 To (bitmap->Width - 1)
         Dim As Integer col = bitmap->buffer[y * bitmap->pitch + x]
         PSet(x, y), RGB(col, col, col)
      Next
   Next

   Sleep



-------------------------------------------------------------- ExtLibgd ----
GD

Open source code library for the dynamic creation of images by programmers.

Website: http://www.libgd.org
Platforms supported: Win32, Linux
Headers to include: gd.bi
Header version: 2.1.0 development version
Examples: yes, in examples/files/GD/



---------------------------------------------------------- ExtLibgiflib ----
GIFLIB

GIFLIB is a package of portable tools and library routines for working with 
GIF images

Website: http://giflib.sourceforge.net/intro.html
Platforms supported: Win32, Linux, DOS
Headers to include: gif_lib.bi
Header version: 4.2.1, 5.0.4 (#define __GIFLIB_VER__ to 4 or 5 if needed; 
default = 5)
Examples: yes, in examples/files/GIFLIB/



------------------------------------------------------------ ExtLibGLUT ----
GLUT, the OpenGL Utility Toolkit

GLUT is a helper library that can be used to create OpenGL applications. It 
allows easy creation of a window with an OpenGL drawing context and also 
handles events such as mouse and keyboard input or timers. GLUT appears to 
be no longer maintained, however there is an active alternative: freeglut.

Website: http://www.opengl.org/resources/libraries/glut/
Platforms supported: Win32
Headers to include: GL/glut.bi
Header version: 3.7
Examples: in examples/graphics/OpenGL/



------------------------------------------------------------ ExtLibGLFW ----
GLFW, an OpenGL library

GLFW is a helper library that can be used to create OpenGL applications. It 
allows the creation of a window with an OpenGL drawing context and input 
handling while still allowing the program to have its own main loop.

Website: http://www.glfw.org/
Platforms supported: Win32, Linux
Headers to include: GL/glfw.bi, GLFW/glfw3.bi
Header version: 2.7.9, 3.1.1
Examples: in examples/graphics/OpenGL/



------------------------------------------------------------- ExtLibgrx ----
GRX

2D graphics library

Website: http://grx.gnu.de/
Platforms supported: Win32, Linux, DOS
Headers to include: grx/grx20.bi
Header version: 2.4.6
Examples: in examples/graphics/grx/



-------------------------------------------------------------- ExtLibIL ----
DevIL

A full featured cross-platform image library.

Website: http://openil.sourceforge.net/
Platforms supported: Win32, Linux
Headers to include: IL/il.bi, IL/ilu.bi, IL/ilut.bi
Header version: 1.7.8
Examples: in examples/files/DevIL/

Example
   '' DevIL example

   #include Once "IL/il.bi"

   '' Version check
   If (ilGetInteger(IL_VERSION_NUM) < IL_VERSION) Then
      Print "DevIL version is different"
      End 1
   End If

   '' Good practice to explicitely initialize it
   ilInit()

   '' Load a bitmap
   Dim As ILuint fblogo
   ilGenImages(1, @fblogo)
   ilBindImage(fblogo)

   Print "Loading fblogo.bmp..."
   ilLoadImage("fblogo.bmp")

   '' Save a copy
   Print "Saving a copy, fblogo-copy.bmp..."
   ilEnable(IL_FILE_OVERWRITE)
   ilSaveImage("fblogo-copy.bmp")

   '' Clean up
   ilDeleteImages(1, @fblogo)



------------------------------------------------------------ ExtLibjapi ----
Java Application Programming Interface

Open source free software GUI toolkit using Java's AWT Toolkit

Website: http://www.japi.de/
Platforms supported: Win32, Linux
Headers to include: japi.bi
Header version: from 2005



--------------------------------------------------------- ExtLibjpeglib ----
jpeglib

Cross-platform library for reading/writing jpeg images

Website: http://ijg.org/
Platforms supported: Win32, Linux, DOS
Headers to include: jpeglib.bi
Header version: 6.2, 7.0, 8.4, 9.0 (#define __JPEGLIB_VER__ to one of 
6,7,8,9 if needed; default = 9)
Example Usage: yes, in examples/files/jpeglib



-------------------------------------------------------- ExtLibjpgalleg ----
JPGAlleg

JPGalleg is a small addon for Allegro that adds JPG images handling 
capabilities to the library

Website: http://www.ecplusplus.com/index.php?page=projects&pid=1
Platforms supported: Win32, Linux
Headers to include: jpgalleg.bi
Header version: 2.5



---------------------------------------------------------- ExtLiblibpng ----
libPNG

Allows reading and writing PNG images.

Website: http://www.libpng.org/pub/png/libpng.html
Platforms supported: Win32, Linux, DOS
Headers to include: png.bi
Header versions: 1.2.53, 1.4.16, 1.5.21, 1.6.16
Examples: in examples/files/libpng/

When #including png.bi, you can #define __LIBPNG_VERSION to one of 12, 14, 1
5, 16 in order to select the desired libpng version. The default is the 
latest version.

Overriding the default allows you to match the exact libpng version on your 
system (interesting for Linux distros which, for example, use the libpng 
1.2 series instead of the latest version).



---------------------------------------------------------- ExtLibOpenGL ----
OpenGL, The Open Graphics Language

OpenGL is a standardized and widely used cross-platform 3D graphics 
library.

Usually OpenGL support comes as part of the system and the graphics 
drivers. There are many different projects providing a library that 
implements the main OpenGL API, and which one is used depends on the 
platform and system setup. For example, on Windows, the client API is 
implemented in Microsoft's opengl32.dll, while on Linux, there is for 
example the free Mesa3D project, which provides a libGL implementation. It 
depends on the used library or system setup which way the OpenGL API does 
its rendering, typically it uses OpenGL hardware drivers and is 
hardware-accelerated, but there also is software-rendered OpenGL (e.g. 
standalone Mesa3D). The system's graphics hardware drivers may provide 
additional OpenGL extensions, access to which is again system dependant.

Besides plain OpenGL, there are several utility, helper and wrapper 
libraries, such as GLUT, freeglut and GLFW, and even FreeBASIC's built-in 
graphics library has an OpenGL mode, see Screen (Graphics) And Fb.Gfx_Opengl
.

Websites:
OpenGL standard: http://www.opengl.org
Mesa3D: http://mesa3d.org/
Windows OpenGL: http://msdn.microsoft.com/en-us/library/dd374278.aspx

Platforms supported: Win32, Linux
Headers to include: GL/gl.bi
Header version: Mesa-3D 10.5.1, MinGW-w64 3.3.0
Examples: yes, in examples/graphics/OpenGL/



---------------------------------------------------------- ExtLibpdflib ----
PDFlib

Portable library for dynamically generating PDF documents

Website: http://www.pdflib.com
Platforms supported: Win32, Linux
Headers to include: pdflib.bi
Header version: 4.0.2
Examples: in examples/files/pdflib/



------------------------------------------------------------- ExtLibSDL ----
SDL, the Simple DirectMedia Layer

Cross-platform mulitmedia library

Website: http://www.libsdl.org
Platforms supported: Win32, Linux
Headers to include: SDL/SDL.bi or SDL2/SDL.bi
Header version: SDL 1.2.15, SDL2 2.0.3
Examples: yes, in examples/graphics/SDL/



--------------------------------------------------------- ExtLibtinyptc ----
TinyPTC

A small and easy to use framebuffer graphics library.

Website: http://sourceforge.net/projects/tinyptc/
Platforms supported: Win32, Linux, DOS
Headers to include: tinyptc.bi
Examples: in examples/graphics/tinyptc/




============================================================================
    Music/Sound, Audio/Video

------------------------------------------------------------ ExtLibbass ----
BASS

Audio library for use in Windows with a Beta Version for Linux.

Website: http://www.un4seen.com/bass.html
Platforms supported: Win32, Linux (beta)
Headers to include: bass.bi
Header version: 2.4.14
Examples: in examples/sound/BASS/

Example
   #include Once "bass.bi"

   '' this mod file should be available in the fbc package:
   Const SOUND_FILE = "..\..\sound\data\dne_trtn.mod"

   If (BASS_GetVersion() < MAKELONG(2,2)) Then
      Print "BASS version 2.2 or above required!"
      End 1
   End If

   If (BASS_Init(-1, 44100, 0, 0, 0) = 0) Then
      Print "Could not initialize BASS"
      End 1
   End If

   Dim As HMUSIC test = BASS_MusicLoad(False, @SOUND_FILE, 0, 0, BASS_MUSIC_LOOP, 0)
   If (test = 0) Then
      Print "BASS could not load '" & SOUND_FILE & "'"
      BASS_Free()
      End 1
   End If

   BASS_ChannelPlay(test, False)

   Print "Sound playing; waiting to keypress to stop and exit..."
   Sleep

   BASS_ChannelStop(test)
   BASS_MusicFree(test)
   BASS_Stop()
   BASS_Free()



--------------------------------------------------------- ExtLibbassmod ----
BASSMOD

BASSMOD is a MOD only (XM, IT, S3M, MOD, MTM, UMX) version of BASS - useful 
for demos, or anything else where you want to play some MOD music.

Website: http://www.un4seen.com/bassmod.html
Platforms supported: Win32, Linux
Headers to include: bassmod.bi
Header version: 2.0
Examples: in examples/sound/BASS/

Example
   #include Once "bassmod.bi"

   Const SOUND_FILE = "test.mod"

   If (BASSMOD_GetVersion() < 2) Then
      Print "BASSMOD version 2 or above required!"
      End 1
   End If

   If (BASSMOD_Init(-1, 44100, 0) = 0) Then
      Print "Could not initialize BASSMOD"
      End 1
   End If

   If (BASSMOD_MusicLoad(False, SOUND_FILE, 0, 0, BASS_MUSIC_LOOP) = 0) Then
      Print "BASSMOD could not load '" & SOUND_FILE & "'"
      BASSMOD_Free()
      End 1
   End If

   BASSMOD_MusicPlay()

   Print "Sound playing; waiting for keypress to stop and exit..."
   Sleep

   BASSMOD_MusicStop()
   BASSMOD_MusicFree()
   BASSMOD_Free()



----------------------------------------------------------- ExtLibFlite ----
Flite

Flite is a run-time speech synthesis engine.

Website: http://www.speech.cs.cmu.edu/flite/
Platforms supported: Win32, Linux
Headers to include: flite/flite.bi
Header version: 1.4, machine-translated only



------------------------------------------------------------ ExtLibfmod ----
FMOD

Audio library supporting just about any format.

Website: https://www.fmod.com/core
Platforms supported: Win32, Linux
Headers to include: fmod.bi
Header version: 3.75
Examples: in examples/sound/FMOD/

Example
   #include Once "fmod.bi"

   Const SOUND_FILE = "test.mod"

   If (FSOUND_GetVersion() < FMOD_VERSION) Then
      Print "FMOD version mismatch"
      End 1
   End If

   If (FSOUND_Init(44100, 32, 0) = 0) Then
      Print "Could not initialize FMOD"
      End 1
   End If

   Dim As FMUSIC_MODULE Ptr song = FMUSIC_LoadSong(SOUND_FILE)
   If (song = 0) Then
      Print "FMOD could not load '" & SOUND_FILE & "'"
      FSOUND_Close()
      End 1
   End If

   FMUSIC_PlaySong(song)

   Print "Sound playing; waiting for keypress to stop and exit..."
   Sleep

   FMUSIC_FreeSong(song)
   FSOUND_Close()

   '' mp3 player based on FMOD

   #include Once "fmod.bi"

   Const SOUND_FILE = "test.mp3"

   Sub print_all_tags(ByVal stream As FSOUND_STREAM Ptr)
      Dim As Integer count = 0
      FSOUND_Stream_GetNumTagFields(stream, @count)

      For i As Integer = 0 To (count - 1)
         Dim As Integer tagtype, taglen
         Dim As ZString Ptr tagname, tagvalue
         FSOUND_Stream_GetTagField(stream, i, @tagtype, @tagname, @tagvalue, @taglen)
         Print Left(*tagname, taglen)
      Next
   End Sub

   Function get_tag _
      ( _
         ByVal stream As FSOUND_STREAM Ptr, _
         ByVal tagv1 As ZString Ptr, _
         ByVal tagv2 As ZString Ptr _
      ) As String

      Dim tagname As ZString Ptr, taglen As Integer

      FSOUND_Stream_FindTagField(stream, FSOUND_TAGFIELD_ID3V1, tagv1, @tagname, @taglen)
      If (taglen = 0) Then 
         FSOUND_Stream_FindTagField(stream, FSOUND_TAGFIELD_ID3V2, tagv2, @tagname, @taglen)
      End If

      Return Left(*tagname, taglen)
   End Function

      If (FSOUND_GetVersion < FMOD_VERSION) Then
         Print "FMOD version " + Str(FMOD_VERSION) + " or greater required!"
         End 1
      End If 

      If (FSOUND_Init(44100, 4, 0) = 0) Then
         Print "Could not initialize FMOD"
         End 1
      End If

      FSOUND_Stream_SetBufferSize(50)

      Dim As FSOUND_STREAM Ptr stream = FSOUND_Stream_Open(SOUND_FILE, FSOUND_MPEGACCURATE, 0, 0)
      If (stream = 0) Then 
         Print "FMOD could not load '" & SOUND_FILE & "'"
         FSOUND_Close()
         End 1
      End If

      '' Read out mp3 tags to show some meta information
      Print "Title:", get_tag(stream, "TITLE", "TIT2")
      Print "Album:", get_tag(stream, "ALBUM", "TALB")
      Print "Artist:", get_tag(stream, "ARTIST", "TPE1")
      ''print_all_tags(stream)

      Print "Playing mp3, press a key to exit..."
      FSOUND_Stream_Play(FSOUND_FREE, stream)

      While (Inkey() = "")
         If (FSOUND_Stream_GetPosition(stream) >= FSOUND_Stream_GetLength(stream)) Then
            Exit While
         End If
         Sleep 50, 1
      Wend
      
      FSOUND_Stream_Stop(stream)
      FSOUND_Stream_Close(stream)
      FSOUND_Close()



------------------------------------------------------- ExtLibMediaInfo ----
MediaInfo

MediaInfo is a cross-platform library allowing you to read out technical 
and tag information from audio and video files in various formats.

Website: http://mediainfo.sourceforge.net/
Platforms supported: Win32, Linux
Headers to include: MediaInfo.bi
Header version: from October 2011



---------------------------------------------------------- ExtLibmpg123 ----
mpg123

libmpg123 is the decoder library used by the mpg123 MPEG player.

Website: http://mpg123.org/
Platforms supported: Win32, Linux
Headers to include: mpg123.bi
Header version: from 2010, machine-translated only



------------------------------------------------------------- ExtLibogg ----
libogg

Ogg multimedia container format creation/decoder library

Website: http://www.xiph.org/ogg/
Platforms supported: Win32, Linux
Headers to include: ogg/ogg.bi
Header version: from 2007



-------------------------------------------------------------- ExtLibal ----
OpenAL

OpenAL is a cross-platform 3D audio API appropriate for use with gaming 
applications and many other types of audio applications. ALUT is the OpenAL 
utility toolkit, a library providing additional functions to work with OpenA
L.

Website: http://www.openal.org
Platforms supported: Win32, Linux
Headers to include: AL/al.bi, AL/alut.bi
Header version: openal-soft-1.16.0, freealut 1.1.0
Examples: in examples/sound/OpenAL/



------------------------------------------------------- ExtLibPortAudio ----
PortAudio

PortAudio is a cross-platform audio I/O library that allows programs to 
access the system's audio devices to record or play sounds.

Website: http://www.portaudio.com/
Platforms supported: Win32, Linux
Headers to include: portaudio.bi
Header version: from 2010, machine-translated only



------------------------------------------------------------- ExtLibsfx ----
sfx

Freebasic sfx library is cross-platform and comes for Windows, Linux, Dos
Author: angros47
Download link: https://sourceforge.net/projects/freebasic-sfx-library/files/

Forum link: https://freebasic.net/forum/viewtopic.php?f=17&t=26256

Compile Library: all the necessary scripts are in the archive, you just 
need to substitute the correct path to the compiler in them

A brief description of the main (not all) functions:

1) SoundmidiSet - setting mode midi (needed for function PLAY)
2) SoundSet - setting mode PCM sound (needed for functions SOUND , PlayWave)

1) PLAY - command is for playing musical notes, octave *.
2) SOUND - command produces sound of a specific frequency for a specific 
duration
3) LoadMidi - load midi from file, returns a pointer MidiSequence ptr
4) PlayMidi - play midi, in parameters you need to pass pointer MidiSequence
 ptr
5) CreateMidi - creates MidiSequence ptr, then you can use the pointer 
using PLAY to write data , and then save in the file
6) SaveMidi - save data MidiSequence ptr in file, in format .mid
7) LoadWave - loads a file into memory WAV (supported only 
WAVE_FORMAT_PCM), returns a pointer WaveHeaderType ptr
8) PlayWave - play wav , in parameters you need to pass pointer WaveHeaderTy
pe ptr

* The command PLAY can play more than one note at time: it supports chords, 
by grouping notes inside curly brackets, and it allows to play up to 16 
channels at the same time. For more information see also command QBASICs 
play.

Description of all functions is in the file readme.txt (in archive)

Example

Example Play#include "sfx.bi"
   #inclib "fbsfx"

   SoundmidiSet ()
   PLAY "a4e4g4a4g4e4c2f4f4f2d4d4d2"

Example Play wih thread#include "sfx.bi"
   #inclib "fbsfx"

   Dim Shared As Any Ptr mutex
   mutex = MutexCreate

   Dim Shared As Long iMusicExit
   Dim As Double dTimer

   Sub procThread(p As Any Ptr)
      SoundmidiSet ()
      PLAY "a4e4g4a4g4e4c2f4f4f2d4d4d2"
      MutexLock(mutex)
      iMusicExit = 1
      MutexUnlock(mutex)
   End Sub

   dTimer = Timer
   ThreadCreate(@procThread)

   Do
      ? Timer - dTimer
      MutexLock(mutex)
      If iMusicExit Then
        Exit Do
      EndIf
      MutexUnlock(mutex)
   Loop

Example CreateMidi, SaveMidi
   #include "sfx.bi"
   #inclib "fbsfx"

   SoundmidiSet ()
   Dim As Any Ptr Midi=CreateMidi()
   PLAY Midi,"a4e4g4a4g4e4c2f4f4f2d4d4d2"
   SaveMidi "music.mid", Midi

Example LoadMidi, PlayMidi
   #include "sfx.bi"
   #inclib "fbsfx"

   SoundmidiSet ()
   Dim As Any Ptr Midi=LoadMidi("music.mid")
   PlayMidi(Midi, 1)
   Sleep

Example Sound
   #include "sfx.bi"
   #inclib "fbsfx"

   SoundSet (44100,1,16)
   sound SineWave(2000), 1 ' sine 2 kHz
   sound NoiseWave(), 1 ' noise
   Sleep

Example LoadWave, PlayWave
   #include "sfx.bi"
   #inclib "fbsfx"

   Dim As WaveHeaderType Ptr pWave
   SoundSet (44100,2,16)
   pWave = LoadWave("1.wav")
   If pWave = 0 Then
      Print "pWave = 0" : End
   End If
   PlayWave(pWave)
   Sleep



--------------------------------------------------------- ExtLibsndfile ----
libsndfile

libsndfile is a library allowing programs to access or modify audio files 
in various formats, for example .wav files, and also convert between them.

Website: http://www.mega-nerd.com/libsndfile/
Platforms supported: Win32, Linux
Headers to include: sndfile.bi
Header version: 1.0.X



------------------------------------------------------------- ExtLibVLC ----
libVLC

Audio/video playback library from the VLC media player.

Website: http://www.videolan.org/, http://wiki.videolan.org/Libvlc
Platforms supported: Win32, Linux
Headers to include: vlc/*.bi
Header version: 1.1.x



---------------------------------------------------------- ExtLibvorbis ----
libvorbis

Ogg Vorbis audio compression library

Website: http://xiph.org/vorbis/
Platforms supported: Win32, Linux
Headers to include: vorbis/vorbisenc.bi, vorbis/vorbisfile.bi
Header version: from 2007




============================================================================
    Database

------------------------------------------------------------ ExtLibGDBM ----
GDBM, the GNU Database manager

Provides database functions using extensible hashing, primarily for storing 
key/data pairs to data files

Website: http://www.gnu.org.ua/software/gdbm/
Platforms supported: Win32, Linux
Headers to include: gdbm.bi
Header version: from 2010



----------------------------------------------------------- ExtLibmysql ----
MySQL

High-Quality, widely used database engine.

Website: http://www.mysql.org
Platforms supported: Win32, Linux
Headers to include: mysql/mysql.bi
Header version: 4.0.17
Examples: in examples/database/



------------------------------------------------------ ExtLibpostgresql ----
PostgreSQL

Free software object-relational database management system 

Website: https://www.postgresql.org/
Platforms supported: Win32, Linux
Headers to include: postgresql/postgres_ext.bi
Header version: 12.0
Example Usage: yes, in examples/database/

   


---------------------------------------------------------- ExtLibsqlite ----
SQLite

Small C library that implements a self-contained, embeddable, 
zero-configuration SQL database engine.

Website: https://sqlite.org
Platforms supported: Win32, Linux, DOS
Headers to include: sqlite2.bi or sqlite3.bi
Header versions: 2.8.17, 3.30.0
Examples: in examples/database/




============================================================================
    Development Helpers

----------------------------------------------------------- ExtLibCUnit ----
CUnit

Lightweight system for writing, administering, and running unit tests in C.

Website: http://cunit.sourceforge.net/
Platforms supported: Win32, Linux, DOS
Headers to include: CUnit/CUnit.bi
Header version: 2.1-3
Examples: in examples/misc/CUnit/



------------------------------------------------------------ ExtLibgdsl ----
GDSL, The Generic Data Structures Library

The Generic Data Structures Library is a collection of routines for generic 
data structures.

Website: https://web.archive.org/web/20170502005430/http://home.gna.org:80/gdsl/ http://home.gna.org/gdsl/ (archived copy)
Platforms supported: Win32, Linux, DOS
Headers to include: gdsl/gdsl.bi
Header version: from 2005
Examples: in examples/misc/gdsl/



--------------------------------------------------------- ExtLibgettext ----
gettext

An internationalization library/toolchain

Website: http://www.gnu.org/software/gettext/gettext.html
Platforms supported: Win32, Linux, DOS
Headers to include: libintl.bi, gettext-po.bi
Header version: from 2010, 0.17



---------------------------------------------------------- ExtLibaspell ----
GNU Aspell

Free and Open Source spell checker.

Website: http://aspell.net/
Platforms supported: Win32, Linux
Headers to include: aspell.bi
Header version: 0.60.6.1

Example
   '' GNU-ASspell example, converted from http://aspell.net/win32/

   #include Once "aspell.bi"

   Dim As AspellConfig Ptr spell_config = new_aspell_config()

   '' Change this to suit the installed dictionary language if desired
   aspell_config_replace(spell_config, "lang", "en_CA")

   '' Create speller object
   Dim As AspellCanHaveError Ptr possible_err = new_aspell_speller(spell_config)
   If (aspell_error_number(possible_err) <> 0) Then
      Print *aspell_error_message(possible_err)
      End 1
   End If
   Dim As AspellSpeller Ptr speller = to_aspell_speller(possible_err)

   Dim As String word
   Do
      Print 
      Input "Enter a word (blank to quit): ", word
      If (Len(word) = 0) Then
         Exit Do
      End If

      If (aspell_speller_check(speller, StrPtr(word), Len(word)) <> 0) Then
         Print "Word is Correct"
      Else
         Print "Suggestions:"
         Dim As AspellStringEnumeration Ptr elements = _
            aspell_word_list_elements(aspell_speller_suggest(speller, StrPtr(word), Len(word)))
         Do
            Dim As Const ZString Ptr w = aspell_string_enumeration_next(elements)
            If (w = 0) Then
               Exit Do
            End If
            Print "   "; *w
         Loop
         delete_aspell_string_enumeration(elements)
      End If

      ' - Report the replacement
      'aspell_speller_store_repl(speller, misspelled_word, size,
      '                          correctly_spelled_word, size);

      ' - Add to session or personal dictionary
      'aspell_speller_add_to_session|personal(speller, word, size)
   Loop

   delete_aspell_speller(speller)



------------------------------------------------------------- ExtLibbfd ----
BFD, the Binary File Descriptor Library

Provides an API to read and write object files in many different object 
file formats. libbfd is the core of the GNU binutils.

Website: http://sourceware.org/binutils/
Platforms supported: Win32, Linux, DOS
Headers to include: bfd.bi
Header version: binutils versions from 2.16 to 2.25

Define __BFD_VER__ to 216, 217, 218, ..., 225 to include the bfd header for 
the corresponding binutils version.

Example
   #define __BFD_VER__ 217
   #include "bfd.bi"




============================================================================
    Embeddable Languages

------------------------------------------------------------- ExtLibjni ----
JNI, The Java Native Interface

Standard programming interface for writing Java native methods and 
embedding the Java virtual machine into native applications.

Website: http://download.oracle.com/javase/6/docs/technotes/guides/jni/index.html, http://java.sun.com/docs/books/jni/
Platforms supported: Win32, Linux
Headers to include: jni.bi
Header version: from 2006
Examples: in examples/other-languages/Java/

Example

   Three files:

   * mylib.bas - A DLL writting in FreeBASIC

   #include "jni.bi"
      
   '' Note: The mangling must be "windows-ms" or the JRE won't find any function
   Extern "windows-ms"
      Function Java_MyLib_add( env As JNIEnv Ptr, obj As jobject, l As jint, r As jint ) As jint Export
         Return l + r
      End Function
   End Extern

   * Mylib.java - The Java class that represents the interface to the 
     FreeBASIC code and ensures the FreeBASIC DLL is loaded

   (cpp)
   Class MyLib {
   	Public native Int Add( Int l, Int r );
   	Static {
   		System.loadLibrary( "mylib" );
   	}
   }

   * Test.java - The Java main() that uses the Mylib class

   (cpp)
   Class Test {
   	Public Static void main(String[] args) {
   		MyLib Lib = New MyLib();
   		System.out.println( "2+2=" + lib.add( 2, 2 ) ); 
   	}
   }

   Steps to test it:

   * Compile the FreeBASIC DLL: fbc mylib.bas -dll
   * Compile the two Java classes: javac Mylib.java Test.java
   * Run the Test class: java Test



----------------------------------------------------------- ExtLibjsonc ----
json-c

A JSON implementation in C

Website: https://github.com/json-c/json-c
Platforms supported: Win32, Linux
Headers to include: json-c/json.bi
Header version: 0.9 (not sure)



------------------------------------------------------------- ExtLibFfi ----
libffi

LibFFI is a foreign function interface library allowing programs to 
arbitrarily call native function without pointers and to bind function 
pointers to generic functions which take variable arguments via closures. 
It is used to bind native code in modern scripting languages.

Website: https://sourceware.org/libffi/
Platforms supported: Windows, Linux, DOS
Headers to include: ffi.bi
Header version: 3.1

Example
   Hello world:
   #include "ffi.bi"

   ' Simple "puts" equivalent function
   Function printer cdecl (ByVal s As ZString Ptr) As Integer
      Print *s
      Return 42
   End Function

   ' Initialize the argument info vectors
   Dim s As ZString Ptr
   Dim args(0 To 0) As ffi_type Ptr = {@ffi_type_pointer}
   Dim values(0 To 0) As Any Ptr = {@s}

   ' Initialize the cif
   Dim cif As ffi_cif
   Dim result As ffi_status
   result = ffi_prep_cif( _
      @cif,              _ ' call interface object
      FFI_DEFAULT_ABI,   _ ' binary interface type
      1,                 _ ' number of arguments
      @ffi_type_uint,    _ ' return type
      @args(0)           _ ' arguments
   )

   ' Call function
   Dim return_value As Integer
   If result = FFI_OK Then
      s = @"Hello world"
      ffi_call(@cif, FFI_FN(@printer), @return_value, @values(0))

      ' values holds a pointer to the function's arg, so to
      ' call puts() again all we need to do is change the
      ' value of s */
      s = @"This is cool!"
      ffi_call(@cif, FFI_FN(@printer), @return_value, @values(0))
      Print Using "Function returned &"; return_value
   End If

   Closures:
   #include "ffi.bi"

   ' Acts like puts with the file given at time of enclosure. 
   Sub Printer cdecl(ByVal cif As ffi_cif Ptr, ByVal ret As Any Ptr, ByVal args As Any Ptr Ptr, ByVal File As Any Ptr)
      Write #*CPtr(Integer Ptr, file), **CPtr(ZString Ptr Ptr, args[0])
      *CPtr(UInteger Ptr, ret) = 42
   End Sub

   ' Allocate the closure and function binding
   Dim PrinterBinding As Function(ByVal s As ZString Ptr) As Integer
   Dim closure As ffi_closure Ptr 
   closure = ffi_closure_alloc(SizeOf(ffi_closure), @PrinterBinding)

   If closure <> 0 Then
      ' Initialize the argument info vector
      Dim args(0 To 0) As ffi_type Ptr = {@ffi_type_pointer}
      
      ' Initialize the call interface
      Dim cif As ffi_cif
      Dim prep_result As ffi_status = ffi_prep_cif( _
         @cif,            _ ' call interface object
         FFI_DEFAULT_ABI, _ ' binary interface type
         1,               _ ' number of arguments
         @ffi_type_uint,  _ ' return type
         @args(0)         _ ' arguments
      ) 
      If prep_result = FFI_OK Then
         ' Open console file to send to PrinterBinding as user data
         Dim ConsoleFile As Integer = FreeFile()
         Open Cons For Output As ConsoleFile
         
         ' Initialize the closure, setting user data to the console file
         prep_result = ffi_prep_closure_loc( _
            closure,         _ ' closure object
            @cif,            _ ' call interface object
            @Printer,        _ ' actual closure function
            @ConsoleFile,    _ ' user data, our console file #
            PrinterBinding   _ ' pointer to binding
         )
         If prep_result = FFI_OK Then
            ' Call binding as a natural function call
            Dim Result As Integer
            Result = PrinterBinding("Hello World!")
            Print Using "Returned &"; Result
         End If
         
         Close ConsoleFile
      End If
   End If

   ' Clean up
   ffi_closure_free(closure)



------------------------------------------------------------- ExtLibJit ----
libjit

LibJIT is a fairly straightforward, lightweight library for runtime 
compilation with a simple and stable ABI.

Website: https://www.gnu.org/software/libjit/
Platforms supported: Windows, Linux, DOS
Headers to include: jit.bi
Header version: git a8293e141b79c28734a3633a81a43f92f29fc2d7

Example
   '' Simple mul/add example

   #include "jit.bi"

   ' initialize libjit
   Dim context As jit_context_t = jit_context_create()
   jit_context_build_start(context)

   ' define function mul_add(x, y, z)
   Dim params(0 To 2) As jit_type_t = {jit_type_int, jit_type_int, jit_type_int}
   Dim signature As jit_type_t = jit_type_create_signature( _  
      jit_abi_cdecl,  _ ' C-style function
      jit_type_int,   _ ' Return type
      @params(0),     _ ' Parameter array
      3,              _ ' Number of components
      1               _ ' Count references?
   )
   Dim mul_add As jit_function_t = jit_function_create(context, signature)

   ' build function (result = (x*y)+z)
   Dim As jit_value_t x, y, z, temp1, temp2
   x = jit_value_get_param(mul_add, 0)
   y = jit_value_get_param(mul_add, 1)
   temp1 = jit_insn_mul(mul_add, x, y)
   z = jit_value_get_param(mul_add, 2)
   temp2 = jit_insn_add(mul_add, temp1, z)
   jit_insn_return(mul_add, temp2)

   ' compile function function
   jit_function_compile(mul_add)
   jit_context_build_end(context)

   ' call function
   Dim As Integer a=3, b=5, c=2, result
   Dim args(0 To 2) As Integer Ptr = {@a, @b, @c}
   jit_function_apply(mul_add, @args(0), @result)
   Print Using "mul__add(&, &, &) = &"; a; b; c; result

   ' clean up libjit
   jit_context_destroy(context)

   '' GCD calculation example

   #include "jit.bi"

   ' initialize libjit
   Dim context As jit_context_t = jit_context_create()
   jit_context_build_start(context)

   ' define function gcd(x as uinteger, y as uinteger) as uinteger
   Dim params(0 To 1) As jit_type_t = {jit_type_uint, jit_type_uint}
   Dim signature As jit_type_t = jit_type_create_signature( _  
      jit_abi_cdecl,  _ ' C-style function
      jit_type_uint,  _ ' Return type
      @params(0),     _ ' Parameter array
      2,              _ ' Number of components
      1               _ ' Count references?
   )
   Dim gcd As jit_function_t = jit_function_create(context, signature)

   ' build function
   ' check x = y
   Dim As jit_value_t x, y, x_eq_y
   x = jit_value_get_param(gcd, 0)
   y = jit_value_get_param(gcd, 1)
   x_eq_y = jit_insn_eq(gcd, x, y)

   ' if x = y, return x
   Dim label_x_ne_y As jit_label_t = jit_label_undefined
   jit_insn_branch_if_not(gcd, x_eq_y, @label_x_ne_y)
   jit_insn_return(gcd, x)

   ' else if...
   jit_insn_label(gcd, @label_x_ne_y)

   ' check x < y
   Dim As jit_value_t x_lt_y
   Dim label_x_gte_y As jit_label_t = jit_label_undefined
   x_lt_y = jit_insn_lt(gcd, x, y)
   jit_insn_branch_if_not(gcd, x_lt_y, @label_x_gte_y)

   ' if x < y, return gcd(x, y-x)
   Dim As jit_value_t gcd_args(0 To 2), gcd_result
   gcd_args(0) = x
   gcd_args(1) = jit_insn_sub(gcd, y, x)
   gcd_result = jit_insn_call( _
      gcd,          _ ' where we are calling from
      "gcd",        _ ' function name
      gcd,          _ ' function reference
      0,            _ ' signature = auto
      @gcd_args(0), _ ' arguments
      2,            _ ' argument count
      0             _ ' flags = nothing special
   )
   jit_insn_return(gcd, gcd_result)

   ' else...
   jit_insn_label(gcd, @label_x_gte_y)

   ' return gcd(x-y, y)
   gcd_args(0) = jit_insn_sub(gcd, x, y)
   gcd_args(1) = y
   gcd_result = jit_insn_call( _
      gcd,          _ ' where we are calling from
      "gcd",        _ ' function name
      gcd,          _ ' function reference
      0,            _ ' signature = auto
      @gcd_args(0), _ ' arguments
      2,            _ ' argument count
      0             _ ' flags = nothing special
   )
   jit_insn_return(gcd, gcd_result)

   ' compile function
   jit_function_compile(gcd)
   jit_context_build_end(context)

   ' call function
   Dim As jit_uint a=21, b=14, result
   Dim As jit_uint Ptr args(0 To 1) = {@a, @b}
   jit_function_apply(gcd, @args(0), @result)
   Print Using "gcd(&, &) = &"; a; b; result

   ' clean up libjit
   jit_context_destroy(context)



------------------------------------------------------------- ExtLibLua ----
Lua

Lightweight, embeddable scripting engine using the Lua language.

Website: https://www.lua.org
Platforms supported: Win32, Linux, DOS
Headers to include: Lua/lua.bi
Header version: 5.2.3
Examples: in examples/other-languages/Lua/



---------------------------------------------------- ExtLibspidermonkey ----
SpiderMonkey

Embeddable javascript engine.

Website: https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMon
key
Platforms supported: Win32, Linux
Headers to include: spidermonkey/jsapi.bi
Header version: from 2006

Example
   '' Evaluating javascript code
   #include Once "spidermonkey/jsapi.bi"

   Dim Shared As JSClass global_class = _
   ( _
      @"global", 0, _
      @JS_PropertyStub, @JS_PropertyStub, @JS_PropertyStub, @JS_PropertyStub, _
      @JS_EnumerateStub, @JS_ResolveStub, @JS_ConvertStub, @JS_FinalizeStub _
   )

   Dim As JSRuntime Ptr rt = JS_NewRuntime(1048576 /'memory limit'/)
   Dim As JSContext Ptr cx = JS_NewContext(rt, 4096 /'stack size'/)
   Dim As JSObject Ptr global = JS_NewObject(cx, @global_class, NULL, NULL) 

   JS_InitStandardClasses(cx, global)

   '' This string could also be read in from a file or as part of HTTP data etc.
   Const TEST_SCRIPT = _
      !"function fact(n)           \n" + _
      !"{                          \n" + _
      !"    if (n <= 1)            \n" + _
      !"        return 1;          \n" + _
      !"                           \n" + _
      !"    return n * fact(n - 1);\n" + _
      !"}                          \n" + _
      !"                           \n" + _
      !"    fact(5)                \n"

   Dim As jsval rval
   If (JS_EvaluateScript(cx, global, TEST_SCRIPT, Len(TEST_SCRIPT), "localhost", 1, @rval) = 0) Then
      Print "JS_EvaluateScript failed"
      Sleep
      End 1
   End If

   Print "result: " & *JS_GetStringBytes(JS_ValueToString(cx, rval))

   JS_DestroyContext(cx)
   JS_DestroyRuntime(rt)

   '' Callback example: Functions that are used by the Javascript code,
   '' but are implemented in FB.
   #include Once "spidermonkey/jsapi.bi"

   Dim Shared As JSClass global_class = _
   ( _
      @"global", 0, _
      @JS_PropertyStub, @JS_PropertyStub, @JS_PropertyStub, @JS_PropertyStub, _
      @JS_EnumerateStub, @JS_ResolveStub, @JS_ConvertStub, @JS_FinalizeStub _
   )

   Private Function print_callback cdecl _
      ( _
         ByVal cx As JSContext Ptr, _
         ByVal obj As JSObject Ptr, _
         ByVal argc As uintN, _
         ByVal argv As jsval Ptr, _
         ByVal rval As jsval Ptr _
      ) As JSBool

      If (argc < 1) Then
         Return 0
      End If

      Print *JS_GetStringBytes(JS_ValueToString(cx, argv[0]))

      Return 1
   End Function

   Private Function ucase_callback cdecl _
      ( _
         ByVal cx As JSContext Ptr, _
         ByVal obj As JSObject Ptr, _
         ByVal argc As uintN, _
         ByVal argv As jsval Ptr, _
         ByVal rval As jsval Ptr _
      ) As JSBool
      
      If (argc < 1) Then
         Return 0
      End If
      
      '' Get the first argument
      Dim As ZString Ptr arg1 = JS_GetStringBytes(JS_ValueToString(cx, argv[0]))
      
      '' Get a buffer for the result string
      Dim As ZString Ptr result = JS_malloc(cx, Len(*arg1) + 1)

      '' Do the work
      *result = UCase(*arg1)

      '' Return it in rval
      *rval = STRING_TO_JSVAL(JS_NewString(cx, result, Len(*result)))

      Return 1
   End Function

      Dim As JSRuntime Ptr rt = JS_NewRuntime(1048576 /'memory limit'/)
      Dim As JSContext Ptr cx = JS_NewContext(rt, 4096 /'stack size'/)
      Dim As JSObject Ptr global = JS_NewObject(cx, @global_class, NULL, NULL) 

      JS_InitStandardClasses(cx, global)

      JS_DefineFunction(cx, global, "print", @print_callback, 1, 0) 
      JS_DefineFunction(cx, global, "ucase", @ucase_callback, 1, 0) 

      Const TEST_SCRIPT = "print(ucase('hello'));" 

      Dim As jsval rval
      If (JS_EvaluateScript(cx, global, TEST_SCRIPT, Len(TEST_SCRIPT), "localhost", 1, @rval) = 0) Then
         Print "JS_EvaluateScript failed"
         Sleep
         End 1
      End If

      JS_DestroyContext(cx)
      JS_DestroyRuntime(rt)




============================================================================
    Cryptography

-------------------------------------------------------- ExtLibcryptlib ----
cryptlib

A powerful security toolkit which allows even inexperienced crypto 
programmers to easily add encryption and authentication services to their 
software.

Website: http://www.cs.auckland.ac.nz/~pgut001/cryptlib/
Platforms supported: Win32, Linux
Headers to include: cryptlib.bi
Header version: from 2005
Examples: in examples/math/cryptlib/

Example
   #include Once "cryptlib.bi"

   Function calc_hash( ByVal filename As String, ByVal algo As CRYPT_ALGO_TYPE ) As String
      Const BUFFER_SIZE = 8192
      Dim As Byte buffer( 0 To BUFFER_SIZE-1 )

      '' create a new context using the wanted algorithm
      Dim As CRYPT_CONTEXT ctx
      cryptCreateContext( @ctx, CRYPT_UNUSED, algo )

      '' open input file in binary mode
      Dim As Integer f = FreeFile()
      If( Open( filename For Binary Access Read As #f ) <> 0 ) Then
         Return ""
      End If

      '' read until end-of-file
      Do Until( EOF( f ) )
         Dim As Integer oldpos = Seek( f )
         Get #f, , buffer()
         Dim As Integer readlength = Seek( f ) - oldpos
         '' encrypt
         cryptEncrypt( ctx, @buffer(0), readlength )
      Loop

      '' close input file
      Close #f

      '' finalize
      cryptEncrypt( ctx, 0, 0 )

      '' get the hash result
      Dim As Long buffersize = BUFFER_SIZE
      cryptGetAttributeString( ctx, CRYPT_CTXINFO_HASHVALUE, @buffer(0), @buffersize )

      '' convert to hexadecimal
      Dim As String result = ""
      For i As Integer = 0 To buffersize-1
         result += Hex( buffer(i) )
      Next
      
      '' free the context
      cryptDestroyContext( ctx )

      Return result
   End Function

      Dim As String filename = Trim( Command(1) )
      If( Len( filename ) = 0 ) Then
         Print "Usage: hash.exe filename"
         End -1
      End If

      '' init cryptlib
      cryptInit( )

      '' calculate hashes
      Print "md5:  "; calc_hash( filename, CRYPT_ALGO_MD5 )
      Print "sha1: "; calc_hash( filename, CRYPT_ALGO_SHA1 )

      '' shutdown cryptlib
      cryptEnd( )

      Sleep

   


------------------------------------------------------------ ExtLibUUID ----
UUID library

The UUID library can be used to generate universally unique identifiers. 
It's part of the e2fsprogs utilities.

Website: http://e2fsprogs.sourceforge.net/
Platforms supported: Win32, Linux
Headers to include: uuid.bi
Header version: from 2010




============================================================================
    Mathematics

---------------------------------------------------------- ExtLibbigint ----
big_int

Library for using arbitrarily large integers. Note: This library seems to 
be dead, a possible alternative is gmp.

Website: https://web.archive.org/web/20060112164857/http://valyala.narod.ru/big_int/ http://valyala.narod.ru/big_int/ (archived copy)
Github: https://github.com/valyala/big_int
Platforms supported: Win32, Linux
Headers to include: big_int/big_int.bi
Header version: from 2005
Examples: in examples/math/big_int/

Example
   #include Once "big_int/big_int_full.bi"

   Sub print_num(ByVal num As big_int Ptr)
      Dim As big_int_str Ptr s = big_int_str_create(1)
      If (s = 0) Then
         Exit Sub
      End If

      If (big_int_to_str(num, 10, s) <> 0) Then
         Exit Sub
      End If

      Print *s->Str;

      big_int_str_destroy(s)
   End Sub

      Dim As big_int Ptr bignum = big_int_create(1)

      big_int_from_int(2, bignum)
      big_int_pow(bignum, 65536, bignum)

      Print "2^65536 = ";
      print_num(bignum)
      Print

      big_int_destroy(bignum)



-------------------------------------------------------- ExtLibChipmunk ----
Chipmunk Physics

Chipmunk is a physics library designed specifically for 2D games.

Website: https://chipmunk-physics.net
Platforms supported: Win32, Linux
Headers to include: chipmunk/chipmunk.bi
Header version: 4.1.0



------------------------------------------------------------- ExtLibgmp ----
gmp, The GNU Multiple Precision Arithmetic Library

Free library for arbitrary precision arithmetic, operating on signed 
integers, rational numbers, and floating point numbers.

Website: https://www.gmplib.org
Platforms supported: Win32, Linux
Headers to include: gmp.bi
Header version: 4.1.4

Example
   #include Once "gmp.bi"

   Dim As mpz_ptr bignum = Allocate(SizeOf(__mpz_struct))
   mpz_init_set_si(bignum, 2)
   mpz_pow_ui(bignum, bignum, 65536)

   Print "2^65536 = ";
   Dim As ZString Ptr s = mpz_get_str(0, 10, bignum)
   Print *s;
   Deallocate(s)
   Print

   mpz_clear(bignum)
   Deallocate(bignum)

   


------------------------------------------------------------- ExtLibgsl ----
gsl, The GNU Scientific Library

Provides a wide range of mathematical routines such as random number 
generators, special functions and least-squares fitting.

Website: https://www.gnu.org/software/gsl/, Windows port: http://gnuwin32.so
urceforge.net/packages/gsl.htm 
Platforms supported: Win32, Linux
Headers to include: gsl/*.bi
Header version: 1.6
Examples: in examples/math/GSL/

Example
   '' Elementary math example
   #include "gsl/gsl_math.bi"

   '' Raise the value of 3.141 to the fourth power
   ? "3.141 ^ 4 = "; gsl_pow_4(3.141)
   ?

   '' Find the hypotenuse of a right triangle with sides 3 and 4 
   ? "The hypotenuse of a right triangle with sides of length 3 and 4 is"; gsl_hypot(3,4)
   ?

   Sleep

   '' Matrix example
   #include "gsl/gsl_matrix.bi"

   '' gsl uses the c-style row major order, unlike VB or Fortran 
   ? "A 3x3 matrix" 
   Dim As gsl_matrix Ptr m = gsl_matrix_alloc(3, 3)
   For i As Integer = 0 To 2
      For j As Integer = 0 To 2
         gsl_matrix_set (m, i, j, 0.23 + 100*i + j)
      Next
   Next

   For i As Integer = 0 To 2
      For j As Integer = 0 To 2
         Print "m(";i;",";j;") = "; gsl_matrix_get (m, i, j)
      Next
   Next
   ?

   gsl_matrix_transpose(m)

   ? "And its transpose"
   For i As Integer = 0 To 2
      For j As Integer = 0 To 2
         Print "m(";i;",";j;") = "; gsl_matrix_get (m, i, j)
      Next
   Next

   Sleep



---------------------------------------------------------- ExtLibnewton ----
Newton

The Newton Physics Engine is an integrated solution for real time 
simulation of physics environments. 

Website: http://newtondynamics.com/
Github: https://github.com/MADEAPPS/newton-dynamics/
Platforms supported: Win32, Linux
Headers to include: Newton.bi
Header version: from 2005
Examples: in examples/math/Newton/



------------------------------------------------------------- ExtLibode ----
ODE, the Open Dynamics Engine

Open source, high performance library for simulating rigid body dynamics.

Website: http://www.ode.org/
Platforms supported: Win32, Linux
Headers to include: ode/ode.bi
Header version: 0.11.1
Examples: in examples/math/ODE/




============================================================================
    Networking

--------------------------------------------------------- ExtLibcgiutil ----
cgi-util

Small C library for creating CGI programs for Websites.

Website: http://www.newbreedsoftware.com/cgi-util/
Platforms supported: Win32, Linux
Headers to include: cgi-util.bi



------------------------------------------------------------ ExtLibcurl ----
curl

Free and easy-to-use client-side URL transfer library supporting almost 
every protocol.

Website: https://curl.haxx.se/libcurl/
Platforms supported: Win32, Linux, DOS
Headers to include: curl.bi
Header version: 7.44.0
Examples: in examples/network/curl/

Example
   '' Curl HTTP Get example

   #include Once "curl.bi"
   #include Once "crt/string.bi"

   '' this callback will be called when any data is received
   Private Function write_callback cdecl _
      ( _
         ByVal buffer As Byte Ptr, _
         ByVal size As Integer, _
         ByVal nitems As Integer, _
         ByVal outstream As Any Ptr _
      ) As Integer

      Static As ZString Ptr zstr = 0
      Static As Integer maxbytes = 0

      Dim As Integer bytes = size * nitems

      '' current zstring buffer too small?
      If( maxbytes < bytes ) Then
         zstr = Reallocate( zstr, bytes + 1 )
         maxbytes = bytes
      End If

      '' "buffer" is not null-terminated, so we must dup it and add the null-term
      memcpy( zstr, buffer, bytes )
      zstr[bytes] = 0

      '' just print it..
      Print *zstr

      Return bytes
   End Function

      '' init
      Dim As CURL Ptr curl = curl_easy_init( )
      If( curl = 0 ) Then
         End 1
      End If

      '' set url and callback
      curl_easy_setopt( curl, CURLOPT_URL, "freebasic.net" )
      curl_easy_setopt( curl, CURLOPT_WRITEFUNCTION, @write_callback )

      '' execute..
      curl_easy_perform( curl )

      '' shutdown
      curl_easy_cleanup( curl )



--------------------------------------------------------- ExtLibFastCGI ----
FastCGI

Open extension to CGI that provides high performance without the 
limitations of server specific APIs.

Website: https://web.archive.org/web/20080213023105/http://www.fastcgi.com:80/ http://www.fastcgi.com (archived copy from 2006)
Github: https://github.com/FastCGI-Archives
See also Forum: https://freebasic.net/forum/viewtopic.php?f=14&t=28126
Platforms supported: Win32, Linux
Headers to include: fastcgi/fastcgi.bi, fastcgi/fcgiapp.bi, 
fastcgi/fcgi_stdio.bi
Header version: 2.4.1-SNAP-0311112127

Example
   #include "fastcgi/fcgi_stdio.bi"

   Dim As Integer count = 0
   While (FCGI_Accept() >= 0)
      count += 1
      Print !"Content-type: text/html\r\n"
      Print !"\r\n"
      Print "<title>FastCGI Hello!</title>"
      Print "<h1>FastCGI Hello!</h1>"
      Print Using "Request number ### running on host <i>&</i>"; count; *getenv("SERVER_NAME");
   Wend



---------------------------------------------------------- ExtLibZeroMQ ----
ZeroMQ

High-performance asynchronous messaging library

Website: https://www.zeromq.org
Platforms supported: Win32, Linux
Headers to include: zmq/zmq.bi
Header version: 2.1.10




============================================================================
    eXtensible Markup Language (XML)

----------------------------------------------------------- ExtLibexpat ----
Expat

Stream oriented XML parser library with several useful features.

Website: https://libexpat.github.io
Platforms supported: Win32, Linux
Headers to include: expat.bi
Header version: 1.95.8
Examples: in examples/xml/

Example
   '' XML file parser command line tool based on libexpat

   '' Can use zstring or wstring (libexpat or libexpatw):
   '#define XML_UNICODE

   #include Once "expat.bi"
   #include Once "crt/mem.bi"

   #ifndef False
   #define False 0
   #endif
   #define NULL 0

   Const BUFFER_SIZE = 1024

   Type Context
      As Integer nesting
      As XML_char * (BUFFER_SIZE+1) text
      As Integer textlength
   End Type

   Dim Shared As Context ctx

   '' Callback called by libexpat when begin of XML tag is found
   Sub elementBegin cdecl _
      ( _
         ByVal userdata As Any Ptr, _
         ByVal element As Const XML_char Ptr, _
         ByVal attributes As Const XML_char Ptr Ptr _
      )

      '' Show its name
      Print Space(ctx.nesting);*element;

      '' and its attributes (attributes are given as an array of XML_char pointers
      '' much like argv, for each attribute there will apparently be the one
      '' element representing the name and a second element representing the
      '' specified value)
      While (*attributes)
         Print " ";**attributes;
         attributes += 1
         Print "='";**attributes;"'";
         attributes += 1
      Wend
      Print

      ctx.nesting += 1
      ctx.text[0] = 0
      ctx.textlength = 0
   End Sub

   '' Callback called by libexpat when end of XML tag is found
   Sub elementEnd cdecl(ByVal userdata As Any Ptr, ByVal element As Const XML_char Ptr)
      '' Show text collected in charData() callback below
      Print Space(ctx.nesting);ctx.text
      ctx.text[0] = 0
      ctx.textlength = 0
      ctx.nesting -= 1
   End Sub

   Sub charData cdecl _
      ( _
         ByVal userdata As Any Ptr, _
         ByVal chars As Const XML_char Ptr, _  '' Note: not null-terminated
         ByVal length As Integer _
      )

      '' This callback will apparently recieve every data between xml tags
      '' (really?), including newlines and space.

      '' Append to our buffer, if there still is free room, so we can print it out later
      If (length <= (BUFFER_SIZE - ctx.textlength)) Then
         memcpy(@ctx.text[ctx.textlength], @chars[0], length * SizeOf(XML_char))
         ctx.textlength += length
         ctx.text[ctx.textlength] = 0
      End If
   End Sub

   ''
   '' Main
   ''

      Dim As String filename = Command(1)
      If (Len(filename) = 0) Then
         Print "Usage: expat <xmlfilename>"
         End 1
      End If

      Dim As XML_Parser parser = XML_ParserCreate(NULL)
      If (parser = NULL) Then
         Print "XML_ParserCreate failed"
         End 1
      End If

      ''XML_SetUserData(parser, userdata_pointer)
      XML_SetElementHandler(parser, @elementBegin, @elementEnd)
      XML_SetCharacterDataHandler(parser, @charData)

      If (Open(filename, For Input, As #1)) Then
         Print "Could not open file: '";filename;"'"
         End 1
      End If

      Static As UByte buffer(0 To (BUFFER_SIZE-1))

      Dim As Integer reached_eof = False
      Do
         Dim As Integer size = BUFFER_SIZE
         Dim As Integer result = Get(#1, , buffer(0), size, size)
         If (result Or (size <= 0)) Then
            Print "File input error"
            End 1
         End If

         reached_eof = (EOF(1) <> False)

         If (XML_Parse(parser, @buffer(0), size, reached_eof) = False) Then
            Print filename & "(" & XML_GetCurrentLineNumber(parser) & "): Error from XML parser: "
            Print *XML_ErrorString(XML_GetErrorCode(parser))
            End 1
         End If
      Loop While (reached_eof = False)

      XML_ParserFree(parser)



---------------------------------------------------------- ExtLiblibxml ----
libxml2

De-facto standard library for accessing xml files.

Website: http://xmlsoft.org/
Platforms supported: Win32, Linux
Headers to include: libxml/*.bi
Header version: 2.6.17
Examples: in examples/xml/

Example
   #include Once "libxml/xmlreader.bi"
   #define NULL 0

   Dim As String filename = Command(1)
   If( Len( filename ) = 0 ) Then
      Print "Usage: libxml filename"
      End 1
   End If

   Dim As xmlTextReaderPtr reader = xmlReaderForFile( filename, NULL, 0 )
   If (reader = NULL) Then
      Print "Unable to open "; filename
      End 1
   End If

   Dim As Integer ret = xmlTextReaderRead( reader )
   Do While( ret = 1 )
      Dim As Const ZString Ptr constname = xmlTextReaderConstName( reader )
      Dim As Const ZString Ptr value = xmlTextReaderConstValue( reader )

      Print xmlTextReaderDepth( reader ); _
         xmlTextReaderNodeType( reader ); _
         " "; *constname; _
         xmlTextReaderIsEmptyElement(reader); _
         xmlTextReaderHasValue( reader ); _
         *value

      ret = xmlTextReaderRead( reader )
   Loop

   xmlFreeTextReader( reader )

   If( ret <> 0 ) Then
      Print "failed to parse: "; filename
   End If

   xmlCleanupParser( )
   xmlMemoryDump()



--------------------------------------------------------- ExtLiblibxslt ----
libxslt

XSLT itself is a an XML language to define transformation for XML.

Website: http://xmlsoft.org/XSLT/
Platforms supported: Win32, Linux
Headers to include: libxslt/libxslt.bi
Header version: 1.1.13



------------------------------------------------------------ ExtLibmxml ----
mxml, Mini-XML

Mini-XML is a small XML parsing library that you can use to read XML and 
XML-like data files in your application without requiring large 
non-standard libraries.

Website: https://www.msweet.org/mxml/
Github: https://github.com/michaelrsweet/mxml
Platforms supported: Win32, Linux
Headers to include: mxml.bi
Header version: 2.7




============================================================================
    Regular Expressions

------------------------------------------------------------ ExtLibpcre ----
PCRE, Perl Compatible Regular Expressions

Consists of a set of functions that implement regular expression pattern 
matching using the same syntax and semantics as Perl 5.

Website: https://www.pcre.org
Platforms supported: Win32, Linux
Headers to include: pcre.bi, pcre16.bi, prceposix.bi
Version: 8.31
Examples: in examples/regex/PCRE/



------------------------------------------------------------- ExtLibtre ----
TRE (regex matching library)

Lightweight, robust, and efficient POSIX compliant regexp matching library

Website: https://laurikari.net/tre/
Github: https://github.com/laurikari/tre/
Platforms supported: Win32, Linux
Headers to include: tre/tre.bi, tre/regex.bi
Header version: 0.8.0
Examples: in examples/regex/TRE/




============================================================================
    Compression

----------------------------------------------------------- ExtLibbzip2 ----
libbzip2

libbzip2 is the library implementing .bz2 file or in-memory compression and 
extraction, with interfaces similar to zlib.

Website: http://bzip.org/
Platforms supported: Win32, Linux, DOS
Headers to include: bzlib.bi
Header version: 1.0.6
Examples: in examples/compression/



------------------------------------------------------------- ExtLibZip ----
libzip

Easy-to-use library for creating, reading out or modifying .zip archives.

Website: https://libzip.org
Github: https://github.com/nih-at/libzip
Platforms supported: Win32, Linux, DOS
Headers to include: zip.bi
Header version: 0.11.2
Examples: in examples/compression/

Example
   '' .zip unpacking using libzip
   #include Once "zip.bi"

   Sub create_parent_dirs(ByVal file As ZString Ptr)
      '' Given a path like this:
      ''	foo/bar/baz/file.ext
      '' Do these mkdir()'s:
      ''	foo
      ''	foo/bar
      ''	foo/bar/baz
      Dim As UByte Ptr p = file
      Do
         Select Case (*p)
         Case Asc("/")
            *p = 0
            MkDir(*file)
            *p = Asc("/")
         Case 0
            Exit Do
         End Select
         p += 1
      Loop
   End Sub

   '' Asks libzip for information on file number 'i' in the .zip file,
   '' and then extracts it, while creating directories as needed.
   Private Sub unpack_zip_file(ByVal zip As Any Ptr, ByVal i As Integer)
      #define BUFFER_SIZE (1024 * 512)
      Static As UByte chunk(0 To (BUFFER_SIZE - 1))
      #define buffer (@chunk(0))

      '' Retrieve the filename.
      Dim As String filename = *zip_get_name(zip, i, 0)
      Print "file: " & filename & ", ";

      '' Retrieve the file size via a zip_stat().
      Dim As zip_stat stat
      If (zip_stat_index(zip, i, 0, @stat)) Then
         Print "zip_stat() failed"
         Return
      End If

      If ((stat.valid And ZIP_STAT_SIZE) = 0) Then
         Print "could not retrieve file size from zip_stat()"
         Return
      End If

      Print stat.size & " bytes"

      '' Create directories if needed
      create_parent_dirs(filename)

      '' Write out the file
      Dim As Integer fo = FreeFile()
      If (Open(filename, For Binary, Access Write, As #fo)) Then
         Print "could not open output file"
         Return
      End If

      '' Input for the file comes from libzip
      Dim As Any Ptr fi = zip_fopen_index(zip, i, 0)
      Do
         '' Write out the file content as returned by zip_fread(), which
         '' also does the decoding and everything.
         '' zip_fread() fills our buffer
         Dim As Integer bytes = _
            zip_fread(fi, buffer, BUFFER_SIZE)
         If (bytes < 0) Then
            Print "zip_fread() failed"
            Exit Do
         End If

         '' EOF?
         If (bytes = 0) Then
            Exit Do
         End If

         '' Write <bytes> amount of bytes of the file
         If (Put(#fo, , *buffer, bytes)) Then
            Print "file output failed"
            Exit Do
         End If
      Loop

      '' Done
      zip_fclose(fi)
      Close #fo
   End Sub

   Sub unpack_zip(ByRef archive As String)
      Dim As Any Ptr zip = zip_open(archive, ZIP_CHECKCONS, NULL)
      If (zip = NULL) Then
         Print "could not open input file " & archive
         Return
      End If

      '' For each file in the .zip... (really nice API, thanks libzip)
      For i As Integer = 0 To (zip_get_num_entries(zip, 0) - 1)
         unpack_zip_file(zip, i)
      Next

      zip_close(zip)
   End Sub

      unpack_zip("test.zip")

   '' .zip packing using libzip
   #include "zip.bi"

   Sub zipAddFileFromString(ByVal fname As ZString Ptr, ByVal id_d As ZString Ptr, ByVal myData As ZString Ptr)
      Dim As Any Ptr pzo
      Dim As Any Ptr pzsb
      
      pzo = zip_open(fname, ZIP_CREATE, 0)
      If pzo = 0 Then End
      
      pzsb = zip_source_buffer(pzo, myData, Len(*myData), 0)
      If pzsb = 0 Then End
      
      zip_file_add(pzo, id_d, pzsb, ZIP_FL_OVERWRITE)
      zip_close(pzo)
      
      Print "OK"
   End Sub

   Dim As String mytext, myzipfile, myfile

   myText    = "<My text           >......6...3..2"
   myZipFile = "26.zip"
   myFile    = "file3.txt"

   zipAddFileFromString(myZipFile, myFile, myText)

   myFile    = "BIMBO/file3.txt"
   zipAddFileFromString(myZipFile, myFile, myText)

   Sleep



------------------------------------------------------------ ExtLibLzma ----
liblzma

Configurable compression library based around the LZMA algorithm with 
zlib-like API. liblzma is the heart of the xz-utils used to handle the 
.lzma and .xz file formats. It is based on 7-Zip's LZMA SDK.

Website: https://tukaani.org/xz/
Platforms supported: Win32, Linux, DOS
Headers to include: lzma.bi
Header version: 5.0.2
Examples: in examples/compression/



------------------------------------------------------------- ExtLibLzo ----
LZO

LZO is a compression library offering fast compression and very fast 
decompression.

Website: https://www.oberhumer.com/opensource/lzo/
Platforms supported: Win32, Linux, DOS
Headers to include: lzo/lzo.bi
Header version: 2.02

Example
   #include "lzo/lzo1x.bi"

   Dim inbuf As ZString Ptr = @"string to compress (or not, since it's so short)"
   Dim inlen As Integer = Len(*inbuf) + 1
   Dim complen As lzo_uint = 100
   Dim compbuf As ZString Ptr = Allocate(complen)
   Dim decomplen As lzo_uint = 100
   Dim decompbuf As ZString Ptr = Allocate(decomplen)
   Dim workmem As Any Ptr

   Print "initializing LZO: ";
   If lzo_init() = 0 Then
      Print "ok"
   Else
      Print "failed!"
      End 1
   End If

   Print "compressing '" & *inbuf & "': ";

   workmem = Allocate(LZO1X_1_15_MEM_COMPRESS)

   If lzo1x_1_15_compress(inbuf, inlen, compbuf, @complen, workmem) = 0 Then
      Print "ok (" & inlen & " bytes in, " & complen & " bytes compressed)"
   Else
      Print "failed!"
      End 1
   End If

   Deallocate(workmem)

   Print "decompressing: ";

   workmem = Allocate(LZO1X_MEM_DECOMPRESS)

   If lzo1x_decompress(compbuf, complen, decompbuf, @decomplen, NULL) = 0 Then
      Print "ok: '" & *decompbuf & "' (" & complen & " bytes compressed, " & decomplen & " bytes decompressed)"
   Else
      Print "failed!"
      End 1
   End If

   Deallocate(workmem)



--------------------------------------------------------- ExtLibquicklz ----
QuickLZ

Cross-platform fast compression library

Website: https://www.quicklz.com
Platforms supported: Win32, Linux, DOS
Headers to include: quicklz.bi
Header version: 1.5.0
Example: examples/compression/QuickLZ.bas



------------------------------------------------------------ ExtLibzlib ----
zlib

Loss-less data compression library using the Deflate algorithm unencumbered 
by patents.

Website: http://www.zlib.net
Platforms supported: Win32, Linux, DOS
Headers to include: zlib.bi
Header version: 1.2.8
Examples: in examples/compression/

Example
   zlib-based PNG save & load code: 
   http://www.freebasic.net/forum/viewtopic.php?t=3936

   In-memory compression example:
   '' Zlib compress/decompress example, by yetifoot

   #include Once "zlib.bi"

   Dim As Integer errlev

   '' This is the size of our test data in bytes.
   Dim As Integer src_len = 100000

   Print "ZLib test - Version " & *zlibVersion()
   Print
   Print "Test data size      : " & src_len & " bytes." 

   '' The size of the destination buffer for the compressed data is calculated by
   '' the compressBound function.
   Dim As Integer dest_len = compressBound(src_len)

   '' Allocate our needed memory.
   Dim As UByte Ptr src = Allocate(src_len)
   Dim As UByte Ptr dest = Allocate(dest_len)

   '' Fill the src buffer with random, yet still compressable data.
   For i As Integer = 0 To src_len - 1
      src[i] = Rnd * 4
   Next

   '' Store the crc32 checksum of the input data, so we can check if the 
   '' uncompression has worked.
   Dim As UInteger crc = crc32(0, src, src_len)

   '' Perform the compression.  dest_len is passed as its address, because when
   '' the function returns it will contain the size of the compressed data.
   errlev = compress(dest, @dest_len, src, src_len)
   If errlev <> 0 Then
      '' If the function returns a value other than 0 then an error occured.
      Print "**** Error during compress - code " & errlev & " ****"
   End If
   Print "Compressed to       : " & dest_len & " bytes."

   '' NOTE: in normal use in a program, you would store the src_len, in order to
   '' be able to tell uncompress the output size.  However in this example we can
   '' just leave it in src_len.  The same goes for dest_len, which is the compressed
   '' datas size.

   '' Wipe the src buffer before we uncompress to it, so that we can check if the 
   '' decompression has worked.
   For i As Integer = 0 To src_len - 1
      src[i] = 0
   Next

   '' Perform a decompression.  This time we uncompress the data back to src.  
   '' src_len is passed as its address, because when
   '' the function returns it will contain the size of the uncompressed data.
   errlev = uncompress(src, @src_len, dest, dest_len)
   If errlev <> 0 Then
      '' If the function returns a value other than 0 then an error occured.
      Print "**** Error during uncompress - code " & errlev & " ****"
   End If
   Print "Uncompressed to     : " & src_len & " bytes."

   '' Make sure the checksum of the uncompressed data matches our original data.
   If crc <> crc32(0, src, src_len) Then
      Print "crc32 checksum      : FAILED"
   Else
      Print "crc32 checksum      : PASSED"
   End If

   '' Free the buffers used in the test.
   Deallocate(src)
   Deallocate(dest)

   Print
   Print "Press any key to end . . . "
   Sleep




============================================================================
    System APIs

------------------------------------------------------------- ExtLibCRT ----
CRT, the C Runtime Library

Standard C language functions. On Windows, this is implemented in 
msvcrt.dll (however, there also are version-specific msvcrXX.dlls, the Micro
soft Visual C++ runtimes). On Linux, the C runtime is typically implemented 
by glibc. For DOS, FreeBASIC uses DJGPP, which provides a libc library.

Websites: http://msdn.microsoft.com/en-us/library/59ey50w6.aspx, https://www
.gnu.org/software/libc/, http://www.delorie.com/djgpp/
Platforms supported: Win32, Linux, DOS
Headers to include: crt.bi
Function reference: C Runtime Functions
MSDN function reference: http://msdn.microsoft.com/en-us/library/634ca0c2.as
px



------------------------------------------------------------- ExtLibdos ----
DOS API

Provides access to low-level BIOS and DOS calls.

Website: http://freedos.org
Platforms supported: DOS
Headers to include: dos/dos.bi
Examples: in examples/DOS/



------------------------------------------------------ ExtLibdisphelper ----
disphelper

Disphelper is a COM helper library that can be used in plain C. No MFC or 
ATL is required. It allows you to call COM objects with an easy printf 
style syntax.

Website: http://disphelper.sourceforge.net/
Platforms supported: Win32, Linux (using WINE)
Headers to include: disphelper/disphelper.bi
Header version: from 2005

Example
   '' HTTP GET example, using MSXML2

   #define UNICODE
   #include "disphelper/disphelper.bi"

   DISPATCH_OBJ(objHTTP)

   dhInitialize(True)
   dhToggleExceptions(True)

   dhCreateObject("MSXML2.XMLHTTP.4.0", NULL, @objHTTP)

   dhCallMethod(objHTTP, ".Open(%s, %s, %b)", "GET", "http://sourceforge.net", False)
   dhCallMethod(objHTTP, ".Send")

   Dim As ZString Ptr szResponse
   dhGetValue("%s", @szResponse, objHTTP, ".ResponseText")

   Print "Response: "; *szResponse
   dhFreeString(szResponse)

   SAFE_RELEASE(objHTTP)
   dhUninitialize(True)

   '' IExplorer example

   #define UNICODE
   #include "disphelper/disphelper.bi"

   Sub navigate(ByRef url As String)
      DISPATCH_OBJ(ieApp)
      dhInitialize(True)
      dhToggleExceptions(True)

      dhCreateObject("InternetExplorer.Application", NULL, @ieApp)
      dhPutValue(ieApp, "Visible = %b", True)
      dhCallMethod(ieApp, ".Navigate(%s)", url)

      SAFE_RELEASE(ieApp)
      dhUninitialize(True)
   End Sub

      navigate("www.freebasic.net")

   '' VB Script example

   #define UNICODE
   #include "disphelper/disphelper.bi"

   '' This function runs a script using the MSScriptControl.
   '' Optionally returns a result.
   Sub RunScript _
      ( _
         ByVal result_identifier As LPWSTR, _
         ByVal result As LPVOID, _
         ByVal script As LPWSTR, _
         ByVal language As LPWSTR _
      )

      DISPATCH_OBJ(control)
      If (SUCCEEDED(dhCreateObject("MSScriptControl.ScriptControl", NULL, @control))) Then
         If (SUCCEEDED(dhPutValue(control, ".Language = %T", language))) Then
            dhPutValue(control, ".AllowUI = %b", True)
            dhPutValue(control, ".UseSafeSubset = %b", False)

            If (result) Then
               dhGetValue(result_identifier, result, control, ".Eval(%T)", script)
            Else
               dhCallMethod(control, ".Eval(%T)", script)
            End If
         End If
      End If

      SAFE_RELEASE(control)
   End Sub

      dhInitialize(True)
      dhToggleExceptions(True)

      '' VBScript sample
      RunScript(NULL, NULL, !"MsgBox(\"This Is a VBScript test.\" & vbcrlf & \"It worked!\",64 Or 3)", "VBScript")

      '' JScript sample
      Dim As Integer result
      RunScript("%d", @result, "Math.round(Math.pow(5, 2) * Math.PI)", "JScript")
      Print "Result ="; result

      Print "Press any key to exit..."
      Sleep

      dhUninitialize(True)



------------------------------------------------------------ ExtLibGLib ----
GLib

Universal utility library most commonly used with GTK+ and GNOME. Provides 
a main loop implementation for event-based programming, portable 
multi-threading, portable file/pipe I/O, many utilities such as command 
line parsing, timers, XML parsing, regular expressions, Unicode 
manipulation, and also general-purpose data structures.

Website: http://developer.gnome.org/glib/
Platforms supported: Linux, Win32
Headers to include: glib.bi
Version: 2.42.2
Examples: in examples/misc/glib/



--------------------------------------------------------- ExtLibwindows ----
Windows API

Standard API for all Windows Systems, used for example for creating Windows 
GUIs (forms and controls), socket programming, inter-process communication, 
and so much more.

Website: http://msdn.microsoft.com/en-us/library/ee663300.aspx
Platforms supported: Win32, Linux (using WINE)
Headers to include: windows.bi
Examples: yes, in examples/win32/



------------------------------------------------------------- ExtLibX11 ----
X11

The X Windowing System is widely used on Linux as the layer that 
coordinates drawing to the screen by providing windows. It also delivers 
events such as mouse and keyboard input from the kernel to applications. It 
is designed to run as a server that can be contacted through a specific 
protocol. The client's side of the protocol is implemented by libraries 
such as the old Xlib or the more modern XCB. Applications can use these to 
create windows and draw to them. However, typically most developers will 
choose to use a GUI library such as GTK+ (which has an X11 backend) 
instead.

Website: http://www.x.org/, http://xcb.freedesktop.org/
Platforms supported: Linux
Headers to include: X11/*.bi





============================================================================
  USING THE FREEBASIC COMPILER
  ----------------------------


---------------------------------------------------- CompilerInstalling ----
Installing

Installing FreeBASIC, any additionally needed packages, and perhaps a text 
editor or IDE.

Note: If the user specifies directory names during the installation of the 
different components, it is recommended in the chosen names to use only 
alphanumeric ASCII characters without accent and preferably not any space, 
otherwise some paths might not work as expected.

Windows 32bit

   * Download the latest FreeBASIC-x.xx.x-win32.zip package, or the latest 
     FreeBASIC-x.xx.x-win32.exe installer (not recommended for Windows 7 
     and later versions).
   * Depending on the chosen method:
      * Zip package: Extract it where you like, for example at 
        ...\FreeBASIC (no further installation required to use fbc).
      * Installer (not recommended for Windows 7 and later versions): Run 
        it and click through it. The installer will install FreeBASIC at 
        C:\%ProgramFiles%\FreeBASIC, or if you chose a different 
        installation directory, in your chosen directory. Start Menu 
        shortcuts to the website will be installed as well.
   * Unless you already have a source code editor or IDE, you should 
     install one too, as FreeBASIC itself does not include one. An IDE can 
     be used to write and save .bas files and to launch the FreeBASIC 
     Compiler to compile them. The following IDEs are known to explicitly 
     support FreeBASIC:
      * FBIDE
      * FBEdit
      * WinFBE Editor and Visual Designer

   To uninstall FreeBASIC:
         * If previously installed using zip package: simply deleted the 
           directory where you extracted it.
         * If previously installed using installer: remove it from the 
           system's list of installed software (Add/remove programs, 
           Uninstall or change a program).

Windows 64bit

   * Download the latest FreeBASIC-x.xx.x-win64.zip package.
   * Extract it where you like, for example at ...\FreeBASIC (no further 
     installation required to use fbc).
   * You may want to install a source code editor or IDE; also see the 
     Windows 32bit section.

   To uninstall FreeBASIC, simply deleted the directory where you extracted 
   it.

Linux

   * Download the latest 
     FreeBASIC-x.xx.x-linux-x86.tar.gz (32bit) or FreeBASIC-x.xx.x-linux-x86_64.tar.gz (64bit) package
   * Extract the archive, for example by doing right-click -> Extract 
     Here, or manually in a terminal:

   $ cd Downloads
   $ tar xzf FreeBASIC-x.xx.x-linux-x86.tar.gz

         * The FreeBASIC compiler can be used from where it was extracted. 
           Usually it is installed into the /usr/local system directory 
           though, so that the fbc program is available through-out the 
           whole system. To do that, run the included installation script:

   $ cd FreeBASIC-x.xx.x-linux-x86
   $ sudo ./install.sh -i

      The install.sh script can also be given a path as in ./install.sh -i 
      /usr if you prefer to install into a directory other than the default 
      /usr/local. This default is a good choice though, as it avoids mixing 
      with the content of /usr which is usually managed by the 
      distribution's packaging tool.

   * FreeBASIC requires several additional packages to be installed before 
     it can be used to compile executables. In general, these are:

         * binutils
         * libc development files (installing gcc will typically install 
           these too)
         * gcc
         * libncurses development files
         * libtinfo development files (if not already installed by 
           libncurses)
         * X11 development files (for FB graphics programs)
         * libffi development files (for the ThreadCall keyword)
         * gpm (general purpose mouse) daemon and libgpm (only needed for 
           GetMouse support in the Linux console)

      The actual package names to install vary depending on the GNU/Linux 
      distribution.

      For native development (32bit FB on 32bit system, or 64bit FB on 
      64bit system):
         * Debian/Ubuntu:
            * gcc
            * libncurses5-dev
            * libtinfo5 (if not already installed by libncurses5)
            * libffi-dev
            * libgl1-mesa-dev
            * libx11-dev libxext-dev libxrender-dev libxrandr-dev 
              libxpm-dev
         * Fedora:
            * gcc
            * ncurses-devel
            * libffi-devel
            * mesa-libGL-devel
            * libX11-devel libXext-devel libXrender-devel libXrandr-devel 
              libXpm-devel
         * OpenSUSE:
            * gcc
            * ncurses-devel
            * libncurses5
            * libffi-devel
            * xorg-x11-devel

      For 32bit development on a 64bit system:
         * Debian/Ubuntu:
            * gcc-multilib
            * lib32ncurses5-dev
            * libx11-dev:i386 libxext-dev:i386 libxrender-dev:i386 
              libxrandr-dev:i386 libxpm-dev:i386
            * (See comment below re Ubuntu 10.04 LTS)
         * OpenSUSE:
            * gcc-32bit
            * ncurses-devel-32bit
            * xorg-x11-devel-32bit
            * xorg-x11-libX11-devel-32bit
            * xorg-x11-libXext-devel-32bit
            * xorg-x11-libXrender-devel-32bit
            * xorg-x11-libXpm-devel-32bit
            * libffi-devel-32bit

               * Unless you already have a text editor or IDE, you should 
                 install one too, as FreeBASIC itself does not include one. 
                 An IDE can be used to write and save .bas files and to 
                 launch the FreeBASIC Compiler to compile them. The 
                 following IDEs are known to explicitly support FreeBASIC:
      * Geany

   To uninstall FreeBASIC from /usr/local, you can run the install.sh 
   script again, but with the -u option: sudo ./install.sh -u

DOS

   * Download the latest FreeBASIC-x.xx.x-dos.zip archive
   * Find a place for FreeBASIC with at least 13 MiB free space.
   * Unpack the ZIP archive, making sure that the directory structure as 
     used inside the archive is preserved ("PKUNZIP -d" for example). 
   * The top-level directory is named FreeBASIC-x.xx.x-dos (will be 
     truncated to "FREEBASI" in DOS without full LFN support), so you might 
     want to rename it then to a convenient DOS-compliant name not longer 
     than 8 characters and containing no white-spaces, like "FB".
   * All the important files used by the compiler (includes, libs) inside 
     the archive do have DOS-compliant names, therefore DOSLFN is not 
     required to use FreeBASIC, however, some examples and texts do have 
     longer names and will be truncated when extracted without full LFN 
     support.  

   (Note: you can install the DOS version "over" the Windows one or 
   vice-versa, or "merge" those installations later, but rename the FBC.EXE 
   file of the previous installation to FBCW.EXE , FBCD.EXE or such, or it 
   will be overwritten by the new one. Other platform specific files are 
   placed in subdirectories making sure that they won't conflict.)

Compiling under Ubuntu 10.04 LTS, 64-bit:
This comment applies to FB 1.01.0, and may apply to other builds also.
Install all of the Libraries listed above; some of the entries ending in 
":i386" may throw "not found" errors.
To verify that you're using a 64-bit build, use: "uname -a" or "uname -m" 
(it'll show x86_64 for 64-bit, i386 for 32-bit).
Then, when running FBC, an error may appear: "error while loading shared 
libraries: libtinfo.so.5: cannot open shared object file: No such file or 
directory".

"libtinfo.so.5" is available as a separate library in Ubuntu 11.10+, but it 
is built into "ncurses.so.5" in 10.04 LTS. So, we need to re-direct the 
libtinfo references into the ncurses.so.5 libraries:
   * Issue: find / -name 'libtinfo.so.5' - just to verify that there are 
     no confusing references to these libraries anywhere. Any references 
     should be checked, and probably deleted?
   * Change to the folder containing the FBC executable (perhaps 
     "/usr/local/bin/").
   * Issue: ldd fbc - it will list the various library folder(s) being 
     searched (probably "/lib32" in most cases).
   * Issue: sudo ln -s /lib32/libncurses.so.5 /lib32/libtinfo.so.5 
     (assuming "/lib32" was emitted in the previous step).
   * Issue: sudo ln -s /lib32/libtinfo.so.5     /lib32/libtinfo.so 
     (assuming "/lib32"...)
   * Retry!
   * [Unrelated point: if "private" Libraries are needed for compiles, 
     they were expected to be in /usr/local/lib/freebasic/. Now, they may 
     have to be in /usr/local/lib/freebasic/linux-x86/].
   * [Mike Kennedy, Jan, 2015. (This note was not acceptable as a standard 
     "comment" - I don't know why?)].

See also
   * Invoking the Compiler
   * Compiler Command Line Options



-------------------------------------------------- CompilerRequirements ----
Requirements

Windows version
   * The FreeBASIC compiler (fbc.exe) and the executables generated by it, 
     need at least Windows 98 to run.
   * The msvcrt.dll (the Microsoft's C runtime library) must be present 
     (note: it wasn't shipped with Windows 95, but it's installed by many 
     applications and can be also downloaded at: Microsoft).
   * The gfx routines will use Direct2D if found on the host system, 
     otherwise they'll fall back on DirectX, and as last resort on standard 
     Win32 GDI which will work on any Windows system.
   * Unicode wide strings (WSTRING's) only work in Windows 
     NT/2000/XP/2003/Vista or above. Applications that depend on 
     wide-strings will run in Windows 98/Me, but no input/output will work 
     if the character set isn't Latin-based, because those platforms don't 
     support Unicode strings. Windows 95 has most Unicode API functions 
     missing; applications using wide strings won't even be loaded by this 
     specific OS.

Linux version
   * The FreeBASIC compiler (fbc) and the executable generated by it 
     depend on libc, libm, libpthread, libdl and libncurses. These are all 
     standard Linux libraries and should be available by default on all 
     modern distros.
   * When using the gfx routines, the dependencies will increase. 
     FreeBASIC gfx programs will also need libX11, libXext, libXpm, 
     libXrender and libXrandr to be installed on the host system to be 
     executed. This is usually not a problem as long as there's a recent 
     X11 server installed in the system (at least XFree86 4.3.0 or any 
     X.org version).
   * If having a working X11 installation is enough to run FreeBASIC gfx 
     programs, it may be not enough to compile them; you may need to 
     install the X11 development libraries from your Linux packages 
     repository.
   * Unicode wide-strings (WSTRING's) with non-ASCII character sets can 
     only be displayed in console if the locale is set to an UTF-8 version 
     - most modern distros come with support that and char sets other than 
     latin may work only in xterm.

DOS version
   * Official requirement: A DPMI (DOS Protected-Mode Interface) server 
     must be present to run fbc.exe and any executable generated by it. 
     This is not as bad as it looks.  It simply means, that the 
     "CWSDPMI.EXE" file (cca 20 KiB) must be present in the same directory 
     or a place where the PATH environment variable points to. CWSDPMI 
     package: homer.rice.edu...cwsdpmi (note: FreeDOS comes with it already 
     installed). Further, there is a possibility to bypass this problem, 
     and to use alternatively HDPMI, for details see DOS related FAQ .
   * You need a 80386 or newer CPU and cca 4 MiB of RAM. For compiling of 
     large programs or libraries, you will need more. Similar applies to 
     executables generated by FBC, those using FB's graphics library 
     however will need a better/faster CPU (200 MHz (?), work in progress, 
     code not yet fully optimized, and exact minimum not known by now). FBC 
     and executables generated by it need an FPU (80387, 80487, always 
     built-in since Pentium). This requirement can by bypassed using 
     "EMU387" (auto-loaded if needed, but not included in FB packages, see 
     delorie.com/djgpp/... ), or by avoiding floats and (non-trivial) 
     removing float-related startup code.
   * The DOS version should run in any DOS, like FreeDOS, 
     [Enhanced-]DR-DOS (do not use the DR-EMM386's included DPMI, use 
     CWSDPMI or HDPMI), or MS-DOS.  It also works properly under a number 
     of "DOS box" environments that emulate a DOS system, such as the 
     Windows NTVDM; however, some of these environments are not implemented 
     faithfully and contain bugs, so caution should be exercised.
   * Long filenames are supported under systems that supply the long 
     filename API defined by Windows 95, including DOS with an LFN TSR (for 
     example DOSLFN (1) (2)).  Long filename support is not required to use 
     the compiler; however, care must be taken in unpacking the 
     distribution, for example, with a Windows program which creates short 
     names with numeric tails (FREEBA~1) instead of truncating to 8 
     characters (FREEBASI).  The filenames of all files in the distribution 
     should be truncated to 8.3 if the compiler is to be used without long 
     filename support.
   * There are a few limitations, see DOS related FAQ .

See also
   * Installing FreeBASIC
   * Compiler Command Line Options
and
   * Compiler FAQ
   * Win32 related FAQ
   * DOS related FAQ
   * LINUX related FAQ



------------------------------------------------------- CompilerRunning ----
Running

Invoking the compiler after installation.

Windows
   The compiler can be manually invoked from the command-line, or 
   automatically by your IDE/Code Editor. If you're using an IDE, you will 
   usually have to tell it where the compiler was installed, so it can find 
   it. How exactly to do that depends on the IDE. 

   To compile manually, you should append the FreeBASIC installation 
   directory to your PATH environment variable, separating it from previous 
   entries using a semi-colon. Now you can simply use "fbc" from the 
   command prompt, instead of always having to type in the full path (e.g. 
   "C:\FreeBASIC\fbc.exe").

   Then, open a console/command prompt/MS DOS prompt, in the same directory 
   as your program. To compile your program, you can use:

      C:\mystuff\myprogram\> fbc myprogram.bas

   and myprogram.exe will be created in the same directory.

   A console can be launched in a specific directory from Explorer by using 
   Microsoft's "Open Command Window Here" PowerToy on Windows XP. On 
   Windows Vista & above you can SHIFT+RightClick on a folder in Explorer 
   to see the 'Open Command Window Here' option. As a last resort, you can 
   also select Start -> Run, type "cmd" and hit Enter, and use the "cd" 
   command to change the current directory.

   Note: You can in fact invoke the compiler from any directory you like, 
   but you have to specifiy the correct path to your program, so the 
   compiler can find it, for example:

      C:\> fbc mystuff\myprogram\myprogram.bas

   The resulting executable will still be put in the same directory as the 
   program.

Linux
   If the install.sh script was successfully executed with enough 
   priviledges, the compiler binary should have been copied 
   /usr/local/bin/fbc, allowing any user access to the compiler from any 
   directory.

   From the prompt, type,

       fbc

   to see a list of options.  To compile the "Hello, world!" example 
   program, navigate to the directory where the FreeBASIC examples were 
   installed (/usr/local/share/freebasic), and type,

      fbc examples/misc/hello.bas

   and a ./hello executable file will be created in the examples/misc 
   directory.

Linux (standalone)
   If the install script install-standalone.sh was successfully executed 
   with enough privileges, a link to the compiler binary should have been 
   created at /usr/bin/fbc, allowing any user access to the compiler from 
   any directory. If it was not possible to create the link, you may want 
   to alter your PATH environmental variable to be able to invoke the 
   compiler from any directory. Navigate to the directory where FreeBASIC 
   was installed.

   From the prompt, type,

       fbc

   to see a list of options. To compile the "Hello, world!" example program 
   type,

      fbc examples/misc/hello.bas

   and a ./hello executable file will be created in the examples/misc 
   directory.

DOS
   Navigate to the directory where FreeBASIC was installed. For example, if 
   FreeBASIC is installed in the directory C:\FB, type,

      C:
      CD FB

   Some DOSes accept "CDD C:\FB" as well. You can also add the FreeBASIC 
   directory to your PATH environment variable (usually something like "SET 
   PATH=C:\FB\;%PATH%") so you can invoke the compiler from any directory.

   At the prompt, type,

      fbc

   to see a list of options. To compile the "Hello, world!" example program 
   type,

      fbc examples\misc\hello.bas

   and a hello.exe executable file will be created in the examples\misc 
   directory.

See also
   * Installing FreeBASIC
   * Compiler Command Line Options
   * Compiler FAQ



------------------------------------------------------- CompilerCmdLine ----
fbc command-line

Using the fbc command-line.

   The official FreeBASIC distribution comes with fbc, FreeBASIC's flagship 
   compiler. fbc is a command line compiler, and can be launched from the 
   console - from DOS, the Windows command prompt or a Linux shell. Running 
   fbc from the console without any arguments displays a list of available 
   options, or command-line switches, that can be used to adjust the 
   behavior of the compiler.

   At its simplest, fbc takes a source file as a command-line argument and 
   produces an executable file. It does this by compiling the source file 
   (.bas) into an assembly (.asm) file, then compiling this into an object 
   file (.o) using GAS and finally linking using LD this object file to 
   other object files and libraries it needs to run, producing the final 
   executable file. The assembly and compiled object files are deleted at 
   this point by default. For example, the following command,

      fbc foo.bas

   produces the executable foo.exe in DOS and Windows, and ./foo in Linux. 
   fbc can accept multiple source files at once, compile and link them all 
   into one executable. For example, the following command,

      fbc foo.bas bar.bas baz.bas

   produces the executable foo.exe in DOS and Windows, and ./foo in Linux. 
   Since foo.bas was listed first, it will be the main entry point into the 
   executable, and also provide its name. To specify a different entry 
   point or executable name, use the "-m" and "-x" switches, respectively. 
   To have, for example, baz.bas provide the main entry point into an 
   executable called foobar.exe, you would use

      fbc -x foobar.exe -m baz foo.bas bar.bas baz.bas

   The "-x" switch names the executable verbatim, so in Linux, the 
   executable produced from the above command would be called ./foobar.exe.

Syntax
   fbc [ options ] [ input_list ]

   Where input_list is a list of filenames. Accepted files are:

         +--------------+--------------------------------+
         |File extension|Description                     |
         |.bas          |FreeBASIC source file           |
         |.a            |Library                         |
         |.o            |Object file                     |
         |.rc           |Resource script (Windows only)  |
         |.res          |Compiled resource (Windows only)|
         |.xpm          |X icon pixmap (Linux only)      |
         +--------------+--------------------------------+

Source code
   -b < name >
      Add a source file to compilation
   -i < name >
      Add a path to search for include files
   -include < name >
      Include a header file on each source compiled
   -d < name=val >
      Add a preprocessor's define
   -lang < name >
      Select language mode: fb, fblite, qb, deprecated
   -forcelang < name >
      Select language mode: fb, fblite, qb, deprecated (overrides 
      statements in code)

Code generation
   -target < platform >
      Set the target platform for cross compilation
   -gen < backend >
      Sets the compiler backend (default is 'gas' for x86 and 'gcc' for 
      x86_64)
   -asm < format >
      Sets the assembler format for Asm block
   -arch < type >
      Set target architecture
   -O < level >
      Set the optimization level (-gen gcc)
   -vec < level >
      Set level of vector optimizations enabled by the compiler (default: 0
      )
   -fpu < type >
      Set the floating point arithmetics unit (default: X87)
   -fpmode < type >
      Select between fast and accurate floating-point operations (default: 
      PRECISE)
   -z < value >
      Sets miscellaneous or experimental options
   -pic
      Generate position-independent code (non-x86 Unix shared libs)

Compilation
   -m < name >
      Define main file (without extension), the entry point (default is the 
      first .bas file on the command line)
   -entry < name >
      Override public exported name of implicit user main function
   -g
      Add debug info
   -profgen < profiler >
      Enable function profiling by selecting a specific profiler
   -profile
      Enable function profiling for gmon/gprof
   -e
      Add error checking
   -ex
      Add error checking with RESUME support
   -exx
      Same as -ex, plus array bounds and dimensions, null-pointer, and 
      error location reporting
   -eunwind
      Enable stack unwind information
   -Wa < opt >
      Pass options to GAS (separated by commas)
   -Wc < opt >
      Pass options to GCC (separated by commas)
   -o < name >
      Set object file path/name (must be passed after the .bas file)
   -earray
      Enable array bounds checking
   -earraydims
      Enable array dimensions checking
   -eassert
      Enable assert() and assertwarn() checking
   -edebug
      Enable __FB_DEBUG__
   -edebuginfo
      Add debug information
   -elocation
      Enable full error location reporting
   -enullptr
      Enable null-pointer checking

Linking
   -a < name >
      Add an object file to linker's list
   -l < name >
      Add a library file to linker's list
   -p < name >
      Add a path to search for libraries
   -mt
      Link with thread-safe runtime library
   -nodeflibs
      Do not include the default libraries
   -nolib < name(s) >
      Do not include specific library(s)
   -static
      Prefer static libraries over dynamic ones when linking
   -map < name >
      Save the linking map to file name
   -Wl < opt >
      Pass options to LD (separated by commas)
   -export
      Export symbols for dynamic linkage
   -lib
      Create a static library
   -dylib
      Create a DLL, including the import library
   -dll
      Create a DLL, including the import library.  (Same as -dylib)
   -x < name >
      Set executable/library path/name
   -nostrip
      Do not strip symbol information from the output file
   -strip
      Omit all symbol information from the output file
   -sysroot < path >
      Tell the linker where to find libraries (needed by some toolchains)

Behaviour
   -prefix < path >
      Set the compiler prefix path
   -buildprefix < name >
      Set the internal buildprefix option
   -version
      Show compiler version on the command line, do not compile or link
   -v
      Be verbose
   -print < option >
      Display certain information (fblibdir, host, target, x)
   -pp
      Emit the preprocessed input file only, do not compile
   -r
      Compile into intermediate file(s) only, do not assemble or link
   -rr
      Compile into asm file(s) only, do not assemble or link
   -c
      Compile and assemble source file only, do not link
   -R
      Do not delete the intermediate file(s)
   -RR
      Do not delete the asm file(s)
   -C
      Do not delete the object file(s)
   -w < value >
      Set min warning level: all, none, param, escape, pedantic, next, 
      funcptr, constness, suffix, error, upcast or a value
   -maxerr < val >
      Only stop parsing if <val> errors occurred
   -noerrline
      Do not show source line where error occurred
   -noobjinfo
      Do not read/write compile-time info from/to .o and .a files
   -showincludes
      Display a tree of file names of #included files

Target specific
   -s < name >
      Set subsystem (gui, console)
   -t < value >
      Set stack size in kbytes (default: 1 MB or 2 MB)

Meta
   @< file >
      Read (additional) command-line options from a file

Example
   fbc myfile.bas
      (With DOS version of FBC, compile and link a DOS executable 
      MYFILE.EXE.)

   fbc -s gui myfile.bas
      (With Windows version of FBC, compile and link a Windows executable 
      myfile.exe. Running the program will not show the console window 
      ("MS-DOS Prompt"))

   fbc -lib module1.bas module2.bas module3.bas -x libmylib.a
      (Compile and link a static library libmylib.a from the three source 
      files)

   fbc -m main_module -c main_module.bas
      (Compile an object file main_module.o and mark it as an entry point)

   fbc -c sub_module.bas
      (Compile an object file sub_module.o)

   fbc -x application.exe main_module.o sub_module.o
      (Link an executable application.exe)

   Note: How to include an icon in a FB executable program
      There is a simple command line option to compile a FB program into an 
      executable with an Icon:
         - Create a *.rc file, for example appicon.rc, with this info:
               FB_PROGRAM_ICON ICON "appicon.ico"
                  (where appicon.ico is the name of icon)
         - Then when compiling program, add appicon.rc in the list of files 
         to compile.

See also
   * Compiler Options
   * Installing FreeBASIC
   * Invoking the FreeBASIC compiler
   * #Cmdline





============================================================================
  COMMAND LINE OPTIONS
  --------------------


---------------------------------------------------- CompilerOptoptfile ----
Compiler Option: @file

Read (additional) command-line options from the file

Syntax
      @file

Parameters
   file
      Name of a text file containing command line options. It's possible to 
      use multiple lines in the file. The options may be separated by 
      spaces or line breaks, and support double-quoted strings to allow 
      spaces in parameters (like the real command line). This file can 
      itself contain additional @file options.

Description
   The @file compiler option tells the compiler to parse the specified file 
   to find more command line options. The options found in the file are 
   treated as if they were found on the command line. This can be useful to 
   pass very long command lines to the compiler, for example on DOS, where 
   command lines are limited in length.

Example
options.txt:

   -d TEST=123

opts.bas:
   Print "TEST=" & TEST

   Compile with:

      fbc @options.txt opts.bas

Output:

   TEST=123

See also
   * Using the Command Line



---------------------------------------------------------- CompilerOpta ----
Compiler Option: -a

Add an object file to the linker's list

Syntax
      [ -a ] < object file >

Parameters
   object file
      Name of the object file with extension.

Description
   The -a compiler option adds a compiled object file to the linker's list. 
   The "-a" is optional if the object file name has a ".o" file extension.

See also
   * Compiler Option: -b
   * Using the Command Line



------------------------------------------------------- CompilerOptarch ----
Compiler Option: -arch

Set target architecture for improved/restricted code generation or 
cross-compiling

Syntax
   -arch < architecture >

Parameters
   architecture
      The target architecture. Recognized values:

         * Related to 32bit x86:
            * 386
            * 486
            * 586 (default for x86 on DOS)
            * 686 (default for x86 except on DOS)
            * athlon
            * athlon-xp
            * athlon-fx
            * k8-sse3
            * pentium-mmx
            * pentium2
            * pentium3
            * pentium4
            * pentium4-sse3
            * x86
         * Related to 64bit x86_64:
            * x86_64, x86-64, amd64
         * Related to 32bit ARM:
            * armeabi
            * armeabi-v7a (default for arm-android)
            * armv5 (alias for armv5te)
            * armv5te (default for armeabi)
            * armv6
            * armv7 (alias for armv7-a)
            * armv7a (alias for armv7-a)
            * armv7-a (default for ARM, but the toolchain may interpret as 
              armv7-a+fp)
            * armv7-a+fp
            * There are variations of arm architecture in the wild and 
              interpretations will vary across toolchains and time
         * Related to 64bit ARM (AArch64):
            * aarch64
         * Related to 32bit PowerPC:
            * powerpc (big endian)
         * Related to 64bit PowerPC:
            * powerpc64 (big endian)
            * powerpc64le (little endian)
         * Others:
            * native: For compiling to the architecture which the compiler 
              is running on.
            * 32, 64: For quick cross-compiling to the 32bit or 64bit 
              version of the default architecture.

Description
   The -arch compiler option sets the target CPU architecture. This can be 
   used for multiple purposes:
      * Improving code generation; for example: You can use -arch 
        pentium4-sse3 to override the default -arch 686, and the compiler 
        will generate faster code in some cases, by using certain 
        instructions which were not available on i686.
      * Restricting code generation; for example: You can use -arch 386 to 
        limit the compiler to using only i386-compatible instructions.
      * Cross-compiling; for example: You can use -arch x86_64 on 32bit 
        x86 systems to cross-compile to 64bit x86_64.

   The exact impact which the -arch setting has on code generation depends 
   on the code generation backend that is being used. The x86 ASM backend (
   -gen gas) handles the -arch setting and adjusts code generation 
   accordingly in some cases. When using the GCC backend (-gen gcc), the 
   specified architecture will be passed on to gcc via gcc -march=<...>, 
   causing gcc to generate code for the specified architecture.

   However, -arch only affects newly generated code, but not pre-compiled 
   code such as the FreeBASIC runtime libraries, or any other library from 
   the lib/ directory. For example, using -arch 386 is not necessarily 
   enough to get a pure i386 executable -- it also depends on how all the 
   libraries that will be linked in were compiled.

   The -arch 32 and -arch 64 shortcuts are similar to gcc's -m32/-m64 
   options. On 32bit architectures, -arch 64 is an abbreviation for 
   cross-compiling to the default 64bit version of the architecture (e.g. 
   from 32bit x86 to 64bit x86_64, or 32bit ARM to 64bit AArch64, or 32bit 
   PowerPC to 64bit PowerPC), and -arch 32 does nothing. On 64bit systems, 
   it is the other way round: -arch 32 cross-compiles to the default 32bit 
   architecture, while -arch 64 does nothing.

   The -arch native shortcut is similar to gcc's -march=native option. On 
   x86, it causes fbc to try and detect the host CPU automatically based on 
   the cpuid instruction and its availability or results. On other 
   architectures, this will currently simply use the architecture which the 
   compiler itself was built for. Under -gen gcc this will use gcc 
   -march=native.

   Specifying an -arch setting incompatible to the native architecture will 
   trigger cross-compilation, just like the -target option, except that 
   only the target architecture, but not the target operating system, is 
   changed.

Version
   * Before fbc 1.10.0, default was 486 for 32bit x86.

See also
   * Using the Command Line
   * -target
   * FB and cross-compiling



-------------------------------------------------------- CompilerOptasm ----
Compiler Option: -asm

Set assembler format for inline assembly under -gen gcc

Syntax
   -asm < format >

Parameters
   format
      The assembler format: intel or att

Description
   The -asm compiler option sets the assembler format for inline Asm blocks 
   when using -gen gcc.

      * -gen gcc -asm intel: FB inline assembly blocks must use FB's usual 
        Intel syntax format. Under -gen gcc, fbc will try to translate it 
        to gcc's format automatically. For example:
   Dim a As Long = 1
   Print a
   Asm
      inc dword Ptr [a]
   End Asm
   Print a

               * -gen gcc -asm att: FB inline assembly blocks must use 
                 gcc's format. For example:
   Dim a As Long = 1
   Print a
   Asm
      "incl %0\n" : "+m" (a) : :
   End Asm
   Print a

   The x86 ASM backend (-gen gas) currently only supports -asm intel and 
   using -asm att results in an error.

See also
   * __FB_ASM__
   * Using the Command Line



---------------------------------------------------------- CompilerOptb ----
Compiler Option: -b

Add a source file to compilation

Syntax
      [ -b ] < source file >

Parameters
   source file
      The name with extension, and optionally a path, of the basic source 
      file.

Description
   The -b option adds a source file to the compilation list. In general, 
   this option is redundant since source files with a .bas extension can be 
   specified without it, but is useful if a source file does not have a 
   .bas extension, or if exists in an other directory.

   To compile and link the source files file1.bas, file2.bas and file3.fb 
   into an executable (file1.exe in DOS/Windows, file1 in Linux), type,

      fbc -b file1.bas file2.bas -b file3.fb

   Note that the -b option was not needed for file1.bas or file2.bas.

See also
   * Compiler Option: -a
   * Using the Command Line



------------------------------------------------ CompilerOptbuildprefix ----
Compiler Option: -buildprefix

Set the internal buildprefix option.

Syntax
   -buildprefix < name >

Parameters
   name
      name to override the internal buildprefix option.

Description
   The -buildprefix command line option overrides the internal buildprefix 
   option.

   Detailed behavior if using -buildprefix, -prefix, -target command line 
   options
      fbc's default options should work for native builds.
      When building for other platforms or developing and building with 
      multiple tool chains, these command line options can help ease the 
      needs of various non-native or uncommon compilations:
         * Default prefix:
               - prefix may have been compiled in when fbc itself was 
               compiled, in which case the default prefix is determined by 
               fbc's build/makefile option 'ENABLE_PREFIX'
            If fbc was not compiled with 'ENABLE_PREFIX':
               - standalone: prefix = <fbc path>/
               - normal : prefix = <fbc path>/../
         * Override default prefix:
               - if the '-prefix <path>' command line option given, 
               overrides the default prefix
         * Default target:
               - determined by target build for fbc itself by fbc's 
               makefile
         * Override default target:
               - if the '-target <target>' command line option given, 
               overrides the default target
         * Default buildprefix:
               - always empty
         * Override default buildprefix:
               - if the '-buildprefix <name>' command line option given, 
               overrides the default build prefix
         * Default binary, include, and library paths:
               - binary path: where tools are located (AS, LD, AR, etc)
               - include path: location of fbc's '*.bi' files
               - library path: where fbc's libraries are located (static 
               libraries and import libraries)
               - toolname: the name of a specific tool, which may include 
               the path for a specific location, or the name of the tool 
               only if relying on PATH environment variable
            standalone fbc:
               - binary path = <prefix>/bin/<target>/
               - toolname = <binary path> + <buildprefix> + <tool name>
               [.exe]
               - include path = <prefix>/inc
               - library path = <prefix>/lib/<target>
            normal fbc:
               - default binary path:
                  - binary path = <prefix>/bin/<target->
               - or if '-buildprefix' given:
                  - binary path = <prefix>/bin/<buildprefix>
               - toolname = <binary path> + <tool name>[.exe]
               - If binary tool not found, then rely on PATH environment 
               variable to find:
                  - toolname = <target-|buildprefix> + <tool name>
               - include path = prefix/include/freebasic
               - library path = prefix/lib[64]/freebasic/target
         * Environment variables override tool name and path completely:
               - environment variables can override the tool name and path 
               completely
               - 'AS' overrides gnu assembler tool
               - 'AR' overrides gnu archiver tool
               - 'LD' overrides gnu linker
               - 'GCC' overrides gnu C compiler
               - 'LLC' overrides LLVM compiler
               - 'CLANG' overrides clang C compiler (currently never used)
               - 'DLLTOOL' overrides gnu dlltool (GAS)
               - 'GORC' overrides resource tool (if fbc was compiled with 
               ENABLE_GORC)
               - 'WINDRES' overrides resource tool (if fbc was compiled 
               without ENABLE_GORC)
               - 'CXBE' overrides xbox xbe generator tool
               - 'DXE3GEN' overrides djgpp DOS dll tool
               - 'EMAR' overrides emscripten archiver ool
               - 'EMCC' overrides emscripten assember, compiler, and linker 
               tools

      The tool name prefix (stored in the binary path) is set by default 
      with 'target' + '-'.
      '-buildprefix <name>' overrides the tool name prefix.

      When 'binary path' is set (internally in the fbc compiler), it 
      includes the prefix of the tool name.

      For examples:
         fbc -prefix /pppp/ -target tttt source.bas
            gnu-AS invoked is: /pppp/bin/tttt-as

         fbc -prefix /pppp/ -target tttt -buildprefix bbbbX source.bas
            gnu-AS invoked is: /pppp/bin/bbbbXas

      '-prefix' command line option controls top level path for fbc.
      '-target' command line option controls code generation and many 
      related options including the default tool name prefix.
      '-buildprefix' command line option overrides the default tool name 
      prefix.

Version
   * Since fbc 1.10.0

See also
   * -prefix
   * -target
   * Using the Command Line



---------------------------------------------------------- CompilerOptc ----
Compiler Option: -c

Compile and assemble source file only, do not link

Syntax
   -c

Description
   The -c option specifies that any source files listed are to be compiled 
   and assembled into object files, and not linked into an executable (the 
   default behavior). When using the "-c" switch, "-m" must be specified 
   when compiling a main source file.

See also
   * Compiler Option: -C
   * Compiler Option: -r
   * Compiler Option: -m
   * Compiler Option: -o
   * Using the Command Line



------------------------------------------------------- CompilerOptcupp ----
Compiler Option: -C

Do not delete the object file(s)

Syntax
   -C

Description
   The -C compiler option causes the object file(s) that are generated 
   during the compile process to not be deleted.

See also
   * Compiler Option: -c
   * Compiler Option: -R
   * Using the Command Line



---------------------------------------------------------- CompilerOptd ----
Compiler Option: -d

Add a preprocessor definition

Syntax
   -d < name=value >
   -d < name >

Parameters
   name
      Name of the preprocessor macro to define.  No parameters are allowed.
   value
      Value to give to the macro.  If omitted, it will be defined as 1

Description
   The -d compiler option adds a preprocessor macro to all source files. 
   The same as using the preprocessor directive #define or #macro.

See also
   * #define
   * #macro
   * Intrinsic Defines
   * Using the Command Line



-------------------------------------------------------- CompilerOptdll ----
Compiler Option: -dll

Create a DLL and import library

Syntax
      -dll

Description
   The -dll compiler option creates a dynamic link library. This creates a 
   DLL under Windows (including the import library), creates a .so under 
   Linux, and a DXE under DOS.

   Note: Same as -dylib

   The intrinsic macro __FB_OUT_DLL__ is set to non-zero (-1) if the -dll 
   option was specified, and set to zero (0) otherwise.

Platform Differences
   * On windows, dynamic link library is created with ".dll" file name 
     extension and import library created as "lib<name>.dll.a" file name
   * On Linux, dynamic link library is created with ".so" file name 
     extension
   * On DOS, dynamic link library is created with ".dxe" file name 
     extension and import library created as "lib<name>_il.a" file name

See also
   * __FB_OUT_DLL__
   * Shared Libraries
   * Using the Command Line



------------------------------------------------------ CompilerOptdylib ----
Compiler Option: -dylib

Create a DLL and import library

Syntax
   -dylib

Description
   The -dylib compiler option creates a dynamic link library. This creates 
   a DLL under Windows (including the import library), creates a .so under 
   Linux, and a DXE under DOS.

   Note: Same as -dll.

   The intrinsic macro __FB_OUT_DLL__ is set to non-zero (-1) if the -dll 
   option was specified, and set to zero (0) otherwise.

Platform Differences
   * See Compiler Option: -dll

See also
   * __FB_OUT_DLL__
   * Shared Libraries
   * Using the Command Line
   * Compiler Option: -dll



---------------------------------------------------------- CompilerOpte ----
Compiler Option: -e

Add error checking

Syntax
   -e

Description
   Adds QuickBASIC-like error checking.

See also
   * __FB_ERR__
   * Compiler Option: -ex
   * Compiler Option: -exx
   * Error Handling
   * Using the Command Line



----------------------------------------------------- CompilerOptearray ----
Compiler Option: -earray

Enable array bounds checking

Syntax
   -earray

Description
   Add array bounds error checking in generated run-time code.  A run-time 
   error is generated if an array index attempts to access an array element 
   that is outside the bounds of the array.

   -earray is automatically implied by the -exx option.

   __FB_ERR__ can be used to determine in user source code if the -earray 
   option was specified or implied on the command line.

Version
   * Since fbc 1.07.0

See also
   * __FB_ERR__
   * Compiler Option: -exx
   * Error Handling
   * Using the Command Line



------------------------------------------------- CompilerOptearraydims ----
Compiler Option: -earraydims

Enable array dimensions checking.

Syntax
   -earraydims

Description
   The -earraydims compiler option enables the array dimensions checking. 
   Enabled by default with '-exx' command line option.

Version
   * Since fbc 1.20.0

See also
   * __FB_ERR__
   * Using the Command Line



---------------------------------------------------- CompilerOpteassert ----
Compiler Option: -eassert

Enable assert() and assertwarn() checking

Syntax
   -eassert

Description
   The -eassert compiler option enables Assert and AssertWarn code 
   generation.

   -eassert is automatically implied by the -g option.

   __FB_ERR__ can be used to determine in user source code if the -eassert 
   option was specified or implied on the command line.

Version
   * Since fbc 1.07.0

See also
   * __FB_ERR__
   * Assert
   * AssertWarn
   * Compiler Option: -g
   * Debugging
   * Using the Command Line



----------------------------------------------------- CompilerOptedebug ----
Compiler Option: -edebug

Enable __FB_DEBUG__

Syntax
   -edebug

Description
   The -edebug compiler option defines the intrinsic macro __FB_DEBUG__ to 
   enable user debug code.

   The intrinsic macro __FB_DEBUG__ is set to non-zero (-1) if the option 
   was specified, and set to zero (0) otherwise.

   -edebug is automatically implied by the -g option.

   __FB_ERR__ can be used to determine in user source code if the -edebug 
   option was specified or implied on the command line.

Version
   * Since fbc 1.07.0

See also
   * __FB_DEBUG__
   * __FB_ERR__
   * Compiler Option: -eassert
   * Compiler Option: -debuginfo
   * Compiler Option: -g
   * Debugging
   * Using the Command Line



------------------------------------------------- CompilerOptedebuginfo ----
Compiler Option: -edebuginfo

Add debug information

Syntax
   -edebuginfo

Description
   The -edebuginfo compiler inserts debugging symbols into output files, to 
   use with GDB-compatible debuggers.

   -edebuginfo is automatically implied by the -g option.

   __FB_ERR__ can be used to determine in user source code if the 
   -edebugingo option was specified or implied on the command line.

Version
   * Since fbc 1.07.0

See also
   * __FB_ERR__
   * Compiler Option: -g
   * Debugging
   * Using the Command Line



-------------------------------------------------- CompilerOptelocation ----
Compiler Option: -elocation

Enable full error location reporting

Syntax
   -elocation

Description
   The -elocation compiler option enables full location reporting in 
   run-time code generation.

   -elocation is automatically implied by the -exx option.

   __FB_ERR__ can be used to determine in user source code if the 
   -elocation option was specified or implied on the command line.

   Note: the intent of this option is for a future fbc feature to optimize 
   out some of the error tracking code associated with error location 
   reporting.  When implemented, only -exx or -elocation will enable the 
   full error location reporting and will be optimized away otherwise.

Version
   * Since fbc 1.07.0

See also
   * __FB_ERR__
   * Compiler Option: -exx
   * Error Handling
   * Using the Command Line



------------------------------------------------------ CompilerOptentry ----
Compiler Option: -entry

Override the public exported name of the implicit user main function

Syntax
   -entry < name >

Parameters
   name
      The custom name that overrides the public exported name of the 
      implicit user main function

Description
   The -entry compiler option changes the name of the publicly export 
   symbol of the implicit user main function (automatically generated by 
   fbc as start-up code).
   It affects the start-up code and implicit user main, which is also 
   affected by the module being the main module or not.

   By default, fbc defines a publicly exported 'main' symbol in the main 
   module as required by the run time start-up system code.
   There is no other way currently to override fbc's use of the 'main' 
   symbol other than to always compile and link separately.

   Proceedings:
      - The custom main function name must only be declared with the 
      following signature (same parameter types, same return type, same 
      calling convention) to be compatible with the (basic) main function:
   '' internally the implicit main function is now named "custom_main"
   Declare Function custom_main cdecl Alias "custom_main" ( ByVal argc As Long, ByVal argv As ZString Ptr Ptr ) As Long
            

      - The (basic) main function must also be provided to satisfy the 
      linker and start-up code. This might be defined in another libray or 
      framework, in C, or ASM, or fb language as shown by the following 
      minimum code example:
   Function main cdecl Alias "main" ( ByVal argc As Long, ByVal argv As ZString Ptr Ptr ) As Long
      '' .....
      '' call the custom main
      Return custom_main( argc, argv )
   End Function
            

      - Then compile with the -entry custom_main option.

   Note:
      This feature is being developed and may change in future (see 
      Compiler Option: -entry in Documentation forum).
      There will maybe a better way to deal with this: a compiler option 
      that lets to outright specify an explicit "main".

Example
   Example of program (option_entry.bas) trying to show the minimal code 
   for fb language only:
   '' option_entry.bas:

   '' - demonstrate alternate named main function
   ''   as an alternate entry point for the implicit user main
   '' - we also can compile and link in separate steps

   '' compile: $ fbc -c -m option_entry option_entry.bas -entry custom_main
   '' compile: $ fbc option_entry.o
   '' OR
   '' compile: $ fbc option_entry.bas -entry custom_main

   '' internally the implicit main function is now named "custom_main"
   Declare Function custom_main cdecl Alias "custom_main" ( ByVal argc As Long, ByVal argv As ZString Ptr Ptr ) As Long

   '' But we still need a main() function to satisfy the linker and start-up code
   '' - this might be defined in another libray or framework
   '' - it's not so let's define it here for the demonstration
   Function main cdecl Alias "main" ( ByVal argc As Long, ByVal argv As ZString Ptr Ptr ) As Long
      '' just call our custom main for demonstration
      Return custom_main( argc, argv )
   End Function

   '' ---------------------------------
   '' START OF USER'S IMPLICIT MAIN
   '' internally this is named "custom_main" and will automatically be
   '' called by our custom frame work

   Print "hello"
   Sleep

   '' END OF USER'S IMPLICIT MAIN
   '' ---------------------------------
         

Version
   * Since fbc 1.09.0

See also
   * Compiler Option: -m
   * Executables



--------------------------------------------------- CompilerOptenullptr ----
Compiler Option: -enullptr

Enable null-pointer checking

Syntax
   -enullptr

Description
   The -enullptr compiler option enables null-pointer error checking in 
   run-time code generation.  A run-time error is generated if an attempt 
   is made to dereference a null-pointer to a value, or call a null 
   function pointer.

   -enullptr is automatically implied by the -exx option.

   __FB_ERR__ can be used to determine in user source code if the -enullptr 
   option was specified or implied on the command line.

Version
   * Since fbc 1.07.0

See also
   * __FB_ERR__
   * Compiler Option: -exx
   * Error Handling
   * Using the Command Line



---------------------------------------------------- CompilerOpteunwind ----
Compiler Option: -eunwind

Enable stack unwind information.

Syntax
   -eunwind

Description
   The -eunwind compiler option turns on the code generation and link 
   options to enable stack unwind information.

Version
   * Since fbc 1.10.0

See also
   * __FB_ERR__
   * Using the Command Line



--------------------------------------------------------- CompilerOptex ----
Compiler Option: -ex

Add error checking with Resume support

Syntax
   -ex

Description
   The -ex compiler option adds error handling as with the -e option plus 
   support for Resume.

See also
   * __FB_ERR__
   * Compiler Option: -e
   * Compiler Option: -exx
   * Error Handling
   * Using the Command Line



-------------------------------------------------------- CompilerOptexx ----
Compiler Option: -exx

Add error checking with Resume support and array bounds/dimensions and 
null-pointer checking, plus stack overflow checking with gas64 backend

Syntax
   -exx

Description
   The -exx compiler option adds error checking with Resume support, array 
   bounds and dimensions, and null-pointer checking (including the 
   procedure pointers), plus stack overflow checking with gas64 backend.

   Use of the -exx option automatically implies -e, -ex, -earray, 
   -earraydims, -elocation, and -enullptr, error checking and code 
   generation options.

Version
   * Before fbc 1.20.0, array dimensions were never checked.
   * Before fbc 1.10.0, stack overflow was never checked.

See also
   * __FB_ERR__
   * Compiler Option: -e
   * Compiler Option: -earray
   * Compiler Option: -earraydims
   * Compiler Option: -elocation
   * Compiler Option: -enullptr
   * Compiler Option: -ex
   * Error Handling
   * Using the Command Line



----------------------------------------------------- CompilerOptexport ----
Compiler Option: -export

Export symbols for dynamic linkage

Syntax
   -export

Description
   The -export compiler option exports symbols for dynamic linkage.

See also
   * Export
   * Shared Libraries
   * Using the Command Line



-------------------------------------------------- CompilerOptforcelang ----
Compiler Option: -forcelang

Provides QuickBASIC or backward compatibility

Syntax
   -forcelang dialect

Parameters
   dialect
      The dialect to use in compilation, one of fb (default), fblite, qb or 
      deprecated.

Description
   The -forcelang compiler option changes the way source code is 
   interpreted, and is meant as a tool to users wanting traditional 
   QuickBASIC-like behavior, or behavior deprecated from previous versions 
   of FreeBASIC.  It overrides any #lang statements within the code.

   The intrinsic macro __FB_LANG__ is set to the string name of the dialect 
   specified on the command line, or "fb" by default.

   To learn more about the differences between each of these language 
   dialects, see Compiler Dialects.

   fb

      This is the default dialect, and allows compilation of source code 
      adhering to the most recent version of the FreeBASIC language.

   fblite

      This dialect provides support for FreeBASIC syntax and functionality, 
      but with a more traditional QuickBASIC programming style.

   qb

      This dialect provides the best support for older QuickBASIC code.

   deprecated

      This dialect is for backward compatibility with some previous 
      versions of FreeBASIC, however, this dialect may not exist in future 
      versions.  Programmers should consider using the "fblite" dialect 
      instead.

See also
   * #lang
   * __FB_LANG__
   * Compiler Option: -lang
   * Compiler Dialects
   * Using the Command Line



----------------------------------------------------- CompilerOptfpmode ----
Compiler Option: -fpmode

Selects faster, less accurate or slower, more precise floating-point math.

Syntax
   -fpmode < mode >

Parameters
   mode
      The floating point mode: FAST | PRECISE.

Description
   The -fpmode compiler option specifies whether speed or precision is more 
   important for floating point math. If this option is not specified, the 
   default is -fpmode PRECISE.

   -fpmode FAST will generate faster, less accurate instructions for 
   certain floating point operations.

   -fpmode PRECISE will generate standard floating point instructions that 
   operate at the default speed and accuracy of the selected floating point 
   unit.

   Currently, the only floating point operations that behave differently 
   when using -fpmode FAST are: Sin(), Cos(), reciprocal, and reciprocal 
   Square Root, all of which must operate on Single precision values.

   A number of changes were made to normalize handling of NaN's (Not a 
   Number) to get consistent results across toolchains and platforms, but 
   that costs extra code, so intention was that -fpmode FAST could allow 
   user to skip that extra code generation if they wanted (and they assume 
   responsibility how things work or do not work across platforms).

   Note:
      - for x86 and x86_64, default is -fpu x87 -fpmode PRECISE
      - -fpmode FAST|PRECISE controls code generation by fbc only
      - for optimizing with '-gen gcc' backend, use '-Wc -ffast-math'

Version
   * Before fbc-1.20.0, an error message would be displayed if -fpmode 
     FAST was with anything but -fpu SSE.

See also
   * Using the Command Line
   * Compiler Option: -fpu
   * __FB_FPMODE__



-------------------------------------------------------- CompilerOptfpu ----
Compiler Option: -fpu

Sets the math unit to be used for floating point arithmetic.

Syntax
   -fpu < type >

Parameters
   type
      The floating point unit: X87 | SSE | NEON.

Description
   The -fpu compiler option sets the math unit to be used for floating 
   point arithmetic.  If this option is not specified, the default is -fpu 
   X87.

   -fpu X87 will generate floating point instructions for the 387.

   -fpu SSE will generate floating point instructions for SSE and SSE2 with 
   some math support still done by the 387.

   -fpu NEON will generate floating point instructions for ARMv7-A Advanced 
   SIMD (Neon) extension.  Specifying this option will automatically set 
   the arch to at least armv7-a if not already set to a later processor.

   Functions normally return a floating point value (Single or Double) in 
   the st(0) register.  Sometimes, this may be optimized by returning the 
   value in the xmm0 register instead.  This can be specified with 
   Option("Sse") after the return type in a function's declaration or 
   definition.  Option("Sse") is ignored unless the source is compiled with 
   the -fpu SSE command line option.

Version
   * -fpu NEON added in fbc-1.20.0

See also
   * Using the Command Line
   * Option()
   * __FB_FPU__



---------------------------------------------------------- CompilerOptg ----
Compiler Option: -g

Add debug information, define __FB_DEBUG__, and enable asserts

Syntax
   -g

Description
   The -g compiler option inserts debugging symbols into output files, to 
   use with GDB-compatible debuggers.

   The intrinsic macro __FB_DEBUG__ is set to non-zero (-1) if the option 
   was specified, and set to zero (0) otherwise.

   Assert and AssertWarn macros are enabled.

   Use of -g automatically implies -edebug, -edebuginfo, and -eassert, 
   command line options.

   __FB_ERR__ can be used to determine in user source code if the -g option 
   was specified or implied on the command line.

See also
   * __FB_DEBUG__
   * __FB_ERR__
   * Assert
   * AssertWarn
   * Compiler Option: -eassert
   * Compiler Option: -debug
   * Compiler Option: -debuginfo
   * Debugging
   * Using the Command Line



-------------------------------------------------------- CompilerOptgen ----
Compiler Option: -gen

Sets the backend code emitter.

Syntax
   -gen < backend >

Parameters
   backend
      gas for x86 GAS assembly, gcc for GNU C, gas64 for x86_64 GAS 
      assembly, clang for clang, llvm for LLVM IR.

Description
   The -gen compiler option sets the backend code emitter and assembler. If 
   this option is not specified, the default is -gen gas for x86 and -gen 
   gcc for x86_64.

   -gen gas
      The compiler will emit GAS assembler code to a .asm file which will 
      then be compiled to an object file using 'as'. This is fbc's original 
      x86 code generation backend.

   -gen gas64
      The compiler will emit GAS assembler code (64-bit) to a .asm file 
      which will then be compiled to an object file using 'as'.

   -gen gcc
      The compiler will emit C code to a .c file which will then be 
      compiled to an .asm file using 'gcc' as a high level assembler. The C 
      backend is intended to make FB portable to more platforms than just 
      x86. This requires gcc to be installed so that fbc can invoke it to 
      compile the C code, also see Installing gcc for -gen gcc.

   -gen clang
      The compiler will emit C code to a .c file which will then be 
      compiled to an .asm file using 'clang' as a high level assembler.

   -gen llvm
      The compiler will emit LLVM IR code to a .ll file which will then be 
      compiled to an .asm file using 'llc'. The LLVM backend is still a 
      work in progress. It is intended for the same purpose as the C 
      backend, and could theoretically solve some of the C backend's 
      problems, such as debugging meta data support.

Version
   * -gen clang added in fbc 1.20.0

See also
   * Tools used by fbc
   * Using the Command Line



---------------------------------------------------------- CompilerOpti ----
Compiler Option: -i

Add a path to search for include files

Syntax
   -i < include path >

Parameters
   include path
      The directory path, relative or absolute, of where to search for 
      include files.

Description
   The -i option allows an additional directory to be used when searching 
   for header files. By default, fbc searches in the current directory, and 
   prefix/inc--in that order--where, prefix is the location where FreeBASIC 
   is installed. A directory specified with the -i option will be searched 
   before these default directories, and when the -i option is used 
   multiple times, fbc will search the directories in the order they are 
   listed on the command-line.

   To search in the subdirectory includes first for header files while 
   compiling the source file file.bas, type,

      fbc -i includes file.bas 

See also
   * #include
   * Compiler Option: -include
   * Header Files
   * Using the Command Line



---------------------------------------------------- CompilerOptinclude ----
Compiler Option: -include

Include a header file on each source compiled

Syntax
   -include < include file >

Parameters
   include file
      The header file name with extension, and optionally a path, to 
      include.

Description
   The -include option has the effect of adding an #include preprocessor 
   directive to the very beginning of each source file before processing 
   it. When used multiple times, the files will be included in the order 
   they are listed on the command-line.

   To include the file header.bi when processing file1.bas and file2.bas, 
   type,

      fbc -include header.bi file1.bas file2.bas

See also
   * #include
   * Compiler Option: -i
   * Header Files
   * Using the Command Line



---------------------------------------------------------- CompilerOptl ----
Compiler Option: -l

Add a library file to the linker's list.

Syntax
   -l < libname >

Parameters
   libname
      Name of the library to link in. The library file name's extension 
      should not be included.  For example, when using -l something, the 
      linker will look for the files:
         * Libsomething.a
         * Libsomething.dll.a (Windows)
         * something.dll (Windows)
         * Libsomething.so (Linux)

Description
   The -l compiler option adds a library file to the linker's list, to be 
   linked into the final executable or library if needed to satisfy 
   dependencies.

See also
   * #inclib
   * Compiler Option: -p
   * Using the Command Line



------------------------------------------------------- CompilerOptlang ----
Compiler Option: -lang

Provides QuickBASIC or backward compatibility

Syntax
   -lang dialect

Parameters
   dialect
      The dialect to use in compilation, one of fb (default), fblite, qb or 
      deprecated.

Description
   The -lang compiler option changes the way source code is interpreted, 
   and is meant as a tool to users wanting traditional QuickBASIC-like 
   behavior, or behavior deprecated from previous versions of FreeBASIC.

   The intrinsic macro __FB_LANG__ is set to the string name of the dialect 
   specified on the command line, or "fb" by default.

   To learn more about the differences between each of these language 
   dialects, see Compiler Dialects.

   fb

      This is the default dialect, and allows compilation of source code 
      adhering to the most recent version of the FreeBASIC language.

   fblite

      This dialect provides support for FreeBASIC syntax and functionality, 
      but with a more traditional QuickBASIC programming style.

   qb

      This dialect provides the best support for older QuickBASIC code.

   deprecated

      This dialect is for backward compatibility with some previous 
      versions of FreeBASIC, however, this dialect may not exist in future 
      versions.  Programmers should consider using the "fblite" dialect 
      instead.

   Note: this command-line option can be overridden by any #lang statements 
   used in the code.

See also
   * #lang
   * __FB_LANG__
   * Compiler Option: -forcelang
   * Compiler Dialects
   * Using the Command Line



-------------------------------------------------------- CompilerOptlib ----
Compiler Option: -lib

Create a static library

Syntax
   -lib

Description
   The -lib compiler option creates a static library.

   The intrinsic macro __FB_OUT_LIB__ is set to non-zero (-1) if the -lib 
   option was specified, and set to zero (0) otherwise.

See also
   * __FB_OUT_LIB__
   * Static Libraries
   * Using the Command Line



---------------------------------------------------------- CompilerOptm ----
Compiler Option: -m

Main file without extension to indicate the main module

Syntax
   -m < source file >

Parameters
   source file
      The name without extension of the main module source file

Description
   The -m compiler option specifies a main entry point for a source file; 
   the argument is the name of a source file minus its extension.
   So the main module file must be called twice in the command line:
      - after compile option "-m", but without specified extension,
      - and also like any module to compile, but there with its specified 
      extension.

   WARNING: the spelling of < source file > is case-sensitive! (unexpected 
   ERRORS may otherwise occure)

   If "-m" is not specified, the first source file listed is given a main 
   entry point.

   When using the "-c" or "-r" switch, "-m" must be specified when 
   compiling a main source file.

   The intrinsic macro __FB_MAIN__ is defined in the main module and not 
   defined in other modules.

See also
   * __FB_MAIN__
   * Compiler Option: -c
   * Compiler Option: -r
   * Using the Command Line



-------------------------------------------------------- CompilerOptmap ----
Compiler Option: -map

Save the linking map to file name

Syntax
   -map < map file >

Parameters
   map file
      Name of the map file to save generated during linking.

Description
   The -map compiler option saves the a map file of the executable made.

See also
   * Using the Command Line



----------------------------------------------------- CompilerOptmaxerr ----
Compiler Option: -maxerr

Set maximum number of errors to report before aborting compilation

Syntax
   -maxerr < value | "inf" >

Parameters
   value | "inf"
      Specifies the maximum number of errors or no maximum if "inf" is 
      given instead of a value.

Description
   The -maxerr compiler option sets the maximum number of errors the 
   compiler must find before stopping. The default is 10. If inf, for 
   infinite, is specified the compiler continues until it finds the end of 
   the source. Useful if an IDE is parsing the error messages.
   -maxerr only applies to compiler errors (therefore excluding compiler 
   warnings, linker/assembler errors and other third party errors).

See also
   * Using the Command Line



--------------------------------------------------------- CompilerOptmt ----
Compiler Option: -mt

Link with thread-safe runtime library

Syntax
   -mt

Description
   The -mt compiler option forces linking with thread-safe runtime library 
   for multithreaded applications. The thread-safe version is always used 
   automatically if the FreeBASIC built-in threading functions are used, so 
   you only need to specify this option if using your own threading 
   routines.

   The intrinsic macro __FB_MT__ is set to non-zero (-1) if the -mt option 
   was specified, or whether one of the Threadtcreate or ThreadCall 
   keywords is used more above in the source code. Otherwise, it is set to 
   zero (0).

See also
   * __FB_MT__
   * Using the Command Line



-------------------------------------------------- CompilerOptnodeflibs ----
Compiler Option: -nodeflibs

Do not include the default libraries

Syntax
   -nodeflibs

Description
   The -nodeflibs compiler option causes default libraries not to be used 
   when linking.  The libraries which are normally linked by default can 
   still be used, but only if they are explicitly specified.

See also
   * Using the Command Line



------------------------------------------------------ CompilerOptnolib ----
Compiler Option: -nolib

Do not include specific library(s).

Syntax
      -nolib < libname1 [, libname2 [, ... ] ] >

Parameters
   libname1, libname2, ...
      Name (without name's extension) of each library to exclude.
   fbrt0.o
   fbrt0pic.o
      Exclude the fb runtime library start-up code module

Description
   The -nolib compiler option allows excluding specific libraries when 
   linking, no matter where it came from (default lib, #inclib, -l, 
   objinfo...).
   (more fine-grained control than -nodeflibs, and not only for default 
   libraries)

   This allows selectively blacklisting libraries and can be used to:
      - remove unused dependencies when linking against shared libraries 
      (when linking against static libraries via -l, the linker 
      automatically skips unused libs, but not for shared libraries),
      - override unwanted #inclibs (although arguably this is not the ideal 
      solution for that, but just a last resort),
      - disable only some default libs, instead of all as done by -nodeflibs
      :
         For example, this could be used to specifically omit libtinfo.
         Using -nodeflibs would omit a lot more (including fbrt0.o) which 
         would have to be re-added manually again.
      - remove only the fb runtime library start-up code module allowing 
      replacement with a custom start-up module without affect any other 
      libraries named in the link

Version
   * Since fbc 1.20.0: -nolib fbrt0.o, -nolib fbrt0pic.o
   * Since fbc 1.10.0.

See also
   * Compiler Option: -nodeflibs
   * Using the Command Line



-------------------------------------------------- CompilerOptnoerrline ----
Compiler Option: -noerrline

Do not show source line where error occurred

Syntax
   -noerrline

Description
   The -noerrline compiler option causes reported errors to not show the 
   place in source where error occurred. Useful if an IDE is parsing the 
   error messages.

See also
   * Using the Command Line



-------------------------------------------------- CompilerOptnoobjinfo ----
Compiler Option: -noobjinfo

Do not read/write compile-time info from/to .o and .a files

Syntax
   -noobjinfo

Description
   The -noobjinfo compiler option disables the writing/reading of 
   compile-time library and other linking options from/to .o and .a files. 
   This also disables the use of fbextra.x (the supplemental linker script) 
   for discarding the .fbctinf sections, which is useful when using the 
   gold linker that doesn't support this kind of linker script.

Version
   * Since fbc 1.06.0

See also
   * Using the Command Line



---------------------------------------------------- CompilerOptnostrip ----
Compiler Option: -nostrip

Do not strip symbol information from the output file

Syntax
   -nostrip

Description
   The -nostrip compiler option explicitly prevents fbc from passing the 
   option to strip (remove) all symbols to the linker.  Object modules and 
   libraries will retain any symbols present after linking.

Version
   * Since fbc 1.07.0

Platform Differences
   * fbc strips all symbols by default on Dos and Windows platforms only

See also
   * -strip
   * Using the Command Line



---------------------------------------------------------- CompilerOpto ----
Compiler Option: -o

Set object file path/name

Syntax
   -o < output file >

Parameters
   output file
      The name, with optional path, of the object file to create.

Description
   The -o option can be used to specify the file name for the object file 
   created while compiling an input file. By default, the name for the 
   object file (and other temporaries like assembly files) is based on the 
   name of the corresponding input file, but with an .o extension. This 
   option is useful for example in combination with -c, or to force the 
   compiler to create temporary object files in other directories (if, for 
   example, the source code directory is or should be treated as 
   read-only).

   Given -o options are only assigned to input files that need to be 
   compiled, namely *.bas, *.rc, *.res and *.xpm.

   Note: -o options can appear in front of or behind the input file they 
   correspond to, but there cannot be multiple -o options for one input 
   file. For example, these are all accepted:
      fbc 1.bas -o 1.o
      fbc -o 1.o 1.bas
      fbc 1.bas -o 1.o 2.bas -o 2.o
      fbc 1.bas -o 1.o -o 2.o 2.bas
   However, this is an error:
      fbc 1.bas 2.bas -o 1.o -o 2.o

   The -v option makes the compiler show the actual file names that it 
   uses.

See also
   * Compiler Option: -b
   * Compiler Option: -c
   * Using the Command Line



----------------------------------------------- CompilerOptoptimization ----
Compiler Option: -O

Set the optimization level for GCC

Syntax
   -O < level >

Parameters
   level
      The optimization level: 0, 1, 2, 3 or max (3).

Description
   Specifies the optimization level to be passed to GCC when using -gen gcc
   .

See also
   * Compiler Option: -gen gcc
   * Using the Command Line



---------------------------------------------------------- CompilerOptp ----
Compiler Option: -p

Add a path to search for libraries

Syntax
   -p < library path >

Parameters
   library path
      The directory path, relative or absolute, of where to search for 
      library files.

Description
   The -p compiler option adds a path to search for libraries. By default, 
   libraries are looked for in the system FreeBASIC libraries directory and 
   in the current directory.

See also
   * #libpath
   * Using the Command Line



-------------------------------------------------------- CompilerOptpic ----
Compiler Option: -pic

Generate position-independent code (non-x86 Unix shared libs)

Syntax
   -pic

Description
   The -pic compiler option tells the compiler to generate 
   position-independent code. This is needed for creating shared libraries 
   on x86_64 or ARM Linux/BSD platforms except Win64 (and also not on 32bit 
   x86). This option should not be used when creating executables (as 
   opposed to shared libraries) though.

   By default, -pic is enabled when using -dll or -dylib, and disabled for 
   all other compilation modes. Usually you only have to specify -pic if 
   you are using -c or -lib and want to link them into shared libraries 
   later.

   -pic is implemented by passing -fPIC to gcc (when using the -gen gcc 
   backend). The -gen gas backend does not support position-independent 
   code since it only supports 32bit x86 and there is no special 
   position-independent code needed for shared libraries on 32bit x86.

See also
   * Using the Command Line



--------------------------------------------------------- CompilerOptpp ----
Compiler Option: -pp

Emit the preprocessed input file only, do not compile

Syntax
   -pp

Description
   The -pp compiler option enables the preprocessor-only mode. The code is 
   parsed & checked as usual, but is not compiled. For every input file <
   source>.bas passed to the compiler, a pre-processed version named <
   source>.pp.bas is generated.
   Specifically, preprocessor commands such as conditional compilation 
   (#if, #ifdef, #ifndef, etc.), text replacement (#define, #macro, etc.) 
   and file inclusion (#include) are processed recursively, and the 
   resulting expanded code is written to the pp.bas file.

See also
   * Using the Command Line
   * Preprocessor commands



----------------------------------------------------- CompilerOptprefix ----
Compiler Option: -prefix

Set the compiler prefix path

Syntax
   -prefix < path >

Parameters
   path
      The directory, relative or absolute to where fbc is located.

Description
   The -prefix compiler option sets the compiler prefix (where the compiler 
   finds the bin, lib, and inc directories); and defaults to the path where 
   fbc resides, if this can be determined.

   For more details, see on page -buildprefix, the paragraph: "Detailed 
   behavior if using -buildprefix, -prefix, -target command line options".

See also
   * -buildprefix
   * -target
   * Using the Command Line



------------------------------------------------------ CompilerOptprint ----
Compiler Option: -print

Print out information

Syntax
      -print option

Description
   The -print option can be used to query the compiler for certain 
   information which may be useful especially for build scripts. It does 
   not prevent compilation of input files given besides the -print option, 
   but the compiler also can be invoked with only a -print option and no 
   input files, in which case it will not compile anything but only respond 
   to the -print option.

   Currently, the following -print options are recognized:

      +--------+-------------------------------------------------------------------------------------------------------------------------------------------------------------+
      |option  |effect                                                                                                                                                       |
      |fblibdir|Prints the compiler's lib/ path                                                                                                                              |
      |host    |Prints the host system on which fbc is running                                                                                                               |
      |target  |Prints the target system for which fbc is compiling (can be affected by the -target option)                                                                  |
      |x       |Prints the file name of the output executable or library that fbc will or would generate (named after the -x option), depending on other command line options|
      |sha-1   |Prints the source code revision sha-1 used to build the compiler if defined at fbc build time, or an empty string if it was not defined                      |
      |fork-id |Prints the custom defined project fork identifier name if defined at fbc build time, or an empty string if it was not defined                                |
      +--------+-------------------------------------------------------------------------------------------------------------------------------------------------------------+

Example
   A makefile could use target := $(shell $(FBC) -print target) to find out 
   the compilation target, which would even work when cross-compiling, with 
   FBC set to something like fbc -target foo.

   fbc -print x alone will print out the executable file extension for the 
   target system.
   fbc -print x -dll on the other hand will print out the dynamic library 
   file name format.
   fbc -print x -m foo will print out the executable file name that would 
   be used when compiling a module called foo.bas.
   fbc 1.bas 2.bas -lib -print x will compile 1.bas and 2.bas into a 
   library, whose file name will be displayed.

See also
   * -x
   * -target
   * Using the Command Line
   * __FB_BUILD_SHA1__
   * __FB_BUILD_FORK_ID__



---------------------------------------------------- CompilerOptprofgen ----
Compiler Option: -profgen

Enable function profiling by selecting a specific profiler

Syntax
   -profgen < profiler >

Description
   The -profgen compiler option enables function profiling by selecting a 
   specific profiler among different profiler code generation backends.

   -profgen fb
      Enable function call profiling using fb's profiler. After running an 
      executable compiled with this option, a <filename[.exe]>.prf file 
      containing the profiling report will be created in the program 
      directory.

   -profgen cycles
      Enable cycle count profiling on some targets using fb's profiler. 
      After running an executable compiled with this option, it can 
      generate a basic report of cycle counts.
      (currently a work in progress on -gen gas64 only)

   -profgen gmon
      Enable profiling code generation for gmon/gprof. After running an 
      executable compiled with this option, a gmon.out file will be created 
      in the program directory, allowing use of GPROF for analysis of the 
      program's execution.

Version
   * Since fbc 1.20.0

See also
   * Compiler Option: -profile
   * Profiling with fb's profiler
   * Profiling for gmon/gprof
   * Using the Command Line



---------------------------------------------------- CompilerOptprofile ----
Compiler Option: -profile

Enable function profiling for gmon/gprof

Syntax
   -profile

Description
   The -profile compiler option enables profiling code generation for 
   gmon/gprof. After running an executable compiled with this option, a 
   gmon.out file will be created in the program directory, allowing use of 
   GPROF for analysis of the program's execution.

See also
   * Compiler Option: -profgen
   * Profiling for gmon/gprof
   * Using the Command Line



---------------------------------------------------------- CompilerOptr ----
Compiler Option: -r

Compile into *.asm/*.c/*.ll file(s) only, do not assemble or link

Syntax
   -r

Description
   The -r option specifies that any source files listed are to be compiled 
   to *.asm/*.c/*.ll files, depending on the used code generation backend, 
   and not compiled or linked into an executable.

   When using the -r option, -m must be specified when compiling the main 
   module.

   Use the -R option to preserve intermediate files without affecting 
   compilation/assembling/linking.
   Use the -rr option to compile input source files to *.asm regardless of 
   the code generation backend.

See also
   * Compiler Option: -c
   * Compiler Option: -R
   * Compiler Option: -m
   * Compiler Option: -gen
   * Compiler Option: -rr
   * Using the Command Line



------------------------------------------------------- CompilerOptrupp ----
Compiler Option: -R

Preserve intermediate *.asm/*.c/*.ll file(s) generated by compilation

Syntax
   -R

Description
   The -R compiler option causes the intermediate *.asm/*.c/*.ll file(s) 
   that are generated during the compile process to be preserved. Other 
   than that, compilation is performed as usual. Which files are generated 
   exactly depends on the used code generation backend and compilation 
   target.

   When compiling a Windows DLL, -R also preserves the intermediate *.def 
   file used for generating the import library for the DLL.

See also
   * Compiler Option: -C
   * Compiler Option: -r
   * Compiler Option: -gen
   * Using the Command Line



--------------------------------------------------------- CompilerOptrr ----
Compiler Option: -rr

Compile into *.asm file(s) only, do not assemble or link

Syntax
   -rr

Description
   The -rr option specifies that any source files listed are to be compiled 
   to *.asm files, and not compiled or linked into an executable. Unlike 
   with the -r option, this works regardless of the used 
   code generation backend.

   When using the -rr option, -m must be specified when compiling a main 
   source file.

   Use the -RR option to preserve the generated *.asm files without 
   affecting compilation/assembling/linking.

See also
   * Compiler Option: -c
   * Compiler Option: -r
   * Compiler Option: -RR
   * Compiler Option: -m
   * Compiler Option: -gen
   * Using the Command Line



------------------------------------------------------ CompilerOptrrupp ----
Compiler Option: -RR

Preserve intermediate *.asm files generated by compilation

Syntax
   -RR

Description
   The -RR compiler option causes the intermediate *.asm file(s) that are 
   generated during the compile process to be preserved. Other than that, 
   compilation is performed as usual.

See also
   * Compiler Option: -C
   * Compiler Option: -rr
   * Compiler Option: -R
   * Using the Command Line



---------------------------------------------------------- CompilerOpts ----
Compiler Option: -s

Sets the executable subsystem

Syntax
   -s < subsystem >

Parameters
   subsystem
      The executable subsystem: gui or console.

Description
   The -s compiler option specifies the executable subsystem. Allowed 
   subsystems are gui and console (by default, console is used). Specifying 
   a gui subsystem prevents the console window from appearing behind the 
   program window.

   The intrinsic macro __FB_GUI__ is set to non-zero (-1) if GUI subsystem 
   mode is active, and set to zero (0) otherwise.  #Pragma Gui and 
   #Pragma Gui = 0 provide the source-level form of the same setting.

Platform Differences
   * On Windows and Cygwin, this controls the linker subsystem.
   * Other targets may use the same mode value for target-specific startup 
     or runtime behavior.

See also
   * __FB_GUI__
   * #pragma
   * Using the Command Line



----------------------------------------------- CompilerOptshowincludes ----
Compiler Option: -showincludes

Display a tree of file names of #included files 

Syntax
      -showincludes

Description
   Tells the compiler to display the file names of loaded source code 
   files, in form of a tree structure with indentation. This includes the 
   *.bas files at the toplevel, aswell as the names of #included files as 
   they are being #included. This is intended to be used for debugging 
   #include dependencies, etc.

Version
   * Since fbc 1.02.0

See also
   * Using the Command Line



----------------------------------------------------- CompilerOptstatic ----
Compiler Option: -static

Prefer static libraries over dynamic ones when linking

Syntax
      -static

Description
   When creating an executable or a shared library/DLL, the -static 
   compiler option can be used to tell the compiler to prefer linking 
   against static libraries rather than shared libraries/DLLs. That way, if 
   the linker finds both static and shared versions of a library, it will 
   use the static version, rather than defaulting to the shared version.

   Installing the proper static libraries and then using -static can be 
   used to avoid some or all dependencies on shared libraries.

Platform Differences
   * On Linux & co it is possible to create purely statically linked 
     executables, because static versions of the system libraries used by 
     FreeBASIC are available.
   * On Windows, there are no static versions of the system libraries, but 
     -static can still be useful to decide between static library or DLL 
     versions of other libraries, if both are installed.

See also
   * Using the Command Line



------------------------------------------------------ CompilerOptstrip ----
Compiler Option: -strip

Omit all symbol information from the output file

Syntax
   -strip

Description
   The -strip compiler option passes an option to the linker to strip 
   (remove) all symbols.

Version
   * Since fbc 1.07.0

Platform Differences
   * fbc strips all symbols by default on Dos and Windows platforms only

See also
   * -nostrip
   * Using the Command Line



---------------------------------------------------- CompilerOptsysroot ----
Compiler Option: -sysroot

Add a path to search for libraries

Syntax
   -sysroot < sysroot path >

Parameters
   sysroot path
      The directory path of the sysroot for the toolchain used.

Description
   The -sysroot compiler option passes this directory location to the 
   linker to indicate where the linker should look for default object 
   modules and libraries.

   This passes on some responsibility of finding needed resources to the 
   toolchain.  Typically only needed when cross compiling where resources 
   are expected to be in a single directory structure and expected to be 
   found at known locations relative to the sysroot.

   To explicitly locate libraries use #libpath or Compiler Option: -p.

Version
   * Since fbc 1.20.0

See also
   * #libpath
   * Using the Command Line



---------------------------------------------------------- CompilerOptt ----
Compiler Option: -t

Set stack size in kilobytes

Syntax
   -t < stack size >

Parameters
   stack size
      Stack size in kilobytes.

Description
   The -t compiler option sets the stack size in kilobytes (defaults to 
   1024 KBytes for 32-bit targets, and 2048 KBytes for 64-bit targets). The 
   local arrays are created in the stack, so 1 MB or 2 MB of stack is not 
   always enough.

Version
   * Before fbc 1.08.0, the default stack size for 64-bit targets was also 
     1024 KBytes.

Platform Differences
   * Supported on Windows, Cygwin and DOS only.

See also
   * Using the Command Line



----------------------------------------------------- CompilerOpttarget ----
Compiler Option: -target

Set the target platform for cross compilation

Syntax
   -target < platform >

Parameters
   platform
      The target platform. Recognized values:
         * android
         * dos
         * win32
         * win64
         * xbox
         * <os>-<arch>
            <os> can be one of:
               * android
               * linux
               * cygwin
               * darwin
               * freebsd
               * netbsd
               * openbsd
            <arch> can be one of:
               * arm
               * aarch64
               * powerpc or ppc
               * powerpc64 or ppc64
               * powerpc64le or ppc64le
               * x86
               * x86_64
            Examples:
               * android-arm
               * android-x86
               * freebsd-x86
               * freebsd-x86_64
               * linux-arm
               * linux-aarch64
               * linux-x86
               * linux-x86_64
               * ...
         * For backwards compatibility, the following values are 
           recognized. They will select the corresponding operating system, 
           together with the compiler's default architecture (same as the 
           host), because these values do not specify an architecture 
           explicitly.
            * linux
            * cygwin
            * darwin
            * freebsd
            * netbsd
            * openbsd
         * fbc (e.g. FB-linux release) additionally recognizes GNU 
           triplets, for example:
            * i686-w64-mingw32
            * x86_64-w64-mingw32
            * i686-pc-linux-gnu
            * arm-linux-gnueabihf
            * i386-pc-msdosdjgpp
            * arm-linux-android
            * armv7a-linux-android
            * armv7a-linux-androideabi
            * armv5te-linux-android
            * i686-linux-android
            * x86_64-linux-android
            * ...

Description
   The -target compiler option can be used to create an executable for a 
   platform which is different from the host on which the source code is 
   being compiled and linked. Appropriate libraries and cross compilation 
   tools (assembler, linker) must be installed for cross compilation to 
   work (also see FB and cross-compiling). 

   If -target <platform> is given, the compiler will compile programs more 
   or less as if they were compiled on the given platform. This affects 
   which __FB_*__ operating-system-specific symbol will be pre-defined, the 
   default calling convention, the object and executable file format (e.g. 
   ELF/COFF), the available runtime libraries and functions, etc.

   With a standalone FB setup such as the FB-dos or FB-win32 releases:
      * Specifying -target <platform> causes the compiler to use the 
        compiler tools in the bin/<platform>/ directory, and 
        target-specific libraries in the lib/<platform>/ directory. For 
        example, -target win32 causes the compiler to compile for Win32 and 
        use tools from bin/win32/ and libraries from lib/win32/.
      * It is unnecessary (but safe) to specify a -target option that 
        matches the host (for example -target win32 on win32). It does not 
        make a difference to the compilation process.
      * If -target is not specified, the compiler defaults to compiling 
        for the native system. It will then use the compiler tools and 
        libraries from the bin/ and lib/ directories corresponding to the 
        native system.
      * -target may be specified as a gnu triplet as an alternate method 
        for specifying the platform target and architecture.  For example, 
        -target i586-pc-mdosdjgpp will identify as -arch 586 -target dos 
        and will look for binaries in bin/dos/ and libraries in lib/dos/.  
        The platform string is not prefixed to names of binary tools.

   With a normal FB setup such as the FB-linux release:
      * Specifying -target <platform> causes the compiler to prefix the <
        platform>- string to the executable names of binutils and gcc. For 
        example, specifying -target i686-w64-mingw32 causes the compiler to 
        invoke i686-w64-mingw32-ld instead of ld (same for other tools 
        besides the linker). This allows fbc to integrate with binutils/gcc 
        cross-compiler toolchains and matches how cross-compiling tools are 
        typically installed on Linux distributions.
      * Note that specifying something like -target win32 does not usually 
        make sense here. It causes the compiler to try to use win32-ld 
        which usually does not exist, because binutils/gcc toolchains for 
        cross-compilation to Windows typically have names such as 
        i686-pc-mingw32, not just win32. Thus, it is necessary to specify 
        something like -target i686-pc-mingw32 instead of -target win32.
      * For backwards compatibility, if the given platform string 
        describes the host and is an FB target name (the values accepted by 
        the -target option with a standalone FB setup) instead of a GNU 
        triplet, then the -target option will be ignored, and the <platform
        >- string will not be prefixed to compiler tools. For example, this 
        allows -target linux to work with the FB-linux release. It will be 
        ignored instead of causing the compiler to try to use linux-ld 
        instead of ld.
      * If -target is not specified, the compiler defaults to compiling 
        for the native system, and it will invoke binutils/gcc without a 
        target-specific prefix. This allows fbc to integrate with usual 
        Linux (and similar) systems where binutils/gcc for native 
        compilation are installed without any target-specific prefix.
      * Libraries besides FB's own runtime libraries are located by 
        running gcc -print-file-name=... (or <platform>-gcc 
        -print-file-name=...). This allows fbc to use the system and gcc 
        libraries installed on Linux and similar systems without knowing 
        the exact installation directories.

   When using triplets they generally have the form os <arch>-<vendor>-<os> 
   but can vary a lot between build systems or over time between different 
   versions of a build system or toolchain.  fbc also accepts the form <
   arch>-<os> and is fairly permissive in what will be accepted and 
   typically will not throw an error if at least part of the gnu triplet is 
   recognized

   For more details, see on page -buildprefix, the paragraph: "Detailed 
   behavior if using -buildprefix, -prefix, -target command line options".

Version
   * Before fbc 1.20.0, android was not recognized as a target
   * Before fbc 1.10.0, gnu triplets were not allowed in standalone 
     builds, and '-target i386-pc-msdosdjgpp' and similar were not allowed.

See also
   * -arch
   * -buildprefix
   * -prefix
   * Using the Command Line
   * FB and cross-compiling



---------------------------------------------------------- CompilerOptv ----
Compiler Option: -v

Be verbose

Syntax
   -v

Description
   The -v compiler option activates verbose mode. In this mode the compiler 
   shows its actions step by step

See also
   * Using the Command Line



-------------------------------------------------------- CompilerOptvec ----
Compiler Option: -vec

Enables vector optimizations by the compiler.

Syntax
   -vec < level >

Parameters
   level
      The level of vectorization: (0 | NONE) | 1 | 2.

Description
   The -vec compiler option enables multiple levels of optimizations by 
   searching for multiple scalar expressions that can be merged into a 
   single vector expression. If this option is not specified, the default 
   is -vec 0.

   -vec 0 | none will disable vector optimizations.

   -vec 1 will enable complete expression merging vectorization.

   -vec 2 includes -vec 1 but also enables intra-expression vectorization.

   This option is dependent on the -fpu SSE command line option.  
   Attempting to enable vector optimizations without using -fpu SSE will 
   generate an error.

See also
   * Using the Command Line
   * Compiler option -fpu



---------------------------------------------------- CompilerOptversion ----
Compiler Option: -version

Show compiler version

Syntax
   -version

Description
   The -version compiler option makes FBC show the compiler version and 
   exit.  Any other command-line options are ignored, and no compilation 
   will be performed.

See also
   * Using the Command Line



---------------------------------------------------------- CompilerOptw ----
Compiler Option: -w

Set minimum warning level.

Syntax
   -w level | all | none | param | Escape | pedantic | Next | funcptr | 
   constness | suffix | Error | upcast

Parameters
   level
      Warning messages only with a level equal or greater to this value 
      will be output.  
   all
      Equivalent to specifying a level of zero (0).
   none
      Suppresses all warnings.
   param
      Warn when procedure parameters aren't specified with either ByVal or 
      ByRef.
   Escape
      Warn when string literals contain any number of escape characters (\
      ).
   pedantic
      Equivalent to specifying the param and Escape arguments, plus length 
      checking of parameters passed ByVal and of any CPtr converting to 
      pointer only, plus warning on useless suffixes in '-lang fb'.
   Next
      Warn when Next is followed by an identifier.
   funcptr
      Warn on mismatched procedure pointers, including conversions in Cast 
      and CPtr expressions.  Implies '-w all'. Experimental.  Behaviour may 
      change in future versions.
   constness
      Warn when Const (Qualifier) is discarded in an assignment. Implies 
      '-w funcptr' and '-w all'.  Behaviour may change in future versions.
   suffix
      Warn on useless suffixes in '-lang fb'.
   Error
      Report warnings as errors.  Warnings cause the error count to 
      increase, warning messages are displayed as "error warning...", 
      compilation / assembly / linking aborts, and fbc exits with an error 
      code.
   upcast
      Warn when up-casting discards initializers.

Description
   The -w compiler option determines which compiler warnings, if any, are 
   output. Each possible warning is associated with a warning level, 
   starting from zero (0) and increasing with the potential problems that 
   may occur.

   The param, Escape, pedantic, Next, funcptr, constness, suffix, Error, 
   and upcast arguments provide additional warnings not ordinarily output, 
   even by default.

   The default, if the -w option is not specified, is as if -w 1 was used. 
   The -w option can be specified multiple times.  Warning messages having 
   a level of 0 are not shown by default.

   -w none, or a significantly high level value will have the effect of 
   suppressing all warning messages.

   fbc does not issue warning or error if the warning name itself is not 
   valid.  For example -w flarg, is not a recognized name for a warning.  
   The compiler silently ignores this to allow command lines with warnings 
   added in new versions of fbc to also be used with older versions of fbc 
   without complaint.

Version
   * Since fbc 1.10.0: '-w upcast' option
   * Since fbc 1.09.0: '-w error' option.
   * Before fbc 1.08.0, default warning level was 0 and some warnings had 
     level of -1.

See also
   * Using the Command Line



--------------------------------------------------------- CompilerOptWa ----
Compiler Option: -Wa

Pass options to the assembler when using the assembly emitter (-gen gas).

Syntax
   -Wa < options >

Parameters
   options
      Additional options to pass to the assembler.

Description
   The -Wa compiler option passes additional options to GAS, the assembler. 
   Options must be separated by commas only.  The -Wa compiler option may 
   be specified multiple times on the command line.

   For example:
      fbc -Wa -o,output.o,--verbose
      fbc -Wa -o -Wa output.o -Wa --verbose

See also
   * Compiler Option: -gen
   * Compiler Option: -Wc
   * Compiler Option: -Wl
   * Using the Command Line



--------------------------------------------------------- CompilerOptWc ----
Compiler Option: -Wc

Pass options to the C compiler when using the C emitter (-gen gcc).

Syntax
   -Wc < options >

Parameters
   options
      Additional options to pass to the C compiler.

Description
   The -Wc compiler option passes additional options to GCC, the C 
   compiler.  Options must be separated by commas only.   The -Wc compiler 
   option may be specified multiple times on the command line.

   For example:
      fbc -gen gcc -Wc -m32,--verbose,-include,some-header.h
      fbc -gen gcc -Wc -m32 -Wc --verbose -Wc -include -Wc some-header.h

See also
   * Compiler Option: -gen
   * Compiler Option: -Wa
   * Compiler Option: -Wl
   * Using the Command Line



--------------------------------------------------------- CompilerOptWl ----
Compiler Option: -Wl

Pass options to linker

Syntax
   -Wl < options >

Parameters
   options
      Additional options to pass to the linker.

Description
   The -Wl compiler option passes additional options to LD, the linker.  
   Options must be separated by commas only.   The -Wl compiler option may 
   be specified multiple times on the command line.

See also
   * Compiler Option: -Wa
   * Compiler Option: -Wc
   * Using the Command Line



---------------------------------------------------------- CompilerOptx ----
Compiler Option: -x

Set executable/library path/name

Syntax
   -x < name >

Parameters
   name
      Name of the executable or library file.

Description
   The -x compiler option set the executable or library name, with 
   extension. Defaults to the name of the first source file passed on the 
   command line. When compiling libraries, be sure to add the "lib" prefix 
   to the file name, otherwise the linker will not be able to find it. If 
   compiling and linking separately, this option must be set only in the 
   linker.

See also
   * Using the Command Line



---------------------------------------------------------- CompilerOptz ----
Compiler Option: -z

Sets miscellaneous or experimental compiler options.

Syntax
   -z < value >

Parameters
   value
      Miscellaneous compiler option.

Description
   The -z compiler option sets miscellaneous, obscure, temporary, or 
   experimental options used by the developers.  There is no guarantee that 
   these options will be supported in future versions of the compiler.

   -z gosub-setjmp
      Specifies that the setjmp/longjmp implementation of GoSub should be 
      used even when the GAS backend is used.  By default, GoSub will be 
      supported in -gen gas using CALL/RET assembly instructions and in 
      -gen gcc using setjmp/longjmp C runtime functions.

   -z valist-as-ptr
      Specifies that the implementation of Cva_List variable argument lists 
      and macros for variadic procedures should use a normal pointer type 
      if the target supports it.  By default, Cva_List data types are 
      mapped to gcc's __builtin_va_list data type when using -gen gcc.

   -z no-thiscall
      Instructs fbc to ignore __Thiscall directives in source files.

   -z no-fastcall
      Instructs fbc to ignore __Fastcall directives in source files.

   -z fbrt
      Instructs fbc to link with the libfbrt[mt].a library instead of the 
      libfb[mt].a library rather than having to copy or move files around 
      or have multiple development directories.

   -z nocmdline
      Instructs fbc to ignore all Cmdline directives in source file and 
      take control from the real compiler command line only.

   -z retinflts
      Instructs fbc to enable returning some structures (types) in floating 
      point registers.

   -z nobuiltins
      Instructs fbc to disable all builtin declarations and definitions 
      except those that are strictly necessary to initialize the compiler 
      to a working state when it can begin to parse user code.  The user 
      code must then supply all of the required declarations and 
      definitions needed by fbc internals to allow compilation of user code 
      to succeed.  Note well that using this option requires knowledge of 
      the internal workings of the compiler.  For experimentation and 
      development this allows declaring and defining nearly all fbc 
      builtins in fb user code.  The actual user code declarations required 
      will depend on the contents of the user code to be compiled.  fbc is 
      expected to throw an error if the required supporting declarations or 
      definitions have not been made before they are required by fbc itself 
      while parsing the user source code (fbc may also crash instead).

   -z optabstract
      Instructs fbc not to emit unused pure abstract types.

Version
   * Since fbc 1.20.0: optabstract compiler option
   * Since fbc 1.20.0: nobuiltins compiler option
   * Since fbc 1.10.0: retinflts compiler option
   * Since fbc 1.10.0: no-fastcall compiler option.
   * Since fbc 1.09.0: nocmdline compiler option
   * Since fbc 1.09.0: fbrt compiler option.
   * Since fbc 1.09.0: no-thiscall compiler option.
   * Since fbc 1.08.1: valist-as-ptr compiler option.
   * Since fbc 0.20.0: gosub-setjmp compiler option.

See also
   * Using the Command Line



------------------------------------------------------- DebuggerRunning ----
Debugging

   The debugger is in the bin\win32 or bin\dos directories (the GDB.EXE 
   file), for the Windows and DOS versions respectively.  It usually comes 
   already installed in most Linux distros.

   (Note: all commands should be typed without quotes and then [return] 
   must be pressed.)

   * Compile the source code for your program in debug mode
      * use the -g command-line option to add debugging support, e.g. fbc 
        -g myapp.bas.

   * Load your compiled program in GDB 
      * For example, in Windows/DOS: gdb myapp.exe
      * Note: under windows if the GDB command prompt seems not to work 
        well (like backspace not working), try set TERM=#win32con before 
        launching GDB.

   * Set any arguments you want to send to your application
      * For example: set args arg1 arg2 argn.
      * You can also run GDB and pass the arguments directly to the 
        application been debugged: gdb --args myapp.exe arg1 arg2 arg3.

   * Ensure GDB can see your program's source code directory
      * If the executable isn't in the same directory of the source files 
        where it was compiled, type: dir path/to/my/application/sources.

   * Set a breakpoint in your program
      * Place a breakpoint in the first line using: b main.
      * To place a breakpoint in a function called func use: b FUNC.
      * Note: fbc exports variable/function names to UPPERCASE.  GDB is 
        case sensitive by default, but you can use the set language pascal 
        command to change GDB to case-insensitive mode.

   * Use GDB shortcuts to run your code or to step through it
      * Type r to start running the application.
      * Type n to step to the next line, stepping over function calls.
      * Keep pressing [return] to step forward to the next line.
      * Type s to step into function calls.
      * As above, keep pressing [return] to step through.
      * Type c to continue execution until the next breakpoint.

   * Use GDB shortcuts to inspect variables
      * Use print VAR_NAME to show the contents of the variable called 
        var_name.
         * GDB supports pointer/pointer field dereferencing, indexing and 
           arithmetics too, so print *MYPOINTER will also work.
         * (note: undeclared variables or the ones with suffixes like % & 
           ! # $ can't be printed).
      * Use disp VAR_NAME to display the contents of a variable called 
        var_name.
      * Use watch VAR_NAME to stop each time a variable called var_name is 
        changed.

   * Additional commands:
      * Use r again to restart the application when it finishes.
      * Type q to quit.
      * Type help to see a list of commands, there are many others.



-------------------------------------------------------- CompilerErrMsg ----
Compiler Error Messages

During the program compilation three types of errors can arise:

Compiler Warnings:
   The warnings don't stop the compilation, just alert the user some 
   non-recommended and error-prone operation is attempted in the code. 
   Sometimes one of these operations is coded deliberately to achieve a 
   result, in this case the warnings can be disabled by setting the -w none 
   option at the command line.

   * 1(2) Passing scalar as pointer
   * 2(2) Passing pointer to scalar
   * 3(2) Passing different pointer types
   * 4(2) Suspicious pointer assignment
   * 5(1) Implicit conversion
   * 6(2) Cannot export symbol without -export option
   * 7(2) Identifier's name too big, truncated
   * 8(2) Literal number too big, truncated
   * 9(2) Literal string too big, truncated
   * 10(1) UDT with pointer, var-len string, or var-len array fields
   * 11(1) Implicit variable allocation
   * 12(1) Missing closing quote in literal string
   * 13(1) Function result was not explicitly set
   * 14(2) Branch crossing local variable definition
   * 15(1) No explicit BYREF or BYVAL
   * 16(1) Possible escape sequence found in
   * 17(1) The type length is too large, consider passing BYREF
   * 18(2) The length of the parameters list is too large, consider 
     passing UDT's BYREF
   * 19(2) The ANY initializer has no effect on UDT's with default 
     constructors
   * 20(3) Object files or libraries with mixed multithreading (-mt) 
     options
   * 21(3) Object files or libraries with mixed language (-lang) options
   * 22(1) Deleting ANY pointers is undefined
   * 23(3) Array too large for stack, consider making it var-len or SHARED
   * 24(3) Variable too large for stack, consider making it SHARED
   * 25(1) Overflow in constant conversion
   * 26(1) Variable following NEXT is meaningless
   * 27(1) Cast to non-pointer
   * 28(1) Return method mismatch
   * 29(1) Passing Pointer
   * 30(1) Command line option overrides directive
   * 31(1) Directive ignored after first pass
   * 32(1) 'IF' statement found directly after multi-line 'ELSE'
   * 33(1) Shift value greater than or equal to number of bits in data 
     type
   * 34(1) '=' parsed as equality operator in function argument, not 
     assignment to BYREF function result
   * 35(1) Mixing signed/unsigned operands
   * 36(1) Mismatching parameter initializer
   * 37(2) Ambiguous LEN or SIZEOF
   * 38(1) Suspicious logic operation, mixed boolean and non-boolean 
     operands
   * 39(1) Redefinition of intrinsic
   * 40(0) CONST qualifier discarded
   * 41(0) Return type mismatch
   * 42(0) Calling convention mismatch
   * 43(0) Argument count mismatch
   * 44(1) Suffix ignored
   * 45(1) FOR counter variable is unable to exceed limit value
   * 46(1) #cmdline ignored
   * 47(1) Use of reserved global or backend symbol
   * 48(1) Expected digit
   * 49(1) Up-casting discards initializer(s)
   * 50(2) Suspicious address expression passed to BYREF parameter
   * 51(1) GCC/Clang didn't provide a proper sysroot. You probably have to 
     pass fbc an argument of the form '-sysroot 
     $NDK/platforms/android-$API/arch-$ARCH'

Compiler Error messages:
   The error messages stop the compilation after 10 errors (see the -maxerr 
   command-line option to change that default value) or a fatal error 
   occurred, and require a correction by the user before the compilation 
   can be continued. The compiler signals the lines where the errors have 
   been found, so the correction can be done quickly. In a few cases the 
   place pointed at by the error messages is not where the errors can be 
   found, it's the place where the compiler has given up in waiting for 
   something that should be somewhere.

   * 1 Argument count mismatch
   * 2 Expected End-of-File
   * 3 Expected End-of-Line
   * 4 Duplicated definition
   * 5 Expected 'AS'
   * 6 Expected '('
   * 7 Expected ')'
   * 8 Undefined symbol
   * 9 Expected expression
   * 10 Expected '='
   * 11 Expected constant
   * 12 Expected 'TO'
   * 13 Expected 'NEXT'
   * 14 Expected identifier
   * 15 Expected '-'
   * 16 Expected ','
   * 17 Syntax error
   * 18 Element not defined
   * 19 Expected 'END TYPE' or 'END UNION'
   * 20 Type mismatch
   * 21 Internal!
   * 22 Parameter type mismatch
   * 23 File not found
   * 24 Invalid data types
   * 25 Invalid character
   * 26 File access error
   * 27 Recursion level too deep
   * 28 Expected pointer
   * 29 Expected 'LOOP'
   * 30 Expected 'WEND'
   * 31 Expected 'THEN'
   * 32 Expected 'END IF'
   * 33 Illegal 'END'
   * 34 Expected 'CASE'
   * 35 Expected 'END SELECT'
   * 36 Wrong number of dimensions
   * 37 Array boundaries do not match the original EXTERN declaration
   * 38 'SUB' or 'FUNCTION' without 'END SUB' or 'END FUNCTION'
   * 39 Expected 'END SUB' or 'END FUNCTION'
   * 40 Return type here does not match DECLARE prototype
   * 41 Calling convention does not match DECLARE prototype
   * 42 Variable not declared
   * 43 Variable required
   * 44 Illegal outside a compound statement
   * 45 Expected 'END ASM'
   * 46 Function not declared
   * 47 Expected ';'
   * 48 Undefined label
   * 49 Too many array dimensions
   * 50 Array too big
   * 51 User Defined Type too big
   * 52 Expected scalar counter
   * 53 Illegal outside a CONSTRUCTOR, DESTRUCTOR, FUNCTION, OPERATOR, 
     PROPERTY or SUB block
   * 54 Expected var-len array
   * 55 Fixed-len strings cannot be returned from functions
   * 56 Array already dimensioned
   * 57 Illegal without the -ex option
   * 58 Type mismatch
   * 59 Illegal specification
   * 60 Expected 'END WITH'
   * 61 Illegal inside functions
   * 62 Statement in between SELECT and first CASE
   * 63 Expected array
   * 64 Expected '{'
   * 65 Expected '}'
   * 66 Expected ']'
   * 67 Too many expressions
   * 68 Expected explicit result type
   * 69 Range too large
   * 70 Forward references not allowed
   * 71 Incomplete type
   * 72 Array not dimensioned
   * 73 Array access, index expected
   * 74 Expected 'END ENUM'
   * 75 Var-len arrays cannot be initialized
   * 76 '...' ellipsis upper bound given for dynamic array (this is not 
     supported)
   * 77 '...' ellipsis upper bound given for array field (this is not 
     supported)
   * 78 Invalid bitfield
   * 79 Too many parameters
   * 80 Macro text too long
   * 81 Invalid command-line option
   * 82 Selected non-x86 CPU when compiling for DOS
   * 83 Selected -gen gas|gas64 ASM backend is incompatible with CPU
   * 84 -asm att used for -gen gas, but -gen gas only supports -asm intel
   * 85 -pic is not supported with -gen gas
   * 86 -pic used, but not supported by target system (only works for 
     Unixes)
   * 87 Var-len strings cannot be initialized
   * 88 Recursive TYPE or UNION not allowed
   * 89 Recursive DEFINE not allowed
   * 90 Identifier cannot include periods
   * 91 Executable not found
   * 92 Array out-of-bounds
   * 93 Missing command-line option for
   * 94 Expected 'ANY'
   * 95 Expected 'END SCOPE'
   * 96 Illegal inside a compound statement or scoped block
   * 97 UDT function results cannot be passed by reference
   * 98 Ambiguous call to overloaded function
   * 99 No matching overloaded function
   * 100 Division by zero
   * 101 Cannot pop stack, underflow
   * 102 UDT's containing var-len string fields cannot be initialized
   * 103 Branching to scope block containing local variables
   * 104 Branching to other functions or to module-level
   * 105 Branch crossing local array, var-len string or object definition
   * 106 LOOP without DO
   * 107 NEXT without FOR
   * 108 WEND without WHILE
   * 109 END WITH without WITH
   * 110 END IF without IF
   * 111 END SELECT without SELECT
   * 112 END SUB or FUNCTION without SUB or FUNCTION
   * 113 END SCOPE without SCOPE
   * 114 END NAMESPACE without NAMESPACE
   * 115 END EXTERN without EXTERN
   * 116 ELSEIF without IF
   * 117 ELSE without IF
   * 118 CASE without SELECT
   * 119 Cannot modify a constant
   * 120 Expected period ('.')
   * 121 Expected 'END NAMESPACE'
   * 122 Illegal inside a NAMESPACE block
   * 123 Symbols defined inside namespaces cannot be removed
   * 124 Expected 'END EXTERN'
   * 125 Expected 'END SUB'
   * 126 Expected 'END FUNCTION'
   * 127 Expected 'END CONSTRUCTOR'
   * 128 Expected 'END DESTRUCTOR'
   * 129 Expected 'END OPERATOR'
   * 130 Expected 'END PROPERTY'
   * 131 Declaration outside the original namespace
   * 132 No end of multi-line comment, expected "'/"
   * 133 Too many errors, exiting
   * 134 Expected 'ENDMACRO'
   * 135 EXTERN or COMMON variables cannot be initialized
   * 136 EXTERN or COMMON dynamic arrays cannot have initial bounds
   * 137 At least one parameter must be a user-defined type
   * 138 Parameter or result must be a user-defined type
   * 139 Both parameters can't be of the same type
   * 140 Parameter and result can't be of the same type
   * 141 Invalid result type for this operator
   * 142 Invalid parameter type, it must be the same as the parent 
     TYPE/CLASS
   * 143 Vararg parameters are not allowed in overloaded functions
   * 144 Illegal outside an OPERATOR block
   * 145 Parameter cannot be optional
   * 146 Only valid in -lang
   * 147 Default types or suffixes are only valid in -lang
   * 148 Suffixes are only valid in -lang
   * 149 Implicit variables are only valid in -lang
   * 150 Auto variables are only valid in -lang
   * 151 Invalid array index
   * 152 Operator must be a member function
   * 153 Operator cannot be a member function
   * 154 Method declared in anonymous UDT
   * 155 Constant declared in anonymous UDT
   * 156 Static variable declared in anonymous UDT
   * 157 Expected operator
   * 158 Declaration outside the original namespace or class
   * 159 A destructor should not have any parameters
   * 160 Expected class or UDT identifier
   * 161 Var-len strings cannot be part of UNION's or nested TYPE's
   * 162 Dynamic arrays cannot be part of UNION's or nested TYPE's
   * 163 Fields with constructors cannot be part of UNION's or nested 
     TYPE's
   * 164 Fields with destructors cannot be part of UNION's or nested 
     TYPE's
   * 165 Illegal outside a CONSTRUCTOR block
   * 166 Illegal outside a DESTRUCTOR block
   * 167 UDT's with methods must have unique names
   * 168 Parent is not a class or UDT
   * 169 CONSTRUCTOR() chain call not at top of constructor
   * 170 BASE() initializer not at top of constructor
   * 171 REDIM on UDT with non-CDECL constructor
   * 172 REDIM on UDT with non-CDECL destructor
   * 173 REDIM on UDT with non-parameterless default constructor
   * 174 ERASE on UDT with non-CDECL constructor
   * 175 ERASE on UDT with non-CDECL destructor
   * 176 ERASE on UDT with non-parameterless default constructor
   * 177 This symbol cannot be undefined
   * 178 RETURN mixed with 'FUNCTION =' or EXIT FUNCTION (using both 
     styles together is unsupported when returning objects with 
     constructors)
   * 179 'FUNCTION =' or EXIT FUNCTION mixed with RETURN (using both 
     styles together is unsupported when returning objects with 
     constructors)
   * 180 Missing RETURN to copy-construct function result
   * 181 Invalid assignment/conversion
   * 182 Invalid array subscript
   * 183 TYPE or CLASS has no default constructor
   * 184 Function result TYPE has no default constructor
   * 185 Missing BASE() initializer (base UDT without default constructor 
     requires manual initialization)
   * 186 Missing default constructor implementation (base UDT without 
     default constructor requires manual initialization)
   * 187 Missing UDT.constructor(byref as UDT) implementation (base UDT 
     without default constructor requires manual initialization)
   * 188 Missing UDT.constructor(byref as const UDT) implementation (base 
     UDT without default constructor requires manual initialization)
   * 189 Invalid priority attribute
   * 190 PROPERTY GET should have no parameter, or just one if indexed
   * 191 PROPERTY SET should have one parameter, or just two if indexed
   * 192 Expected 'PROPERTY'
   * 193 Illegal outside a PROPERTY block
   * 194 PROPERTY has no GET method/accessor
   * 195 PROPERTY has no SET method/accessor
   * 196 PROPERTY has no indexed GET method/accessor
   * 197 PROPERTY has no indexed SET method/accessor
   * 198 Missing overloaded operator: 
   * 199 The NEW[] operator does not allow explicit calls to constructors
   * 200 The NEW[] operator only supports the { ANY } initialization
   * 201 The NEW operator cannot be used with fixed-length strings
   * 202 Illegal member access
   * 203 Expected ':'
   * 204 The default constructor has no public access
   * 205 Constructor has no public access
   * 206 Destructor has no public access
   * 207 Accessing base UDT's private default constructor
   * 208 Accessing base UDT's private destructor
   * 209 Illegal non-static member access
   * 210 Constructor declared ABSTRACT
   * 211 Constructor declared VIRTUAL
   * 212 Destructor declared ABSTRACT
   * 213 Member cannot be static
   * 214 Member isn't static
   * 215 Only static members can be accessed from static functions and 
     parameter initializers
   * 216 The PRIVATE and PUBLIC attributes are not allowed with REDIM, 
     COMMON or EXTERN
   * 217 STATIC used here, but not the in the DECLARE statement
   * 218 CONST used here, but not the in the DECLARE statement
   * 219 VIRTUAL used here, but not the in the DECLARE statement
   * 220 ABSTRACT used here, but not the in the DECLARE statement
   * 221 Method declared VIRTUAL, but UDT does not extend OBJECT
   * 222 Method declared ABSTRACT, but UDT does not extend OBJECT
   * 223 Not overriding any virtual method
   * 224 Implemented body for an ABSTRACT method
   * 225 Override has different return type than overridden method
   * 226 Override has different calling convention than overridden method
   * 227 Implicit destructor override would have different calling 
     convention
   * 228 Implicit LET operator override would have different calling 
     convention
   * 229 Override is not a CONST member like the overridden method
   * 230 Override is a CONST member, but the overridden method is not
   * 231 Override has different parameters than overridden method
   * 232 This operator cannot be STATIC
   * 233 This operator is implicitly STATIC and cannot be VIRTUAL or 
     ABSTRACT
   * 234 This operator is implicitly STATIC and cannot be CONST
   * 235 Parameter must be an integer
   * 236 Parameter must be a pointer
   * 237 Expected initializer
   * 238 Fields cannot be named as keywords in TYPE's that contain member 
     functions or in CLASS'es
   * 239 Illegal outside a FOR compound statement
   * 240 Illegal outside a DO compound statement
   * 241 Illegal outside a WHILE compound statement
   * 242 Illegal outside a SELECT compound statement
   * 243 Expected 'FOR'
   * 244 Expected 'DO'
   * 245 Expected 'WHILE'
   * 246 Expected 'SELECT'
   * 247 No outer FOR compound statement found
   * 248 No outer DO compound statement found
   * 249 No outer WHILE compound statement found
   * 250 No outer SELECT compound statement found
   * 251 Expected 'CONSTRUCTOR', 'DESTRUCTOR', 'DO', 'FOR', 'FUNCTION', 
     'OPERATOR', 'PROPERTY', 'SELECT', 'SUB' or 'WHILE'
   * 252 Expected 'DO', 'FOR' or 'WHILE'
   * 253 Illegal outside a SUB block
   * 254 Illegal outside a FUNCTION block
   * 255 Ambiguous symbol access, explicit scope resolution required
   * 256 An ENUM, TYPE or UNION cannot be empty
   * 257 ENUM's declared inside EXTERN .. END EXTERN blocks don't open new 
     scopes
   * 258 STATIC used on non-member procedure
   * 259 CONST used on non-member procedure
   * 260 ABSTRACT used on non-member procedure
   * 261 VIRTUAL used on non-member procedure
   * 262 Invalid initializer
   * 263 Objects with default [con|de]structors or methods are only 
     allowed in the module level
   * 264 Static member variable in nested UDT (only allowed in toplevel 
     UDTs)
   * 265 Symbol not a CLASS, ENUM, TYPE or UNION type
   * 266 Too many elements
   * 267 Only data members supported
   * 268 UNIONs are not allowed
   * 269 Arrays are not allowed
   * 270 COMMON variables cannot be object instances of CLASS/TYPE's with 
     cons/destructors
   * 271 Cloning operators (LET, Copy constructors) can't take a byval arg 
     of the parent's type
   * 272 Local symbols can't be referenced
   * 273 Expected 'PTR' or 'POINTER'
   * 274 Too many levels of pointer indirection
   * 275 Dynamic arrays can't be const
   * 276 Const UDT cannot invoke non-const method
   * 277 Elements must be empty for strings and arrays
   * 278 GOSUB disabled, use 'OPTION GOSUB' to enable
   * 279 Invalid -lang
   * 280 Can't use ANY as initializer in array with ellipsis bound
   * 281 Must have initializer with array with ellipsis bound
   * 282 Can't use ... as lower bound
   * 283 FOR/NEXT variable name mismatch
   * 284 Selected option requires an SSE FPU mode
   * 285 Expected relational operator ( =, >, <, <>, <=, >= )
   * 286 Unsupported statement in -gen gcc/clang mode
   * 287 Too many labels
   * 288 Unsupported function
   * 289 Expected sub
   * 290 Expected '#ENDIF'
   * 291 Resource file given for target system that does not support them
   * 292 -o <file> option without corresponding input file
   * 293 Not extending a TYPE/UNION (a TYPE/UNION can only extend other 
     TYPEs/UNIONs)
   * 294 Illegal outside a CLASS, TYPE or UNION method
   * 295 CLASS, TYPE or UNION not derived
   * 296 CLASS, TYPE or UNION has no constructor
   * 297 Symbol type has no Run-Time Type Info (RTTI)
   * 298 Types have no hierarchical relation
   * 299 Expected a CLASS, TYPE or UNION symbol type
   * 300 Casting derived UDT pointer from incompatible pointer type
   * 301 Casting derived UDT pointer from unrelated UDT pointer type
   * 302 Casting derived UDT pointer to incompatible pointer type
   * 303 Casting derived UDT pointer to unrelated UDT pointer type
   * 304 ALIAS name string is empty
   * 305 LIB name string is empty
   * 306 UDT has unimplemented abstract methods
   * 307 Non-virtual call to ABSTRACT method
   * 308 #ASSERT condition failed
   * 309 Expected '>'
   * 310 Invalid size
   * 311 ALIAS name here does not match ALIAS given in DECLARE prototype
   * 312 vararg parameters are only allowed in CDECL procedures
   * 313 the first parameter in a procedure may not be vararg
   * 314 CONST used on constructor (not needed)
   * 315 CONST used on destructor (not needed)
   * 316 Byref function result not set
   * 317 Function result assignment outside of the function
   * 318 Type mismatch in byref function result assignment
   * 319 -asm att|intel option given, but not supported for this target 
     (only x86 or x86_64)
   * 320 Reference not initialized
   * 321 Incompatible reference initializer
   * 322 Array of references - not supported yet
   * 323 Invalid CASE range, start value is greater than the end value
   * 324 Fixed-length string combined with BYREF (not supported)
   * 325 Illegal use of reserved symbol
   * 326 Expected ',' or ';'
   * 327 Expected file number expression
   * 328 Malformed SOURCE_DATE_EPOCH environment variable
   * 329 Graphics routines were used, but the gfxlib has not been ported 
     to this target
   * 330 -fpu sse option can only be used on x86 and x86_64 architectures
   * 331 -fpu neon option can only be used on arm architectures
   * 332 Undefined built-in symbol

Third party programs errors
   These errors occur after the source has been compiled into assembler, 
   they come from the auxiliary programs FB requires to compile a source 
   into an executable: the linker, the assembler and (for Windows programs) 
   the resource compiler.

   If an IDE or a make utility are been used, additional errors can arise. 
   These errors are outside the scope of this help.



--------------------------------------------------------- CompilerTools ----
Tools used by fbc

External tools the FreeBASIC compiler (fbc) may invoke during the 
compilation process.

Description
   FreeBASIC uses several tools for compiling source code in addition to 
   the fbc compiler.  The exact tools used by fbc and how they are invoked 
   depends on how fbc was configured, the host platform (where fbc is 
   running), the target platform (where the produced executable will be 
   run), and other options (like environment variables and command line 
   options).

   FreeBASIC (fbc) may have been configured in one of two ways: either as 
   standalone or prefixed.  The standalone version searches directories 
   relative to where the executable is located.  The prefixed version has a 
   hardcoded path configured in to the compiler indicating where it expects 
   to find additional tools and libraries.  For more information on 
   configuring FreeBASIC, see the INSTALL text file located in the 
   src/compiler directory of the FreeBASIC sources.

   You can check if your installed version of fbc is "standalone" or 
   "prefixed" by invoking fbc with the -version command line option.

Standalone
   If fbc was configured as "standalone", it will search for files relative 
   to where the fbc executable is located.  fbc is at the "top" of the 
   directory tree and searches sub-directories below it.  The "top" 
   directory (which defaults to the location where fbc is located) can be 
   overridden with the -prefix command line option.  "topdir" shown in the 
   directories below represents the directory where the fbc executable is 
   located, or the directory specified with the -prefix command line option 
   (if it was given). "<target>" refers to the target platform having the 
   same name as specified by the -target option.

   If not cross compiling, fbc looks in these locations: 
      * /topdir/inc
      * /topdir/lib/<target>
      * /topdir/bin/<target>
      * gcc is queried for missing libraries (currently on linux/freebsd 
        only) 

   If cross compiling, fbc looks in the these locations: 
      * /topdir/inc
      * /topdir/lib/<target>
      * /topdir/bin/<target>
      * gcc is not queried (only target library directory is used)

Prefixed
   If fbc was configured as "prefixed", it will search for files relative 
   to the configured prefix (hardcoded in the fbc executable).  "prefix" 
   shown in the directories below represents the configured prefix, or the 
   directory specified with the -prefix command line option (if it was 
   given).  "<target>" refers to the target platform having the same name 
   as specified by the -target option.

   If not cross compiling, fbc looks in these locations: 
      * /prefix/include/freebasic
      * /prefix/lib/freebasic/<target>
      * /prefix/bin/freebasic/<target>
      * gcc is queried for missing libraries (currently on linux/freebsd 
        only) 

   If cross compiling, fbc looks in the these locations: 
      * /prefix/include/freebasic
      * /prefix/lib/freebasic/<target>
      * /prefix/bin/freebasic/<target>
      * gcc is not queried (only target library directory is used)

GCC Queries
   If fbc is unable to locate a file, it may invoke gcc -print-file-name=<
   file> to query the location of the file.  The following are files that 
   may be located using gcc:
      * crt1.o
      * crtbegin.o
      * crtend.o
      * crti.o
      * crtn.o
      * gcrt1.o
      * libgcc.a
      * libsupc++.a
      * libc.so (Linux only)

Finding Binaries
   fbc will invoke additional tools (binary executables) as part of the 
   compiling and linking process.  The following is a list of tools 
   (executables) that may be invoked by fbc depending on the host platform, 
   target, or type of executable or library to be produced:
      * as
      * ar
      * ld
      * gcc
      * GoRC
      * dlltool
      * pexports
      * cxbe

   fbc will search for these tools in the following manner:
      * If an environment variable (having same name as the tool without 
        any extension, all in uppercase) has been set, it explicitly 
        indicates the path and name of the executable to be invoked.
      * If the file (or a symlink) exists in prefix/bin/freebasic/<target>
        , or ./bin/<target> for the standalone version, then use it.
      * On Linux, if the tool could not be found in prefix/bin/freebasic/<
        target>, or ./bin/<target> for the standalone version, fbc tries to 
        invoke it anyway as it may be installed on the system and located 
        on the PATH.

   "<target>" refers to the target platform having the same name as 
   specified by the -target option.

See also
   * Running FreeBASIC
   * Compiler Command Line Options
   * Compiler FAQ



------------------------------------------------- CompilerInstallingGcc ----
Installing gcc for -gen gcc

Windows 32bit

If you are using the FreeBASIC-x.xx.x-win32 package, you can use our 
pre-made gcc package. Download gcc-x.x.x-for-FB-win32-gengcc.zip from the 
Binaries - Windows/More/ directory at the fbc downloads area, and extract 
it into the FreeBASIC installation directory (where fbc.exe is), such that g
cc.exe and cc1.exe will be placed in these locations:

   * bin\win32\gcc.exe
   * bin\libexec\gcc\i686-w64-mingw32\x.x.x\cc1.exe

You can also download Win32 versions of gcc directly from the MinGW.org or 
MinGW-w64 projects.

Windows 64bit

The FreeBASIC-x.xx.x-win64 package already comes with gcc included, and 
uses -gen gcc by default (because -gen gas does not support 64bit).

DOS

It requires a (minimal) DJGPP installation. DJGPP can be downloaded from 
the DJGPP website. At least the djdev*.zip and gcc*b.zip are needed. In 
order to run the DJGPP gcc, the DJGPP environment variable must be set to 
point to the djgpp.env file.

To use the DJGPP gcc with the FreeBASIC-x.xx.x-dos package, copy gcc.exe 
and cc1.exe into the FreeBASIC installation directory, such that they will 
be placed in these locations:

   * bin\dos\gcc.exe
   * bin\libexec\gcc\djgpp\x.xx\cc1.exe

Linux

Typically the gcc package is already installed, or it can be installed by 
doing something like:
   sudo apt-get install gcc
(the exact command depends on your GNU/Linux distribution)

Non-standalone fbc installed into DJGPP/MinGW toolchains

If you are using a non-standalone version of fbc (e.g. from one of the 
fbc-x.xx.x-win32 packages), and have it installed inside a DJGPP or MinGW 
toolchain, then -gen gcc should already work, as the DJGPP or MinGW 
toolchains provide gcc.

As long as gcc.exe is in the same directory as fbc.exe (typically 
C:\DJGPP\bin\ or C:\MinGW\bin\), or available in the PATH environment 
variable, fbc.exe should be able to find and use it.

See also
   * -gen <backend>





============================================================================
  FREEBASIC DIALECTS AND QBASIC
  -----------------------------


------------------------------------------------------------ CompilerQB ----
FreeBASIC and QBasic

FreeBASIC the Successor
   FreeBASIC is designed as an official successor of sorts to a high level 
   compiler for MS-DOS titled "QuickBASIC", which compiled BASIC code, an 
   easy-to-read programming language created in 1964 by John Kemeny and 
   Thomas Kurtz.  "QB" was packaged with a user-friendly IDE and 
   interpreter that made it very easy to write custom applications.  This 
   line of products is officially continued today in the form of "Visual 
   Basic", part of Microsoft's Visual Studio .NET programming suite.

Microsoft and BASIC Products
   Microsoft and BASIC extend far prior to QuickBASIC.  In fact, 
   Microsoft's first product was a small BASIC interpreter for Altair 
   computers released in 1975, and until the early 1980s Microsoft was 
   known only as a language vendor.  They ported their BASIC software to 
   several different personal computers at the time and made decent 
   business doing it.

   In August of 1981 Microsoft released the next major step in its BASIC 
   line, "Advanced BASIC", as part of a commission for IBM's PC-DOS, and is 
   more often called by its executable name, BASICA.EXE.  For Microsoft's 
   new MS-DOS, they released GW-BASIC, which was, for the most part, a port 
   of BASICA that did not require IBM's Basic ROM included with its 
   systems.

   BASICA and GW-BASIC are interpreters.  Interpreters read source code and 
   "interpret" it into computer code as it is read.  This is useful, but 
   slow.  Microsoft, in 1983, released BASCOM for MS-DOS.  BASCOM compiled 
   BASIC code into native machine code, which ran much faster than 
   interpreted code.  This was repackaged with an IDE and released as 
   QuickBASIC in 1985.

QuickBASIC
   From 1985 to 1992, QuickBASIC was the primary BASIC product, released by 
   Microsoft and using BASCOM, and later the Microsoft BASIC Compiler.  In 
   1991, a slimmed down interpreter often thought to be the missing 
   "QuickBASIC 5.0" was packaged with MS-DOS 5.0 and released as "QBasic 
   1.1".

   QuickBASIC as a BASIC dialect provides a loose standard for modern BASIC 
   compilers.  It abolishes the need for line numbers as a used in previous 
   BASIC interpreters, is case sensitive and has keywords that are in plain 
   English.  QuickBASIC also featured a runtime library, a library compiled 
   by default and usable in source code, with many useful commands.

   In 1991, Microsoft combined a drag-and-drop GUI designer made in 1988 
   called 'Ruby' with QuickBASIC.  This product was called "Visual Basic", 
   and marks the beginning of the end of QuickBASIC.  Microsoft released 
   one last version of QuickBASIC called "Visual Basic for DOS" in 1992, 
   and discontinued the product forever.

The Internet and QBasic's Second Wind
   Because the "QBasic 1.1" interpreter was packaged with MS-DOS, it was 
   released with every copy of DOS until its dying days, Windows 3.1, and 
   even Windows 95, 98 and ME.  With the wild success of Windows, QBasic 
   became the most widely available programming tool available for 
   Microsoft operating systems.  

   When the World Wide Web became popular in the mid-90s, many hobbyist 
   programmers made websites dedicated to QuickBASIC not as an application 
   tool, but as a platform for their demos and games.  Many assembly 
   libraries were created for it after Microsoft dropped support, and as 
   these demos and games became more elaborate, so did the "QB Community".  
   From the mid-90s, through the new millennium to today, QuickBASIC has 
   enjoyed a small but present cult following.  

   Andre Victor, FreeBASIC's creator, was first known over the internet as 
   the author of several extensions to QuickBASIC in the form of libraries. 
   He created routines to improve the speed of floating point operations, 
   access the internet, use SVGA graphics, and provide powerful QBasic 
   language programming features.  In the late summer of 2004, he began 
   work on a 32-bit compiler using Visual Basic for DOS.

FreeBASIC is Born
   FreeBASIC was first programmed in VB-DOS, with the goal of compiling 
   itself.  Because of this, both its syntax and runtime library are 
   designed to emulate QB's syntax and runtime as far as it is practical in 
   a 32-bit Windows environment.  For the most part, the two dialects are 
   extremely similar, and most code can be ported with little or no 
   modification, though in some cases routines reliant on 16-bit DOS must 
   be rewritten.  The resulting compiler shares a greater similarity to QB 
   than any compiler on the market, including Visual Basic.

   Because of its open source, its well-written code and its similarity to 
   QB, FreeBASIC has become popular among the "QB Community" and its 
   boundaries continue to grow as it receives more attention and gathers 
   more features that promise to move BASIC into the future.



---------------------------------------------------------------- LangQB ----
Differences from QB

FreeBASIC introduced a -lang command-line option, that is used to change 
the language compatibility mode. Use the -lang qb option when compiling to 
select the most QB compatible parser. All differences listed below assume 
that -lang qb was used.

Architecture/Platform incompatibilities
   * FreeBASIC is written for 32-bit operating systems and a 32 bit DOS 
     extender, and cannot utilize code which depends on 16-bit DOS, 16 bit 
     assembly or memory model (segment & offset, XMS/EMS, ...). 	
   * DEF SEG is no longer necessary and will not work - any code which 
     POKEs to video memory this way will no longer function, however, for 
     DOS it can be easily rewritten using DPMI features. 
   * CALL INTERRUPT no longer functions, as it relies on 16-bit DOS. DOS 
     interrupts can be called in the DOS32 version by using the DPMI 
     library, but they might work slowly because of the 32bit-16bit-32bit  
     mode changes the processor will have to perform. 

Changed due to ambiguity
   * A scalar variable and an array with the same name and suffix can no 
     longer share the same name.
   * SHARED can't be used inside a SUB or FUNCTION as it resulted in 
     shared variables not defined in the main program. A proper DIM SHARED 
     in the main program must be used.
   * COMMON declarations do not depend on the order they are made, 
     variables are matched by name and for that reason named COMMON is no 
     longer supported. All COMMON arrays are variable-length arrays in FB.
   * If a single line If has an (unnecessary) colon directly after the 
     THEN, it has to be terminated by an End If in FB. If that unneeded 
     colon is removed, FB will behave as QB.

Design differences
   * Graphics support was internally redesigned, see GfxLib overview
   * CLEAR is no longer used to reset all variables and set the stack. 
     Variables must be reset one by one, and stack size can be changed in 
     the compiler command line. The keyword CLEAR is used to do memory 
     fills in FB.
   * String DATA items must be enclosed in quotes in FB, in QB this was 
     optional
   * All functions must have been declared, even with a CALL in FreeBASIC. 
     With CALL it was possible to invoke prototype-less functions in 
     QuickBASIC. (to be supported in future with -lang qb)
   * In FreeBASIC all arrays must be explicitly declared. (Interpreted 
     QuickBASIC arrays are automatically created with up to 10 indices.)
   * Strings, except fixed length strings of STRING*N type since fbc 
     version 1.20.0, use a null (char 0) terminator to be compatible with C 
     libraries and the Windows API, so such fixed-length strings can't 
     contain chr$(0) chars.
   * When INKEY[$] reads an extended key (Num Pad, Arrows...) it returns a 
     two character string. In FB the first character is CHR[$](255), while 
     in QB this first char is CHR$(0). 
   * With fixed length strings, except fixed length strings of STRING*N 
     type since fbc version 1.20.0, FreeBASIC gives the real length as Len 
     plus one (null-char), even on Type fields.
   * In FreeBASIC, unused characters of fixed-length strings are set to 0, 
     regardless of what "-lang" compiler option is used. In QB, unused 
     characters are set to 32 (space, or " ", in ASCII).
   * When a fixed-length string, except fixed length strings of STRING*N 
     type since fbc version 1.20.0, is declared, but still not initialized, 
     all characters are set to 0, both in FreeBASIC and QB. Since fbc 
     version 1.20.0, when a fixed-length string of STRING*N type is 
     declared, but still not initialized, all characters are set to space.
   * The arrays are stored in row-major order in FB, they were stored in 
     column-major order in QB by default. Row major order: data with 
     consecutive last index are contiguous. Column-major order: data with 
     consecutive first index are contiguous.  For example, if you have DIM 
     A(1 TO 6, 1 TO 8), in row-major order the elements are stored such 
     that A(3,5) is followed in memory by A(3,6); in column-major order 
     A(3,5) is followed in memory by A(4,5).
   * Programs don't stop anymore on runtime errors unless -e, -ex or -exx 
     option is used in the command line. Using these options allow the use 
     of QB style error handling (ON ERROR, RESUME...).
   * Octal numbers are written &o..., whereas in QB they could be written 
     as &o... or &....
   * In FB FOR loops in subs/functions do not accept arguments received 
     byref as counters. A local variable must be used. 
   * FB's Locate does not respect the fourth and fifth arguments for 
     cursor shape.
   * FB's Screen (Graphics) does not allow switching the visible or the 
     work-page. Use ScreenSet instead.
   * FB's Color does not allow a third argument for border color.
   * FB's Timer returns the number of seconds since the computer started, 
     while QB's TIMER returns the number of seconds since midnight. (Win32 
     and Linux only: No more wrapping at midnight! :))
   * In QB a chr$(13) inside a string did a CR+LF when PRINTed. In FB the 
     CHR(13) prints just at what it is, a CR.
   * EOF can no longer be used to detect an empty comms buffer. Empty 
     buffer should be tested comparing Loc with 0 in FB. Also, for files 
     opened in RANDOM or BINARY mode, EOF returns non-zero already after 
     reading exactly the file size, see EOF.
   * Integer variables do not signal overflow errors in FB, even with the 
     -ex or -exx option on. Any QB code relying in catching integer 
     overflow errors will not work in FB. 

Archaic commands
   * BSAVE and BLOAD can be used in FB only to save and retrieve screens 
     or graphic buffers. They will work only if gfxlib is linked, this is,  
     if a graphics screen mode is requested somewhere in the program. The 
     console can't be saved with BSAVE or retrieved with BLOAD. The other 
     use of BSAVE-BLOAD, saving and loading full arrays, can be achieved 
     easily with GET and PUT.
   * FIELD statement (for record definition at runtime) has been left 
     aside. The keyword FIELD is used in FB to specify field alignment in 
     Type variables.
   * PC Speaker commands no longer function: Any references to SOUND or 
     PLAY statements will result in an error message. There is a third 
     party library available to emulate this functionality, but it's not 
     included with FreeBASIC.
   * Fake event-driven programming (ON KEY, ON PEN, ON STRIG, ON TIMER) no 
     longer works. They could be emulated by a separate library.
   * MKSMBF$ and all the MKxMBF$ commands supporting the pre-QB4.0 
     Microsoft proprietary floating point format (MBF) are not implemented.
   * The use of parenthesis in the arguments passed to a function to 
     emulate by-value passing is not permitted. The CALL quirk resulting in 
     all arguments being passed by value, no longer works. The proper ByVal 
     and ByRef keywords must be used.
   * FILES is not implemented. Instead, PDS 7.1-compatible Dir[$] can be 
     used.
   * IOCTL, ERRDEV and ERRDEV$, low level functions to access hardware are 
     not implemented as they were OS-dependent. 
   * CALL ABSOLUTE to run inline machine code is no longer supported. 
     Instead you can use Asm...END ASM blocks to insert inline assembler 
     commands. Or use the ASM ... one line command.



------------------------------------------------------ CompilerDialects ----
FreeBASIC Dialects

   FreeBASIC version 0.17b introduces a -lang command-line option, used to 
   change the language compatibility mode for different dialects of the 
   basic language.

   Starting with version 0.18.3b the -lang qb dialect has been further 
   restricted to only allow what would have been allowed in QuickBASIC.

   In version 0.18.4b the -lang fblite dialect was added, intended to 
   replace -lang deprecated in future.

   In version 0.20.0b the #lang directive and $Lang metacommand were added 
   to specify a dialect from source.

      +------------+----------------------------------------------------------------------------+
      |-lang option|description                                                                 |
      |fb          |FreeBASIC compatibility (default)                                           |
      |qb          |qbasic compatibility                                                        |
      |fblite      |FreeBASIC language compatibility, with a more QBASIC-compatible coding style|
      |deprecated  |compatibility with FB 0.16                                                  |
      +------------+----------------------------------------------------------------------------+

   The -lang option was needed to allow FreeBASIC to support 
   object-orientation and other features in the future, without crippling 
   the QuickBASIC support or breaking compatibility with old FreeBASIC 
   sources, and without making FreeBASIC difficult to maintain with many 
   different versions of very similar packages. The QuickBASIC support can 
   continue to be improved, if needed, without breaking the sources written 
   specifically for FreeBASIC.

   To compile old GW-BASIC or QuickBASIC/QBasic sources without too many 
   changes, use the -lang qb option on the command-line when running fbc. 
   This option will evolve into a better compatibility with 
   QuickBASIC/QBasic code.

   To compile FreeBASIC sources from 0.16b, use the -lang deprecated 
   option. This option is maintained for compatibility and will not evolve 
   in the future, and it's likely to disappear when FreeBASIC reaches a 
   non-beta release.

   For programmers who want to access some of FreeBASIC's newer features, 
   but want to retain a more QBASIC-friendly programming style, use the 
   -lang fblite option.  This dialect will not undergo significant changes 
   in the future, but will continue to be maintained and supported.
   This option is also the most compatible with sources that were made 
   using older versions of FreeBASIC.

   It is recommended to use -lang fb for new projects, as new features 
   (object classes, inheritance..) will be added exclusively to this 
   dialect.

   -lang fb (the default mode)
    
   Not supported:
    
   1) implicit variable declaration
      * All variables must be explicitly declared, using Dim, ReDim, Var, 
        Const, Extern or Common.
    
   2) type suffixes (!, #, $, %, &)
      * They are only allowed for numeric literals, but it's recommended 
        to use Cast or the f (single), d (double), ll (longint), ul (ulong
        ), ull (ulongint) numeric literal suffixes to resolve overloading.
    
   3) DefByte, DefUByte, DefShort, DefUShort, DefInt, DefUInt, DefLng, 
   DefLongInt, Defulongint, DefSng, DefDbl, DefStr
      * An explicit type ("As T") is needed when declaring variables using 
        Dim, ReDim, Extern or Common. Variables declared using Var or Const 
        have their types inferred from an initialization value (an explicit 
        type is optional using Const).
    
   4) all parameters passed by reference by default
      * By default, all intrinsic scalar types - numeric and pointer types 
        - are passed by value (ByVal). Any other type - String or 
        user-defined type - is passed by reference (ByRef).
      * Use the -w pedantic command-line option to have parameters without 
        explicit ByVal or ByRef reported.
    
   5) OPTIONs of any kind (no context-sensitivity)
      * Instead of Option NoKeyword, use #undef.
      * Instead of Option Escape, use: !"some esc seq \n\r" (notice the '!
        ' char) and pass -w pedantic to check for possible escape 
        sequences.
      * Option Explicit isn't needed, see item 1.
      * Instead of Option Dynamic, declare variable-length arrays using 
        ReDim. Dim can also be used to declare variable-length arrays using 
        variable or no subscripts.
      * Instead of Option Base, use explicit lower-bound subscripts in 
        arrays declarations.
      * Instead of Option Private, use Private to declare procedures with 
        internal linkage.
      * Instead of Option Gosub and Option Nogosub, use procedures with Sub
        or Function.
    
   6) periods in symbol names 
      * Use namespaces instead.
    
   7) GoSub or Return (From Gosub)
      * Nested procedures may be allowed in future.
    
   8) On Gosub
      * Use Select Case As Const Integer_Expression instead.
    
   9) Resume
      * Most runtime and graphics library procedures now return an error 
        code, like:  IF OPEN( "text" FOR INPUT AS #1 ) <> 0 THEN error... 
    
   10) '$DYNAMIC, '$STATIC, '$INCLUDE meta-commands embedded in comments
      * See item 5 about Option Dynamic.
      * Use #include "filename" instead of '$include.
    
   11) Call or Let
      * Just remove them.
    
   12) numeric labels
      * Named labels can be used instead, e.g. label_name: / Goto 
        label_name.
    
   13) global symbols with the same name as keywords 
      * Declare them inside a namespace. 

-lang deprecated
    
   Supported: Anything allowed in version 0.16b, but:
    
   1) GOSUB/RETURN and ON ... GOSUB (even at module-level)
      * so the GOSUB implementation could be thread-unsafe in the -lang qb 
        mode, allowing fast execution (-lang qb doesn't support 
        multi-threading, while -lang deprecated does).
    
   Not supported:
    
   1) Classes
      * Periods allowed in symbol names make it too difficult and/or 
        ambiguous.
    
   2) Operator overloading
      * Periods allowed in symbol names make it too difficult and/or 
        ambiguous.
    
   3) Constructors, destructors and methods in TYPEs.
      * Periods allowed in symbol names make it too difficult and/or 
        ambiguous.

-lang fblite
    
   Supported: Anything allowed in the -lang deprecated dialect, plus..
    
   1) GOSUB/RETURN
      * Use Option Gosub to enable.  This will disable RETURN from exiting 
        a procedure, due to ambiguity.
    
   Not supported:
    
   1) Scope blocks
      * All variables are given procedure scope.  Explicit Scope blocks 
        may be added later.

-lang qb
    
   Supported: Everything not supported/allowed in the -lang fb dialect, 
   plus..

   1) Call can be used with forward-referenced functions.

   2) Shared can be used inside functions. (W.I.P.)

   3) All variables, implicitly or explicitly declared, are always 
   allocated in the procedure scope, like in QuickBASIC.

   4) The Data statement won't look up symbols, every token is assumed to 
   be a literal string even without quotes, like in QuickBASIC.

   Not supported:

   1) Multi-threading
      * None of the threading procedures may be used.
    
   2) Classes and Namespaces

   3) Procedure and operator overloading

   4) Constructors, destructors and other member procedures in Type 
   definitions.

   5) Scope blocks

   6) Extern blocks

   7) Variable initialization
      * All variables are moved to the procedure scope (like in QuickBASIC
        ), making initializing local variables too difficult to support.





============================================================================
  FAQS
  ----


----------------------------------------------------------- CompilerFAQ ----
Frequently Asked Questions

FreeBASIC questions:

   - What is FreeBASIC?
   - Who is responsible for FreeBASIC?
   - Why should I use FreeBASIC rather than QBasic?
   - Why should I use FreeBASIC rather than some other newer BASIC ?
   - How fast is FreeBASIC?
   - How compatible is FreeBASIC with QuickBASIC?
   - How compatible is FreeBASIC with Windows? DOS? Linux?
   - Does FreeBASIC support Object Oriented Programming?
   - What are the future plans with FB / ToDo list ?
   - Can I program GUI applications in FB ?
   - Is FB suitable for complex / big applications?
   - Can I use a non-latin charset in my FreeBASIC applications?
   - Can I use Serial/COM and Hardware/CPU ports in FB?

Getting Started with FreeBASIC questions

   - Where can I find more information about FreeBASIC?
   - Why doesn't the QB GUI open when I start FreeBASIC?
   - Can I have an offline version of the documentation?
   - What's the idea behind the FB dialects?
   - Why does my program crash when I define an array larger than xx?
   - Why does my program fail to compile with the message 'cannot find -llibname'?

Advanced FreeBASIC

   - How do I link to C libraries?
   - Can I use a debugger?
   - What's the goal of the AR.EXE, AS.EXE and LD.EXE files included with FB ?
   - Is there a limit on how big my source files can be?
   - Can I write an OS in FreeBASIC ?
   - I'm developing an OS, can FreeBASIC be ported to my OS ?
   - Does FreeBASIC support returning reference from Functions, like in C++?

See also

FreeBASIC questions

What is FreeBASIC?
   FreeBASIC is a free, BASIC compiler for Windows (32-bit and 64-bit), 32 
   bit protected-mode DOS (COFF executables, like DJGPP), and Linux (x86, 
   x86_64, and ARM). It began as an attempt to create a code-compatible, 
   free alternative to Microsoft QuickBASIC, but has quickly grown into a 
   powerful development tool, already including support for libraries such 
   as Allegro, SDL, OpenGL, and many others with its default installation.

   Aside from having a syntax mostly compatible with QuickBASIC, FreeBASIC 
   introduces several new features to the aged language, including pointers 
   to variables and functions, and unsigned data types.

   FreeBASIC compiler is self-hosting - written in FreeBASIC, the libraries 
   however are written in C.

Back to top

Who is responsible for FreeBASIC?
   The first versions of FreeBASIC were developed exclusively by V1ctor. 
   Later versions gained contributions from many people, including Lillo, 
   who developed the Linux port and the graphics library, and DrV, who 
   developed the DOS port. 

   See the FreeBASIC Credits page.

Back to top

Why should I use FreeBASIC rather than QBasic?
   FreeBASIC has innumerable advantages over QBasic, QuickBASIC, PDS, and 
   Visual Basic for DOS. 
      * It supports 32-bit and 64-bit processors, where QBasic is designed 
        for 16-bit CPU's.
      * It supports modern OSes. It has ports to Windows, Linux, and 
        32-bit DOS.
      * It supports modern APIs such as SDL, Direct2D or DirectX, Win32, 
        and OpenGL.
      * It is distributed under the GPL, meaning it's free and legal to 
        use, unlike most copies of QuickBASIC / other BASICs.
      * The library is distributed under the LGPL with additional 
        exception, meaning you may do whatever you want with your compiled 
        programs, including selling them.
      * FreeBASIC is many times faster than QuickBASIC / other BASICs.
      * FreeBASIC supports many features, such as pointers and inline 
        Assembly, which are not available in QuickBASIC / other BASICs.
      * QuickBASIC only supports DOS. Windows support for DOS emulation 
        (and thus QuickBASIC) is becoming thinner with every new version. 
        Vista does not support graphics or fullscreen text for DOS 
        applications.

Back to top

Why should I use FreeBASIC rather than some other newer BASIC ?
   FreeBASIC has many traits which make it more desirable than most other 
   BASIC language implementations:
      * FreeBASIC adheres closely to the standard BASIC syntax, making it 
        easier to use.
      * FreeBASIC is compiled to actual programs (executables), not 
        bytecode.
      * FreeBASIC has a large, dedicated community which has actively 
        participated in the development of FreeBASIC.
      * FreeBASIC utilizes standard methods of accessing common C 
        libraries. SDL, for example, is standard C SDL, not a new set of 
        intrinsic commands.
      * FreeBASIC has ports to Windows, Linux, and 32-bit DOS. It retains 
        consistent syntax between the three ports.

Back to top

How fast is FreeBASIC?
   Most tests run by the community have shown FreeBASIC is significantly 
   faster than QuickBASIC, faster than most other GPL or commercial BASICs, 
   and often approaching GCC in terms of speed.
   The Computer Languages Benchmark Game, an independent test team, give 
   FreeBASIC for Linux a speed 1.8 times slower than  GNU g++. Tests are 
   about calculation, memory and disk access speed in console programs, no 
   graphics capabilities were tested. This is not a bad result considering 
   FreeBASIC is not yet an optimizing compiler.
   One area where there is a notable speed deficiency is in 32-bit console 
   modes. While FreeBASIC is consistently on-par with other 32-bit console 
   mode applications, 32-bit console mode operations are significantly 
   slower than 16-bit console operations, as seen in QuickBASIC. In DOS 
   version, some I/O operations can slow down after porting from a 16-bit 
   BASIC to FB - optimizing the code brings the speed back.

Back to top

How compatible is FreeBASIC with QuickBASIC?
   The FreeBASIC built in graphics library emulates the most used QB 
   graphics modes (modes 7,12,13) and implements all the drawing primitives 
   featured in QB. 
   Most compatibility problems arise from the use of 8086-DOS-hardware 
   specific low-level techniques in the old QB programs. VGA port 
   programming, DOS interrupts, memory segment switching, poking to the 
   screen memory or music playing using the PC speaker are not directly 
   supported, even if they can be supported/emulated by external libraries. 
   
   Other issues in porting old QB programs, like variable name clashes with 
   new FB keywords, variables with the name of a QB keyword plus a type 
   suffix, default integer size being 32 bits in FB, are addressed by 
   running FreeBASIC with the commandline switch -lang qb .

   See Differences between FreeBASIC and QuickBASIC.

Back to top

How compatible is FreeBASIC with Windows? DOS? Linux? 
   FreeBASIC is fully compatible with Windows, MS-DOS, FreeDOS and Linux. 
   When planning to create a program for all three platforms, however, keep 
   API availability in mind -- code utilizing OpenGL will work in Windows 
   and Linux, for example, but won't in DOS, because OpenGL is not 
   available for DOS.

Back to top

Does FreeBASIC support Object Oriented Programming?
   FreeBASIC supports classes (user-defined types) with member functions 
   (methods), static methods, static member variables, constructors, 
   destructors, properties, operator overloading, single inheritance, 
   virtual and abstract methods (polymorphism) and Run-Time Type 
   Information (RTTI). Future plans regarding OOP functionality include 
   adding support for multiple inheritance and/or interfaces. For more 
   information see: A Beginners Guide to Types as Objects.

Back to top

What are the future plans with FB / ToDo list ?

   You can find out what's planned for the future releases by directly 
   looking at fbc's todo.txt.

Back to top

Can I program GUI applications in FB ?
   Yes, you can. Headers allowing you to call the  GUI API of Windows and 
   Linux are supplied with the respective versions, but the programs made 
   this way are not portable.
   There are some API wrappers and experimental RAD applications that 
   create non-portable GUI code for Windows.
   For portable programming a multiplatform GUI wrapper  library  as GTK or 
   wx-Widgets may be used. GTK headers are provided with FB, but the OOP 
   functionality currently available in FB prevents the use of wx-Widgets. 
   The programs created with these libraries may require the user to 
   install the wrapper libraries in their systems.
   For games and small graphics applications there are some FB-specific 
   libraries that draw and manage  simple controls as buttons and edit 
   boxes inside the graphics screen, programs made with those libs are 
   entirely portable. 

Back to top

Is FB suitable for complex / big applications?
   The FB compiler is self-hosting, it is programmed itself in FB. That 
   means more than 120 000 lines of code at the moment, a fairly complex 
   application.

Back to top

Can I use a non-latin charset in my FreeBASIC applications?

   FreeBASIC has the Unicode support provided by the C runtime library for 
   the given platform. This means FB DOS won't help you with Unicode. On 
   other platforms you can use Wstrings to support any charset you need. 
   The File OPEN keyword  has an additional Encoding parameter allowing for 
   different encodings. As FreeBASIC is coded itself in FB, this means you 
   can code your source in an Unicode editor so the comments and string 
   literals can be in any character set (keywords, labels and names for 
   variables and procedures must be kept inside the  ASCII set..).
   For the output to screen the support is different from console to 
   graphics. In console mode wstring printing in non latin charsets is 
   supported if the console font supports them. Graphics mode uses an  
   internal CP437 charset (the old DOS charset) font so non-latin output 
   requires a custom made raster font and the use of the Draw String 
   keyword. Third party tools exist to grab an external font and convert it 
   to the  DRAW STRING format.

Back to top

Can I use Serial/COM and Hardware/CPU ports in FB?
    Yes, FB has built in functions to access the serial/COM port and 
   hardware/CPU ports with no need of external libraries. See the 
OS specific FAQ's for details for your OS, and Open Com, Inp and Out .

Back to top

Getting Started with FreeBASIC questions

Where can I find more information about FreeBASIC?
   The FreeBASIC Wiki is the most up-to-date manual for using FreeBASIC, 
   available here.

   Active FreeBASIC related forums, besides the official one, can be found 
   at qbasicnews, Pete's QB Site , the FB Games directory  or  
   freebasic-portal.de (in German).

   Active magazines which regularly have FreeBASIC related articles are 
   QB Express and QBXL Magazine. These magazines are always looking for new 
   articles, so if you think you've got a good idea for an article about 
   FreeBASIC, submit it!

Back to top

Why doesn't the QB GUI open when I start FreeBASIC?
   QB had an Integrated Development Environment (IDE).  FreeBASIC does not.
   FreeBASIC is only a compiler, not a complete QuickBASIC clone. It is a 
   console mode application. It will accept a BAS file on the command line, 
   and spit out an EXE file.
   You can create the BAS file with the simplest plain text editor in your 
   OS (Notepad, EDIT, nano,...), then run the compiler. 
   If you can't live without  syntax coloring, error highlighting, multiple 
   file managing, integrated debugger, context help or other features, you 
   need an IDE. See the OS specific FAQ's for the IDE's and editors 
available.
 
Back to top

Can I have an offline version of the documentation?
   This online Wiki is the official documentation for FB. Usually it is 
   up-to-date with the latest improvements found in the development version 
   of FB.
   Offline versions of this wiki (in CHM, HTML and other formats) are 
   available from the 
   Documentation directory at fbc's downloads site on SourceForge.

Back to top

What's the idea behind the FB dialects?
   The idea is to allow improvements in the language while maintaining 
   backwards compatibility with QB code. The quirks of the QB syntax are 
   not compatible with the more rigid style required by OOP. The new FB 
   keywords often clashed with variable names in old QB programs. QB 
   allowed to use freely dots in variable names and procedures not being 
   UDT's.
   The three dialects  (-lang fb, -lang qb, -lang fblite) allow to combine 
   the best of two worlds. 
   *lang fb provides the framework required for OOP programming . Other 
     dialects don't give access to OOP.
   *lang qb will allow the developers to keep increasing the compatibility 
     with qb programs. Newer keywords in FB can be used by preceding them 
     with two underscores.  For example, Getmouse can be called by using _
     _Getmouse
   *lang fblite offers FreeBASIC language compatibility, with a more 
     QBASIC-compatible coding style.

   See Compiler Dialects for details.

Back to top

Why does my program crash when I define an array larger than xx ?

   This generally happens because you made an automatic fixed-length array 
   too large, and it is corrupting the program stack. You have a couple of 
   options:

   * if possible, reduce the size of the automatic array
   * create a variable-length array, by
      * defining the array with an empty subscript list (using Dim), or
      * defining the array with variable subscripts instead of numeric 
        literals, Constants or Enums (using Dim), or
      * defining the array with ReDim
   * reserve more memory for the program stack by using the -t 
     command-line option when compiling. The default is -t 1024 (kilobytes) 
     or -t 2048 (kilobytes). Note: it's a bad idea to use very large values 
     here.
   * create a static array by defining the array with Static rather than 
     Dim (only locally visible, but globally preserved)
   * define the array with Shared access using Dim (this makes the array 
     fully global)
   * use Pointers and Memory Functions like Allocate and Deallocate to 
     manage memory yourself - this is the preferred way for storing big 
     buffers, but not for beginners.

   Static and variable-length arrays don't use the program stack for their 
   element data, so do not have the problem associated with automatic 
   fixed-length arrays. See Storage Classes for more information. Note that 
   storing huge buffers as static or increasing the stack size far above 
   the default is not a very good idea, since it increases the fixed amount 
   of memory needed to load and start you program, even if most of it is 
   not used later, and can result in performance degrade, or even refusing 
   your program to load at all.    

Back to top

Why does my program fail to compile with the message 'cannot find 
-llibname'"?
   This is an error raised by the linker.  The program is supposed to link 
   to an external library, designated in the program code with #inclib or 
   on the compiler command line with -l.  However, the linker has been 
   unable to find a matching file in any of the library paths.  Check the 
   homepage of the library you want to compile with to find out how to 
   download it, or check ExtLibTOC to see if information about the library 
   can be found there. For general information on libraries and how to use 
   them see Using Prebuilt Libraries and the related pages listed there.

Back to top

Advanced FreeBASIC

How do I link to C libraries?
   C libraries are set up in much the same way in FreeBASIC as they are in 
   C. Every library included with FreeBASIC has a basic include file named 
   "library name.bi" which uses the #inclib metacommand to include the 
   library, and the Declare Statement to declare the functions within the 
   library. FreeBASIC includes hundreds of BI files, see full list of 
   library headers here.

Back to top

Can I use a debugger?
   FreeBASIC can use preferably a debugger compatible with GNU GDB. 
      * Win32: Insight is an user friendly wrapper for GDB, see 
        Win32 related FAQ. 
      * DOS: Be warned that DOS also has product named "Insight", but it's 
        a real mode debugger not usable with FreeBASIC, use GDB or some 
        DPMI32 debugger at least.
      * Linux: use GDB.

   See the OS specific FAQ's for details for your OS.

Back to top

What's the goal of the AR.EXE, AS.EXE and LD.EXE files included with FB ?
   AS.EXE is GAS, the "GNU assembler". It is always involved in 
   compilation. LD.EXE is the "GNU linker", involved in creation of 
   executables. AR.EXE is the "GNU archiver", in fact a librarian, creating 
   .A libraries. 

Back to top

Is there a limit on how big my source files can be?
   Yes, since FreeBASIC is a fully 32-bit compiler it may operate on source 
   files up to theoretically 4GB or 4294967296 bytes, however your RAM 
   capacity should be significantly above the size of your source, 
   otherwise the compilation won't finish or will be very slow at least. 

Back to top

Can I write an OS in FreeBASIC ?

   YES and NO. If you really insist to write an OS and involve FB, the 
   answer is YES. If the question is, whether it is a good idea that you, 
   even more if a beginner, should start coding an OS using FB now, the 
   answer is NO. Several pitfalls apply:
      * OS development is hard, see 
        http://www.osdev.org/wiki/Getting_Started .
      * FB won't help you to bypass the need to deal with assembly, also C 
        might be almost impossible to avoid.
      * You won't be able to use most of the trusted FB features, like 
        graphics, file I/O, threads, memory management, even console I/O 
        ... just control flow, math and logic. If you need those library 
        functions, you will have to reimplement them.
   FreeBASIC relies on GCC, and available informations about developing an 
   OS in C apply to FreeBASIC as well. FB will help you neither more nor 
   less than GCC.

Back to top

I'm developing an OS, can FreeBASIC be ported to my OS ?

Depends. If your OS at least egalizes the functionality of DOS with DPMI32 
(console I/O (seeking, multiple files open, ...), file I/O, memory 
management) and has a port of GCC, then the answer is YES. If you have at 
least an other somewhat compliant C compiler with libraries, it might be 
possible. You can't reasonably port FB for example to an OS allowing to 
load or save a file in one block only, or a 16-bit OS.   

Back to top

Does FreeBASIC support returning references from Functions, like in C++?

Yes, this functionality exists. Procedures can now return references using 
ByRef as datatype for the return type.

Back to top

See also
   * Win32 related FAQ
   * DOS related FAQ
   * Linux related FAQ
and
   * FB Runtime Library FAQ
   * Frequently Asked FreeBASIC Graphics Library Questions



---------------------------------------------------------- FaqPggfxlib2 ----
Frequently Asked FreeBASIC Graphics Library Questions

FreeBASIC Graphics Library questions:

   - How can I link/use Gfxlib?
   - What about the fbgfx.bi header file?
   - How are Get/Put arrays managed?
   - Why is Bsave/Bload crashing?
   - How can I get the red, green, blue, or alpha component of a colour?
   - How can I make the 'x' button in the window header close my application?
   - Can't run programs using Screen 13 or 14 in fullscreen !
   - Why does Imagecreate return a NULL pointer?

FreeBASIC Graphics Library questions

How can I link/use Gfxlib?
   Gfxlib is "built in" into the language, it is not necessary to include 
   any .bi file or to link any library explicitly. FreeBASIC detects you 
   want to use Gfxlib when you use the Screen (Graphics) or ScreenRes 
   statements. So to use Gfxlib, just start a graphics screen mode and use 
   the graphics commands.

Back to top

What about the fbgfx.bi header file?
   The fbgfx.bi header file is available for inclusion by your program, and 
   contains constant and type definitions that may be helpful to the 
   programmer when using Gfxlib. You do not have to explicitly include this 
   file to use Gfxlib however; the header is only available as an aid. It 
   contains the constants for the mode flags that can be passed to 
   Screen (Graphics) and ScreenRes, and also definitions of 
   Keyboard scancodes and the fb.Image buffer structure.

Back to top

How are Get/Put arrays managed?
   In FreeBASIC, images can be used as arrays (as in QB) or as pointers. 
   Either way, the image data is contained in one continuous chunk. The 
   chunk consists of an header followed by the image data. The header can 
   be of two types (old-style and new-style) and determines the format of 
   the following image data, for details see GfxInternalFormats .

Back to top

Why is Bsave/Bload crashing?
   Bsave/Bload can only be used to load and save graphics screens in 
   FreeBASIC. It can't be used to save a text mode screen. To load and save 
   an array check this snippet using file Get/Put .

Back to top

How can I get the red, green, blue, or alpha component of a color?

   Each byte in a color attribute corresponds with the red, green, blue, 
   and alpha components.  The following example shows how to extract the 
   component values from a 16, 24, or 32 bit color attribute.

   #define rgb_a(x) ((x) Shr 24)
   #define rgb_r(x) ((x) Shr 16 And 255)
   #define rgb_g(x) ((x) Shr 8 And 255)
   #define rgb_b(x) ((x) And 255)

   Dim As UInteger c
   Dim As Integer x, y
   Dim As UByte red, green, blue, Alpha

   '' Assume a 16, 24, or 32 bit screen mode has been set
   c = Point(x, y)
   red = rgb_r(c)
   green = rgb_g(c)
   blue = rgb_b(c)
   Alpha = rgb_a(c)

Back to top

How can I make the 'x' button in the window header close my application?
   In windowed graphics mode you can test for the press of the window's X 
   (close) button with Inkey, checking for the value Chr( 255 ) + "k" 
   (which is also the code returned for Alt+F4). This applies to Win32 and 
   Linux, in DOS there is no "X" button.

   Here is a small example:

   '' "X" close button example , Win32 and Linux only
   Dim As String key
   Screen 13
   Do
     Print "Click the 'x' to close this app."
     Sleep
     key = Inkey
   Loop Until key = Chr(27) Or key = Chr(255, 107) 'escape or x-button

Back to top

Can't run programs using Screen 13 or 14 in full-screen!
   It's a hardware/driver limitation (Win32 and Linux only?). Video cards 
   don't implement those low resolution graphic modes nowadays. If 
   full-screen is required you should rewrite it using at least Screen 17 
   or 18, or a resolution of 640x480 or higher to be sure modern hardware 
   can handle it.

Back to top

Why does Imagecreate return a NULL pointer?
   ImageCreate needs to create an image buffer that fits the current 
   screen's pixel format, and it cannot do so if there is no screen mode 
   setup yet, so it returns NULL, very likely resulting in a NULL pointer 
   access later on that crashes the program.

   This is known to happen when Imagecreate is called before the graphics 
   library was initialized with a call to Screen (Graphics) or ScreenRes, 
   as may happen when Imagecreate is called in a global constructor that is 
   invoked before the Screen or Screenres call in the main part of the 
   program. In such a case it is necessary to move the screen 
   initialization into a constructor too, and have it execute before the 
   image-creating constructors.

Back to top

See also
   * Compiler FAQ
   * FB Runtime Library FAQ
   * Frequently Asked FreeBASIC Graphics Library Questions



------------------------------------------------------------ FaqPgrtlib ----
Frequently Asked FB Runtime Library Questions

FreeBASIC Runtime Library questions:

   - How do I play sound?
   - How do I access the serial ports?
   - How do I print?
   - How do I access the hardware ports?

FreeBASIC Runtime Library questions

 How do I play sound?
   Of the QB's sound keywords only BEEP is implemented in FB. 
   If PC speaker sound is required, it should be programmed using IN and 
   OUT. See the example in the OUT keyword for a replacement of SOUND. 
   There is a library called QBSound that allows to emulate qb's ability to 
   PLAY in the background tunes encoded in strings, it uses the soundcard's 
   synthesizer.
   If what's required is to play .wav or .mp3 files thru a soundcard, 
   external libraries as FMOD or BASS can be used in Linux and Windows. For 
   DOS see the DOS FAQ section.

Back to top

How do I access the serial ports?

   DOS
   See DOS FAQ section.

   Windows and Linux
   See Open Com.

Back to top

How do I print?
   FB supports character output to printer.
   To print graphics two approaches are possible:
   * Preprocess the graphics data, program the printer, and send the data 
     to it (see wikipedia.org/wiki/ESC/P). This is OS-portable but depends 
     on the printer model. The only way for DOS, see also DOS FAQ section.
   * In Windows and Linux there are specific API calls. This is not 
     OS-portable but the OS's printer driver makes it printer-independent.

Back to top

How do I access the hardware ports?

   INP, OUT and WAIT known from QB are implemented in FB.
   The GfxLib intercepts the calls to some VGA ports to emulate the widely 
   used QB's palette manipulation and vsync methods. So ports &H3DA, &H3C7, 
   &H3C8 and &H3C9 can't be accessed it GfxLib is used. All other ports are 
   accessible.
   No further tricks are required to use INP and OUT in Linux or DOS. For 
   the Windows version the required device driver is installed each first 
   time the program is run in a windows session; this requires 
   Administrator rights for this first run or the program will end with an 
   error. Note that accessing hardware ports by applications is not common 
   practice in Windows and Linux.

Back to top

See also
   * Compiler FAQ
   * Frequently Asked FreeBASIC Graphics Library Questions
and
   * Win32 related FAQ
   * DOS related FAQ



------------------------------------------------------------- FaqPgxbox ----
Frequently Asked Questions

FreeBASIC on Xbox general questions

   - Can FreeBASIC really make Xbox games?
   - How was the FreeBASIC Xbox port made?
   - How about a port for Xbox 360?
   - How about a port for PlayStation or another console?
   - Why don't you use an emulator until a developer gets a modded Xbox?
   - Why don't you use the Microsoft XDK?
   - Why don't you use the Microsoft debugger to fix it?
   - Isn't this illegal? Can't Microsoft sue you?

Getting Started with FreeBASIC on Xbox questions

   - What do I need to compile Xbox games with FreeBASIC?
   - How would you get input?
   - Does it only run on certain Xboxes?
   - Is another language (eg C or ASM) needed for the job?
   - Do you need a special lib?
   - Can you use premade functions (inkey, line etc)?
   - What else should I know?

FreeBASIC on Xbox general questions

Can FreeBASIC really make Xbox games?

In theory, yes. A copy of FreeBASIC 0.13 was ported to the Xbox in July 
2005, and produced working executables. However, changes to the compiler 
for the 0.14 release broke compatiblity. 

The Xbox port is currently in zombie mode; nobody in the project team has 
the console at the moment - the original port was done by SJ Zero, but it 
got broken with the runtime library modifications done in v0.14.

The port is on hold until the GCC backend port is complete, because it is 
believed that this port will fix the Xbox port.

How was the FreeBASIC Xbox port made?

FreeBASIC for Xbox is possible because of the efforts of Open Source 
developers who created OpenXDK, the legal software development kit for 
Xbox. OpenXDK is created for a unixish environment, which is quite 
compatible with the FreeBASIC source.

The port was created by forcing the FreeBASIC runtime library to use the 
OpenXDK version of Glibc instead of the mingw32 version. When compiled with 
the correct flags, this creates what looks like a standard EXE file. CXBE 
then strips the Windows PE header on this executable file and replaces it 
with an Xbox header.

In effect, all the port really does is change the runtime library and link 
in a certain way to allow the CXBE utility to create an Xbox executable.

How about a port for Xbox 360?

The Xbox is an Intel Pentium 3 running a derivative of the NVIDIA nForce 
chipset, with an NVIDIA video chip and an NVIDIA SoundStorm sound card. 
This is why the Xbox port was possible and relatively straightforward to 
do. 

The Xbox 360, on the other hand, uses an alien CPU, and similarly alien 
hardware. FreeBASIC cannot presently be made to produce executables for the 
Xbox 360. 

Another problem is the lack of an equivilent to OpenXDK for the Xbox 360. 
This would force any port to use the Xbox 360 XDK, a copyrighted piece of 
software created by Microsoft. This would be illegal, immoral, and would 
put FreeBASIC in legal jeparody. 

Therefore, a port to the Xbox 360 is to be considered impossible at this 
time.

How about a port for PlayStation or another console?

The Xbox is an Intel Pentium 3 running a derivative of the NVIDIA nForce 
chipset, with an NVIDIA video chip and an NVIDIA SoundStorm sound card. 
This is why the Xbox port was possible and relatively straightforward to 
do. 

The PlayStation, on the other hand, uses a RISC chip, which FreeBASIC 
cannot currently produce code for. Almost all consoles utilize non x86 
processors, stopping development using FreeBASIC from being possible.

Another problem is the lack of an equivilent to OpenXDK for many consoles. 
This would force any port to use the commercial software development kit, a 
copyrighted piece of software created by the console manufacturer. This 
would be illegal, immoral, and would put FreeBASIC in legal jeparody. 

Therefore, a port to other consoles are to be considered impossible at this 
time. However, many ports to consoles and other platforms with legally 
available development kits will be possible when the GCC backend port is 
complete.

Why don't you use an emulator until a developer gets a modded Xbox?

No known Xbox emulator is capable of running FreeBASIC code. A legitimate 
hardware console is required to run the programs made. This makes an 
emulator completely useless for development. 

Why don't you use the Microsoft XDK?

There are two main reasons not to use the Microsoft XDK.

1) Microsoft's XDK is a piece of copyrighted software, and utilizing it 
would be illegal and immoral, putting FreeBASIC at risk of legal action. 
Furthermore, no member of the FreeBASIC team has ever had any access to the 
Microsoft XDK, to prevent "tainting" FreeBASIC legally.

2) OpenXDK is developed around gcc and UNIX-style systems such as MinGW or 
Cygwin. This means that it can be integrated into FreeBASIC with very 
little effort. Microsoft's XDK, on the other hand, is developed around 
Microsoft based compilers, and thus would not easily integate into the 
source code of FreeBASIC.

NOTE: PROTECTION OF MICROSOFT'S COPYRIGHT, AND BY PROXY OF FREEBASIC, IS OF 
PRIMARY IMPORTANCE IN THIS PROJECT. WE DO NOT WANT HELP FROM ANYONE WITH 
THE XDK, NOR DO WE WANT HELP FROM ANYONE WITH A DEBUGGER XBOX. ANY ATTEMPT 
TO OFFER THE XDK OR XDK RELATED HELP SHALL BE FORWARDED TO THE PROPER LAW 
ENFORCEMENT AGENCIES.

Why don't you use the Microsoft debugger to fix it?

There are two very good reasons not to use the Microsoft debugger. 

1) Microsoft's XDK is a piece of copyrighted software, and utilizing it 
would be illegal and immoral, putting FreeBASIC at risk of legal action. 
Furthermore, no member of the FreeBASIC team has ever had any access to the 
Microsoft XDK, to prevent "tainting" FreeBASIC legally.

2) Microsoft's debugger requires a specially modified Xbox which neither SJ 
Zero nor any development team member has, and frankly, nobody who has 
worked on the port believes the debugger would work with FreeBASIC 
executables -- just as Microsoft's debugger can't read FreeBASIC debugger 
files, we doubt the Xbox debugger could read FreeBASIC debugger files. 
Regardless, point #1 trumps any attempt.

NOTE: PROTECTION OF MICROSOFT'S COPYRIGHT, AND BY PROXY OF FREEBASIC, IS OF 
PRIMARY IMPORTANCE IN THIS PROJECT. WE DO NOT WANT HELP FROM ANYONE WITH 
THE XDK, NOR DO WE WANT HELP FROM ANYONE WITH A DEBUGGER XBOX. ANY ATTEMPT 
TO OFFER THE XDK OR XDK RELATED HELP SHALL BE FORWARDED TO THE PROPER LAW 
ENFORCEMENT AGENCIES.

Isn't this illegal? Can't Microsoft sue you?

Copyright is important for the protection of both commercial firms like 
Microsoft, and for small projects such as FreeBASIC. Without copyright, 
neither could enforce any rights over the code (In our case, such as the 
GPL). Generally speaking, it is copyright issues which are most often the 
cause of problems for open source projects attempting to do things like 
this.

Because the FreeBASIC Xbox port is created using software tools whose 
legality has already been established, themselves often derived from other 
sources whose legality has been established, FreeBASIC for Xbox is not 
illegal. Careful care has been taken to protect FreeBASIC from using any 
Microsoft copyrighted code, and diligence is and will be followed to 
prevent access to copyrighted code.

Getting Started with FreeBASIC on Xbox questions

What do I need to compile Xbox games with FreeBASIC?

The port isn't currently working, but when it is ready, you will only need 
a copy of FreeBASIC for Xbox.

How would you get input?

Initially, input will be acquired through SDL, as a gfxlib port is not yet 
complete. One of the developers is working on a generic SDL version of 
gfxlib, however, and it will provide full gfxlib functionality to the Xbox 
port.

Does it only run on certain Xboxes?

FreeBASIC for Xbox executables will only run on modded Xboxes. However, 
modding an Xbox is often as simple as loading a savegame in a certain game. 
More information is available on the Xbox-Linux website.

Is another language (eg C or ASM) needed for the job?

No. FreeBASIC for Xbox is the only thing needed.

Do you need a special lib?

No. FreeBASIC for Xbox will come with all supported libraries.

Can you use premade functions (inkey, line etc)?

Currently, input and output commands such as inkey and line aren't 
available, but all other functions, including file I/O, are. One of the 
developers is working on a generic SDL version of gfxlib, however, and if 
it functions, it will provide full gfxlib functionality to the xbox port.

What else should I know?

Executables created by FreeBASIC for Xbox are free of copyrighted Microsoft 
code, making them legal for distribution.

Windows and Linux source files which are designed to use SDL and rtlib will 
be capable of compiling for Xbox out of the box. While the Xbox does have 
keyboard support through the gamepad ports (proprietary USB connection), 
the input scheme will have to be altered to account for a gamepad.



---------------------------------------------------------------- FaqDOS ----
DOS related FAQ

DOS

The FreeBASIC port to DOS is based on the DJGPP port of the GNU toolchain 
to 32-bit protected-mode DOS.

The current maintainer of this port is DrV.

To be written: platform-specific information, differences from Win32/Linux, 
differences from QB?, tutorials, etc. 

WANTED TESTERS

The DOS version/target of FreeBASIC needs more testers. If you are 
interested in using FreeBASIC on DOS, please don't wait for future 
releases, give it a try now. Tests from running in DOS on both old and new 
PC's are welcome (graphics, file I/O, serial port, ...). If something 
doesn't work, please place a detailed bug report into the forum or bug 
Tracker. If all works well, you can write about your success as well. Make 
sure to test a recent version of FB (reports from FB older than 0.90 will 
be probably considered as obsolete and useless), and check this document bef
ore complaining about anything.

Limitations

The DOS target is fairly well working and supported by FreeBASIC, and 
up-to-date. A few differences compared to other platforms exist, however. 
The features missing are mostly those not supported by the operating system 
or DOS extender or C runtime:
   * Cross-compiling to an other target
   * Multithreading (see FAQ 23)
   * Graphics in windowed mode or using OpenGL
   * Setting ScreenRes to a size not matching any resolution supported by 
     the graphics card  
   * Unicode isn't supported in DOS, WString will be the same as ZString, 
     character sets other than latin aren't supported. (do it yourself)
   * Shared libraries (DLL's) can't be created/used (at least not 
     "easily"), amount of available static external libraries usable with 
     DOS is limited

FreeBASIC DOS related questions:

   - 1. FB is a 32-bit compiler - do I need a 32-bit DOS?
   - 2. What about FreeDOS-32? Does/will FB work, is/will there be a version?
   - 3. When running FreeBASIC in DOS, I get a 'Error: No DPMI' message!
   - 4. Is there a possibility how to get rid of this CWSDPMI.EXE and CWSDPMI.SWP?
   - 5. Can I use other DOS extenders, like DOS/4GW, Causeway, DOS/32A?
   - 6. Where is the nice blue screen with all the ... / where is the IDE?
   - 7. How can I view the documentation in CHM or PDF format in DOS?
   - 8. How can I write/edit my source code?
   - 9. How can I play sound in DOS?
   - 10. How can I use USB in DOS?
   - 11. How can I use graphics in DOS?
   - 12. DEF SEG is missing in FB! How can I workaround this in my code?	
   - 13. How can I rewrite QB's CALL INTERRUPT / access the DOS and BIOS interrupts?
   - 14. How can I rewrite QB's XMS/EMS handling?
   - 15. FBC gives me a 'cannot find lsupcxx' error!
   - 16. How can I use the serial or parallel port?
   - 17. How can I use a printer?
   - 18. How can I make a screenshot of a FreeBASIC program running in DOS?
   - 19. Graphics mode doesn't work  (freeze / black screen / garbage output)!
   - 20. Mouse trouble! Mouse doesn't work at all in DOS / arrow 'jumps' / etc. ...
   - 21. What about the 64 KiB and 640 KiB problems / how much memory is supported by FB in DOS?
   - 22. My program crashes when I try to use more than cca 1 MiB RAM! Is this a bug in FreeBASIC?
   - 23. Threading functions are disallowed in DOS? Help!
   - 24. Executables made with FB DOS are bloated!
   - 25. Compilation is very slow with FB!
   - 26. SLEEP doesn't work! How can I cause a delay?
   - 27. The performance is very bad in DOS!
   - 28. Can I access disk sectors with FB?
   - 29. Can I use inline ASM with advanced instructions like SSE in DOS ?

See also

FreeBASIC DOS related questions

1. FB is a 32-bit compiler - do I need a 32-bit DOS?
   No, the DOS version of FreeBASIC uses a DOS extender, allowing you to 
   execute 32-bit code on top of a 16 bit DOS kernel. You can use FreeDOS 
   (16-bit), Enhanced-Dr-DOS, old closed Dr-DOS, or even MS-DOS down to 
   version cca 4. You need at least 80386 CPU, see also Requirements.

2. What about FreeDOS-32? Does/will FB work, is/will there be a version?
   FreeDOS-32 is experimental at time of writing, but it should execute 
   FreeBASIC and applications generated by it with no change. While FB DOS 
   support already works on FreeDOS (16), it should be ready for FreeDOS-32 
   as well. 

3. When running FreeBASIC in DOS, I get a 'Error: No DPMI' message!
   You need a DPMI host (DPMI kernel, DPMI server), means the file 
   "CWSDPMI.EXE" (cca 20 KiB) or HDPMI32.EXE (cca 34 KiB). See 
   requirements, and FAQ 4 for more details.

4. Is there a possibility how to get rid of this CWSDPMI.EXE and 
CWSDPMI.SWP?
   Yes, 2 possibilities. To get rid of CWSDPMI.EXE and create a standalone 
   DOS executable embedding CWSDPMI, you need the CWSDPMI package and the 
   "EXE2COFF.EXE" file. Using EXE2COFF, you remove the CWSDPMI.EXE loader 
   (file loses 2 KiB of size, resulting in a "COFF" file without 
   extension), and then glue the file "CWSDSTUB.EXE" before this COFF. The 
   new executable is cca 21 KiB bigger than the original one, but it is 
   standalone, no additional files are needed. To get rid of CWSDPMI.SWP, 
   you can then edit your executable with CWSPARAM.EXE, and disable the 
   swapping (occasionally also - incorrectly - referred as paging).  Note, 
   however, that this will limit the memory that can be allocated to the 
   amount of physical memory that is installed in a system. This work can 
   be done both with the FBC.EXE file and all executables created by FBC. 
   The method is also described in the CWSDPMI docs in the package. 
   Alternatively, you can use the WDOSX or D3X extender. They don't swap 
   and create standalone executables. Since they run your executable in 
   Ring 0, the crash handling of them is not very good and can cause 
   freezers or reboots on bugs where other hosts exit the "civil" way with 
   a register dump. Also, spawning might not work well / at all with WDOSX 
   or D3X. Finally, you can use HDPMI . Download the "HXRT.ZIP" file (here: 
   japheth.de/HX.html alternative links), extract "HDPMI32.EXE" (cca 34 KiB)
   and "HDPMI.TXT" (not required by the code, just for your information), 
   and include it to your DOS startup ("HDPMI32 -r"). This will make HDPMI 
   resident and prevent all FreeBASIC (also FreePASCAL and DJGPP) programs 
   from both crying about missing DPMI and swapping. HDPMI can not (easily 
   / yet) be included into your executables. Running an executable 
   containing D3X, CWSDPMI or some DPMI host inside under HDPMI or other 
   external host is fine - the built-in host will be simply skipped. Using 
   DPMI is definitely required for FreeBASIC, since it can't generate 
   16-bit real mode code, and there is no other good way to execute 32-bit 
   code in DOS.

5. Can I use other DOS extenders, like DOS/4GW, Causeway, DOS/32A?
   Not any extender around. So-called WATCOM-like extenders can't be used 
   because of important differences in memory management and executable 
   structure. WDOSX and D3X do work, since they are a multi-standard 
   extenders, not only WATCOM-like. You also can use PMODE/DJ (not 
   "original" Tran's PMODE, nor PMODE/W (!), saves cca 5 KiB compared to 
   CWSDPMI, can be included into the EXE, but might affect stability or 
   performance) or, as aforementioned, HDPMI.

6. Where is the nice blue screen with all the ... / where is the IDE?
   The FreeBASIC project focuses on the compiler, generating the 
   executables from your BAS sources. It looks unspectacular, but is most 
   important for the quality of software developed by you. The project does 
   not include an IDE. There are several external IDEs for FreeBASIC, but 
   probably none does have a DOS version by now.  If you really need one, 
   you could try Rhide, but note that it is complicated and buggy, so use 
   it at your own risk. See also FAQ 7 and 8.

7. How can I view the documentation in CHM or PDF format in DOS?
   There is no good way to view CHM or PDF files in DOS by now. But you can 
   view the FreeBASIC documentation nevertheless. One of the FreeBASIC 
   developers, coderJeff provides a FreeBASIC documentation viewer with the 
   docs included in a special format, and having also a DOS version. It 
   looks similar the QB's built-in help viewer, but does not contain an 
   editor or IDE. Download here: 
   http://www.execulink.com/~coder/FreeBASIC/docs.html

8. How can I write/edit my source code?
   There are many editors for DOS around, but only few of them are good - 
   some possibilities are FreeDOS EDIT (use version 0.7d (!!) or 0.9, 64 
   KiB limit, suboptimal stability (save your work regularly) ), SETEDIT, 
   INFOPAD (comes with CC386 compiler, can edit big texts also, has syntax 
   highlighting for C and ASM, but not for BASIC).

9. How can I play sound in DOS?
   There are 2 ways how to play sound in DOS: either the ("archaic") PC 
   speaker, famous for beeping if something goes wrong, or a soundcard. The 
   speaker is easy to control, allows more than one might think, even to 
   play audio files (WAV, with decompression code also OGG Vorbis, MP3 
   etc.), you can re-use most of existing QB code easily (example: 
   o-bizz.de/qb...speaker.zip) or ASM code via inline ASM,  but provides 
   one channel and 6 bits only, and of course significantly worse quality 
   than a soundcard, and, on some newest (P4) PC's the speaker quality is 
   very bad or there is no speaker at all. For old ISA soundcards, there is 
   much example code around, a newer PCI soundcard can be accessed 
   (supposing bare DOS in this category) either using a ( "emulation" SB16 
   compatible) driver, if it is available for your card (unfortunately, 
   this is becoming more and more a problem, the DOS drivers are poor or 
   even inexistent), or access the card directly (this is low-level 
   programming, hardware-related, assembler is also needed, and you need 
   technical docs about the card). There are a few sources of inspiration 
   like the DOS audio player MPXPLAY (written in C with some ASM), 
   supporting both methods (native + "emu" drivers), see an up-to-date list 
   here: drdos.org/...wiki...SoundCardChip. Support of sound in DOS is not 
   business FB DOS port, actually FB doesn't "support" sound on Win32 and 
   Linux either - the games "connect to the API" rather than use FreeBASIC 
   commands or libraries. To play compressed files (MP3, OGG Vorbis, FLAC, 
   ...) , you additionally need the decompressing code, existing DJGPP 
   ports of those libraries should be usable for this.

10. How can I use USB in DOS?
   Again, not business of FB, you need a driver, FB doesn't "support" USB 
   on Win32 or Linux either, see other Wiki: drdos.org/...wiki...USB about 
   possibilities of USB usage in DOS.

11. How can I use graphics in DOS?
   GUI or graphics in DOS is definitely possible, there are several 
   approaches:
      *Use the FB graphics library. It uses VESA (preferably linear, but 
        also supports banked) to access the video card and supports any 
        resolution reported by the card's VESA VBE driver, in addition to 
        standard VGA modes.
      *VGA mode 320x200x8bpp: very simple, maximum reliability and 
        compatibility, but low resolution and 256 colours only, see 
        example.
      *VGA "ModeX" 320x240x8bpp: similar to above, less easy, good 
        reliability and compatibility, but low resolution and 256 colours 
        only, see example.
      *VGA "planed" mode 640x480x4bpp: difficult to set pixels, maximum 
        reliability and compatibility, but low resolution and 16 colours 
        only, no public example yet (?).
      *Some other "odd" VGA "ModeX" modes (like 360x240x8bpp): possible, 
        but for freaks only ;-)
      *Write your own VESA code: More difficult, good compatibility, 
        high-res and true color possible, there might be reliability 
        problems if not implemented carefully.
      *Use an external library (DUGL, Allegro, MGL, WxWidgets): Allows to 
        create "expensive" graphics & GUI's, bloats EXE size, need to 
        respect library license, potential loss of reliability.
   Note that some graphic cards report limited features through VESA, most 
   notably less memory (for example 8 MiB instead of 64 MiB) or less modes 
   (for example only 24 bpp modes visible while 32 bpp hidden, only lower 
   resolutions visible (up to cca 1280x1024) while higher hidden, only 
   "4:3" modes visible while "wide" modes hidden). This is a problem of the 
   card, not of DOS or FreeBASIC. You will see the additional features in 
   systems other than DOS, or in DOS only using hardware detection tools 
   going to the lowest level bypassing VESA.

12. DEF SEG is missing in FB! How can I workaround this in my code?
   DEF SEG is related to 16-bit RM addressing and was removed because of 
   this. "direct" access to VGA or other low memory areas is not possible, 
   because FreeBASIC's memory model (same as DJGPP's) is not zero-based. 
   For accessing low DOS memory, use DOSMEMGET and DOSMEMPUT , see 
   "vga13h.bas" example, or "_dos_ds" selector for inline ASM, see example:

   '' DOS only example of inline ASM accessing low memory 
   '' Run in text mode 80x25 only

   '' Including dos/go32.bi will define "_dos_ds"
   '' "pointing" into GO32 block

   #include "dos/go32.bi" 

   Dim As UInteger DDS

   DDS=_dos_ds

   ? : ? "Hello world !"
   ? "_dos_ds=$";Hex$(DDS) 
   ? "This is just a tEst - abcd ABCD XYZ xyz @[`{ - press any key ..."

   Do
     Sleep 1000
     If Inkey$<>"" Then Exit Do
     Asm
      mov  eax,[DDS] '' Directly using "_dos_ds" won't work here !!!
      push eax
      pop  gs        '' Just to get sure, it is usually set anyway
      Xor  ebx,ebx
      aa3:
      mov  al,[gs:0xB8000+2*ebx]
      cmp  al,65  '' "a"
      jb   aa1
      cmp  al,122 '' "z"
      ja   aa1   
      cmp  al,90  '' "Z"
      jbe  aa2
      cmp  al,97  '' "a"    
      jb   aa1 
      aa2: 
      Xor  al,32  '' Swap case
      aa1:
      mov  [gs:0xB8000+2*ebx],al
      inc  ebx
      cmp  ebx,2000
      jne  aa3
     End Asm  
   Loop
   ? : ? "Bye"
   End

13. How can I rewrite QB's CALL INTERRUPT / access the DOS and BIOS 
interrupts?
   Those interrupts can be accessed only using the DOS version/target of 
   FB.

   The access to interrupts is slower than in QB: with FB the DPMI host 
   will have to do 2 context switches, going to real-mode and coming back. 
   All of that will eat hundreds of clocks in raw DOS and thousands of 
   clocks if emm386 is loaded or if inside a Windows' DOS box. The slow 
   down might be negligible or relevant, it depends. You should try to 
   minimize the number of such calls, and process more data per call  - at 
   least several KiB, not just one byte or a few bytes.
 
   Use DJGPP's DPMI wrapper:

   #include "dos/dpmi.bi"

   Type RegTypeX As __dpmi_regs

   #define INTERRUPTX(v,r) __dpmi_int( v, @r )

   Alternatively you can call INT's via inline ASM, 2 important things you 
   have to care about are the fact that FB's memory model is not zero-based 
   (see also FAQ 12, "DEF SEG" issues), and additionally "direct" passing 
   of addresses (like DS:[E]DX) to an INT will not work except you have a 
   DPMI host with "DOS API translation".  

14. How can I rewrite QB's XMS/EMS handling?
   Depends why original code uses it. If it's just to bypass low memory 
   limits, simply remove it and use "ordinary" FB's data types / memory 
   handling features instead. If it is used for (sound) DMA, you are out of 
   luck and have to redesign the code completely, about sound see FAQ 9. 
   For DMA use preferably the low memory (should be no big problem, since 
   the application code and most buffers are in DPMI memory instead), DMA 
   in DPMI memory is possible but more difficult.  

15. FBC gives me a 'cannot find lsupcxx' error!
   The source of this problem is the libsupcxx.a file in LIB\DOS\ 
   directory, having 9 characters in the name. Your fault is to have 
   extracted the ZIP with long file names enabled, usually in Windows, and 
   then using FB in DOS with no LFN support, resulting in this file looks 
   LIBSUP~1.A and can't be found. Rename the file in LIBSUPCX.A (one X 
   only) or extract the ZIP again in DOS. Note: changes in FB 0.18, retest 
   needed. 

16. How can I use the serial or parallel port?
   The DOS INT14 is not very useful/efficient as it sends/reads a single 
   char in each call. So it's better to use an external DOS32 comms 
   library. /* does someone know a good one ? */ FB up to 0.18.2 doesn't 
   support OPEN COM on DOS target, coderJeff has an experimental 
   library/driver available, included with FB since 0.18.3. 

17. How can I use a printer?
   DOS kernel won't help you here, so you have to prepare the text 
   (trivial) or pixel data (acceptably easy for printers compatible with 
   the "ESC/P" standard) yourself and send in to the printer via the 
   parallel port or USB using an additional driver (see FAQ 10). So-called 
   "GDI" or "Windows" printers can't be made working in DOS with reasonable 
   effort.

18. How can I make a screenshot of a FreeBASIC program running in DOS?
   Ideally include this feature into your own code. DOS TSR based 
   screenshooters like SNARF mostly will work with text based screens, but 
   probably none of them with FreeBASIC's GFX library. It's not really a 
   bug on one or other side, it's a problem "by design".

19. Graphics mode doesn't work  (freeze / black screen / garbage output)!
   Place a bug report into the forum. To make it as useful and productive 
   as possible, please beware of the following, proceed given steps and 
   provide all related information:
      * Check the limitations listed on the page GfxLib
      * The graphics might not work well / at all on very old PC's. If 
        your CPU has less than cca 500 MHz, provide exact info about it, if 
        you don't know, use RayeR's CPUID or similar program to test.
      * Exact info about your graphics card is needed. Test on DOS using 
        DrV's VBEDIAG (reports info only) and RayeR's VESATEST (also tries 
        to set mode, allows visual inspection of the result). Find out what 
        "useful" modes (640x480, 800x600) are supported and with what 
        bitdepths (8, 16, 24, 32 bpp), and whether they can be set and look 
        correctly.
      * Find out and describe exactly what's wrong ("mode works with 
        VESATEST but not with FB", "no graphics but no error either", 
        "black screen and freezer", "graphics is messy/incomplete", ...).
      * If some sophisticated program doesn't work, try also a minimal 
        test like placing a circle in middle of the screen.
      * Try without a mouse driver (this reduces the CPU "cost").
      * Find out what modes are affected. If a mode doesn't work, reduce 
        the resolution or bitdeph, make sure to test the "cheapest"/safest 
        modes 640x480 with 32/24/16/8 bpp, 640x480 with 4 bpp, and 320x200 
        with 8bpp.
      * For some old cards there are VESA drivers available 
        (S3VBE/UVIVBE). Test both with and without, and include this info 
        into your report.
      * Remove potentially problematic content (memory managers, drivers) 
        from DOS startup files. Nothing of such is required for FB, except 
        a DPMI host (see also FAQ 4.).
      * Post info about your graphics card, CPU (if old), DOS type and 
        version, bug symptoms, and a simple example code.
   RayeR's VESATEST and CPUID can be downloaded here: 
   rayer.ic.cz/programm/programe.htm , VBEDIAG here drv.nu/vbediag/.

20. Mouse trouble! Mouse doesn't work at all in DOS / arrow 'jumps' / etc. 
...
   To use a mouse in DOS, you need a compatible driver, recognizing your 
   mouse, and recognized by FreeBASIC library. For optimal results, you 
   need a good driver and a suitable mouse.

   Mouse: the optimal choice, and pretty well available nowadays, is a PS/2 
   mouse. The old type would be a serial mouse, also this one should work. 
   The newest is USB mouse - but is not very suitable for use in DOS, since 
   it would need a compatible (INT33) high quality native USB mouse driver 
   (none available by now, only some experimental), or rely on BIOS 
   emulation (not always available, or "unprecise").

   Driver: the preferred choice is CTMOUSE from FreeDOS project. There are 
   versions 1.9a1, 2.0a4, and 2.1b4 from 2008-July available. It is 
   included with (but not limited to) FreeDOS, or download a version from 
   here: ibiblio.org/pub/...mouse . None of them is perfect, but still they 
   are well usable and better than most competitors. 1.9xx and 2.1xx will 
   cooperate with BIOS, allowing USB emulation, 2.0xx bypasses BIOS and 
   thus USB emulation will NOT work. Also Logitech mouse drivers usually do 
   a good job, download from here: uwe-sieber.de/util_e.html - version 6.50 
   is a good start. Known for problems are DRMOUSE and some (old ?) 
   versions of MSMOUSE.

   If the mouse does not work at all, then most likely the driver is not 
   loaded, doesn't recognize the mouse (see driver messages), or is not 
   compatible with the INT33 "standard". For USB mouse, activating the "USB 
   mouse emulation" in BIOS settings can help. 

   If the mouse control is "unprecise", the arrow "jumps" , then you either 
   have a bad driver - use a better one, or the BIOS emulation is bad - the 
   solution is to buy a PS/2 mouse then.

21. What about the 64 KiB and 640 KiB problems / how much memory is 
supported by FB in DOS?
   Memory management is business of the DPMI host, rather than the 
   compiler. FreeBASIC and executables generated by it do not suffer from 
   this problem, since they use 32-bit DPMI code, rather than real mode. 
   You can use almost all the memory of your PC, with some limitations, but 
   they are far above 64 or 640 KiB. CWSDPMI r5 is verified to work well up 
   to 512 MiB only, additional memory does not crash it (unlike some older 
   versions), but is silently ignored. HDPMI is supposed to support more: 
   up to 4 GiB (the limit of 32-bit addressing), but there was not much 
   testing on such huge machines - verified up to cca 1.5 GiB. FreeBASIC 
   and code generated by it do not require classical DOS based memory 
   managers (HIMEM/XMS and EMM386/EMS), but are supposed to coexist with 
   them if they are present. All this of course applies to true DOS only, 
   things like "Dos Box" will keep the control over the memory management 
   and provide only a small piece of memory (depends, up to cca 64 MiB) to 
   your DOS code. 

22. My program crashes when I try to use more than cca 1 MiB RAM! Is this a 
bug in FreeBASIC?
   No, it's not a bug in FreeBASIC and it's not really DOS specific, see 
   also Compiler FAQ. For a beginner, the easy solution is to use Shared 
   for arrays. More advanced users could consider using memory management 
   functions like Allocate. This is even more important in DOS, since it 
   allows the application to run on (old) PCs with little memory (and still 
   edit at least small texts for example), as well as to use all huge RAM 
   if available (and edit huge texts for example).

23. Threading functions are disallowed in DOS? Help!
   The Threading Support Functions are not supported for DOS target, and 
   most likely won't be soon/ever. The reason is simple: neither the DOS 
   kernel, nor the DPMI host/standard, nor "GO32" DOS Extender support 
   threading, unlike the Win32 or Linux kernel. However nothing is 
   impossible in DOS: you can set up your threading on the top of DPMI. 
   There are multiple possibilities, two of which are:
      * Set up an ISR, see "ISR_TIMER.BAS" example. This is not a "full" 
        replacement, but sufficient in some cases.
      * There is a pthreads library for DJGPP allowing to "emulate" 
        Linux-like threading to some degree. It works acceptably for 
        [P]7-ZIP DJGPP port (written in C++), no tests with FB yet.
      * See forum t=21274

24. Executables made with FB DOS are bloated!
   This is true but there is no easy/fast way to fix. FB is a 32-bit HLL 
   compiler, and most of the size is imported from DJGPP. !writeme! (see 
   forum: t=11757)

25. Compilation is very slow with FB!
   Problem: "FBC takes 10 seconds to compile a "Hello world" program ! 
   TurboBASIC / QBASIC / VBDOS / PowerBASIC do take < 1 second for the same 
   job ..."

   True, but this is "by design": FB compiles your sources in 3 steps, 
   saving the intermediate files, as described in CompilerCmdLine, while 
   many older compilers do just 1 pass in memory. This is related mostly to 
   file I/O performance, see FAQ 27 below about possibilities of 
   improvements, additionally a small improvement can be achieved here by 
   making the DPMI host resident (HDPMI32 -r or CWSDPMI -p , see FAQ 4 
   above). Note that the delay is mostly "additive" , so it won't hurt too 
   much with bigger projects.

26. SLEEP doesn't work! How can I cause a delay?
   Sleep does work ... but has a resolution of cca 55ms = 1/18s only, thus 
   "SLEEP 500" is fine, while for example using "SLEEP 2" for 2 
   milliseconds won't work. !writeme! / !fixme! 
      * PIT / BIOS timer (runs at 18.2 Hz by default), peek the BIOS timer 
        or set your own, see "ISR_TIMER.BAS" example, raise PIT frequency 
        (use with care)
      * Poll the BIOS timer + PIT counter, method from TIMERHLP.ASM from 
        DKRNL32, allows to enhance precision of above without raising the 
        PIT frequency 
      * RDTSC instruction (Pentium and newer)
      * RTC clock
      * Delay loops

27. The performance is very bad in DOS!
   Problem: "The performance in DOS is poor compared to Win32 / Linux 
   binary compiled from the very same source !" or "Even worse, the very 
   same DOS binary runs much faster in NTVDM than in DOS !"

   Both indeed can happen, nevertheless, DOS is no way predestined to be 
   slow, the inefficiencies can be fixed. First you have to identify the 
   area where you code looses performance. 

      File I/O: DOS by default uses very little memory for its buffers, 
      while other systems use much more and are "aggressive" with file 
      caching. When dealing with many small files, this results in serious 
      performance degrade. The solution is to install a filecache, for 
      example LBACache, or you can install a RAMDISK (a good one: SRDISK ) 
      and copy the "offending" files (for example FreeBASIC installation) 
      there in and work there (make sure to backup your work to a more 
      durable media regularly). Both will need an XMS host (use HIMEMX ). 
      Also DOS by default uses BIOS to access the hard drives, while other 
      systems try hard to find and use DMA. Test util: IDECHECK by Japheth 
      (Download: japheth.de/Download/IDECheck.zip) - run it in "I13" and 
      "DMA" modes and compare results. If "DMA" is much faster (can be 
      1...10 times, depends from PC model), then installing a DOS DMA 
      driver (for example XDMA 3.1 is worth to try) can bring a big speedup 
      on large files. Also make sure to read and write data in large pieces 
      (16 KiB at least), not just single bytes. Other OSes are more 
      forgiving here, but on DOS every single file I/O call causes a small 
      "additive" delay, thus an efficient code design with good buffering 
      is crucial.

      Graphics: Pentium 2 and newer CPU's have a cache related feature 
      called "MTRR" to speed up writes to video RAM. Drivers of other OSes 
      usually do enable it.  DOS doesn't (since it doesn't deal with 
      graphics at all), neither does FB GFX. Use "VESAMTRR" tool by Japheth 
      (contained in "HXGUI.ZIP" package), it will enable the speedup, 
      surviving also mode switches and most "non-fatal" application 
      crashes, up to a reboot. The possible speedup factor varies much 
      depending from the PC model, up to cca 20 times. Also the mouse 
      handling eats some (too much) CPU performance on DOS, this is a known 
      weak point (the design of DOS FB GFX is not "very bad", it's just the 
      common "standard" - which is not very good), fixing is theoretically 
      possible but not easy, you just can try several mouse drivers (see 
      FAQ 20).

28. Can I access disk sectors with FB?
   You can ... but FreeBASIC won't help you too much here: no "portable" 
   solution, use OS specific low level way. For DOS 3 methods are possible 
      * Use logical disk access features of DOS for sector access 
        bypassing the filesystem, see example in the forum: 
        freebasic.net/forum/viewtopic.php?t=11830
      * Use physical disk BIOS INT 13, bypassing DOS
      * Use CPU ports, lowest level, bypassing both DOS and BIOS, see 
        forum freebasic.net/forum/viewtopic.php?t=16196, source of IDECHECK 
        from FAQ 27 above, FASM forum or some OS development resources
   Note that such experiments are a bit "dangerous" - you can easily lose 
   data or make your PC unbootable if something goes wrong.

29. Can I use inline ASM with advanced instructions like SSE in DOS ?
   You can ... but SSE2 and above need to get enabled before. This is 
   usually considered as business of the DPMI host, HDPMI32 and CWSDPMI 7 
   will do that, most other hosts won't. Make sure to properly CPUID for 
   such instructions before using them. It's a good idea to provide a code 
   branch compatible with older CPU's (early Pentium, 80386) besides 
   supporting latest instructions, and to avoid CMOV in those too.

See also
   * Compiler FAQ.
   * FB Runtime Library FAQ.
   * Frequently Asked FreeBASIC Graphics Library Questions



------------------------------------------------------------ FaqPgWin32 ----
Windows Related FAQ

Windows:

   - Which IDEs are available for Windows?
   - Can I get rid of the console / 'DOS' screen in a graphics application?
   - My GUI program does nothing when run / The program compiles but I get a permission denied error in the linker
   - How can I debug my program?
   - Why Windows refuses to run my code using OUT and/or INP?
   - I get the error 'Cannot start blah.exe because xxxx.dll was not found.' or similar. What is missing?
   - Does FreeBASIC work with Windows Vista/7?
   - Where can I find some tutorials on programming the Windows GUI?
   - Are there Windows GUI code builders for FB?	

FreeBASIC Windows questions

Which IDEs are available for Windows?

   At the moment three full featured IDEs have been developed specifically 
   for FB: FBIde (not being updated, avoid using of old versions of FBC 
   bundled with it), FbEdit and WinFBE Editor. These IDEs require a minimum 
   configuration -as path to the compiler- to work. 
   You can also download  FBIde and FbEdit as bundles  (Editor + Compiler) 
   that install in a single operation. But the bundled version of the 
   compiler may be out of date.
   WinFBE Editor (WinFBE_Suite) comes packaged with the latest FB Compiler. 
   It is an all-in-one solution. 
   Commercial "general use" IDEs can be used with FreeBASIC but may require 
   an extensive setup. They are handy for multi language programming, as 
   they provide a unified user interface.
   Instructions for installing WinFBE, FBIde, and FbEdit can be found here:
      - IDE Installation guide for Windows

Back to top	

Can I get rid of the console / 'DOS' screen in a graphics application?
   Yes. You have to give FreeBASIC the right command for it when you 
   compile your program.
   * If you compile from a command prompt, simply add "-s gui" to the end, 
     like "fbc myprg.bas -s gui"
   * If you compile in a specific IDE, you have to edit the "Compiler 
     Defaults". 
      * In WinFBE, its "Options->Build Configurations". Add "-s gui" (NO 
        QUOTES) for the build of your choice.
      * In FbEdit select Windows GUI in the targets dropdown list in the 
        right of the tool bar.

Back to top

My GUI program does nothing when run / The program compiles but I get a 
permission denied error in the linker
   The problem may be related with the previous question. If a program 
   tries to PRINT and it was compiled with "-s gui" it will freeze because 
   no console is available. If the PRINT is issued before the first window 
   is registered/opened, nothing will show in the screen or in the taskbar. 
   The running program can only be seen in (and killed from) the task 
   manager's processes tab. If a new compilation is tried  before killing 
   the process it will give a "Permission denied" error when the compiler 
   tries to modify a still running .exe.
   In Windows GUI programs do not use console commands. Use MessageBox or 
   print to a log file to issue any error message to the user. Be sure any 
   PRINT to console you used for debugging is not compiled in the final 
   version. 

Back to top

How can I debug my program?
   FreeBASIC can use any debugger compatible with GNU GDB. Insight Win32 
   debugger is an user friendly wrapper for GDB. 
   * Get Insight from Dev-C++
   * Rename the file to Insight.tar.bz2, and decompress it to an empty 
     folder
   * Compile your program with the -g switch
   * Run <Your_Insight_Dir>\bin\usr\bin\Insight.exe
   * Do File>Open to load your program into Insight
   * From there you can watch, set breakpoints, step, examine memory and 
     registers. Check Insight's help

Back to top

Why Windows refuses to run my code using OUT and/or INP?
   Windows requires a driver to be installed to access the hardware ports. 
   FB-Win32 programs using INP and OUT include a built-in driver that 
   installs temporarily for a session. Windows allows only users with Admin 
   rights to run driver installations. This means if you usually run your 
   windows sessions without Admin rights, you will have to use the windows 
   command line command RUNAS to run your program for the first time in 
   each session so Windows allows it to install the driver.
   If this behavior is not acceptable you can use an external library as 
   PortIO32 that installs a permanent port driver.

Back to top

I get the error 'Cannot start blah.exe because xxxx.dll was not found.' or 
similar. What is missing?
   You are trying to run a program using a third party library that resides 
   in a dll not installed in your system.
   FreeBASIC comes with headers and wrappers required to code for a lot of 
   third party libraries but does not provide the actual runtime dll files.
   You have to download and install these from their home page. Find in 
   the Links thread in the Libraries subforum the URL's of the home pages 
   of the libraries provided. You need the binaries for Win32 of the 
   libraries. If you want to develop programs with the libs you will need 
   the documentation too.
   When releasing compiled code it is good etiquette to provide the third 
   party dll's required to run it.

Back to top

Does FreeBASIC work with Windows Vista/7?
   Yes. (Write me!!!)

Back to top

Where can I find some tutorials on programming the Windows GUI?
   See the answers to this question in this thread in the forum
   More advanced use requires a frequent consultation of the reference at 
   the Microsoft Developers Network. A local install of the API reference 
   is possible, search Microsoft for the Platform SDK (a huge download) and 
   install just the documentation.

Back to top

Are there Windows GUI code builders for FB?	
   Yes there are some 3rd party developments generating Windows API code 
   from a windows designer &agrave; la Visual Basic:
   WinFBE Editor (open source) full visual designer similar to Visual 
   Basic.
   Jerry Fielden' Ezeegui (freeware) uses a "graphical" textmode interface 
   to let you build your code.
   mrhx Software's VISG (GPL) has a more classical user interface.
   Less helpful may be the graphical resource editors generating scripts 
   for the resource compiler. Any editor generating scripts compatible with 
   GoRC can be used, as the  one included with FbEdit. Graphical resource 
   editors are a great help in designing dialogs and menus, but they leave 
   to you the task of writing the window procedures required to make them 
   active.

Back to top

See also
   Compiler FAQ
   FB Runtime Library FAQ



------------------------------------------------------------ FaqPgLinux ----
Linux Related FAQ

FreeBASIC Linux questions:

   - FreeBASIC gives me an error 'ld: can't find -lX11' or something similar!
   - How do I install FreeBASIC in Ubuntu?

FreeBASIC Linux questions

FreeBASIC gives me an error 'ld: can't find -lX11' or something similar!
   FreeBASIC uses ld to link its files under linux. This program requires 
   that any libraries you use have the '-dev' versions installed. For 
   example, for the above error message, you'd want to install xlib-dev for 
   your distribution. Other common errors are for glibc, which requires 
   glibc-dev, and sdl, which requires sdl-dev. Most distributions make 
   these easily available on your install media.

Back to top

How do I install FreeBASIC in Ubuntu?"
   See This thread in the FB forums 

Back to top

See also
   Compiler FAQ
   FB Runtime Library FAQ





============================================================================
  MISCELLANEOUS
  -------------


--------------------------------------------------------- ObsoletedKwds ----
Obsolete Keywords

   Along the way FB has had a few keywords changed. Here is the list of 
   those no longer supported. Old code must be updated if recompiled.

   OPEN "CON:" 
      Use Open Cons    
   OPEN "ERR:" 
      Use Open Err 
   OPEN "PIPE:" 
      Use Open Pipe 
   POKEI  
      Use Poke (Integer,Address,N)  
   POKES 
      Use Poke (Short,Address,N) 
   SCREENINFO (Function returning a pointer to a structure)  
      Use Screeninfo, Sub Returning Values In Its Arguments
   VAL64  
      Use Vallng() 
   GOSUB
      Do not use GoSub in SUBs or FUNCTIONs anymore; allowed in -lang qb 
      mode.


--------------------------------------------------------- GlossaryIndex ----
Glossary

Brief definitions and explanations for words and phrases used in the FreeBAS
IC manual.

Index: A - B - C - D -  E -  F -  G -  H -  I -  J - K - L - M - N - O - P 
- Q - R - S - T - U - V - W - X - Y - Z

 A

abstract member function
   A member function without body that must be overridden by a member 
   function of a type more derived than the type it was declared in. See 
   Abstract (Member).

access rights
   The level of access associated with Type or Class members. Public 
   members are accessible to any code; protected members are accessible to 
   member functions and any derived Type or Class member functions; private 
   members are accessible only to member functions of that Type or Class. 
   By default, Type members have public access rights, while Class members 
   are private.

any pointer
   A variable or expression that points to a memory address where it is not 
   known, at least from the compiler's point of view, what type of data is 
   stored at that address.  In C this would be the same as a void pointer 
   or (void *).  See Ptr.

archive
   An archive is a group or files or a single file packed into a container 
   format and usually compressed before or afterward. Typical container 
   formats are GNU Tar and Zip. Typical compression formats are Gzip and 
   Zip.

argument
   Data that is passed to a procedure. The procedure refers to this data 
   using the parameter(s) in its parameter list.

argument passing convention
   The method in which arguments are passed to procedures, being either 
   By Reference or By Value.  See Passing Arguments to Procedures.

array (container)
   A collection of data whose elements are stored contiguously in memory 
   (one after the other, in increasing order). Because of this, an array 
   offers random-access to its elements (any element can be accessed at any 
   time). Insertion or removal of elements anywhere but at the back of the 
   container requires that those elements that follow be relocated, so a 
   linked-list is typically preferred when insertion or removal needs to be 
   efficient.

assembler
   A component in the tool chain for translating source code in to 
   executable programs.  The assembler converts the low level assembly 
   instruction mnemonics emitted by the compiler to object code.

assignment
   Assignment is one of the fundamental operations of computing.  All it 
   means is copying a value into the memory location pointed at by a 
   variable.  The value might be a literal, another variable, or the result 
   of some expression. For an instance of a Type or Class, this involves 
   calling one of its assignment operators. Not to be confused with 
   initialization.

automatic storage
   Refers to storage on the call stack. Local procedure variables, objects 
   and arrays with automatic storage are allocated when the procedure is 
   called, initialized when defined, destroyed (in the case of objects) 
   when leaving the scope they're declared in and deallocated when 
   returning from the procedure.

automatic variable/object/array
   A variable, object or array with automatic storage.

Back to top

 B

byref
   ByRef specifies passing arguments to procedures by reference. Arguments 
   passed by reference can be modified by the procedure and the changes 
   seen by the caller.

byval
   ByVal specifies passing arguments to procedures by value. Procedures 
   receive a copy of the argument passed. With Type or Class instances, 
   this involves instantiating temporary objects by calling their copy 
   constructor. These temporaries are destroyed upon procedure exit.

binaries
   Binaries are the end result of source code. Binaries include executable 
   files (.exe on windows), static library files (.a), dynamic library 
   files (.dll on windows, .so on Linux), and relocatable object files. 
   (.o)

.BSS section
   The part of the executable program that will contain zero bytes only 
   when the program starts.  Since all of the bytes are zero, the final 
   size of the executable can often be reduced by placing uninitialized 
   data, or zero initialized data in this section.

buffer
   A region of memory that allows data to be saved or manipulated before 
   being copied somewhere else.  In a communications device this may hold 
   incoming or outgoing data yet to be processed.  In graphics, a buffer 
   may contain an image before being copied to the screen.

Back to top

 C

call back
   A control mechanism where a caller lets a procedure call another 
   procedure (the call back) provided by the caller typically through a 
   function pointer.

call stack
   A chunk of memory reserved for a process or thread that is used as a 
   stack for storing various information needed by procedures when they are 
   called. Among the information stored on the call stack are all of the 
   local automatic variables, objects and array data and usually whatever 
   parameters are passed to the procedure. These items are allocated (
   pushed onto the call stack) when the procedure is called and deallocated 
   (popped from the call stack) when the procedure returns, either by the 
   caller or the callee, depending on the calling convention used. The 
   initial and maximum sizes of this reserved memory vary by platform.

caller
   A misnomer used to refer to the point in code in which a procedure is 
   called.

cast
   A cast operation changes one data type to another using specified rules. 
   A Type structure can implement a custom Cast for any intrinsic data 
   type, and/or other TYPEs, See Cast.

code block
   Several lines of source code grouped together all sharing at least one 
   common scope.  For example a procedure's code block will be all the 
   lines of code between Sub and End Sub.

com port
   A short name for serial communications port.  A program can communicate 
   with an external device, such as modem or another computer through a com 
   port (nowadays the good old com ports are deprecated in favor of USB).  
   See Open Com.

compiler
   A compiler is a computer program which takes source code and transforms 
   it into machine or object code.

compiler directives
   These are instructions included in the text of the program that affect 
   the way the compiler behaves.  For instance the compiler might be 
   directed to include one section of code or another of depending on the 
   target operating system.

compound statement
   A statement composed one or more additional statements. Typically, a 
   compound statement has a beginning (opening statement), a middle (a 
   statement block) and an end (closing or ending statement), while some 
   have additional parts. Examples of compound statements would be If and 
   Function.

constant
   A symbol that retains a consistent value throughout the execution of the 
   program. See Const.

constructor (module)
   A special type of module-level procedure that is automatically called 
   prior to the module-level code flow. See Constructor (Module).

constructor (TYPE or CLASS)
   A special member function of a Type or Class that is called when an 
   object is instantiated.

contravariance (TYPE or CLASS)
   A typing rule for Type or Class that allows you to use a more generic 
   (less derived) type than the one originally specified.

covariance (TYPE or CLASS)
   A typing rule for Type or Class that allows you to use a less generic 
   (more derived) type than the one originally specified.

CVS
   Concurrent Versions System. The file manager implemented at Sourceforge 
   where sources are stored, it keeps the history of the changes introduced 
   by the developers.  Used by FB in the past. (see also SVN and GIT)

Back to top

 D

.DATA section
   The part of the executable program that will data that can be changed 
   while to program is running.

debugger
   A program that allows controlled execution of compiled code. The values 
   of variables can be tracked, execution can be paused, stepped or 
   accelerated, etc. A debugger is typically used to help find the source 
   of programmer errors in source code, called 'bugs'.

declaration
   A source code statement that introduces a symbol, constant, variable, 
   procedure, data type, or similar, to the compiler but not necessarily 
   allocate any space for it.  See Dim, Declare, Extern, Type.

definition
   A source code statement (or statements) that allocates space for data or 
   code.  For example, Sub defines a procedure by allocating space for the 
   program code it will contain.  Some statements can be both a declaration 
   and a definition.  For example, Dim both declares and defines a 
   variable.

dereference
   The act of accessing (in read and in write) a variable stored at a given 
   address. See Operator * (Valueof), Pointers.

descriptor
   Refers to the internal data structure used by the compiler and runtime 
   library for managing variable length strings and arrays.

destroy (TYPE or CLASS)
   The act of deconstructing and deallocating memory for an object 
   instance. When an object is destroyed, its destructor is called. This 
   happens automatically when an object goes out of scope, or when 
   Delete (Statement) is called with a pointer to an object.

destructor (module)
   A special type of module-level procedure that is automatically called at 
   program termination. See Destructor (Module).

destructor (TYPE or CLASS)
   A special member function of a Type or Class that is called when an 
   object is destroyed.

dll
   Shorthand for dynamically linked library.

DPMI
   A method / standard allowing to execute protected mode code (mostly also 
   32-bit) on a 16-bit real mode DOS kernel. Affects only DOS version of 
   FreeBASIC. See also DOS related FAQ 

DJGPP
   A complete 32-bit C/C++ development system for Intel 80386 (and higher) 
   PCs running DOS and includes ports of many GNU development utilities.

dynamically linked library
   A file containing executable code that is loaded by another application 
   when it is started.  Also referred to as a dll or shared library.  See 
   Shared Libraries (DLLs).

Back to top

 E

enum
   A data type restricted to a sequence of named values given in a 
   particular order. See Enum.

executable
   A binary file that can be run. It consists of libraries and object files 
   bound together by the linker.

exit sub/function
   When called inside a procedure, leaves the procedure and returns control 
   to the calling program.

expression
   An instruction to execute a statement that will evaluate/return a value.

Back to top

 F

field
   Commonly refers to a data member in a Type or Class.

file number
   An integer associated with an open file or device as given in Open.  All 
   subsequent operations on the opened file or device must use the same 
   file number.

format string
   A sequence of characters that controls how data should be presented.  
   See Format, Print Using.

function
   A procedure defined using Function, optionally taking parameters and 
   returning a value.

function pointer
   A variable containing the address of a function.  The address (function) 
   to which the variable points can be changed while the program is running 
   allowing for dynamic program flow, such as call back functions.

Back to top

 G

get/put buffer
   See: Image Buffer. An image buffer in FreeBASIC's native format.

GIT
   The file manager implemented at Sourceforge where sources are stored, it 
   keeps the history of the changes introduced by the developers.  Used by 
   FB now. (see also CVS , SVN and GIT).

global variable
   A variable that is visible to all procedures within a module, across 
   multiple modules, or both. See Common and Extern.

GNU
   A mass collaboration project with the primary goal to provide a free and 
   non-proprietary Unix-like operating system.

GPL
   Short hand for GNU General Public License: a license for software and 
   other kinds of works. Open source, obligates the user to keep the 
   project open source and under the GPL.

graphics primitive
   A graphics primitive is another term for common shapes like circles and 
   rectangles.

Back to top

 H

hash table
   A data structure that associates keys with values allowing for efficient 
   look-up of values based on a given key.

header
   When talking about a collection of data, this is generally the first 
   part of that data that describes the rest. When talking about (header) 
   files, this refers to an include file. In FreeBASIC the file extension 
   '.bi' is usually used.

heap
   The area of memory (free store) provided by the runtime library (and 
   operating system) from which the program can dynamically allocate 
   memory.  See Allocate.

Back to top

 I

image buffer
   A collection of data used to describe an image, containing such 
   information as width, height, color depth and pixel data.

include file
   A kind of source file that typically contains type definitions and 
   declarations for variables and procedures that one or more other source 
   files refer to. In general, these files provide a public interface to 
   some module or modules, although a file that is #included can contain 
   any text whatsoever.

inheritance (TYPE or CLASS)
   Inheritance is when deriving a type from a base type, by using the 
   Extends declaration. Members of the base type become members of the 
   derived type. Private members of a base type are never directly 
   accessible from a derived type, but can be accessed through calls to the 
   Public and Protected members of the base type.

initialization
   The act of giving a variable a value at the point of its creation. For 
   object instances, this involves calling one of its constructors. Not to 
   be confused with assignment, which gives an already existing variable 
   another value.

instance
   An instantiated object of a Type or Class.

instantiate
   The act of creating an object of a Type or Class, either directly with 
   Dim, or indirectly by, for example, passing an object to a procedure by 
   value.

invariance (TYPE or CLASS)
   A typing rule for Type or Class that requires you to use exactly the 
   same type as the one originally specified.

Back to top

 J

Back to top

 K

Back to top

 L

library
   Compiled code stored in a single file that can be used when making other 
   programs.  A library typically has one or more headers (or include 
   files) to provide all the needed declarations for using the library.

linked list (container)
   A collection of data whose elements are typically stored on the heap. 
   The linked list's elements store the addresses of their adjacent 
   elements, and so only sequential access (an element is accessed by 
   following the links from adjacent elements) is possible. This scheme 
   does provide constant-time insertion of elements anywhere into the 
   container, however, and because of this is often preferred over the 
   array.

linker
   A program which combines multiple modules and libraries into a single 
   executable which can be loaded into the computer's memory and followed 
   by the computer. FreeBASIC uses the LD linker. Linkers are the most 
   common, but not the only way to produce executables.

LGPL
   Shorthand for GNU Lesser General Public License.  Like the GNU GPL, but 
   more permissive allowing non-(L)GPL'd works to be statically linked to 
   the LGPL'd work, provided that the new work can have the LGPL'd portion 
   relinked or replaced.

LHS
   Acronym for "Left Hand Side".

local variable
   A variable that is visible only within the scope in which it is 
   declared, and that is destroyed when program execution leaves that 
   scope.

lock
   A synchronization mechanism such that only one thread or process can 
   have access to a shared object, for example a global variable, a device, 
   or a file.

Back to top

 M

member
   A data field, procedure, enumeration, type alias or anything else 
   declared within a Type or Class definition.

member data
   Variables associated with a Type or Class. Member data can be static or 
   non-static.

member function
   A procedure associated with a Type or Class. Member functions have full 
   access rights to the members of its type or class, and can be static or 
   non-static.

method
   See member function.

module
   A source file in its entirety, including any include files that may be 
   present as well. Typically, a module is a logical unit of code, 
   containing parts of a program that relate to one another. For example, 
   if making a game, one may separate the procedures needed for error 
   logging from the procedures that control graphics into their own 
   modules.

Back to top

 N

non-static member data
   Member data that each instance of a Type or Class gets their own copy 
   of.

non-static member function
   A member function that has an implicit This reference as an argument.

null
   A constant usually associated with pointers denoting a 'nothing' value. 
   This value is typically an integer '0' (zero) - the 'NULL terminator' 
   appended to zstrings is chr(0), or asc(!"\0") - but can also be defined 
   as a pointer type, like Cast(any ptr, 0).

Back to top

 O

object (built-in TYPE or CLASS)
   Object is a built-in type which provides Run-Time Type Information 
   (RTTI) for all types derived from it using the Extends declaration, 
   allowing them to be used with Operator Is, and to support Virtual and 
   Abstract member functions.

object code
   Code in machine-readable form that can be executed by your computer's 
   CPU and operating system, usually linked with libraries to create an 
   executable file.

operand
   One of the arguments passed to an operator.  For example, in the 
   expression a = b + c, the operands are a, b and c, while the operators 
   are = and +.

operator
   A function taking one or more operands (arguments) and returning a 
   value.  Operators can work on built-in data types, or can be overloaded 
   to work on user defined types.  See Operators.

overload
   To declare a procedure having the same name as another, but with 
   different parameters. Free functions, or module-level functions, can be 
   overloaded using the Overload keyword. Type or Class member functions 
   can be overloaded by default.

override
   Attribute to specify that a member function must override a Virtual or 
   Abstract member function of a type less derived than the type it was 
   declared in. Using the Override attribute, the compiler will show an 
   error if the member function does not override anything.

Back to top

 P

page buffer
   A buffer used for holding the contents of the screen before being 
   displayed on screen.  Where multiple page buffers are allowed, one page 
   will be visible to the users while all others are hidden.  Also the 
   active page (the one to which changes are made) need not be the visible 
   one allowing changes to one page while showing another.

parameter
   The name used by a procedure that corresponds to the argument that is 
   passed to it.

parameter list
   The parenthesized comma-separated list of parameters in a procedure 
   declaration or definition.

PDS
   Professional Development System.  Sometimes referred to as QB7.1.

pitch
   The number of bytes per row, in an image or screen buffer.  If there is 
   no padding between rows, then this can be calculated by width * 
   bytes_per_pixel, but this is not necessarily safe to assume.  The 
   screen's pitch can be found using ScreenInfo, and an image buffer's 
   pitch can be found by checking the pitch value in the image's header.

pointer
   A data type used to hold addresses. The kind of pointer determines how 
   the data at the address is interpreted when the pointer is dereferenced, 
   or when used with Operator -> (Pointer To Member Access). See Pointers.

polymorphism (TYPE or CLASS)
   Polymorphism is the ability of an object to provide different behaviors 
   (use different implementations) depending on its own nature, 
   specifically depending on position of its real type in the inheritance 
   hierarchy. Polymorphism is achieved by overriding Virtual or Abstract 
   member functions of the base type.

preprocessor
   The FreeBASIC preprocessor is responsible for expanding Macros and 
   replacing Defined values with their values.

procedure
   A generic name for any block of code that can be called from somewhere 
   else in a program.  See Sub, Function.

property
   A property is a special sort of type/class members, intermediate between 
   a field (or data member) and a method. See Property.

ptr
   Shorthand for pointer. See pointer.

Back to top

 Q

queue (container)
   A collection of data that offers first-in first-out (FIFO) storage and 
   retrieval. Typically, elements can only be inserted at the back and 
   removed from the front but can be accessed from either end.

Back to top

 R

ragged array (container)
   A ragged array is an array having rows of differing lengths.

real number
   Any positive or negative number including fractions, irrational and 
   transcendental numbers (like pi or e) and zero.  Variables containing a 
   real number have a limited range and precision depending on the number 
   of bits used to represent the number.  See: Single and Double.

reference
   A reference is an entity that is a way to access (in read and in write) 
   data at memory location. A reference can be thought of as a pointer 
   having as value the memory location, and which is implicitly 
   dereferenced.  See: Byref (Variables).

registers
   Places inside the CPU for data storage. 80386 and compatible 32-bit 
   models have EAX, EBX, ECX, EDX, ESI, EDI, EBP and ESP, plus some special 
   (control/test/debug) registers. NOT related to "Windows registry".

RHS
   Acronym for "Right Hand Side".

RTTI
   Acronym for "Run-Time Type Information". The Object built-in type 
   provides the RTTI capacity for all types derived from it using the 
   Extends declaration, allowing them to be used with Operator Is, and to 
   support Virtual and Abstract member functions.

Back to top

 S

scope
   Refers to the life-time and visibility of some component of the program, 
   like a variable or a procedure.  For example, a variable defined inside 
   a procedure would have procedure scope: it is visible throughout the 
   procedure, but not outside the procedure's code block.  When the 
   procedure ends, the variable goes out of scope and no longer exists.

scope block
   A code block where all the lines of source have the same scope.  An 
   explicit scope block can be indicated with the Scope statement.  Scope 
   blocks may also be implicit with the usage of If..Then, For..Next, and 
   other compound statements.

shared library
   A library that exists once on a system that multiple executables can 
   link to at runtime. See Shared Libraries (DLLs).

source code
   Code written by the programmer, in a human-readable form, not yet 
   compiled.

stack (container)
   A collection of data that offers last-in first-out (LIFO) storage and 
   retrieval. Typically, elements can only be inserted, accessed and 
   removed from the top of the stack.

statement block
   One or more lines of code bookended by a compound statement.

static library
   A library that is linked into a program at link time. There is one copy 
   of the library for each executable that links to it. All data is 
   executable specific. See Static Libraries.

static member data
   Member data that each instance of a Type or Class shares. This data is 
   defined outside of any Type or Class, and takes up no space in the 
   resulting object instance.

static member function
   A member function without an implicit this reference as an argument. 
   Static member functions can be called normally through a variable, or 
   directly using the type's name and the scope resolution operator See 
   Static (Member).

static storage
   Refers to storage in the .BSS or .DATA sections of an executable. 
   Variables, objects and arrays with static storage are allocated and 
   initialized at compile-time and destroyed (in the case of objects) and 
   deallocated at program-termination. Explicitly initialized variables, 
   objects and arrays are allocated in the .DATA section.

static variable/object/array
   A variable, object or array with static storage.
   Note: Some times, we talk about 'static array/string' (as opposed to 
   'dynamic array/string'), but here, the 'static' term applies on the size 
   of the array/string (fixed length as opposed to 'dynamic' term for a 
   variable length) .
   Thus this 'static/dynamic' term does not apply on the storage type for 
   data.

sub
   A procedure defined using Sub, optionally taking parameters and not 
   returning a value.

SVN
   Subversion. A version control system that allows users to keep track of 
   changes made to sources and documents. Used by FB in the past. (see also 
   CVS and GIT)

SWIG
   A tool that automatically translates C headers to FreeBASIC (although 
   not always perfectly).

symbol
   Used to refer to variables, labels, functions, methods, procedures, or 
   other programmatic constructs in a program.

Back to top

 T

.TEXT section
   The part of the executable program that will contain program 
   instructions and constant data.

this reference
   A reference to an instance of a Type or Class that is passed as a hidden 
   argument to non-static member functions of that type or class. 
   Throughout the member function, this instance is referred to using the 
   this keyword, See This.

thread
   A thread of execution within a process (running program) that shares 
   execution time with other threads in the same process.  See Threading.

trace
   To follow the execution of a program step-by-step either manually by 
   examining the source code, or more practically with a debugger.

Back to top

 U

union
   A structure that can be used to store different types of variables, such 
   as integers, doubles and fixed-length strings in the same location, but 
   only one at a time.  See Union.

user defined data type
   A Type, Union, Enum, or Class data type.

Back to top

 V

variable
   A symbol representing data in memory.

VBDOS
   Visual BASIC for DOS, a historical BASIC compiler by M$ from 1992, 
   following after QBASIC. DOS platform dropped very soon, VBDOS never 
   became popular.

vector
   A series of data items in memory that can be accessed by an index 
   number.  Similar to an array except that vector elements are not 
   necessarily all contained within a single block of memory.

virtual member function
   A member function that can be overridden by a member function of a type 
   more derived than the type it was declared in. See Virtual (Member).

Back to top

 W

warning
   A message displayed by the compiler during compilation that suggests 
   there may be potential problems with the current code.
   
wiki
   An on-line system that provides a set of pages containing information 
   that can be viewed and modified by the public. In this context, it is 
   typically used to refer to the FreeBASIC on line documentation.

Back to top

 X

x86
   Refers to the instruction set compatible with the 8086 (and later) CPU 
   architecture, FreeBASIC only supports 80386 and later.

Back to top

 Y

Back to top

 Z

zstring
   A zstring is in essence a standard C style string terminated by a null 
   character. This data type is provided for greater compatibility with C 
   libraries.

Back to top



------------------------------------------------------------- CatPgMisc ----
Miscellaneous Keywords

Data
   * Data
   * Read
   * Restore

Debugging
   * Assert
   * AssertWarn
   * Stop

Hardware Access
   * Inp
   * LPrint
   * LPos
   * Out
   * Wait

Operating System
   * Beep
   * Sleep
   * End (Statement)

Stub Pages
   * As
   * For
   * To
   * Is
   * Step
Control Flow
   * Do
   * End If
   * IIf
   * Loop
   * Next
   * Then
   * Until
   * Wend
   * While

Uncategorized
   * End (Block)
   * OffsetOf
   * SizeOf
   * TypeOf
   * Let
   * Rem
   * Option()



--------------------------------------------------------- ProPgCruntime ----
C Standard Library Functions

This is a list of function prototypes in the standard C library in 
alphabetical order and a list of prototypes grouped by functionality. 

Alphabetical List
Buffer Manipulation
Character Classification and Conversion
Data Conversion
Directory Manipulation
File Manipulation
Stream I/O
Low level I/O
Mathematics
Memory Allocation
Process Control
Searching and Sorting
String Manipulation
Time

Description
   The Comments column contains a very brief description of the use of the 
   function. The list is not complete, however it provides information on 
   the major functions in the C Runtime Library. It should, at the very 
   least, indicate what functions are available in the standard C library 
   allow you to do more investigation on your own.  Some of the C library 
   functions documented elsewhere may not be available in FreeBASIC.  Check 
   the appropriate include file for more information. 

   Note: The following prototypes are not the official FreeBASIC prototypes 
   (see the include files), however, they will give you enough information 
   to properly use the functions. 

   The Include File column contains the name of the file which you must 
   include, using the #include directive at the beginning of your program. 
   If you don't include the appropriate include file, the program either 
   will not compile, or it will compile apparently correctly but give 
   incorrect results when run.  All of the C Runtime headers are located in 
   the crt directory; for example, if the specified header is math.bi, use 
   #include "crt/math.bi" or #include "crt\math.bi", our just #include 
   "crt.bi" including all the others.

   The Prototype column contains the following information: 
      * The name of the function; 
      * The parameters required for the function in parenthesis, together 
        with the data-type of the parameters; 
      * The data-type of the value returned by the function. 

   For example atoi(a as zstring ptr) as integer means that the function 
   atoi returns a value of type integer and requires a character zstring 
   ptr as its argument. 

   Note: In order to make calling the C runtime functions very easy, any 
   string type argument may be directly passed to a procedure referring to 
   a parameter declared as 'zstring ptr'. The compiler performs itself an 
   automatic conversion (without warning message) between any string type 
   argument and the 'zstring ptr' type parameter.

Alphabetical List

      +--------+----------------------------------------------------------------------------+------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
      |Name    |Prototype (with parameters)                                                 |Include File|Comments                                                                                                                                                                                                      |
      |abs_    |abs_(n as integer) as integer                                               |stdlib.bi   |Returns the absolute value (i.e. positive value)                                                                                                                                                              |
      |acos_   |acos_(a as double) as double                                                |math.bi     |Returns the inverse cosine (angle in radians)                                                                                                                                                                 |
      |asin_   |asin_(a as double) as double                                                |math.bi     |Returns the inverse sine (angle in radians)                                                                                                                                                                   |
      |atan_   |atan_(a as double) as double                                                |math.bi     |Returns the inverse tan (angle in radians)                                                                                                                                                                    |
      |atan2_  |atan2_(y as double, x as double) as double                                  |math.bi     |Returns the inverse tan (pass the opposite as y and the adjacent as x)                                                                                                                                        |
      |atoi    |atoi(s as zstring ptr) as integer                                           |stdlib.bi   |Converts a character zstring of digits to a number of type integer.                                                                                                                                           |
      |atof    |atof(s as zstring ptr) as double                                            |stdlib.bi   |Converts a character zstring of digits to a number of type double.                                                                                                                                            |
      |calloc  |calloc(NumElts as integer, EltSiz as integer) as any ptr                    |stdlib.bi   |Allocates memory. Returns a pointer to a buffer for an array having NumElts elements, each of size EltSiz bytes.                                                                                              |
      |ceil    |ceil(d as double) as double                                                 |math.bi     |Returns the nearest whole number above the value passed.                                                                                                                                                      |
      |clearerr|clearerr(s as FILE ptr)                                                     |stdio.bi    |Clears the error indicators on a file stream (read or write).                                                                                                                                                 |
      |cos_    |cos_(ar as double) as double                                                |math.bi     |Returns the cosine of an angle measured in radians.                                                                                                                                                           |
      |cosh    |cosh(x as double) as double                                                 |math.bi     |Returns the hyperbolic cosine of an angle measured in radians.                                                                                                                                                |
      |div     |div(num as integer, denom as integer) as div_t                              |stdlib.bi   |Returns the quotient and remainder of a division as a structure of type div_t.                                                                                                                                |
      |ecvt    |ecvt(x as double) as zstring ptr                                            |math.bi     |Converts a number to a zstring.                                                                                                                                                                               |
      |exit_   |exit_(status as integer)                                                    |stdlib.bi   |Exits a program. It will flush file buffers and closes all opened files, and run any functions called by atexit().                                                                                            |
      |exp_    |exp_(a as double) as double                                                 |math.bi     |Returns the value of e raised to the power of the argument (Inverse to natural logarithm).                                                                                                                    |
      |fabs    |fabs(d as double) as double                                                 |math.bi     |Returns the absolute value (i.e. positive value) of type double.                                                                                                                                              |
      |fclose  |fclose(s as FILE ptr) as FILE ptr                                           |stdio.bi    |Closes a file. Returns 0 if successful otherwise EOF.                                                                                                                                                         |
      |feof    |feof(s as FILE ptr) as integer                                              |stdio.bi    |Returns value of end-of-file indicator . (0 if not eof). Indicator will clear itself but can be reset by clearerr().                                                                                          |
      |ferror  |ferror(s as FILE ptr) as integer                                            |stdio.bi    |Returns error indicator for a stream (0 if no error). Error indicator is reset by clearerr() or rewind().                                                                                                     |
      |fflush  |fflush(s as FILE ptr) as integer                                            |stdio.bi    |Flushes (i.e. deletes) a stream (use stdin to flush the stream from the keyboard). Returns 0 if successful.                                                                                                   |
      |fgetc   |fgetc(s as FILE ptr) as integer                                             |stdio.bi    |Single character input (in ASCII) from passed stream (stdin for keyboard).                                                                                                                                    |
      |fgetpos |fgetpos(s as FILE ptr, c as fpos_t ptr) as integer                          |stdio.bi    |Saves the position of the file pointer on stream s at the location pointed to by c.                                                                                                                           |
      |fgets   |fgets(b as zstring ptr, n as integer, s as FILE ptr) as zstring ptr         |stdio.bi    |From the stream s reads up to n-1 characters to buffer b.                                                                                                                                                     |
      |floor   |floor(d as double) as double                                                |math.bi     |Returns the nearest whole number below the value passed.                                                                                                                                                      |
      |fmod    |fmod(x as double, y as double) as double                                    |math.bi     |Calculates the remainder of x divided by y.                                                                                                                                                                   |
      |fopen   |fopen(file as zstring ptr, mode as zstring ptr) as FILE ptr                 |stdio.bi    |Opens a file. Pass the DOS name of the file and a code to indicate whether for reading, writing, or appending. Codes are r for read, w for write, + for read and write, a for append and b to indicate binary.|
      |fprintf |fprintf(s as FILE ptr, fmt as zstring ptr, ...) as integer                  |stdio.bi    |Prints on stream s as many items as there are single % signs in fmt that have matching arguments in the list.                                                                                                 |
      |fputc   |fputc(c as integer, s as FILE ptr) as integer                               |stdio.bi    |Outputs the single character c to the stream s.                                                                                                                                                               |
      |fputs   |fputs(b as zstring ptr, s as FILE ptr) as integer                           |stdio.bi    |Sends the character stream in b to stream s, returns 0 if the operation fails.                                                                                                                                |
      |fread   |fread(buf as any ptr, b as size_t, c as size_t, s as FILE ptr) as integer   |stdio.bi    |Reads the number c items of data of size b bytes from file s to the buffer buf. Returns the number of data items actually read.                                                                               |
      |free    |free(p as any ptr)                                                          |stdlib.bi   |Frees the memory allocation for a pointer p to enable this memory to be used.                                                                                                                                 |
      |freopen |freopen(file as zstring ptr, mode as zstring ptr, s as FILE ptr) as FILE ptr|stdio.bi    |Opens a file for redirecting a stream. e.g. freopen("myfile", "w", stdout) will redirect the standard output to the opened "myfile".                                                                          |
      |frexp   |frexp(x as double, p as integer ptr) as double                              |math.bi     |Calculates a value m so that x equals m times 2 to some power. p is a pointer to m.                                                                                                                           |
      |fscanf  |fscanf(s as FILE ptr, fmt as zstring ptr, ...) as integer                   |stdio.bi    |Reads from stream s as many items as there are % signs in fmt with corresponding listed pointers.                                                                                                             |
      |fseek   |fseek(s as FILE ptr, offset as integer, origin as integer) as integer       |stdio.bi    |Locates a file pointer. With origin 0, 1 or 2 for the beginning, offset bytes into and at the end of the stream.                                                                                              |
      |fsetpos |fsetpos(s as FILE ptr, p as fpos_t ptr) as integer                          |stdio.bi    |Sets the file pointer for the stream s to the value pointed to by p.                                                                                                                                          |
      |ftell   |ftell(s as FILE ptr) as long                                                |stdio.bi    |Locates the position of the file pointer for the stream s.                                                                                                                                                    |
      |fwrite  |fwrite(buf as any ptr, b as integer, c as integer, s as FILE ptr) as integer|stdio.bi    |Writes the number c items of data of size b bytes from the buffer buf to the file s. Returns the number of data items actually written.                                                                       |
      |getc    |getc(s as FILE ptr) as integer                                              |stdio.bi    |Macro for single character input (in ASCII) from passed stream. (stdin for keyboard)                                                                                                                          |
      |getchar |getchar() as integer                                                        |stdio.bi    |Single character input from the standard input                                                                                                                                                                |
      |gets    |gets(b as zstring ptr) as zstring ptr                                       |stdio.bi    |Reads a stream of characters from the standard input until it meets \n or EOF.                                                                                                                                |
      |hypot   |hypot(x as double, y as double) as double                                   |math.bi     |Calculates the hypotenuse from the sides x and y.                                                                                                                                                             |
      |isalnum |isalnum(c as integer) as integer                                            |ctype.bi    |Returns a non zero value if character c is alphabetic or a digit.                                                                                                                                             |
      |isalpha |isalpha(c as integer) as integer                                            |ctype.bi    |Returns a non zero value if character c is alphabetic.                                                                                                                                                        |
      |iscntrl |iscntrl(c as integer) as integer                                            |ctype.bi    |Returns a non zero value if character c is a control character.                                                                                                                                               |
      |isdigit |isdigit(c as integer) as integer                                            |ctype.bi    |Returns a non zero value if character c is a digit.                                                                                                                                                           |
      |isgraph |isgraph(c as integer) as integer                                            |ctype.bi    |Returns a non zero value if character c is alphabetic.                                                                                                                                                        |
      |islower |islower(c as integer) as integer                                            |ctype.bi    |Returns a non-zero value if character c is a lower case character.                                                                                                                                            |
      |isprint |isprint(c as integer) as integer                                            |ctype.bi    |Returns a non zero value if character c is printable.                                                                                                                                                         |
      |ispunct |ispunct(c as integer) as integer                                            |ctype.bi    |Returns a non zero value if character c is a punctuation character.                                                                                                                                           |
      |isspace |isspace(c as integer) as integer                                            |ctype.bi    |Returns a non zero value if character c denotes a space.                                                                                                                                                      |
      |isupper |isupper(c as integer) as integer                                            |ctype.bi    |Returns a non-zero value if character c is an upper case character.                                                                                                                                           |
      |isxdigit|isxdigit(c as integer) as integer                                           |ctype.bi    |Returns a non-zero value if character c is a hex digit (0 to F or f).                                                                                                                                         |
      |ldexp   |ldexp(x as double, n as integer) as double                                  |math.bi     |Returns the product of x and 2 to the power n.                                                                                                                                                                |
      |ldiv    |ldiv(num as long, denom as long) as ldiv_t                                  |stdlib.bi   |Returns the quotient and remainder of a division as a structure of type ldiv_t.                                                                                                                               |
      |log_    |log_(a as double) as double                                                 |math.bi     |Returns the natural logarithm of the argument.                                                                                                                                                                |
      |log10   |log10(a as double) as double                                                |math.bi     |Returns the logarithm to the base 10 of the argument.                                                                                                                                                         |
      |malloc  |malloc(bytes as integer) as any ptr                                         |stdlib.bi   |Allocates memory. Returns a pointer to a buffer comprising storage for the specified size.                                                                                                                    |
      |modf    |modf(d as double, p as double ptr) as double                                |math.bi     |Returns the fractional part of a floating point number d. p points to the integral part expressed as a float.                                                                                                 |
      |perror  |perror(mess as zstring ptr)                                                 |stdio.bi    |Prints on the stream stderr a message passed as the argument.                                                                                                                                                 |
      |pow     |pow(x as double, y as double) as double                                     |math.bi     |Returns x to the power y.                                                                                                                                                                                     |
      |pow10   |pow10(x as double) as double                                                |math.bi     |Returns 10 to the power x (inverse function to log10()).                                                                                                                                                      |
      |printf  |printf(fmt as zstring ptr, ...) as integer                                  |stdio.bi    |Prints on standard output as many items as there are single % signs in fmt with matching arguments in the list.                                                                                               |
      |putc    |putc(c as integer, s as FILE ptr) as integer                                |stdio.bi    |Macro to output the single character c to the stream s.                                                                                                                                                       |
      |putchar |putchar(c as integer) as integer                                            |stdio.bi    |Macro to output the single character c to the standard output.                                                                                                                                                |
      |puts    |puts(b as zstring ptr) as integer                                           |stdio.bi    |Sends the character stream in b to the standard output, returns 0 if operation fails.                                                                                                                         |
      |rand    |rand() as integer                                                           |stdlib.bi   |Returns a pseudo random number. A seed is required. The seed is set with srand.                                                                                                                               |
      |realloc |realloc(p as any ptr, newsize as size_t) as any ptr                         |stdlib.bi   |Allocates memory. Returns a pointer to a buffer for a change in size of object pointed to by p.                                                                                                               |
      |rewind  |rewind(s as FILE ptr)                                                       |stdio.bi    |Clears the error indicators on a file stream (read or write). Necessary before reading an amended file.                                                                                                       |
      |scanf   |scanf(fmt as zstring ptr, ...) as integer                                   |stdio.bi    |Reads from standard input as many items as there are % signs in fmt with corresponding listed pointers.                                                                                                       |
      |sin_    |sin_(ar as double) as double                                                |math.bi     |Returns the sine of an angle measured in radians.                                                                                                                                                             |
      |sinh    |sinh(x as double) as double                                                 |math.bi     |Returns the hyperbolic sine of an angle measured in radians.                                                                                                                                                  |
      |sprintf |sprintf(p as zstring ptr, fmt as zstring ptr, ...) as integer               |stdio.bi    |Prints on zstring p as many items as there are single % signs in fmt that have matching arguments in the list.                                                                                                |
      |sqrt    |sqrt(a as double) as double                                                 |math.bi     |Returns the square root of the value passed. Domain error if value is negative.                                                                                                                               |
      |srand   |srand(seed as uinteger)                                                     |stdlib.bi   |Sets the seed for a random number. A possible seed is the current time.                                                                                                                                       |
      |sscanf  |sscanf(b as zstring ptr, fmt as zstring ptr, ...) as integer                |stdio.bi    |Reads from buffer b as many items as there are % signs in fmt with corresponding listed pointers.                                                                                                             |
      |strcat  |strcat(s1 as zstring ptr, s2 as zstring ptr) as zstring ptr                 |string.bi   |Concatenates (appends) zstring s2 to s1.                                                                                                                                                                      |
      |strchr  |strchr(s as zstring ptr, c as integer) as zstring ptr                       |string.bi   |Returns a pointer to the first occurrence of c in s or NULL if it fails to find one.                                                                                                                          |
      |strcmp  |strcmp(s1 as zstring ptr, s2 as zstring ptr) as integer                     |string.bi   |Compares zstring s2 to s1. Returns 0 or signed difference in ASCII values of first non matching character.                                                                                                    |
      |strcpy  |strcpy(s1 as zstring ptr, s2 as zstring ptr) as zstring ptr                 |string.bi   |Copies s2 into s1.                                                                                                                                                                                            |
      |strcspn |strcspn(s1 as zstring ptr, s2 as zstring ptr) as integer                    |string.bi   |Returns the number of characters in s1 encountered before meeting any of the characters in s2.                                                                                                                |
      |strerror|strerror(n as integer) as zstring ptr                                       |string.bi   |Returns a pointer to a system error message corresponding to the passed error number.                                                                                                                         |
      |strlen  |strlen(s as zstring ptr) as integer                                         |string.bi   |Returns the number of bytes in the null terminated zstring pointed to by s (does not count null).                                                                                                             |
      |strncat |strncat(s1 as zstring ptr, s2 as zstring ptr, n as integer) as zstring ptr  |string.bi   |Concatenates (appends) n bytes from zstring s2 to s1.                                                                                                                                                         |
      |strncmp |strncmp(s1 as zstring ptr, s2 as any ptr, n as integer) as integer          |string.bi   |Compares n bytes of zstring s2 to the same of s1. Returns 0 or signed difference in ASCII values of first non matching character.                                                                             |
      |strncpy |strncpy(s1 as zstring ptr, s2 as zstring ptr, n as integer) as zstring ptr  |string.bi   |Copies n bytes from s2 into s1.                                                                                                                                                                               |
      |strpbrk |strpbrk(s1 as zstring ptr, s2 as zstring ptr) as zstring ptr                |string.bi   |Returns a pointer to the first character encountered in s1 that is also in s2.                                                                                                                                |
      |strrchr |strrchr(s as zstring ptr, c as integer) as zstring ptr                      |string.bi   |Returns a pointer to the last occurrence of c in s or NULL if it fails to find one.                                                                                                                           |
      |strspn  |strspn(s1 as zstring ptr, s2 as zstring ptr) as integer                     |string.bi   |Returns the number of characters in s1 encountered before meeting a character which is not in s2.                                                                                                             |
      |strstr  |strstr(s1 as zstring ptr, s2 as zstring ptr) as zstring ptr                 |string.bi   |Finds the location of the zstring s2 in s1 and returns a pointer to its leading character.                                                                                                                    |
      |strtod  |strtod(s as zstring ptr, p as zstring ptr) as double                        |stdlib.bi   |Converts a zstring to double, provided the zstring is written in the form of a number.                                                                                                                        |
      |strtok  |strtok(s1 as zstring ptr, s2 as zstring ptr) as zstring ptr                 |string.bi   |Returns pointers to successive tokens utilizing the zstring s1. Tokens regarded as separators are listed in s2.                                                                                               |
      |system  |system(command as zstring ptr) as integer                                   |stdlib.bi   |Executes, from within a program, a command addressed to the operating system written as a zstring (e.g. DIR on Windows and DOS and LS on Linux).                                                              |
      |tan_    |tan_(ar as double) as double                                                |math.bi     |Returns the tangent of an angle measured in radians.                                                                                                                                                          |
      |tanh    |tanh(x as double) as double                                                 |math.bi     |Returns the hyperbolic tangent of an angle measured in radians.                                                                                                                                               |
      |tolower |tolower(c as integer) as integer                                            |ctype.bi    |Converts a character from upper case to lower case (uses ASCII code).                                                                                                                                         |
      |toupper |toupper(c as integer) as integer                                            |ctype.bi    |Converts a character from lower case to upper case (uses ASCII code).                                                                                                                                         |
      |ungetc  |ungetc(c as integer, s as FILE ptr) as integer                              |stdio.bi    |Pushes a character c back into the stream s, returns EOF if unsuccessful. Do not push more than one character.                                                                                                |
      +--------+----------------------------------------------------------------------------+------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

Buffer Manipulation

   #include "crt/string.bi"

      +----------------------------------------------------------------+--------------------------------------------------+
      |Prototype (with parameters)                                     |Comments                                          |
      |memchr(s as any ptr, c as integer, n as size_t) as any ptr      |Search for a character in a buffer.               |
      |memcmp(s1 as any ptr, s2 as any ptr, n as size_t) as integer    |Compare two buffers.                              |
      |memcpy(dest as any ptr, src as any ptr, n as size_t) as any ptr |Copy one buffer into another .                    |
      |memmove(dest as any ptr, src as any ptr, n as size_t) as any ptr|Move a number of bytes from one buffer lo another.|
      |memset(s as any ptr, c as integer, n as size_t) as any ptr      |Set all bytes of a buffer to a given character.   |
      +----------------------------------------------------------------+--------------------------------------------------+

Character Classification and Conversion

   #include "crt/ctype.bi"

      +---------------------------------+-------------------------------------+
      |Prototype (with parameters)      |Comments                             |
      |isalnum(c as integer) as integer |True if c is alphanumeric.           |
      |isalpha(c as integer) as integer |True if c is a letter.               |
      |isascii(c as integer) as integer |True if c is ASCII .                 |
      |iscntrl(c as integer) as integer |True if c is a control character.    |
      |isdigit(c as integer) as integer |True if c is a decimal digit.        |
      |isgraph(c as integer) as integer |True if c is a graphical character.  |
      |islower(c as integer) as integer |True if c is a lowercase letter.     |
      |isprint(c as integer) as integer |True if c is a printable character.  |
      |ispunct(c as integer) as integer |True if c is a punctuation character.|
      |isspace(c as integer) as integer |True if c is a space character.      |
      |isupper(c as integer) as integer |True if c is an uppercase letter.    |
      |isxdigit(c as integer) as integer|True if c is a hexadecimal digit.    |
      |toascii(c as integer) as integer |Convert c to ASCII .                 |
      |tolower(c as integer) as integer |Convert c to lowercase.              |
      |toupper(c as integer) as integer |Convert c to uppercase.              |
      +---------------------------------+-------------------------------------+

Data Conversion

   #include "crt/stdlib.bi"

      +---------------------------------------------------------------------------------+--------------------------------------------------------+
      |Prototype (with parameters)                                                      |Comments                                                |
      |atof(string1 as zstring ptr) as double                                           |Convert zstring to floating point value.                |
      |atoi(string1 as zstring ptr) as integer                                          |Convert zstring to an integer value.                    |
      |atol(string1 as zstring ptr) as integer                                          |Convert zstring to a long integer value.                |
      |itoa(value as integer, zstring as zstring ptr, radix as integer) as zstring ptr  |Convert an integer value to a zstring using given radix.|
      |ltoa(value as long, zstring as zstring ptr, radix as integer) as zstring ptr     |Convert long integer to zstring in a given radix.       |
      |strtod(string1 as zstring ptr, endptr as zstring ptr) as double                  |Convert zstring to a floating point value.              |
      |strtol(string1 as zstring ptr, endptr as zstring ptr, radix as integer) as long  |Convert zstring to a long integer using a given radix.  |
      |strtoul(string1 as zstring ptr, endptr as zstring ptr, radix as integer) as ulong|Convert zstring to unsigned long.                       |
      +---------------------------------------------------------------------------------+--------------------------------------------------------+

Directory Manipulation

   #include "crt/io.bi"

      +----------------------------------------------------------------+------------------------------------------+
      |Prototype (with parameters)                                     |Comments                                  |
      |_chdir(path as zstring ptr) as integer                          |Change current directory to given path.   |
      |_getcwd(path as zstring ptr, numchars as integer) as zstring ptr|Returns name of current working directory.|
      |_mkdir(path as zstring ptr) as integer                          |Create a directory using given path name. |
      |_rmdir(path as zstring ptr) as integer                          |Delete a specified directory.             |
      +----------------------------------------------------------------+------------------------------------------+

File Manipulation

   #include "crt/sys/stat.bi"
   #include "crt/io.bi"

      +------------------------------------------------------------------+------------------------------------------+
      |Prototype (with parameters)                                       |Comments                                  |
      |chmod(path as zstring ptr, pmode as integer) as integer           |Change permission settings of a file.     |
      |fstat(handle as integer, buffer as type stat ptr) as integer      |Get file status information.              |
      |remove(path as zstring ptr) as integer                            |Delete a named file.                      |
      |rename_(oldname as zstring ptr, newname as zstring ptr) as integer|rename a file.                            |
      |stat(path as zstring ptr, buffer as type stat ptr) as integer     |Get file status information of named file.|
      |umask(pmode as uinteger) as uinteger                              |Set file permission mask.                 |
      +------------------------------------------------------------------+------------------------------------------+

Stream I/O

   #include "crt/stdio.bi"

      +------------------------------------------------------------------------------------------------------------+-----------------------------------------------------------------+
      |Prototype (with parameters)                                                                                 |Comments                                                         |
      |clearerr(file_pointer as FILE ptr)                                                                          |Clear error indicator of stream,                                 |
      |fclose(file_pointer as FILE ptr) as integer                                                                 |Close a file,                                                    |
      |feof(file_pointer as FILE ptr) as integer                                                                   |Check if end of file occurred on a stream.                       |
      |ferror(file_pointer as FILE ptr) as integer                                                                 |Check if any error occurred during file I/0.                     |
      |fflush(file_pointer as FILE ptr) as integer                                                                 |Write out (flush) buffer to file.                                |
      |fgetc(file_pointer as FILE ptr) as integer                                                                  |Get a character from a stream.                                   |
      |fgetpos(file_pointer as FILE ptr, fpos_t current_pos) as integer                                            |Get the current position in a stream.                            |
      |fgets(string1 as zstring ptr, maxchar as integer, file_pointer as FILE ptr) as zstring ptr                  |Read a zstring from a file.                                      |
      |fopen(filename as zstring ptr, access_mode as zstring ptr) as FILE ptr                                      |Open a file for buffered I/0.                                    |
      |fprintf(file_pointer as FILE ptr, format_string as zstring ptr, args) as integer                            |Write formatted output to a file,                                |
      |fputc(c as integer, file_pointer as FILE ptr) as integer                                                    |Write a character to a stream.                                   |
      |fputchar(c as integer) as integer                                                                           |Write a character to stdout.                                     |
      |fputs(string1 as zstring ptr, file_pointer as FILE ptr) as integer                                          |Write a zstring to a stream.                                     |
      |fread(buffer as zstring ptr, size as size_t count as size_t, file_pointer as FILE ptr) as size_t            |Read unformatted data from a stream into a buffer.               |
      |freopen(filename as zstring ptr, access as zstring ptr mode, file_pointer as FILE ptr) as FILE ptr          |Reassign a file pointer to a different file.                     |
      |fscanf(file_pointer as FILE ptr, format as zstring ptr zstring, args) as integer                            |Read formatted input from a stream.                              |
      |fseek(file_pointer as FILE ptr, offset as long, origin as integer) as integer                               |Set current position in file to a new location.                  |
      |fsetpos(file_pointer as FILE ptr, current_pos as fpos_t) as integer                                         |Set current position in file to a new location.                  |
      |ftell(file_pointer as FILE ptr) as long                                                                     |Get current location in file.                                    |
      |fwrite(buffer as zstring ptr, size as size_t, count as size_t file_pointer as FILE ptr) as size_t           |Write unformatted data from a buffer to a stream.                |
      |getc(file_pointer as FILE ptr) as integer                                                                   |Read a character from a stream.                                  |
      |getchar() as integer                                                                                        |Read a character from stdin.                                     |
      |gets(buffer as zstring ptr) as zstring ptr                                                                  |Read a line from stdin into a buffer.                            |
      |printf(format as zstring ptr _string, args) as integer                                                      |Write formatted output to stdout.                                |
      |putc(c as integer, file_pointer as FILE ptr) as integer                                                     |Write a character to a stream.                                   |
      |putchar(c as integer) as integer                                                                            |Write a character to stdout.                                     |
      |puts(string1 as zstring ptr) as integer                                                                     |Write a zstring to stdout.                                       |
      |rewind(file_pointer as FILE ptr)                                                                            |Rewind a file.                                                   |
      |scanf(format_string as zstring ptr, args) as integer                                                        |Read formatted input from stdin.                                 |
      |setbuf(file_pointer as FILE ptr, buffer as zstring ptr)                                                     |Set up a new buffer for the stream.                              |
      |setvbuf(file_pointer as FILE ptr, buffer as zstring ptr, buf_type as integer, buf as size_t size) as integer|Set up new buffer and control the level of buffering on a stream.|
      |sprintf(string1 as zstring ptr, format_string as zstring ptr, args) as integer                              |Write formatted output to a zstring.                             |
      |sscanf(buffer as zstring ptr, format_string as zstring ptr, args) as integer                                |Read formatted input from a zstring.                             |
      |tmpfile() as FILE ptr                                                                                       |Open a temporary file.                                           |
      |tmpnam(file_name as zstring ptr) as zstring ptr                                                             |Get temporary file name.                                         |
      |ungetc(c as integer, file_pointer as FILE ptr) as integer                                                   |Push back character into stream' s buffer                        |
      +------------------------------------------------------------------------------------------------------------+-----------------------------------------------------------------+

Low level I/O

   #include "crt/io.bi"

   So far Win32 only, connects to MSVCRT.DLL (headers missing for other 
   platforms)

      +------------------------------------------------------------------------------+----------------------------------------------------+
      |Prototype (with parameters)                                                   |Comments                                            |
      |_close(handle as integer) as integer                                          |Close a file opened for unbuffered I/O.             |
      |_creat(filename as zstring ptr, pmode as integer) as integer                  |Create a new file with specified permission setting.|
      |_eof(handle as integer) as integer                                            |Check for end of file.                              |
      |_lseek(handle as integer, offset as long, origin as integer) as long          |Go to a specific position in a file.                |
      |_open(filename as zstring ptr, oflag as integer, pmode as uinteger) as integer|Open a file for low-level I/O.                      |
      |_read(handle as integer, buffer as zstring ptr, length as uinteger) as integer|Read binary data from a file into a buffer.         |
      |_write(handle as integer, buffer as zstring ptr, count as uinteger) as integer|Write binary data from a buffer to a file.          |
      +------------------------------------------------------------------------------+----------------------------------------------------+

Mathematics

   #include "crt/math.bi"

      +---------------------------------------------------+----------------------------------------------------------+
      |Prototype (with parameters)                        |Comments                                                  |
      |abs_(n as integer) as integer                      |Get absolute value of an integer.                         |
      |acos_(x as double) as double                       |Compute arc cosine of x.                                  |
      |asin_(x as double) as double                       |Compute arc sine of x.                                    |
      |atan_(x as double) as double                       |Compute arc tangent of x.                                 |
      |atan2_(y as double, x as double) as double         |Compute arc tangent of y/x.                               |
      |ceil(x as double) as double                        |Get smallest integral value that exceeds x.               |
      |cos_(x as double) as double                        |Compute cosine of angle in radians.                       |
      |cosh(x as double) as double                        |Compute the hyperbolic cosine of x.                       |
      |div(number as integer, denom as integer) as div_t  |Divide one integer by another.                            |
      |exp_(x as double) as double                        |Compute exponential of x.                                 |
      |fabs(x as double) as double                        |Compute absolute value of x.                              |
      |floor(x as double) as double                       |Get largest integral value less than x.                   |
      |fmod(x as double, y as double) as double           |Divide x by y with integral quotient and return remainder.|
      |frexp(x as double, expptr as integer ptr) as double|Breaks down x into mantissa and exponent of no.           |
      |labs(n as long) as long                            |Find absolute value of long integer n.                    |
      |ldexp(x as double, exp as integer) as double       |Reconstructs x out of mantissa and exponent of two.       |
      |ldiv(number as long, denom as long) as ldiv_t      |Divide one long integer by another.                       |
      |log_(x as double) as double                        |Compute log(x).                                           |
      |log10(x as double) as double                       |Compute log to the base 10 of x.                          |
      |modf(x as double, intptr as double ptr) as double  |Breaks x into fractional and integer parts.               |
      |pow(x as double, y as double) as double            |Compute x raised to the power y.                          |
      |rand() as integer                                  |Get a random integer between 0 and 32767.                 |
      |random(max_num as integer) as integer              |Get a random integer between 0 and max_num.               |
      |randomize()                                        |Set a random seed for the random number generator.        |
      |sin_(x as double) as double                        |Compute sine of angle in radians.                         |
      |sinh(x as double) as double                        |Compute the hyperbolic sine of x.                         |
      |sqrt(x as double) as double                        |Compute the square root of x.                             |
      |srand(seed as uinteger)                            |Set a new seed for the random number generator (rand).    |
      |tan_(x as double) as double                        |Compute tangent of angle in radians.                      |
      |tanh(x as double) as double                        |Compute the hyperbolic tangent of x.                      |
      +---------------------------------------------------+----------------------------------------------------------+

Memory Allocation

   #include "crt/stdlib.bi"

      +-------------------------------------------------------------+-------------------------------------------------------+
      |Prototype (with parameters)                                  |Comments                                               |
      |calloc(num as size_t elems, elem_size as size_t) as any ptr  |Allocate an array and initialise all elements to zero .|
      |free(mem_address as any ptr)                                 |Free a block of memory.                                |
      |malloc(num as size_t bytes) as any ptr                       |Allocate a block of memory.                            |
      |realloc(mem_address as any ptr, newsize as size_t) as any ptr|Reallocate (adjust size) a block of memory.            |
      +-------------------------------------------------------------+-------------------------------------------------------+

Process Control

   #include "crt/stdlib.bi"

      +------------------------------------------------------------------------------------------+-------------------------------------------------------+
      |Prototype (with parameters)                                                               |Comments                                               |
      |abort()                                                                                   |Abort a process.                                       |
      |execl(path as zstring ptr, arg0 as zstring ptr, arg1 as zstring ptr,..., NULL) as integer |Launch a child process (pass command line).            |
      |execlp(path as zstring ptr, arg0 as zstring ptr, arg1 as zstring ptr,..., NULL) as integer|Launch child (use PATH, pass command line).            |
      |execv(path as zstring ptr, argv as zstring ptr) as integer                                |Launch child (pass argument vector).                   |
      |execvp(path as zstring ptr, argv as zstring ptr) as integer                               |Launch child (use PATH, pass argument vector).         |
      |exit_(status as integer)                                                                  |Terminate process after flushing all buffers.          |
      |getenv(varname as zstring ptr) as zstring ptr                                             |Get definition of environment variable,                |
      |perror(string1 as zstring ptr)                                                            |Print error message corresponding to last system error.|
      |putenv(envstring as zstring ptr) as integer                                               |Insert new definition into environment table.          |
      |raise(signum as integer) as integer                                                       |Generate a C signal (exception).                       |
      |system_(string1 as zstring ptr) as integer                                                | Execute a resident operating system command.          |
      +------------------------------------------------------------------------------------------+-------------------------------------------------------+

Searching and Sorting

   #include "crt/stdlib.bi"
            Note: The compare callback function required by bsearch and 
            qsort must be declared as cdecl. It must return a value <0 if 
            its first argument should be located before the second one in 
            the sorted array, >0 if the first argument should be located 
            after the second one, and zero if their relative positions are 
            indifferent (equal values).  

      +-------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+
      |Prototype (with parameters)                                                                                                                            |Comments                                     |
      |bsearch(key as any ptr, base as any ptr, num as size_t, width as size_t, compare as function(elem1 as any ptr, elem2 as any ptr) as integer) as any ptr|Perform binary search.                       |
      |qsort(base as any ptr, num as size_t, width as size_t, compare as function(elem1 as any ptr, elem2 as any ptr) as integer)                             |Use the quicksort algorithm to sort an array.|
      +-------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+

String Manipulation

   #include "crt/string.bi"

      +-----------------------------------------------------------------------------------+----------------------------------------------------------+
      |Prototype (with parameters)                                                        |Comments                                                  |
      |stpcpy(dest as zstring ptr, src as zstring ptr) as zstring ptr                     |Copy one zstring into another.                            |
      |strcmp(string1 as zstring ptr, string2 as zstring ptr) as integer                  |Compare string1 and string2 to determine alphabetic order.|
      |strcpy(string1 as zstring ptr, string2 as zstring ptr) as zstring ptr              |Copy string2 to string1.                                  |
      |strerror(errnum as integer) as zstring ptr                                         |Get error message corresponding to specified error number.|
      |strlen(string1 as zstring ptr) as integer                                          |Determine the length of a zstring.                        |
      |strncat(string1 as zstring ptr, string2 as zstring ptr, n as size_t) as zstring ptr|Append n characters from string2 to string1.              |
      |strncmp(string1 as zstring ptr, string2 as zstring ptr, n as size_t) as integer    |Compare first n characters of two strings.                |
      |strncpy(string1 as zstring ptr, string2 as zstring ptr, n as size_t) as zstring ptr|Copy first n characters of string2 to string1.            |
      |strnset(string1 as zstring ptr, c as integer, size _t n) as zstring ptr            |Set first n characters of zstring to c.                   |
      |strrchr(string1 as zstring ptr, c as integer) as zstring ptr                       |Find last occurrence of character c in zstring.           |
      +-----------------------------------------------------------------------------------+----------------------------------------------------------+

Time

   #include "crt/time.bi"

      +----------------------------------------------+-------------------------------------------------------------+
      |Prototype (with parameters)                   |Comments                                                     |
      |asctime(time as type tm ptr) as zstring ptr   |Convert time from type tm to zstring.                        |
      |clock() as clock_t                            |Get elapsed processor time in clock ticks.                   |
      |ctime(time as time_t ptr) as zstring ptr      |Convert binary time to zstring.                              |
      |difftime(time_t time2, time_t time1) as double|Compute the difference between two times in seconds.         |
      |gmtime(time as time_t ptr) as type tm ptr     |Get Greenwich Mean Time (GMT) in a tm structure.             |
      |localtime(time as time_t ptr) as type tm ptr  |Get the local time in a tm structure.                        |
      |time_(timeptr as time_t ptr) as time_t        |Get current time as seconds elapsed since 0 hours GMT 1/1/70.|
      +----------------------------------------------+-------------------------------------------------------------+

See also
   * #include



-------------------------------------------------------------- CptAscii ----
Table of ASCII Characters

FreeBASIC graphics programs support in all versions the same "ASCII 
extended" USA character set the old DOS (and QBasic) supported. It is also 
called CP437 or Code page 437.  Each character is represented with one (1) 
byte of data.  Here is a table.  Each entry has decimal code, hex code, and 
printed representation.

      
     0  0  ³ 16 10  ³ 32 20  ³ 48 30 0³ 64 40 @³ 80 50 P³ 96 60 `³112 70 p
     1  1  ³ 17 11  ³ 33 21 !³ 49 31 1³ 65 41 A³ 81 51 Q³ 97 61 a³113 71 q
     2  2  ³ 18 12  ³ 34 22 "³ 50 32 2³ 66 42 B³ 82 52 R³ 98 62 b³114 72 r
     3  3  ³ 19 13  ³ 35 23 #³ 51 33 3³ 67 43 C³ 83 53 S³ 99 63 c³115 73 s
     4  4  ³ 20 14  ³ 36 24 $³ 52 34 4³ 68 44 D³ 84 54 T³100 64 d³116 74 t
     5  5  ³ 21 15  ³ 37 25 %³ 53 35 5³ 69 45 E³ 85 55 U³101 65 e³117 75 u
     6  6  ³ 22 16  ³ 38 26 &³ 54 36 6³ 70 46 F³ 86 56 V³102 66 f³118 76 v
     7  7  ³ 23 17  ³ 39 27 '³ 55 37 7³ 71 47 G³ 87 57 W³103 67 g³119 77 w
     8  8  ³ 24 18  ³ 40 28 (³ 56 38 8³ 72 48 H³ 88 58 X³104 68 h³120 78 x
     9  9  ³ 25 19  ³ 41 29 )³ 57 39 9³ 73 49 I³ 89 59 Y³105 69 i³121 79 y
    10  A  ³ 26 1A  ³ 42 2A *³ 58 3A :³ 74 4A J³ 90 5A Z³106 6A j³122 7A z
    11  B  ³ 27 1B  ³ 43 2B +³ 59 3B ;³ 75 4B K³ 91 5B [³107 6B k³123 7B {
    12  C  ³ 28 1C  ³ 44 2C ,³ 60 3C <³ 76 4C L³ 92 5C \³108 6C l³124 7C |
    13  D  ³ 29 1D  ³ 45 2D -³ 61 3D =³ 77 4D M³ 93 5D ]³109 6D m³125 7D }
    14  E  ³ 30 1E  ³ 46 2E .³ 62 3E >³ 78 4E N³ 94 5E ^³110 6E n³126 7E ~
    15  F  ³ 31 1F  ³ 47 2F /³ 63 3F ?³ 79 4F O³ 95 5F _³111 6F o³127 7F 

   128 80 €³144 90 �³160 A0  ³176 B0 °³192 C0 À³208 D0 Ð³224 E0 à³240 F0 ð
   129 81 �³145 91 ‘³161 A1 ¡³177 B1 ±³193 C1 Á³209 D1 Ñ³225 E1 á³241 F1 ñ
   130 82 ‚³146 92 ’³162 A2 ¢³178 B2 ²³194 C2 Â³210 D2 Ò³226 E2 â³242 F2 ò
   131 83 ƒ³147 93 “³163 A3 £³179 B3 ³³195 C3 Ã³211 D3 Ó³227 E3 ã³243 F3 ó
   132 84 „³148 94 ”³164 A4 ¤³180 B4 ´³196 C4 Ä³212 D4 Ô³228 E4 ä³244 F4 ô
   133 85 …³149 95 •³165 A5 ¥³181 B5 µ³197 C5 Å³213 D5 Õ³229 E5 å³245 F5 õ
   134 86 †³150 96 –³166 A6 ¦³182 B6 ¶³198 C6 Æ³214 D6 Ö³230 E6 æ³246 F6 ö
   135 87 ‡³151 97 —³167 A7 §³183 B7 ·³199 C7 Ç³215 D7 ×³231 E7 ç³247 F7 ÷
   136 88 ˆ³152 98 ˜³168 A8 ¨³184 B8 ¸³200 C8 È³216 D8 Ø³232 E8 è³248 F8 ø
   137 89 ‰³153 99 ™³169 A9 ©³185 B9 ¹³201 C9 É³217 D9 Ù³233 E9 é³249 F9 ù
   138 8A Š³154 9A š³170 AA ª³186 BA º³202 CA Ê³218 DA Ú³234 EA ê³250 FA ú
   139 8B ‹³155 9B ›³171 AB «³187 BB »³203 CB Ë³219 DB Û³235 EB ë³251 FB û
   140 8C Œ³156 9C œ³172 AC ¬³188 BC ¼³204 CC Ì³220 DC Ü³236 EC ì³252 FC ü
   141 8D �³157 9D �³173 AD ­³189 BD ½³205 CD Í³221 DD Ý³237 ED í³253 FD ý
   142 8E Ž³158 9E ž³174 AE ®³190 BE ¾³206 CE Î³222 DE Þ³238 EE î³254 FE þ
   143 8F �³159 9F Ÿ³175 AF ¯³191 BF ¿³207 CF Ï³223 DF ß³239 EF ï³255 FF ÿ

 

Many of the standard ASCII characters cannot be Printed in FreeBASIC, 
because the console interprets some characters as controls: 7 is bell, 8 is 
backspace, 9 is tab, 10 is line feed, 13 is carriage return, and others.  
There are symbols associated with these characters also, but there is no 
way in FreeBASIC to output them to the screen. 

The acronym ASCII stands for American Standard Code for Information 
Interchange. For more information, see http://en.wikipedia.org/wiki/Ascii.  
The symbols for codes 32 through 127 are the same as the standard 
Latin ISO-8859-1 char set most Windows fonts use. Others are often very 
different.

In console mode (i.e. Screen (Graphics) 0/ non-graphics mode) the 
characters less than 32 or greater than 127 may display using different 
characters, depending on the operating system and code page of the screen / 
console in use.
UNICODE is a newer standard of character sets involving two or more bytes 
per character, and may be used to print other characters to a 
Unicode-enabled console.

In graphics modes, Draw String does not give special meaning to control 
characters allowing an alternative to display all characters in the set. 



------------------------------------------------------ TblRuntimeErrors ----
Runtime Error Codes

Runtime error codes and messages used by the runtime library.

Description
   Freebasic returns the following runtime error codes:
      +----+-----------------------------+
      |  0 |No error                     |
      |  1 |Illegal function call        |
      |  2 |File not found signal        |
      |  3 |File I/O error               |
      |  4 |Out of memory                |
      |  5 |Illegal resume               |
      |  6 |Out of bounds array access   |
      |  7 |Null Pointer Access          |
      |  8 |No privileges                |
      |  9 |interrupted signal           |
      | 10 |illegal instruction signal   |
      | 11 |floating point error signal  |
      | 12 |segmentation violation signal|
      | 13 |Termination request signal   |
      | 14 |abnormal termination signal  |
      | 15 |quit request signal          |
      | 16 |return without gosub         |
      | 17 |end of file                  |
      +----+-----------------------------+

   No user error code range is defined. If Error is used to set an error 
   code it is wise to use high values to avoid collisions with the list of 
   built-in error codes. (This built-in list may be expanded later.)

See also
   * Err
   * Error
   * On Error
   * Error Handling

   


-------------------------------------------------------- TblComparisonC ----
Comparison of C/C++ and FreeBASIC

C/C++FreeBASIC

variable declaration
int a;
int a, b, c;dim a as long
dim as long a, b, c

uninitialized variable
int a;dim a as long = any

zero-initialized variable
int a = 0;dim a as long

initialized variable
int a = 123;dim a as long = 123

array
int a[4];
a[0] = 1;dim a(0 to 3) as long
a(0) = 1

pointer
int a;
int *p;
p = &a;
*p = 123;dim a as long
dim p as long ptr
p = @a
*p = 123

structure, user-defined type
struct UDT {
   int myfield;
}type UDT
   myfield as long
end type

typedef, type alias
typedef int myint;type myint as long

struct pointer
struct UDT x;
struct UDT *p;
p = &x;
p->myfield = 123;dim x as UDT
dim p as UDT ptr
p = @x
p->myfield = 123

function declaration
int foo( void );declare function foo( ) as long

function body
int foo( void ) {
   return 123;
}function foo( ) as long
   return 123
end function

sub declaration
void foo( void );declare sub foo( )

sub body
void foo( void ) {
}sub foo( )
end sub

byval parameters
void foo( int param );
foo( a );declare sub foo( byval param as long )
foo( a )

byval pointers to parameters
void foo( int *param );
foo( &a );declare sub foo( byval param as long ptr )
foo( @a )

byref parameters
void foo( int& param );
foo( a );declare sub foo( byref param as long )
foo( a )

statement separator
;

:
<end-of-line>

for loop
for (int i = 0; i < 10; i++) {
   ...
}for i as long = 0 to 9
   ...
next

while loop
while (condition) {
   ...
}while condition
   ...
wend

do-while loop
do {
   ...
} while (condition);do
   ...
loop while condition

if block
if (condition) {
   ...
} else if (condition) {
   ...
} else {
   ...
}if condition then
   ...
elseif condition then
   ...
else
   ...
end if

switch, select
switch (a) {
case 1:
   ...
   break;
case 2:
case 3:
   ...
   break;
default:
   ...
   break;
}select case a
case 1
   ...

case 2, 3
   ...

case else
   ...

end select

string literals, zstrings
char *s = "Hello!";
char s[] = "Hello!";dim s as zstring ptr = @"Hello!"
dim s as zstring * 6+1 = "Hello!"

hello world
#include <stdio.h>
int main() {
   printf("Hello!\n");
   return 0;
}print "Hello!"

comments
// foo
/* foo */' foo
/' foo '/

compile-time checks
#if a
#elif b
#else
#endif#if a
#elseif b
#else
#endif

compile-time target system checks
#ifdef _WIN32#ifdef __FB_WIN32__

module/header file names
foo.c, foo.hfoo.bas, foo.bi

typical compiler command to create an executable
gcc foo.c -o foofbc foo.bas

Last reviewed by MrSwiss on April 6, 2018 Note: changed Integer to Long 
(where needed)

--------------------------------------------------- TblComparisonCTypes ----
Comparison of integer data types: FreeBASIC vs. C/C++ (using GCC)

   +-------------------+------+------------------+-------------+--------+-----------+-----------+
   |                   | C int| C long long [int]| C long [int]| FB Long| FB LongInt| FB Integer|
   | 32bit win32       | 32   | 64               | 32 (ILP32)  | 32     | 64        | 32        |
   | 32bit linux-x86   | 32   | 64               | 32 (ILP32)  | 32     | 64        | 32        |
   | 64bit win64       | 32   | 64               | 32 (LLP64)  | 32     | 64        | 64        |
   | 64bit linux-x86_64| 32   | 64               | 64 (LP64)   | 32     | 64        | 64        |
   +-------------------+------+------------------+-------------+--------+-----------+-----------+

Some public symbols (like namespaces, and user defined type member 
procedures) will have data type information encoded in to the public name 
(also known as name mangling or name decoration).  Specific mapping of data 
types between FreeBASIC and gcc is required when linking fbc compiled 
object modules with gcc compiled object modules.  
   +-------------+-------------------+-------------------------+-----+
   |Target       | fbc data type     | c data type             | bits|
   | all         | byte              | signed char             | 8   |
   | all         | ubyte             | unsigned char           | 8   |
   | all         | byte alias "char" | char                    | 8   |
   | all         | ubyte alias "char"| char                    | 8   |
   | all         | short             | [signed] short [int]    | 16  |
   | all         | ushort            | unsigned short [int]    | 16  |
   | all         | long              | [signed] int            | 32  |
   | all         | ulong             | unsigned int            | 32  |
   | x86         | integer           | [signed] long [int]     | 32  |
   | x86         | uinteger          | unsigned long [int]     | 32  |
   | win64       | long alias "long" | [signed] long [int]     | 32  |
   | win64       | ulong alias "long"| unsigned long [int]     | 32  |
   | win64       | integer           | INTEGER                 | 64  |
   | win64       | uinteger          | UINTEGER                | 64  |
   | linux-x86_64| integer           | [signed] long [int]     | 64  |
   | linux-x86_64| uinteger          | unsigned long [int]     | 64  |
   | all         | longint           | [signed] long long [int]| 64  |
   | all         | ulongint          | unsigned long long [int]|  64 |
   +-------------+-------------------+-------------------------+-----+

See also
   * Creating FB bindings for C libraries - How to translate C data types 
     to FB





============================================================================
  HACKING ON FREEBASIC
  --------------------


---------------------------------------------------------------- DevToc ----
Information for hacking on FreeBASIC

This area of the Wiki is for documenting everything about the compiler and 
the runtime libraries. It is, however, incomplete. If you find that 
information provided here does not match what the source is doing then 
please update the relevant pages here. New pages and articles may be added 
freely, provided they help understanding what's going on inside FB.

Developing FreeBASIC Itself

   Compiling a Development Version of FreeBASIC
      Getting the source code
      Compiling FB for DOS
      Compiling FB on Linux
      Compiling FB on Windows
      Compiling FB with Emscripten
      Getting source code updates and recompiling FB
      Debugging FB
      FB build configuration options
      Known problems when compiling FB
      GCC toolchain choice

   Running the FreeBASIC test suite
   Normal vs. Standalone
   Glossary
   Notes on the creation of FB releases
   FB and cross-compiling
   Bootstrapping/cross-compiling fbc

   Creating FB bindings for C libraries
   C Header Translation Tutorial
   Header Style Guidelines
   External Libraries Index (header status)

Compiler internals

   Quick overview of all modules
   The objinfo feature
   Memory management
   Lexer & preprocessor

   Parser & compiler (fb, parser, symb, rtl)
      Purpose
      Top level parsing process
      Symbols
      Representation of data types

   Arrays
   SELECT CASE
   Profiling with fb's profiler
   Profiling for gmon/gprof
   Structure packing/field alignment

Run-time (rtlib) and Graphics (gfxlib2) Libraries

   Keyboard input: inkey(), multikey(), etc.
   Overview of drivers (backends)
   Pixel formats



