Talk About Network



Register and Login
Nick
Password
Register create new account Sign up is FREE and you can post replies, new topics, bookmark posts and more!
Recover lost password


Programming > Basic Powerbasic > PowerBASIC-FAQ,...
Latest [ Topics | Posts ] Archive Post A New Topic Post a Reply
<< Topic < Post Post 1 of 1 Topic 204 of 266
Post > Topic >>

PowerBASIC-FAQ, english issue

by Thomas Gohel <gohel@[EMAIL PROTECTED] > Oct 1, 2006 at 05:27 PM

==========================================================================

           PowerBASIC.GER-FAQ for Versions 3.00, 3.10, 3.20 & 3.50
                            English Version (DOS)

            (c) 1995/2005 by Thomas Gohel, All Rights reserved!
        English Team: Thomas Geiger, Andras Hoeffken, Wolfgang Bruske

                       Date: 29.09.2005 - Version 1.00

         Tip's, Trick's, Bug's and some more or less important stuff

==========================================================================

    ====================
    Foreword to this FAQ
    ====================

    The links listed within this FAQ are provided without concern about
    possible Copyright-Notices and without concern about any trademarks.
    Further, the Author does not quarantee that the problems, hints and
    bugs below are totally correct. Should you have suggestions to this
    FAQ, pleasce contact me. I am open to suggestions and will let them
    flow into future Versions of this FAQ.
    I would also like to point out that some of the 'Bugs' in the 'Bugs
    Section are only 'Bugs' in a matter of speech. Those mistakes or
    barriers are documented here for all to see (So that future Versions
    of PowerBASIC may be developed).


    ===========
    Suggestions
    ===========

    Suggestions may be presented to the Author of this FAQ at any time.
    Current Netmail-Addresses are:

        Thomas Gohel@[EMAIL PROTECTED]
  (FidoNet)
        pbfaq@[EMAIL PROTECTED]
             (InterNet)

    There is also the possibility to log into a Mailbox in which the
    Author of this FAQ is reachable:

        Port 1: +49-30-47300910 (PBSOUND HQ, Berlin - 64.0, ISDN, X75,
V42B)
        Port 2: +49-30-47300910 (PBSOUND HQ, Berlin - 33.6, VFC, V34, FAX)

    You can post your suggestions and problems there. To do so, please
    write a Message in the PBSOUND-Message-Area. An answer should be
    available within 48 hours.


    ============================================
    How to obtain the current PowerBASIC.GER-FAQ
    ============================================

    The current PowerBASIC.GER-FAQ can be downloaded from my Home BBS
online
    anytime. The phone numbers are:

        Port 1: +49-30-47300910 (PBSOUND HQ, Berlin - 64.0, ISDN, X75,
V42B)
        Port 2: +49-30-47300910 (PBSOUND HQ, Berlin - 33.6, VFC, V34, FAX)

    Please switch to the 'PowerBASIC: FAQ'-Filearea after login.
    There are 16 more 'PowerBASIC-Fileareas':

        PowerBASIC: PBSOUND
        PowerBASIC: Sound Blaster
        PowerBASIC: FAQ
        PowerBASIC: Sourcen (allgemein)
        PowerBASIC: Sourcen (Deutschland)
        PowerBASIC: Sourcen (Netherlands)
        PowerBASIC: Toolkits (allgemein)
        PowerBASIC: Toolkits (Deutschland)
        PowerBASIC: Toolkits (Netherlands)
        PowerBASIC: Grafik (allgemein)
        PowerBASIC: Grafik (Deutschland)
        PowerBASIC: Grafik (Netherlands)
        PowerBASIC: DFUE, BBS und FidoNet Sourcen
        PowerBASIC: allgemeine Pakete und Info's
        PowerBASIC: Demos
        PowerBASIC: User Uploads / Incoming
        (Note: The PowerBASIC filebase is in german!)

    Many of the Sources and Toolboxes mentioned in this FAQ can be
    downloaded here online or using FidoNet Filerequest.

    InterNet-Users can get the PowerBASIC.GER-FAQ anytime using World Wide
    Web (WWW) under:

        - http://www.gohel.de

    A Request of this FAQ using FidoNet is possible using the Magic
    'PBFAQ'!

        Port 1: +49-30-47300910 (PBSOUND HQ, Berlin - 64.0, ISDN, X75,
V42B)
        Port 2: +49-30-47300910 (PBSOUND HQ, Berlin - 33.6, VFC, V34, FAX)

    Further PowerBASIC-Magics are: PBSOUND and PBFILES.


    ==============
    Complete Index
    ==============

       1.  Obtaining, Toolboxes, Prices and Infos about PowerBASIC
       2.  Errors/Inconsistencies in PowerBASIC-Versions 3.0, 3.1 and 3.2
       3.  PowerBASIC and the CoProcessor
       4.  Standardproblems
       5.  Hints in Connection with the InLine-Assembler
       6.  Hints in Connection with Pointers
       7.  Hints in Connection with Turbo-C or Borland C++
       8.  Hints to the Conversion of Sources from PDS to PowerBASIC 3.x
       9.  Available Shareware & Public Domain Solutions
      10.  The People from PowerBASIC


    ===========================================================
    1.  Obtaining, Toolboxes, Prices and Infos about PowerBASIC
    ===========================================================

       1.1. The Current Versions of PowerBASIC
       1.2. The Original Distributors of PowerBASIC
       1.3. German Speaking Area
       1.4. German PowerBASIC Prices
       1.5. Denmark, Norway, Sweden and Finland
       1.6. New in Version 3.1 of PowerBASIC
       1.7. New in Version 3.2 of PowerBASIC
       1.8. New in Version 3.5 of PowerBASIC
       1.9. PowerBASIC - The next Generation


    1.1. The Current Versions of PowerBASIC
    ---------------------------------------
    The current Version of PowerBASIC in Germany (in January 1998) is
    Version 3.50. This Version has been available in the US and other
    countries since December 1997.


    1.2. The Original Distributors of PowerBASIC
    --------------------------------------------
    PowerBASIC was and is developed in the United States and there are
    multiple possibilites to get contact to these people. Here are the
    currently known addresses from PowerBASIC Inc.:

    Address:
            PowerBASIC, Inc.
            1978 Tamiami Trail S.#200
            Venice, FL  34293

            Ordering      : +1 (800) 780-7707
            Service       : +1 (941) 408-8700
            Fax           : +1 (941) 408-8820

    InterNet:
            World Wide Web                : www.powerbasic.com
            List of InterNet Sites        : info@[EMAIL PROTECTED]
            Ordering                      : order@[EMAIL PROTECTED]
            Sales and Marketing           : sales@[EMAIL PROTECTED]
            Technical Support             : support@[EMAIL PROTECTED]
            Suggestions for future
            PowerBASIC Versions           : suggest@[EMAIL PROTECTED]
    FTP- & WWW-Sites:
            http://pbsound.basicguru.com
            http://www.gohel.de
            http://www.xlsior.org
            http://www.basicguru.com
            http://www.uni-jena.de/~p6sepa/rshp.html
            http://home/t-online.de/home/mstadler/homepage.htm
           
http://www.leo.org/pub/comp/platforms/pc/msdos/programming/pbasic/
            http://www.fys.ruu.nl/~bergmann/basic.html
            http://www.zephyrsoftware.com
            http://www.blarg.net/~future/shareware.html
            http://www.cdrom.com/simtel.net/msdos/basic.html
            http://www.cyberbox.north.de/FILES/DOS/dos106.html
            ftp.global2000.net/pub/pbasic
    Newsgroups (english):
            alt.lang.powerbasic
            comp.lang.powerbasic
|   Newsgroups (german):
|           news.kannofant.de/de.comp.lang.powerbasic
|           Hote: Needs authentication with user/password (basic/basic)!

    1.3. German Speaking Area
    -------------------------
    In Germany PowerBASIC is distributed by "Kirschbaum Software GmbH".
    The current address is:
            Kirschbaum Software GmbH
            Kronau 15
            83550 Emmering
            GERMANY
            Phone: +49-8067-9038-0
            Fax  : +49-8067-903898

    The current Version of PowerBASIC is Version 3.50. Following Toolboxes
    are available from Kirschbaum:

        PB/DLL      - PowerBASIC DLL-Compiler for Windows
        PowerGRAPH  - for graphical Menu systems (PCX, Fonts, etc.)
        PowerISAM   - Databases (also available in English from PowerBASIC
Inc.)
        PowerTOOLS  - SAA-Shell, Helpsystem, helpfull Routines
        PB/xtra     - Collection of Shareware programs and Source code

    Kirschbaum does not have a Mailbox or any official EMail addresses!
    There are some EMail addresses and Support-Areas or unofficial
    Newsgroups etc. from the Toolbox Developers. In this case please see
    the Manual of the Toolbox.


    1.4. German PowerBASIC Prices
    -----------------------------
    All prices noted here are NOT validated. Changes can occur at any
time!
    A currently valid pricing Information can be optained from Kirschbaum
    by FAX.

    Complete Version: 199,-DM
    Complete Version 3.5 for Students, Pupils: 150,-DM
    Update from VOBIS-Basisversion 2.10f to V3.5: 149,-DM
    Update from V2.10 to V3.5: 149,-DM
    Update from a  3.x-Version to V3.5: 36,80DM


|   1.5. Denmark, Norway, Sweden and Finland
|   ----------------------------------------
|   In some european countries (incl. Germany and Austria) PowerBASIC is
|   distributed by:
|
|           Berggreen Service
|           Lodsgaarden A 111
|           DK-2791 Dragoer
|           DENMARK
|           info@[EMAIL PROTECTED]
|           http://www.berggreen.dk


    1.6. New in Version 3.1 of PowerBASIC
    -------------------------------------
    - Userdefined Type- and Union-Variables can be compared directly.
    - Constants in Binary, Hex or Octal Format (&B, &H, &O) can be set
      to a specific Datatype, by simply adding the correct Identifier.
      Examples:
              A?? = &HFFFF??   '= 65535
              B%  = &HFFFF%    '= -1

    - Constants (%Test) can have a 64-Bit Range (signed) from this
      PowerBASIC Version on.
      Examples:
              %MaxNumber = 500000
              %Konst1    = &HFFFF   '= -1 (Integer)
              %Konst2    = &H0FFFF  '= 65535 (Long)

      When using Binary, Hexdecimal or Octal Numbers, adding a proceeding
      Zero defines whether the calculated Value is signed or not.

    - BIN$, HEX$ and OCT$ can now calculate Values up to 32Bit Long-
      Integer.

    - From Version 3.1 on you can give alternative Names to SUBs or
      FUNCTIONs, with which you can call these Subroutines from within
      OBJ-Routines (compiled with Assembler or C).

      Example:
              SUB MySub ALIAS "_my_sub" (Var1%,Var2$) PUBLIC
                 PRINT "Hello", Var1%, Var2$
              END SUB

    - The keyword ANY in a definiton of a Procedure allows the passing of
      a parameter of any type. The parameter is then passed by REFERENCE
      as a 32Bit Address. To let the Programm know what kind of type it
      is you should pass a Type identification as the first parameter to
the
      Procedure. When this Procedure is coded in PowerBASIC, the Inline-
      Assembler must be used to pass on the parameters.

      Example:
              i% = 11
              CALL TestAny(0,i%)      'the free parameters must be
Variables
              s$ = "Hello"
              CALL TestAny(1,s$)

              SUB TestAny(ParamType AS INTEGER, ANY)
                  DIM Int.Param    AS INTEGER
                  DIM String.Param AS STRING
                  SELECT CASE ParamType
                      CASE 0                  'Integer
                          ! les bx, [bp+6]    :Load Offset of Var. in BX
                          ! mov ax, es:[bx]   ;Load Value of Var. in AX
                          ! mov Int.Param, ax ;Load Varibale to AX
                          PRINT Int.Param
                      CASE 1                  'String
                                              ;Load Offset of Stringmarker
                          ! les bx, [bp+6]    ;into BX
                          ! mov ax, es:[bx]   ;Load Stringmarker into AX
                          ! mov String.Param,AX
                          PRINT String.Param
                  END SELECT
              END SUB

    - The Return value of FUNCTIONs written with the Inline-Assembler can
      now be set without using a temporary Variable. The Keyword FUNCTION
      is used for this.

      Example:
              PRINT AsmTest(2)
              FUNCTION AsmTest(BYVAL int.param AS INTEGER) AS INTEGER
                      ! mov ax, int.param
                      ! inc ax
                      ! mov FUNCTION, ax  ;the Value will be returned
              END FUNCTION

      (Also see chapter 'Hints with the Inline-Assembler')

    - The use of FUNCTION instead of the Functionname is also possible
      with FUNCTIONs coded in BASIC.

      Example:
              PRINT FuTest(2)
              FUNCTION FuTest(BYVAL int.param AS INTEGER) AS INTEGER
                     FUNCTION = int.param + 1
              END FUNCTION

    - The Function FRE() was extended:

      FRE(-3) returns the free Space on the Stack
      FRE(-4) returns the maximum Length available for dynamic Strings,
set
              using $STRING
      FRE(-5) returns the Number of used Stringsegments
      FRE(-6) returns the Number of unused Blocks in the current
              Stringsegment
      FRE(-7) returns the amount of unused Memory in the current
              Stringsegment


    1.7. New in Version 3.2 of PowerBASIC
    -------------------------------------
    - Data Pointers
    - Code Pointers
      Following Jumps can now be executed directly in BASIC:
      "CALL DWORD x", "GOTO DWORD x" ans "GOSUB DWORD x". In this case "x"
      is the 32Bit Pointer to a SUB/Function or the Label. (There is a
      DIR$- Demo to the new Pointer- Functions.)

    - 32-Bit implementation of:
      STRPTR32, VARPTR32 und CODEPTR32

    - Pointer to Structures can now be passed on to a SUB/FUNCTION using
      the "BYVAL" Keyword.

      Example:
              DECLARE SUB MySUB(x AS INTEGER)
              DIM z AS INTEGER PTR
              z = &HB8000000
              CALL MySUB(BYVAL z)

    - 16550 UART Support

    - The LEN() Function now also returns the length of User-defined
      Structures.

    - Labels ans Variables can now contain the so-calles Underlines '_' so
      that they can be kept appart easier.


    1.8. New in Version 3.5 of PowerBASIC
    -------------------------------------
    - some important Bugfixes
    - ASCIIZ strings:  Dim xyz as Asciiz * 100.
    - Arrays as User Type Members, may have one or two static dimensions.
    - & operator is recognized for string concatenation.
    - STRING PTR is now legal as a Type/Union member.
    - $ELSEIF metastatement.
    - ASC(x$,n) function and statement offer an optional starting
position.
    - REDIM PRESERVE of the outer bound of dynamic and huge arrays only.
    - RND() is a legal substitute for RND.
    - RND(x,y) returns a LONG INTEGER in the range of x -> y.
    - TRIM$() is a combination of LTRIM$() and RTRIM$().
    - Indexed pointers:   @[EMAIL PROTECTED]
    - DIM VIRTUAL x(1000000) arrays in ems memory, may not be dynamic
strings
      nor used as a ByRef parameter.
    - HUGE and VIRTUAL Arrays may use LONG INTEGER indexes.  With this
      expansion, you may see a slight increase in the size of some code
      generation. When a segment is now very close to the 64k limit, it
      may require that $SEGMENT metastatements be moved.
    - ERRCLEAR statement resets the error flag to nul.
    - ERRCLEAR function returns ERR, then resets the error flag to nul.
    - ERRCLEAR is a synonym for the old function Errtest.
    - CVI(x$[,n]), CVL... offer an optional starting position in the
string
          CVL(x$,3) would extract the 3rd through 6th bytes of x$, and
          convert the 4 bytes to the corresponding long integer value.
          In this case, x$ must be at least 6 bytes long.
    - SIZEOF(var) function returns the physical size of a variable,
      particularly useful for determining the maximum length of a fixed-
      length string, ASCIIZ string, or user-defined type. It always
returns
      2 for a dynamic string.
    - STDIN x, y$ reads up to x characters from the standard input device
      (which may be redirected), and assigns them to the string variable
      specified. If less than x characters are ready immediately, then a
      string shorter than x bytes is returned.
    - STDIN LINE, y$ reads one line of text from the standard input device
      (which may be redirected), and assigns them to the string variable
      specified.  When enf-of-file is reached, a one-byte string
consisting
      of a CHR$(26) is returned.
    - STDOUT x$ [;] outputs the string expression x$ to the standard
output
      device (which may be redirected), followed by a cr/lf. If an
optional
      trailing semi-colon is included, then the cr/lf is suppressed.
    - SETEOF #1  statement has been added to truncate an open file to
      its current position.
    - FRE(-11) returns the number of unallocated bytes of EMS memory.


    1.9. PowerBASIC 4.0 - The next Generation / Wishlist
    ----------------------------------------------------
    Such a short time before the release of V3.5 of the Compiler it is
    naturally very, very hard to find Points for improvement, but they do
    exist anyways.

    - XMS Support for VIRTUAL Arrays
    - SORT ARRAY Support fuer VIRTUAL Arrays
    - 32bit Inline-Assembler
    - Syntax Highlighting within the IDE
    - A better IDE


    =================================================================
    2. Errors/Inconsistencies in PowerBASIC Versions 3.0, 3.1 and 3.2
    =================================================================

    Shortindex:
    2.0.  PowerBASIC-Errorlibraries
    2.1.  The NUMERIC/OVERFLOW-Problem in PowerBASIC 3.0
    2.2.  The NUMERIC/OVERFLOW-Problem in PowerBASIC 3.1/3.2
    2.3.  No Overflow-Error with Doublewords
    2.4.  Crash of the PowerBASIC IDE and compiled EXE's while loading
    2.5.  EXEs of different size when compiling with PB/PBC
    2.6.  Different EXE-Files with same Compilation
    2.7.  Problems with the Mouse within the IDE
    2.8.  The Fixup Overflow Syndrome
    2.9.  The story with ASCII-154 after a Remark in the Inline-ASM
    2.10. Error 454: END FUNCTION expected
    2.11. Another REMARK-Problem with $ALIAS
    2.12. The Mistake CDWRD in the german Online-Help
    2.13. The Mistake CVDWRD in the german Online-Help
    2.14. Crash when pressing CTRL-C
    2.15. Error when producing Output with "CONS:" and CTRL-C
    2.16. The Problem with Error 244 in a Stand Alone EXE
    2.17. Problems with linking of multiple Lines of Source
    2.18. Problems with the WATCH-Window and multidimensional Arrays
    2.19. Buggy internal Function/Variable: pbvScrnCols
    2.20. Incorrect internal Function/Variable: pbvHost
    2.21. A little difference in the new Inline-Assembler of V3.1/3.2
    2.22. The dd-Problem in PowerBASIC 3.1/3.2
    2.23. Undocumented internal Variables in PowerBASIC 3.0/3.1/3.2
    2.24. The PRINT-Bug in PowerBASIC 3.2
    2.25. The "File not found"-Error after using NAME
    2.26. Calculationerror when using Constants
    2.27. Wrong "Bit Movement" with ROTATE
    2.28. Overflow when using FOR/NEXT-Loops
    2.29. Overflow when using STEP -1 in FOR/NEXT-Loops
    2.30. The Bug in the VARPTR32 Command
    2.31. The "KEY ON" Bug
    2.32. Crash of the PowerBASIC IDE in the Pick- Menu
    2.33. Crash of the PowerBASIC IDE with faulty Syntax
    2.34. Error when swapping variables using SWAP
    2.35. The Multiplexer Interrupt Error in the REG-Command
    2.36. Contents of a Directory will be deleted with KILL
    2.37. The thing with the "USR" string
    2.38. Runtimeerror in the PowerBASIC Helpcompiler
    2.39. The Bug "Truncatig" in the PowerBASIC Helpcompiler
    2.40. Crash of the PowerBASIC-IDE after calling its own Help


    2.0. PowerBASIC-Errorlibraries
    ------------------------------
    For better Security of your own programs I would recommend that you
    link all Errorlibraries. This is the only way to make sure that
    PowerBASIC shows a correct Error and not an unexplainable Error at:

            SELECT CASE pbvrevision

    You can remove all Errorlibraries in the finished program, because
    they are only needed in development.
    The $ERROR-Libraries can be linked within the IDE or directly in your
    Source. The Settings in the Source are used above the Settings in the
    IDE!

    The $ERROR-Libraries are linked as follows:

            $ERROR NUMERIC ON
            $ERROR OVERFLOW ON
            $ERROR BOUNDS ON
            $ERROR STACK ON

    Note: Some of the Bugs shown here can only be found with these
    Libraries linked!


    2.1. The NUMERIC/OVERFLOW-Problem in PowerBASIC 3.0
    ---------------------------------------------------
    Versions: 3.0
    Known   : partly removed in version 3.10

    The problems shown here only apply to the use of unsigned variables
    and are shown with variables of type WORD:

    Example 1:
            Demo?? = &hA000

    causes an Overflow, because PowerBASIC interprets this as a signed
    variable. This error can be solved by using a real number.
    Similar effects can occur with the $NUMERIC-System when using the
    REG()-Command:

    Example 2:
            Demo?? = REG(1)

    can, under special circumstances, cause an Overflow, too, if the
    passed value would be negative as INTEGER. This error can be solved,
    if only using variables of type INTEGER with REG(), by removing the
    NUMERIC-Library when compiling
    It would be much better though to trash the old BASIC-Crap and do the
    whole thing in InLine-Assembler right away! :-)

    It is also interesting to see the 'floating' of error with deactivated
    $ERROR NUMERIC library. The error occurs some later time in the
    program, strangely at variables of type WORD, too. Even stranger that
    you can at best see this at internal PowerBASIC variables of type
    WORD.

    Another Overflow effect is hidden behind the PowerBASIC-Functions
    STRSEG/STRPTR, VARSEG/VARPTR, CODESEG/CODEPTR. Unlike REG(1) the
    variables MUST be of type WORD, else an Overflow can occur in bigger
    programs.


    2.2. The NUMERIC/OVERFLOW-Problem in PowerBASIC 3.1/3.2
    -------------------------------------------------------
    Versions: 3.1/3.2
    Known   : Correction recommended at PowerBASIC Inc.

    One shouldn't think that a new version lets the old bugs be forgotten
    ;-).

    Example 1:
            Demo?? = &hA000

    can still cause an Overflow. This can't be demonstrated in one line
    anymore, because it sometimes still occurs in very complex programs.
    This still has not changed with version 3.20. Unlike version 3.00 this
    bug can be passed by using definite unsigned variables:

            Demo?? = &h0A000

    Should you be Toolbox-Developer and want to make sure that your
    sources work under PowerBASIC 3.0 then enter the following lines:

            ! mov ax, &hA000
            ! mov Demo??, ax

    Example 2:
            Demo?? = REG(1)

    does not cause an Overflow anymore, as far as I know, but you can't be
    sure about that. But one should still use variables of type INTEGER
    when using REG. Many PowerBASIC-Functions work better now, others
    still cause trouble. this affects some special routines which are only
    set for INTEGER variables, but still work with variables of type WORD.

    The Overflow problem with STRSEG/STRPTR, VARSEG/VAROTR and CODESEG/
    CODEPTR is still existing.


    2.3.  No OVERFLOW-Error with Doublewords
    ----------------------------------------
    Versions: 3.0/3.1/3.2/3.5
    Known   : Yes

    There is no internal Overflow test for Variables of type Doubleword.
    You can test this with a little example.

    Example:
            i??? = -1
            PRINT i???

    The cause for this problem lies within the Intel CPU itsself, because
    there is no Overflow created that the Compiler could test for.


    2.4. Crash of the PowerBASIC IDE and compiled EXE's while loading
    -----------------------------------------------------------------
    Versions: 3.0/3.1 (3.2 not tested)
    Known   : No (partly)

    A Crash of the IDE while loading occurs rather rarely and can usually
    be traced back to one of the following:

        - QEMM Memorymanagementsystem (up to Version 7.03)
        - extremly low ammount of free Low Dos Memory
        - You have tried to load the IDE with the LOADHIGH-Command
        - 4DOS

    In most cases the IDE will return to the Commandline with a graphical
    Error (Cursor within the IDE) while loading.
    Also struck with this effect are all compiled PowerBASIC-EXE Files. If
    you want to get around this effect at any cost, you will have to
    compress the PowerBASIC-EXE with an EXE-Packer like PKLITE.


    2.5. EXEs of different size when compiling with PB/PBC
    ------------------------------------------------------
    This isn't really a Bug, because there is only a small difference in
    the cause of the IDE-Compiler and the Commandlinecompiler, which
    explains the differently sized EXE-Files.
    The IDE always compiles the EXE-File with the Settings in the IDE,
    meaning that if you don't want to compile the VGA-Lib into it, you set
    it in the IDE. The PBC always compiles the VGA-Lib into it, IF you
    haven't declared it differently with a Metastatement.
    The Metastatements are always taken before the IDE-Settings!


    2.6. Different EXE-Files with same Compilation
    ----------------------------------------------
    Versions: 3.0/3.1
    Known   : Seems so

    A nice effect can be reported, when you compile Sources more than
    once and then compare them with a Filecompare-Utility. If your free
    Memory has changed, the created EXE-Files will be different.
    As far as I see it, the two PowerBASIC Compilers save some Information
    about the system they were compiled on, which are of Integer/Word type
    and are at the Offset's &h9C/&hA0. (PB3.1) This effect can be shown as
    well in the PB-IDE as with PBC.

    Some say that PB-EXE-Files which were compiled under a PowerBASIC-
    Shell with PBC seem to crash more often.

    But even since I have been compiling all of my projects like this for
    two years, I can not approve to this effect. Version 3.0 of the
    PowerBASIC-Compiler SHELL seemed to cause other effects with big EXE-
    Files. The problems were solved back then by using an alternativ
    PBSHELL-Command.


    2.7  Problems with the Mouse within the IDE
    -------------------------------------------
    Versions: 3.0
    Known   : Seems corrected in Version 3.1

    Should you work with a Mouse in the IDE, so that you can insert and
    cut Sorucecode easily, this could cause a partial crash when marking
    long texts which go past the right screen border. Furthermore the
    Mouse cursor does not mark the text correctly.
    There also seem to be some problems when using the Mouse in the
    80*43/50 Mode.


    2.8. The Fixup Overflow Syndrome
    --------------------------------
    Versions: 3.0/3.1/3.2
    Known   : Correction demanded at PowerBASIC Inc.

    This is my favorite Bug, since it is actually caused by a real error
    in the programming of a PowerBASIC- User. The description in the
    Manual, as well as in the Online-Help is slightly irritating, but
    principally correct.

    Personally I would decribe the Bug like this:

    < new Bugdescription >
    PowerBASIC could not find the named Jumpaddress. A possible cause for
    this is a SHORT-Jump to a Label not in the valid Area for a SHORT-
    Jump. Please check all Jumpcommands for validity.
    < End >

    There is a small Bug in this Errormessage in both PowerBASIC Versions.
    But since the human mind will not really believe what is written
    there, the Source is compiled again (without change). The IDE crashes
    for doing that immediately.

    I will save myself a closer description of the working of the
    different Assemblercommands, especially the different ways of
    addressing in relation to the CPU. There are many Assemblerbooks out
    there, and they are something really needed for good programming with
    the Inline-Assembler anyways.


    2.9. The story with ASCII-154 after a REMARK in the Inline-Assembler
    --------------------------------------------------------------------
    Versions: 3.0/3.1/3.2
    Known   : Error corrected in Version 3.50

    There is a nice little thing that can drive you crazy when doing good
    commenting in the Inline-Assembler Source. It's the story with the
    ASCII-154 after a REMARK (REM or ; ):

    Example:
            CLS
            PRINT "1"
            ! nop                ; Ue   <- (ASCII-154)
            PRINT "2"

    PowerBASIC will in this case continue to run the program to the line
with
    the ASCII-154 (after the REM) and then stop. The hard guys can
    trace the whole thing with the Debugger. They'll notice that in this
    case PowerBASIC will simply add seven ASCII-Zeros to the Code and then
    stops compiling.


    2.10.  Error 454: END FUNCTION expected
    ---------------------------------------
    Versions: 3.0/3.1/3.2
    Known   : Error corrected in Version 3.50

    This Bug can occur when a comment in an Inline-Assemblerline contains
    the ASCII- 154. Please read the previous paragraph for more
    information.


    2.11. Another REMARK-Problem with $ALIAS
    ----------------------------------------
    Versions: 3.0/3.1/3.2
    Known   : Error corrected in Version 3.50

    This error ist described quite easily. When you are using $ALIAS you
    may not use ':' (ASCII 58) after a REMARK, because PowerBASIC
    interprets this as an Error 462 (Undefined SUB/FUNCTION). This Problem
    only occurs because of downward compatability to GWBASIC!


    Example:
            $ALIAS DATA AS "_DATA"  ': Fit C-Segments to PowerBASIC
                                     ^
                                     causes Error 462


    2.12. The Mistake CDWRD in the german OnLine-Help
    -------------------------------------------------
    Versions: 3.0 (only german Version)

    There is a small typpo in the  in the OnLine-Help. Instead of 'CDWD'
    (the correct Command), 'CDWRD' was written. The syntax is spelled
    correctly in the german manuals.

    Example:
            i??? = 1
            PRINT CDWRD(i???)        : 'wrong  Syntax
            PRINT CDWD(i???)         : 'correct Syntax


    2.13. The Mistake CVDWRD in the german OnLine-Help
    --------------------------------------------------
    Versions: 3.0 (only german Version)

    This time the typpo is 'CVDWRD'. Correct syntax is 'CVDWD'. The syntax
    is correct in the german manuals.


    2.14. Crash when pressing CTRL-C
    --------------------------------
    Versions: 3.0
    Known   : Error corrected in Version 3.10

    This Bug is widely known and only occurs when you set the
    Compileroption $OPTION CNTLBREAK OFF while the BREAK-Flag in DOS is
    set to ON. (Usually it is set to OFF by MS-DOS). When you press CTRL-C
    under these circumstances your finished program will simply crash.
    You can get past this by locking the BREAK-Flag using your own
    PowerBASIC-FUNCTION. You can achieve this using the following
    routines:

            SHARED BreakFlag%
            FUNCTION BreakAus public
                    'Save and deactivate CTRL-BREAK Interrupt
                    ! mov ax, &h3300
                    ! int &h21
                    ! mov BreakFlag%, dx
                    ! mov ax, &h3301
                    ! mov dx, 0
                    ! int &h21
            END FUNCTION

            FUNCTION BreakReset public
                    'Restore Control-Break-Interrupt
                    ! mov ax, &h3301
                    ! mov dx, BreakFlag%
                    ! int &h21
            END FUNCTION

    You can find a file named CNTL.ZIP in some BBS's, it is the official
    BugFix.


    2.15. Error when producing Output with "CONS:" and CTRL-C
    ---------------------------------------------------------
    Versions: 3.0
    Known   : Error corrected in Version 3.10

    This Error is also a cause of the CTRL-C Bug, some side effects can
    occur when producing Output with "CONS:". More detailed Information is
    not known to me personally.


    2.16. The Problem with Error 244 in a Stand Alone EXE
    -----------------------------------------------------
    Versions: 3.0
    Known   : Error corrected in Version 3.10

    Should you use PowerBASIC 3.0 and work with the Inline-Assembler a
    lot, in connection with the two internal PowerBASIC FUNCTIONS

            GetStrLoc
            GetStrAlloc

    the above named Error 244 (Library does not exist) can occur. This
    Error only occurs in a Stand Alone EXE and not within the PowerBASIC-
    IDE. The two internal PowerBASIC FUNCTIONS must be within a PowerBASIC
    Unit. To get aorund this problem use STRSEG/STRPTR, temporary save
    them and then MOV them into the correct Processorregisters.


    2.17. Problems when linking multiple Lines of Source
    ----------------------------------------------------
    Versions: 3.0/3.1
    Known   : Error corrected in Version 3.20

    The PowerBASIC-IDE as well as the Commandlinecompiler have some casual
    problems when you spread Sourcecode over more than one line, when it
    actually has to be in one line.

    Example:
            C$ = CHR$( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)+_
                 CHR$( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)

    Experience shows that in connection with bigger projects the Compiler
    likes the wrong interpreting of the lines. Saying: The programmer will
    get a strange Error somewhere in the Sourcecode. Luckily at the
correct
    position most of the time.


    2.18. Problems with the WATCH-Window and multidimensional Arrays
    ----------------------------------------------------------------
    Versions: 3.0/3.1
    Known   : Error corrected in Version 3.20

    The WATCH-Window can not display multidimensional Arrays correctly.


    2.19. Buggy internal Function/Variable: pbvScrnCols
    ---------------------------------------------------
    Versions: 3.0/3.1/3.2
    Known   : No

    This internal Variable should return the number of currently displayed
    columns on the screen. In connection with all modes that do not use
    the 40 or 80 column mode, an incorrect number will be returned. Such
    modes can be set on every VGA-Card and quite a few Tools (i. e. Disk
    Command Center) even support them!
    This little FUNCTION can solve this problem:

            DIM fixScrnCols AS BYTE
            ! mov  ah, &h0f
            ! int  &h10
            ! mov fixScrnCols, ah


    2.20. Incorrect internal Function/Variable: pbvHost
    ---------------------------------------------------
    Versions: 3.0/3.1/3.2
    Known   : No

    Bit 8 is not set under Microsoft Windows(NT) 3.x


    2.21. A little difference in the new Inline-ASM of V3.1/3.2
    ------------------------------------------------------------
    Versions: 3.1/3.2
    Known   : Correction demanded at PowerBASIC Inc.

    This is explained quickly. While PowerBASIC 3.0 accepts the following
    line of Inline-Assembler code:

            ! mov ax, &h0A000

    PowerBASIC 3.1/3.2 will not work with it, even if this feature is new
    in Version 3.1/3.2.


    2.22. The dd-Problem in PowerBASIC 3.1/3.2
    -------------------------------------------
    Versions: 3.1/3.2
    Known   : Feature removed in Version 3.5

    This feature is explained fast, because the new 32Bit &h...., &o....,
&b
    Statements are taken as common knowledge. PowerBASIC Inc. simply
forgot
    their implementation into the Inline-Assembler!! You don't believe
    me? Then just try the following:

           ! dd &h12345678

    This little problem was explained by PowerBASIC Inc. using the 8Bit
    Inline Assembler, but the Inline-Assembler of Version 3.5 was fixed
    in these ways.


    2.23. Undocumented internal Variables in PowerBASIC 3.0/3.1/3.2
    ---------------------------------------------------------------
    The following internal Variables already exist in PowerBASIC 3.0, but
    are not documented:

    pbvBinBase
    pbvDefSeg
    pbvHost
    pbvScrnBuff
    pbvSwitch
    pbvVTxtX1
    pbvVtxtX2
    pbvVTxtY1
    pbvVtxtY2

    The following internal Variables are not documented from Version 3.1
    on, but still exist:

    pbvRestore

    The position of the Datasegments are identical in PowerBASIC 3.0 and
    PowerBASIC 3.1/3.2.


    2.24. The PRINT-Bug in PowerBASIC 3.2
    -------------------------------------
    Known    : ????

    In Version 3.2 of PowerBASIC Variables of type DWORD are not printed
    correctly with PRINT:

    Example:
            Demo??? = 1234567890
            PRINT Demo???

    causes the following output:

    PowerBASIC 3.0/3.1: 1234567890
    PowerBASIC 3.2    : 1.234568+E

    Using PRINT USING can help here...

    2.25. The "File not found"-Error after using NAME
    -------------------------------------------------
    Versions: 3.0/3.1/3.2
    Known   : Error corrected in Version 3.50

    There is a very strange Error in the internal PowerBASIC filehandle
    management after using the command "NAME".

    Example:
           OPEN "B",1,"DATEI1.TMP"       ' Open first file
           OPEN "B",2,"DATEI2.$$$"       ' Open
           CLOSE 2                       ' ... and close immediately
           OPEN "B",3,"DATEI3.TMP"       ' Open
           CLOSE 3                       ' ... and close immediately
           KILL "DATEI2.$$$"             ' Delete second file
           NAME "DATEI3.TMP" AS "DATEI2.$$$"
                                         ' Rename third file to second
file
           CLOSE 1                       ' ... Close first file
           END


    2.26. Calculationerror when using Constants
    -------------------------------------------
    Versions: 3.0/3.1/3.2
    Known   : No

    Sometimes PowerBASIC does not calculate correctly when using
    constants. Of course there is the question why you don't insert the
    answer right away, because it is just a matter of form.

    Example:
           i% = -20-4   : %k= -20-4
           PRINT i%     , %k


    2.27. Wrong "Bit movement" with ROTATE
    --------------------------------------
    Versions: 3.0/3.1
    Known   : Error corrected in Version 3.20

    The ROTATE-Command in PowerBASIC 3.0/3.1 has a Bug when using QUAD-
    Type Varibles.

    Example:
           i&& = 1
           ROTATE RIGHT i&&, 1
           ROTATE LEFT i&&, 1
           PRINT i&&


    2.28. Overflow when using FOR/NEXT-Schleifen
    --------------------------------------------
    Versions: 3.0/3.1/3.2/3.5
    Known   : Yes

    PowerBASIC does not allow you to use the maximum value of a variable
    in a FOR/NEXT-Loop. The maximum value is used internally by
PowerBASIC,
    because (AFAIK) first increases the variable and then checks it. As
you
    can see it then comes a an overflow, if the maximum value had already
    been reached.

    This bug occurs as far as I know on all variables.

    Example:
           FOR Demo? = 1 TO 255
               PRINT Demo?
           NEXT Demo?

    Should you NOT use "$ERROR NUMERIC", this Loop will turn into an
    endless loop.

    This effect is caused by downward compatability to other BASIC
    Compilers and the internal works of the Intel CPU.


    2.29. Overflow when using STEP -1 in FOR/NEXT-Loops
    ---------------------------------------------------
    Versions: 3.0/3.1/3.2/3.5
    Known   : Yes

    In PowerBASIC all variable must be of the same type (signed/unsigned),
    if they are used in a FOR/NEXT- Loop. For example, the following is
    not valid:

    Example:
           FOR Demo?? = 10 TO 2 STEP -1
           NEXT Demo??

    or:
           FOR Demo??? = 10 TO 2 STEP -1
               PRINT Demo???
           NEXT Demo???

    Should you NOT use "$ERROR NUMERIC", this Loop will turn into an
    endless loop.


    2.30. The Bug in the VARPTR32-Command
    -------------------------------------
    Versions: from 3.2 on
    Known   : Error corrected in Version 3.50

    Against the correct implementation of STRPTR32 and CODEPTR32 there is
    a Bug in the VARPTR32-Command. It is not possible to do a mathematical
    operation at the same time.

    Example:
           DIM Demo AS STRING * 10
           Wert1??? = VARPTR32(Demo) + 1
           Wert2??? = VARPTR32(Demo)
           Wert2??? = Wert2??? + 1
           PRINT  Wert1???, Wert2???


    2.31. The 'KEY ON' Bug
    ----------------------
    Versions: 3.0/3.1/3.2
    Known   : No

    Listening to the PowerBASIC manual and the BASIC specifications of the
    KEY- Command the 'KEY ON'- Command is supposed to show the current
KEY-
    Setup in line 25 similar to 'Norton Commander'. If this is the case
    PowerBASIC is supposed to put out an 'Error 5: Illegal Function' if
    the programmer wants to access line 25 using LOCATE. Line 25 is also
    supposed to be protected from scrolling.
    This is not the case anymore since PowerBASIC V3.x (unlike PowerBASIC
    V2.10) !

    Example:
            KEY OFF
            FOR i% = 1 TO 10
                READ A$
                KEY i%, A$ + CHR$(13)
            NEXT i%
            KEY LIST
            COLOR 3, 0
            KEY ON
            COLOR 7, 0
            LOCATE 25, 1: PRINT " This text should be captured!! ";
            WHILE NOT INSTAT
            WEND
            KEY OFF
            END
            DATA "Help", "Return"', "Edit", "Change", "Report"
            DATA "PRINT", "Setup", "DOS", "Copy", "Quit"

    The question here is wether this is a bug in the PowerBASIC manual or
    in the Compiler. In any case you can fix this using:

            VIEW TEXT (1,1)-(80,24)


    2.32. Crash of the PowerBASIC IDE in the Pick-Menu
    --------------------------------------------------
    Versions: 3.0/3.1/3.2/3.5
    Known   : No

    The PowerBASIC IDE crashes when you press DEL instead of RETURN the
    first time you chose the menu "File\Pick". If you have opened "Pick"
    before with the RETURN- Key in the same session, this error will not
    occur. Personally I think this is a very serious error, because both
    keys are very close on the keyboard.


    2.33. Crash of the PowerBASIC IDE with faulty Syntax
    ----------------------------------------------------
    Versions: 3.0/3.1/3.2
    Known   : Error corrected in Version 3.50

    The PowerBASIC IDE crashes if you try to compile the following line:

            PRINT Test1$ XOR Test2$ XOR Test3$

    I'd rather not discuss the function of this line. <g>


    2.34. Error when swapping variables using SWAP
    ----------------------------------------------
    Versions: 3.0/3.1/3.2/3.5
    Known   : No

    When using the SWAP-Command in connection with TYPE-Structures and
    indexing a fiels using a variable ("a(c%).x" for example) the fields
    will not be swapped correctly. If the field is accessed with a
    constant ("a(1).x" for example) this does not occur.

    Example:
            TYPE SwapTest                 ' Userdefined Datatype
                x AS INTEGER
                y AS INTEGER
            END TYPE

            DIM a(1 TO 2) AS SwapTest     ' Create Array

            c%     = 1
            d%     = 2
            a(1).x = 1                    ' Init Fields
            a(1).y = 2
            a(2).x = 3
            a(2).y = 4
            CLS
            PRINT "before SWAP: "; a(c%).y, a(d%).y
            SWAP                   a(c%).y, a(d%).y
            PRINT "after SWAP: " ; a(c%).y, a(d%).y


    2.35. The Multiplexer Interrupt Error in the REG-Command
    --------------------------------------------------------
    Versions: 2.x/3.0/3.1/3.2
    Known   : Error corrected in Version 3.50

    Astonishingly there are even problems when you call the Multiplexer-
    Interrupt &h2F using the REG-Command. Normally it seems that the call
    was refused by the system. A test using the Inline-Assembler on the
    other hand works fine. This was seen when programming MSCDEX, checking
    for the Windows-Version and using Timeslice-Functions of the
Multiplexer-
    Interrupt.

    The only way around this is to use the Inline-Assembler.

    Example:
            ! mov ax, &h1680
            ! int &h2F
            ! mov Taskfreeing%, ax
            Taskfreeing% = Taskfreeing% AND 255
            SELECT CASE Taskfreeing%
                CASE &h80 : PRINT "Taskfreeing not supported"
                CASE &h0  : PRINT "Taskfreeing supported"
                CASE ELSE : PRINT "Unknown value"
            END SELECT

            REG 1, &h1680
            CALL INTERRUPT &h2F
            Taskfreeing% = REG(1)
            Taskfreeing% = Taskfreeing% AND 255
            SELECT CASE Taskfreeing%
               CASE &h80 : PRINT "Taskfreeing not supported"
               CASE &h0  : PRINT "Taskfreeing supported"
               CASE ELSE : PRINT "Unknown value"
            END SELECT

    The explanation of this lies within the working routines of the REG-
    Command, although QuiBASIC does not have these problems. <g>


    2.36. Contents of a Directory will be deleted with KILL
    -------------------------------------------------------
    Versions: 3.0/3.1/3.2
    Known   : No

    One can find a nice feature behind the KILL-Command of PowerBASIC.
    Should the path end with a Backslash (without other Wildcards or file
    names), the entire directory will be deleted.

    Example:
           KILL "C:\TEMP\"               ' Deletes all files in the TEMP
                                         ' Directory


    2.37. The thing with the "USR" string
    -------------------------------------
    Versions: 3.0/3.1/3.2
    Known   : Error corrected in Version 3.50

    A completely strange behaviour can be noticed in the IDE or the
    Command Line Interpreter if the string "USR" can be found in the
    source code. Because the compiler crashes in the first example, this
    can definetly be considered a Bug.

    Example:
           PRINT USR                     ' PB/PBC crashes
           Test% = USR                   ' Error 477


    2.38. The GOTO DWORD Bug
    ------------------------
    Versions: 3.2
    Known   : Removed in Version 3.50

    PowerBASIC simply forgets the Segment part of the address, that's all.

    Example:
            Demo??? = CODEPTR32(TestLabel)
            GOTO DWORD c???
            $SEGMENT
            TestLabel:
            PRINT "Test"
            END


    2.39. The 'ON LOCAL ERROR' Bug
    ------------------------------
    Versions: 3.0/3.1/3.2
    Known   : Error corrected in Version 3.50

    Using 'ON LOCAL ERROR' in a PBU can cause a crash of the program.

    Example:
            'Main file
            $COMPILE EXE
            $LINK "TEST.PBU"            'or PBL
            FileName$ = "TEST.DOC"
            CALL ResumeDemo(Demo%)
            PRINT "Error", Demo%
            END

            'Unit file
            $COMPILE UNIT
            SUB ResumeDemo (Demo%) PUBLIC
                ON LOCAL ERROR RESUME NEXT
                  ' To test create this File with WinWord and save once.
                OPEN "TEST.DOC" FOR BINARY AS #1
                Demo% = ERRTEST
            END SUB


    2.40. ... and again 'ON LOCAL ERROR'
    ------------------------------------
    Versions: 3.0/3.1/3.2/3.5
    Known   : No

    PowerBASIC crashes when someone uses "ON ERROR" instead of "ON LOCAL
    ERROR" in a SUB/FUNCTION. It can come to STACK or STRING memory
    problems in this case, if the error occurs.
    Of course this is definetly the error of the programmer, but the
    Compiler should recognize this when compiling.


    2.41. Runtimeerror in the PowerBASIC Helpcompiler
    -------------------------------------------------
    Versions: 3.0 (Helpcompiler)
    Known   : No

    The Helpcompiler (Encoder) seems to have quitr a few Bugs. Mostly
    beginners will have some problems with Runtimeerror 9 at address
    10095. This is an internal Bug of the Helpcompile, which is caused by
    the missing of the Command '/LOOKUP'.


    2.42. The Error "Truncating" in the PowerBASIC Helpcompiler
    -----------------------------------------------------------
    Versions: 3.0 (Helpcompiler)

    The Error 'Truncating ... to 76 characters' will be shown sometimes,
    because the commandcharacters will not be taken into concern.


    2.43. Crash of the PowerBASIC-IDE after calling its own Help
    ------------------------------------------------------------
    Versions: 3.0 (Helpcompiler)

    When programming or actually the writting of the Help you will have to
    watch out that the effective length of the shown textline are not
    bigger than the actually existing number of characters available in
    the PowerBASIC-Helpwindow, because the PowerBASIC-IDE will in that
    case crash with a graphical error.
    This Bug will only occur in the developmentphase of a self-written
    Helpfile (*.PBH)!

    =================================
    3. PowerBASIC and the CoProcessor
    =================================

    3.1. Does PowerBASIC support a CoProcessor?
    3.2. Which Floatingpointlibrary is the right one?
    3.3. Does the CoProcessor work with $FLOAT PROCEDURE, too?
    3.4. Which PowerBASIC-Functions are affected?
    3.5. Possible reasons for the CoProcessor-Effect
    3.6. PowerBASIC-Benchmark Source


    3.1. Does PowerBASIC support a CoProcessor?
    -------------------------------------------
    The answer is simply YES. The Compileroptions already have the
    possibility to choose three different Floatingpointlibraries. There
    are some Hooks when working with the CoPorcessor under PowerBASIC,
    which will be shown here so that you can develop faster hopefully only
    cleanly running programs.


    3.2. Which Floatingpointlibrary is the right one?
    -------------------------------------------------
    PowerBASIC has a total of three Floatingpointlibraries:

    a) $FLOAT EMULATE
       This is the DEFAULT-Library an usually uin use 95 % of the time.
       She has the power to automatically support the i87, if such a
       CoProcessor has been found. The huge problem is on the upper hand:
       PowerBASIC has to test for the CoProcessor all of the time and is
       slowed down a lot if NO i87 is installed.

    b) $FLOAT PROCEDURE
       This Library is fastest when no CoProcessor is available.

    c) $FLOAT NPX
       This Library is top when a i87 is available.


    3.3. Does the CoProcessor work with $FLOAT PROCEDURE, too?
    ----------------------------------------------------------
    The answer here is YES, too. Even if PowerBASIC did not implement the
    CoProcessorsupportroutines, the Source below proves that it does. The
    riddles answer lies in the PowerBASIC-Runtime-Library, which supports
    the i87 from beginning on. That is why the speed advantages can't be
    generalized.


    3.4. Which PowerBASIC-Routines are affected?
    --------------------------------------------
    The following internal PowerBASIC-Functions are affected. Measures
    have shown that SELECT CASE needs 5 seconds with the i87. Under the
    same cirumstances (but without i87) SELECT CASE can need 200 seconds
    ($FLOAT EMULATE). The can be an extreme speedup with $FLOAT PROCEDURE
    (only 35 seconds).
    All in one you can say: SELECT CASE should not be used in time
    critical routines!
    Same, even if not as bad, is the PRINT-Output of numerical Values.


    3.5. Possible reasons for the CoProcessor-Effect
    ------------------------------------------------
    As I see it this effect has natural causes, because all effected
    commands have to work with the new 80-Number-System. It seems that the
    programmers of PowerBASIC tried to compensate the additionally needed
    time by using the CoProcessor. And it seems that it worked quite good
    for them when a CoProcessor is available. On the other side there is
    the question why the Compiler doesn't optimize it further when only
    the normal 16/32-Bit numbers are used.


    3.6. PowerBASIC-Benchmark Source
    --------------------------------
    This source shall show you the connection between the previous
    paragraphs. It is best if you just compile it and then try around a
    bit.

    Source:
        REM
*****************************************************************
        REM
        REM   PBBENCH.EXE - Performance-Measuringprogram for PowerBASIC
        REM
        REM   To test the differences in speed of different
        REM   PowerBASIC-Commands in connection with used Floatingpoint-
        REM   libraries when using or not using a CoProcessor
        REM
        REM   Copyright: Thomas Gohel & Andras Hoeffken         Version
2.10
        REM   All rights reserved
        REM
        REM
-----------------------------------------------------------------
        REM
        REM   Important Notice:
        REM   For reliable Maesures the Porcessor must be in REAL-Mode.
        REM   There may not be any TSRs, no KEYB.COM, SMARTDRV.EXE or
        REM   other.
        REM   Important:
        REM   For reliable Measures the program will have to be started
        REM   more than once and an avergae must be built.
        REM
        REM   Users of 486/586 or 286/386 Processors with CoProcessor can
        REM   turn the x87 CoPro off in PowerBASIC with the in this Source
        REM   implemented listing.
        REM
        REM  
***************************************************************
        REM
        $COMPILE EXE "PBBENCH.EXE"
        $CPU 80386
        $LIB ALL OFF
        REM $FLOAT NPX              ' for Computers with CoProzessor
                                    ' (fastest)
        REM $FLOAT PROCEDURE        ' for Computers without CoProzessor
                                    ' (not recommended)
        REM $FLOAT EMULATE          ' Automatic aupport (Extremly slow
                                    ' without CoProcessor)
        REM $DEBUG MAP OFF

        PRINT
        PRINT "Performance-Testprogram for PowerBASIC";:
        PRINT TAB(58); "(c) A.Hoeffken/Th.Gohel";:
        PRINT TAB(68); "Version 2.10";:
        PRINT STRING$(80,"-");
        PRINT
        a% = 1                           ' some Variables
        i% = 1234                        '       -"-
        e& = 12345678                    '       -"-

        REM Zc1! fuer 5000000-Schleifen   ; To take out the time for the
        REM Zc2! fuer 2000000-Schleifen   ; FOR/NEXT-Loops
        REM Zc3! fuer 100000-Schleifen
        REM Zc4! fuer 2000-Schleifen

        IF pbvnpx > 0 THEN
            PRINT "CoProcessor " + CHR$(pbvnpx+48) + "87 found!"
            PRINT
            PRINT "Shoulod the CoProcessor be turned of for next";
            PRINT "measure (Y/N)?"
            BEEP
            A$ = UCASE$(INPUT$(1))
            IF A$ = "Y" THEN CoPro "AUS"
        ELSE
            PRINT "no CoProcessor found!"
            PRINT
            PRINT "Should the CoProcessor be turned on for the next";
            PRINT "measure (Y/N)?"
            PRINT
            PRINT "Note: Turning on a not existing CoProcessor";
            PRINT "will cause a crash!"
            BEEP
            A$ = UCASE$(INPUT$(1))
            IF A$ = "Y" THEN CoPro "EIN"
        END IF

        PRINT
        GOSUB HoleZeitKonstanten
        GOSUB MesseFORNEXT
        GOSUB MesseIFTHEN
        GOSUB MesseSELECTCASE
        GOSUB MesseMATHEMATIK
        GOSUB MesseSTRING
        GOSUB MesseNUMPRINT
        GOSUB MesseSTRPRINT
        PRINT
        END

        '***********************************************
        '  Get the Timeconstants for the different tests
        '***********************************************

        HoleZeitKonstanten:
        PRINT "Messung der Zeitkonstanten ";

        t1! = TIMER
        FOR i& = 1 TO 2000           ' Time for 2000-Loops
        NEXT i&
        t2! = TIMER
        Zc4! = t2! - t1!

        PRINT ".";
        t1! = TIMER
        FOR i& = 1 TO 5000000        ' Time for 5-Mio-Loops
        NEXT i&
        t2! = TIMER
        Zc1! = t2! - t1!

        PRINT ".";
        t1! = TIMER
        FOR i& = 1 TO 100000         ' Time for 100000-Loops
        NEXT i&
        t2! = TIMER
        Zc3! = t2! - t1!

        PRINT "."
        t1! = TIMER
        FOR i& = 1 TO 2000000        ' Time for 2-Mio-Loops
        NEXT i&
        t2! = TIMER
        Zc2! = t2! - t1!
        RETURN

        MesseFORNEXT:
            PRINT "Testing FOR/NEXT   : ";
            t1! = TIMER
            FOR i& = 1 TO 5000000        'Get 5-Millions-Loop
            NEXT i&                      'i = long integer
            t2! = TIMER
            PRINT t2! - t1!; "sec "
            RETURN

        MesseIFTHEN:
            PRINT "Testing IF/THEN    : ";
            t1! = TIMER
            FOR i& = 1 TO 5000000
                IF a% = 0 THEN           'IF THEN Method
                ELSEIF a% = 2 THEN
                ELSE
                END IF
            NEXT i&
            t2! = TIMER
            PRINT t2! - t1! - Zc1!; "sec "
            RETURN

        MesseSELECTCASE:
            PRINT "Testing SELECT CASE: ";
            t1! = TIMER
            FOR i& = 1 TO 2000000
                SELECT CASE A%           'SELECT CASE Method
                    CASE 0
                    CASE 1
                    CASE ELSE
                END SELECT
            NEXT i&
            t2! = TIMER
            PRINT t2! - t1! - Zc2!; "sec "
            RETURN

        MesseMATHEMATIK:
            PRINT "Testing MATHEMATIC : ";
            t1! = TIMER
            FOR i& = 1 TO 2000000
                i% = i% + 100            'extremly simple Calculations
                e& = e& * 2
                e& = e& \ 2
                i% = i% - 100
            NEXT i&
            t2! = TIMER
            PRINT t2! - t1! - Zc2!; "sec "
            RETURN

        MesseSTRING:
            PRINT "Testing STRING's   : ";
            t1! = TIMER
            FOR i& = 1 TO 2000
                A$ = STRING$(20000, 32)
                A$ = RIGHT$(A$, 10000) + "Test"
                e% = INSTR(A$, "Test")
                A$ = ""
            NEXT i&
            t2! = TIMER
            PRINT t2! - t1! - Zc4!; "sec "
            RETURN

        MesseNUMPRINT:
            PRINT "Testing NUM-PRINT's  ";
            t1! = TIMER
            FOR i& = 1 TO 100000
                LOCATE , 1
                PRINT "Testing NUM-PRINT's: "; i&;
            NEXT i&
            t2! = TIMER
            LOCATE , 20
            PRINT t2! - t1! - Zc3!; "sec "
            RETURN

        MesseSTRPRINT:
            PRINT "Testing $$$-PRINT's  ";
            t1! = TIMER
            FOR i& = 1 TO 100000
                LOCATE , 1
                PRINT "Testing $$$-PRINT's: ";
            NEXT i&
            t2! = TIMER
            LOCATE , 20
            PRINT t2! - t1! - Zc3!; "sec "
            RETURN

        '**********************************************
        ' Here is a routine to turn off the CoProcessor
        '**********************************************

        SUB Copro(Switch$)
                SELECT CASE UCASE$(Switch$)
                     CASE "AUS", "OFF", "-"
                         ! mov ax, &h0040
                         ! mov es, ax
                         ! mov ax, word ptr es:[&h10]
                         ! and ax, &b1111111111111101
                         ! mov word ptr es:[&h10], ax
                     CASE "EIN", "ON", "+"
                         ! mov ax, &h0040
                         ! mov es, ax
                         ! mov ax, word ptr es:[&h10]
                         ! or  ax, &b0000000000000010
                         ! mov word ptr es:[&h10], ax
                END SELECT
        END SUB

    ===================
    4. Standardproblems
    ===================

    4.1.  Compatability between the PBUs and LIBs of the 3.x Versions
    4.2.  Not enough memory in the PowerBASIC-IDE
    4.3.  Finding out the filename and path to the filename
    4.4.  No free memory with ENVIRON$
    4.5.  No Returnerrorlevel with SHELL
    4.6.  Cutting files
    4.7.  Error 502/514 when using C-OBJ-Files
    4.8.  Preventing a Warmboot with CTRL-ALT-DEL
    4.9.  Opening more than 15 Files with PowerBASIC and/or DOS
    4.10. HEX$-DWORD Routine for PowerBASIC 3.1/3.2

    <I can't think of any more right now>


    4.1. Compatability between the PBUs and LIBs of the 3.x Versions
    ----------------------------------------------------------------
    Other than the PowerBASIC-Update from V2.10 to 3.00, the PBU/LIBs of
    the 3.x Versions are downwards compatible. That means that you can
    continue to use an under PowerBASIC 3.0 developed PBU/LIB under the
    two higher PowerBASIC Versions. But you can't use a PowerBASIC 3.1
PBU/
    LIB with any of the older Versions. There are probably some
    differences between the Versions 3.0-3,1 because of the new Number-
    System when exchanging sourcecode. In that case please read the
    Chapter 'Errors ...'.


    4.2. Not enough memory in the PowerBASIC-IDE
    --------------------------------------------
    There is a Tool by Bob Zale himself which activates parts of the VGA-
    Graphic-RAM and the parts of the monochrome Herculescard for
    PowerBASIC. The Tool 'PBPLUS96' (96kByte more RAM) was written for
    PowerBASIC Version 2.00, but still works with Version 3.10.


    4.3. Finding out the filename and the path to the filename
    ----------------------------------------------------------
    We often stand in front of the problem that we can start our program
    over a path command, but that it can't find its own data and INI-Files
    anymore after that. The solution is quite simple: DOS saves this
    information in the PSP or in its Environmentblock.

    --- Cut --------------------------------------------------------------
    '*********************************************************************
    '
    '   Finding the path and filename of the current program in
    '   PowerBASIC 3.0/3.2
    '
    '   von Thomas Gohel
    '
    '*********************************************************************

    $COMPILE EXE

        ! mov ax, &h6200
        ! int &h21
        ! mov es, bx
        ! mov ax, word ptr es:[&h2C]
        ! mov pbvDefSeg, ax           ; undocumented in PowerBASIC 3.0
        FOR i% = 0 TO 1024
            IF PEEK$(i%, 4) = CHR$(0,0,1,0) THEN EXIT FOR
        NEXT i%
        WHILE PEEK(i% + 4) <> 0
            Temp$ = Temp$ + CHR$(PEEK(i% + 4))
            i% = i% + 1
        WEND
        DEF SEG
        FOR i%=LEN(Temp$) TO 1 STEP -1
            IF RIGHT$(MID$(Temp$,1,i%),1) = "\" THEN EXIT FOR
        NEXT i%
        ExeDir$ = MID$(Temp$,1,i%)
        ExeName$ = MID$(Temp$,i%+1)
        PRINT ExeDir$; "  "; ExeName$
    --- Cut End ----------------------------------------------------------


    4.4. No free memory with ENVIRON$
    ---------------------------------
    This chapter is partly documented in the manuals, but I want to give
    some advanced tips, because this subject often causes misunderstandig.
    The structure of the environmentblock in connection with the Program
    Segment Prefix (PSP) is not documented further, but it is of enourmous
    meaning gor the better understanding of this error.

    Shortly said, you can only modify the existing environent, and not add
    any new entries!! You can use three ways if you want to add entries
    anyways:

    a) Delete part of the environment and then add the new entry or first
    create a Dummy-Environmententry and the delete or modify it using the
    ENVIRON-Command.

    b) When you want to start a DOS-SHELL with an information:

           OldEnv$ = ENVIRON$("PROMPT")
           SHELL "COMMAND.COM /K SET PROMPT=PowerBASIC " + OldEnv$

    The trick with this is that when you call a SHELL a new PSP will be
    created and the memory will be allocated correctly.

    c) Get the address of the PSP, get the pointer to the current
    Environmentblock and then read the environment into a string, where it
    can be modified. The allocate a DOS-Memoryblock using INT21, save the
    modified environment therem abd the set the pointer to the
    Environmentblock within the PSP to the new one.
    (Also see: Already available PD-Solutions)


    4.5. No Returnerrorlevel with SHELL
    -----------------------------------
    You often need to check the Errorcode of an ended program in a SHELL-
    Command. This is not possible directly under PowerBASIC, because
    PowerBASIC runs a program using COMMAND.COM and because of that the
    Errorcode can't be returned (This is a problem of MS-DOS!!).

    Example:
            SHELL "C:\DOS\COMMAND.COM /C MEINDEMO.EXE"

    To solve this problem there is for instance an alternative SHELL-
    Command in form of a FUNCTION (as Sourcecode):

    --- Cut
---------------------------------------------------------------
   
'**********************************************************************
    '
    '   Errorlevel in PowerBASIC 3.0/3.2
    '
    '   by Thomas Gohel (after a pattern from PDS, by Bernd Hohmann)
    '
   
'***********************************************************************

    $COMPILE EXE
    DECLARE FUNCTION PBShell% (FileName$)

    CLS
    PRINT
    PRINT "Fehlercode ist: "; PBShell%("c:\dos\command.com")
    END

    FUNCTION PBShell% (FileName$)
        LOCAL Dummy%

        Datei$ = FileName$                  ' Copy filename.
        Datei$ = LTRIM$(Datei$)             ' Trim filename.
        i% = INSTR(Datei$, " ")             ' Pass Command ?
        IF i% > 0 THEN                      '
           Cmd$ = MID$(Datei$, i%)          ' Cut Command
           Datei$ = LEFT$(Datei$, i% - 1)   ' Cut filename
        END IF                              '
        Datei$ = UCASE$(Datei$)
        i% = INSTR(Datei$, ".")             ' Is a dot in it ?
        IF i% > 0 THEN                      '
           Ext$ = MID$(Datei$, i%)          ' Get extension
        ELSE                                '
           Ext$ = ""                        ' Extension is empty
        END IF                              '
        SELECT CASE Ext$                    ' Test extension.
            CASE ".BAT"                     ' Batch over COMMAND.COM
                Cmd$ = "/C " + Datei$ + " " + Cmd$
                Datei$ = ENVIRON$("COMSPEC")
            CASE ".COM"                     ' Free
            CASE ".EXE"                     ' Free
            CASE ELSE                       ' No Extension,
                Datei$ = Datei$ + ".EXE"    ' Add .EXE.
        END SELECT                          '

        Datei$ = Datei$ + CHR$(0)           ' Create ASCII-String.
        dNul$ = CHR$(0) + CHR$(0)           ' Doublezero for
Parameterblock

        nul$ = SPACE$(127)                  ' Save 127 bytes for Strings
        MemFree& = SETMEM(0)                ' Get free space
        x& = SETMEM(-MemFree&)              ' Free all memory
                                            '
        nul$ = ""                           ' restore 127 Bytes.
        IF Cmd$ > "" THEN                    ' Commandline ?
            CmdLen$ = CHR$(LEN(Cmd$))        ' Length of Cmd$ as String
            Cmd$ = CmdLen$ + Cmd$ + CHR$(13) ' Length + Cmd$ + '13'
            segm$ = MKI$(STRSEG(Cmd$))       ' Single parts of the
                                             ' Parameter-Block
            Offs$ = MKI$(STRPTR(Cmd$))       ' Add ( MID$(....)
                                             ' = segm$ doesn't work)
            Param$ = dNul$ + Offs$ + segm$   ' Create Parameterblock.
        ELSE                                 '
            Cmd$ = CHR$(13)                  ' Start of Bug-Fixed
            segm$ = MKI$(STRSEG(Cmd$))       ' Segment of Terminator
            Offs$ = MKI$(STRPTR(Cmd$))       ' Offset         -"-
            Param$ = dNul$ + Offs$ + segm$   ' Create Parameterblock.
        END IF                               ' End of Bugfixed
        DateiSeg% = STRSEG(Datei$)           ' Get addresses
        DateiOff% = STRPTR(Datei$)
        ParamSeg% = STRSEG(Param$)
        ParamOff% = STRPTR(Param$)
        ! push ds                            ; Save DS
        ! mov  ax, &h4B00                    ; EXEC-Funktion 4Bh / INT 21h
        ! mov  es, ParamSeg%                 ; Segment of Parameterblock
        ! mov  bx, ParamOff%                 ; Offset of Parameterblock
        ! mov  dx, DateiOff%                 ; Offset of Filename
        ! mov  ds, DateiSeg%                 ; Segment of Filename
        ! int  &h21                          ; Interrupt &h21
        ! pop  ds
        ! jc   ExecError
        ! jmp  ExecOk
        ExecError:
        ! mov Dummy%, ax
        SELECT CASE Dummy%                   ' Evaluate Error.
            CASE 1   : PRINT "illegal Function call!"
            CASE 2,3 : PRINT "File not found: " + FileName$
            CASE 4   : PRINT "to many files opened"
            CASE 5   : PRINT "Access denied " + Filename$
            CASE 8   : PRINT "Not enough free memory for " + FileName$
            CASE 10  : PRINT "wrong Environmentblock"
            CASE 11  : PRINT "wrong Format"
            CASE ELSE: PRINT "Problem while executing " + FileName$
        END SELECT
        ExecOk:

        Mem2& = SETMEM(MemFree&)             ' Completely free memory.
        IF MemFree& <> Mem2& THEN            ' Free memory changed
           PRINT "Warning: possibly a TSR was installed!!"
        END IF

        ! mov  ah, &h4d                      ; Get Exit-Code
        ! int &h21                           ; Interrupt &h21
        ! mov Dummy%, al
        PBShell% = Dummy%

        ! mov  ah, &h03                      ; Pass current cursor
        ! mov  bh, &h00                      ; position
        ! int &h10                           ; Interrupt &h10
        ! inc dh                             ; Recalc to basis of 1
        ! inc dl
        ! mov NewZeile?, dh
        ! mov NewSpalte?, dl
        LOCATE NewZeile?, NewSpalte?         ' Set cursor
    END FUNCTION
    - Cut End
-------------------------------------------------------------

    Further on your can modify the COMSPEC-Variable in your environment
    and directly run your program with COMMAND.COM.
    Example:
            Comspec$ = ENVIRON$("COMSPEC")  'Save COMSPEC
            ENVIRON "COMSPEC=MEINDEMO.EXE"
            SHELL                           'Execution of MEINDEMO.EXE
            ENVIRON "COMSPEC="+Comspec$     'Restore COMSPEC

    Always remember, that the SHELL-Function always transfers the
    Parameter '/C' to the executing program, if you want to transfer
    Commandlineparamters yourself.


    4.6. Cutting files
    ------------------
    You often stand in front of the problem that you have cleaned your
    datafile, but it is still too big. In this case this small but
    effective trick helps:

    Example:
            OPEN "DEMO.DAT" FOR BINARY AS #1
            SEEK #1, 20
            PUT$ #1, ""
            CLOSE #1

    Shortens the file 'DEMO.DAT' to a length of 20 Bytes.


    4.7. Error 502/514 when using C-OBJ-Files
    -----------------------------------------
    When using C-OBJ-Files you should take care that there not multiple
    Statements for the Datasegment in it, because PowerBASIC only supports
    one Datasegment per OBJ-File.
    Since there is no solution known to me and there seems to be none from
    PowerBASIC, it seems that it is your only choice to adapt your C-
    Source.


    4.8. Preventing a Warmboot with CTRL-ALT-DEL
    --------------------------------------------
    The following Source prevents a possible Warmboot:

    Example:
            KEY 15, CHR$(&h0C, &h53, &h73)
            ON KEY(15) GOSUB NoBoot
            KEY(15) ON

            DO
               IF INKEY$ <> "" THEN EXIT LOOP
            LOOP
            PRINT "Done!"
            END

            NoBoot:
            PRINT "Warmboot not wanted!!"
            RETURN


    4.9. Opening more than 15 Files with PowerBASIC and/or DOS
    ----------------------------------------------------------
    You often seem to come to the limits of PowerBASIC when you want to
    open more than 15 Files. But this is not a problem of the Compiler,
    but a genetic birth error of MS-DOS.
    I'll have to bring up some of the dark sides of DOS in order to
    describe this effect, baecause this is where we find the answer. Many
    of you know that when a file is opened, a handle is returned from DOS.
    Now where does DOS save this handle an the information belonging to
    that handle?

    To many of you PSP (Program Segment Prefix) is a well known statement
    (already described shortly in the finding of the filename). If not,
    you shoud better not read the following explanations and just test the
    source.
    This PSP also contains a table, which was declared reserved by
    Microsoft, but its use is widely known. This table is called 'Job File
    Table' (short JFT) and is located at Offset 18Hex from DOS 2.0 on and
    is a 20 fields long BYTE-Array. When you now subtract the used handles
    for: NUL, $CLOCK, CON, AUX and PRN, what is left over are the magic 15
    usable handles.
    But it is only job of the JFT to manage a pointer to the 'System File
    Table', short SFT.
    The SFT on the other hand is a structure similar to a MCB (Memory
    Control Block), which manages important data like Startclusters and
    Sharingattributes. A SFT of this kind can only hold a limited amount
    of handles, to raise this you have to include a higher amount with
    FILES in your CONFIG.SYS. After a restart of the system MS-DOS
    reserves more MCBs marked as SFT. Now you can theoretically open more
    than 20 Files, because the default numbe of FILES is '8'. Unluckily we
    come to another limited number of entries in the JFT within the PSP.
    There is a solution from MS-DOS 3.3 on, because the Interrupt &h21,
    function &h67 enables you to raise the amount of usable handles. But
    how is this done when the space in the PSP is limited??
    Therefore we remember some of the undocumented fields within the PSP.
    Offset &h32 has become interresting, because this holds the new size
    of the JFT in WORD. After that there is the new pointer to the
    Extended JFT. Interrestinf is, that the new array is an array of WORD.
    Theoretically 65535 handles can be managed like that, but that is
    hypothetically, because the SFT can only handle 255 entries.
    Actually there are two important things when creating a new JFT:
        - The new JFT needs memory, that means that you have to decrease
          the size if the current programs Heap!
        - Ab extended JFT will not be passed to a Childprogram with SHELL/
          EXECUTE! The 15 Files Border still exists for the Childprogram.

     Ok, but now here is the Source:

   
'***********************************************************************  
  '
    '  Set the Amount of uasable Handles in PowerBASIC 3.2
    '
    '    developed by Th.Gohel  Fido:      2:2410/301.12
    '                           InterNet:  support@[EMAIL PROTECTED]
    '                           Homepage:  http://www.snafu.de/~pbsound/
    '
   
'***********************************************************************

    MaxFiles% = 30                       ' Same as FILES = 30
    PBFiles MaxFiles%                    ' Set the amount of usable Files

    FOR i% = 1 TO MaxFiles%              ' Test all usable Files
        PRINT "Opening File:  PBFILES." + STR$(i%)
        OPEN "PBFILES." + STR$(i%) FOR BINARY AS i%
        PUT$ i%, "Testfile" + STR$(i%) + " for PBFILES, please delete!"
    NEXT i%
    FOR i% = 1 TO MaxFiles%              ' and close again
        CLOSE i%
    NEXT i%

    SUB PBFiles(BYVAL MoreFiles%)
        x& = SETMEM(-255)                ' Should be enough for all cases
        ! mov ah, &h67                   ; Set amount of usable Handles
        ! mov bx, MoreFiles%             ;
        ! add bx, 6                      ; The Standard-Handles for PB
        ! int &h21
        ! jnc PBFiles_Ok
        PRINT "Error while creating the usable Handles!!"
        PBFiles_Ok:
    END SUB


    4.10. HEX$-DWORD Routine for PowerBASIC 3.1/3.2
    -----------------------------------------------
    The following routine should make HEX$-Support possible for variables
    of type DWORD, which is missing for some reason.

    Example:
            d??? = &h1234ABCD

            PRINT DHex$(d???)

            FUNCTION DHex(HexDWord???) AS STRING
                    DIM Lo AS WORD
                    DIM Hi AS WORD
                    ! les  bx, [bp+6]
                    ! mov  ax, es:[bx+0]
                    ! mov  Lo??, ax
                    ! mov  ax, es:[bx+2]
                    ! mov  Hi??, ax
                    DHex = RIGHT$("000" + HEX$(Hi??), 4) + RIGHT$("000" +
_
                    HEX$(Lo??), 4)
            END FUNCTION

    ================================================
    5. Hints in connection with the Inline-Assembler
    ================================================

    Shortindex:
    5.1.  Principles of the function of the Inline-Assembler
    5.2.  Assembler Syntax Error
    5.3.  Faulty passing of Variables in the Inline-Assembler
    5.4.  Problems with LDS/LES
    5.5.  Crash after calling own INT-Functions
    5.6.  Fixup Overflow
    5.7.  Dividing Variables from WORD to BYTE
    5.8.  Dividing Variables from DWORD to WORD
    5.9.  Access to Arrays / Structures with the Inline-Assembler
    5.10. Parameter return with the Inline-Assembler
    5.11. Parameter return in Interrupt-Procedures
    5.12. Creating 32bit-Pointers
    5.13. Converting from REG to Inline-ASM
    5.14. Converting from A86 to Inline-ASM

    The tips shown here are not a tutorial in Inline-Assembler, but may
    help solve many beginner mistakes. A more detailes description of the
    interactions will not be written here, if it does not belong to the
    problem itself.


    5.1. Principles of the function of the Inline-Assembler
    -------------------------------------------------------
    The PowerBASIC Inline-Assembler contains the functions of the Intel
    8086 CPU. This means that you may have to adapt the Inline-Assembler-
    Code of other High-Language-Compilers or true Assembler-Code to the
    PowerBASIC Inline-Assembler, because they quite often contain 80286
    commands. Usually the following commands have to be converted:
    <Listing>
        Source             - >      PowerBASIC
        shr ax, 2                   ! shr  ax, 1
                                    ! shr  ax, 1
                                    or like this:
        -----------------------------------------------------------
        shl ax, 3                   ! push cx
                                    ! mov  cl, 3
                                    ! shl  ax, cl
                                    ! pop  cx
        -----------------------------------------------------------
        pusha                       ! push ax
                                    ! push bx
                                    and so on until all registers are
                                    saved
        -----------------------------------------------------------
        popa                        analog, only restore registers
    <End>


    5.2. Assembler Syntax Error
    ---------------------------
    When we forget the 'true' Syntax Errors, which usually occurs when you
    are not quite used to Assemblercommands, there still is an 'obvious'
    Syntax Error which can be marked by the Inline-Assembler of
    PowerBASIC. This is the case when the Compiler can't use a Variable in
    the Inline-Assembler because it isn't defined in any way.
    PowerBASIC usually creates used Variables within true BASIC-Source by
    itself and allocates memory for it. You have to do that yourself
    within the Inline-Assembler.
    Example:
            ! mov ax, Demo%
    This causes a Syntax Error because the Compiler can't do anything with
    the Variable 'Demo%'. You should first set the Variable to a value:
            Demo% = 1
            ! mov ax, Demo%
    Now the Compiler accepts the Assemblerline. You don't have to assign a
    value to a Variable every time, a simple DIM or SHARED, PUBLIC, LOCAL
    etc. is enough and initialises 'Demo%'.


    5.3. Faulty passing of Variables in the Inline-Assembler
    --------------------------------------------------------
    You probably often swore around because a working routine with REG(x)
    didn't work crrectly after conversion to the Inline-Assembler or when
    your Testroutine wouldn't do its job in a SUB/FUNCTION.
    The solution is relatively simple: You have to pass the variables to
    the Inline-Assembler BYVAL.
    Example:
            Demo 1
            FUNCTION Demo(BYVAL i%) public
                    ! mov ax, i%
                    ! inc ax
                    ! mov i%, ax
                    PRINT i%
            END FUNCTION
    This little Demo simply adds the value '1' using the Inline-Assembler
    and then prints it on the screen. Simply leave out the BYVAL and then
    test the Demo again!


    5.4. Problems with LDS/LES
    --------------------------
    Compareable to the passing of the parameters is the function of the
    commands LDS/LES. It is also essential whether a variable  is passed
    'BY COPY', 'BY REFERENCE' or 'BY VALUE'. The followingcan be taken as
    rule of thumb:

    BY REFERENCE: - default in the main program
                  - or when a variable is declared SHARED/PUBILC etc.
    BY COPY:      - default in a SUB/FUNCTION, if the variables aren't
                    passed BY VALUE.
    BY VALUE:     - always interpreted by the Inline-Assembler as BY VALUE

    You should only pass variables of type BY COPY to LDS/LES, because
    only then the DS/ES Segmentaddresses will be loaded and the
    Offsetaddresses into the other Registers.
    When passing BY REFERENCE DS/ES will be loaded with the high value
    contents of the variable, if of type Long/DWord, else the DS/ES
    Register will contain an irrelevant value. The other Registers will
    contain the low value of the variable.
    Example:

            SHARED DemoSeg%, DemoOff%

            i& = &h12345678
            Demo1 i&
            Demo2 i&
            Demo3 i&

            FUNCTION Demo1(i&) public
                    PRINT "PB-Adresse   : ";:
                    PRINT HEX$(VARSEG(i&));":"; HEX$(VARPTR(i&))
            END FUNCTION

            FUNCTION Demo2(i&) public
                    ! les bx, i&
                    ! mov DemoSeg%, es
                    ! mov DemoOff%, bx
                    PRINT "LES /BY COPY : ";:
                    PRINT HEX$(DemoSeg%);":"; HEX$(DemoOff%)
            END FUNCTION

            FUNCTION Demo3(BYVAL i&) public
                    ! les bx, i&
                    ! mov DemoSeg%, es
                    ! mov DemoOff%, bx
                    PRINT "LES /BY VALUE: ";:
                    PRINT HEX$(DemoSeg%);":"; HEX$(DemoOff%)
            END FUNCTION


    5.5. Crash after calling own INT-Functions
    ------------------------------------------
    You will ask yourself: Why this section in the FAQ? Does the
    PowerBASIC Inline-Assembler have any Bugs? The answer is definetly:

    NO.

    But many calls using INT-Functions of the BIOS/DOS are connected to
    some trouble, because they change important Segments or specially
    address them. Many buffers that have to be passed to a function look
    for their pointer in the Datasegment-Register (DS). PowerBASIC also
    addresses its variables using DS, so that conflicts are 'programmed'
    here. It should not be like this, for example:

            ! mov ax, &h3D90        ; Function File open
            ! mov ds, FileSeg??     ; Load segment of Filename,
            ! mov dx, FileOff??     ; First error, because FileOff??
                                    ; can't be addressed using DS. DS
                                    ; is already pointing somewhere else.
            ! int &h21              ; INT-Call
            ! mov Handle%, ax       ; Because DS still points to nowhere
                                    ; for PowerBASIC, this is wrong, too,
                                    ; and PowerBASIC will crash sooner or
                                    ; later.

    A clean listing should look like this:

            ! push ds               ; Save DS
            ! mov  ax, &h3D90
            ! mov  dx, FileOff??    ; Load Offset of Filename
            ! mov  ds, fileSeg??    ; Load Segment of Filename, not needed
                                    ; by PowerBASIC anymore
            ! int &h21              ; INT-Call
            ! pop ds                ; Restore PowerBASIC Segment
            ! mov Handle%, ax       ; Save Handle% (Or Errorcode)
            ! jnc ...               ; Check Carry-Flag


    5.6. Fixup Overflow
    -------------------
    The problem is relatively easy and simple: The 8086 CPU only allows
    jumps of type SHORT, meaning that you can only jump to labels within
    -127/+128 OpCodes directly.
    The following example also creates such an error:

            DemoLabel:
            <more than 128 Bytes Opcode>
            ! jc DemoLabel

    To get around this, you'll just have to address the whole thing a
    little different. This is principally no problem once you know it:

            DemoLabel:
            <more than 128 Bytes Opcode>
            ! jnc DemoWeiter
            ! jmp near DemoLabel
            DemoWeiter:

    But this can be found in any good Assembler book...


    5.7. Dividing variables from WORD to BYTE
    -----------------------------------------
    Should you still turn your 16bit variables into its 8bit parts with
    mathematical work, it is time to finally stop it! The CPU can do it by
    itsself:
    Example:

            DIM Demo     AS WORD
            DIM DemoHigh AS BYTE
            DIM DemoLow  AS BYTE

            Demo?? = &H1234

            ! mov  ax, Demo??
            ! mov DemoLow? , al
            ! mov DemoHigh?, ah


    5.8. Dividing variables frob DWORD to WORD
    ------------------------------------------
    More often you have the problem that you have pointers of type DWORD
    in PowerBASIC, but you don't know how to pass them to the Inline-
    Assembler or turn them into WORD. Principally this is quite simple
    (When you know how):
    Example:

            DIM Demo     AS DWORD
            DIM DemoHigh AS WORD
            DIM DemoLow  AS WORD

            Demo??? = &H12345678

            ! mov  ax, Demo???[00]
            ! mov  bx, Demo???[02]
            ! mov DemoLow??,  ax
            ! mov DemoHigh??, bx


    5.9.  Access to Arrays / Structures with the Inline-Assembler
    -------------------------------------------------------------
    Access to static Datastructures is relatively easy with the Inline-
    Assembler if you already know the correct Offsetaddresses.
    PowerBASIC allows the following Syntax:
    Example:

            ! mov ah, byte ptr es:[di][22]

    This copies the value to Offset 22 of the address ES:DI into the AH-
    Register.

    5.10. Parameter return with the Inline-Assembler
    -----------------------------------------------
    In opposite to true Assembler the return of a variable works slightly
    different in the PowerBASIC Inline-Assemble. PowerBASIC 3.0 for
    example does not allow the direct return from the Inline-Assembler to
    the FUNCTION, this is only possible with a little trick.

    Example:
            High% = &h1234
            Low%  = &h4578
            PRINT HEX$(Demo1&(High%, Low%))

            FUNCTION Demo1&(BYVAL High%, BYVAL Low%)
                    LOCAL Dummy&
                    ! mov dx, High%
                    ! mov ax, Low%
                    ! mov Dummy&[02], dx
                    ! mov Dummy&[00], ax
                    Demo1& = Dummy&
            END FUNCTION

    From PowerBASIC 3.1 on you can directly pass the return value to the
    FUNCTION, only with 32bit (and bigger) values have to be passed using
    a little trick:

    Example:
            High% = &h1234
            Low%  = &h4578
            PRINT HEX$(Demo2&(High%, Low%))

            FUNCTION Demo2&(BYVAL High%, BYVAL Low%)
                    ! mov dx, High%
                    ! mov ax, Low%
                    ! mov FUNCTION[02], dx
                    ! mov FUNCTION[00], ax
            END FUNCTION


    5.11. Parameter return in Interrupt-Procedures
    ---------------------------------------------
    Very hard is the passing of variables from within an own
    Interruptroutine, because you can guess that the Datasegment isn't the
    same as the one used by PowerBASIC. But the developers of PowerBASIC
    have left us a big back door here. The addressing using the
    Codesegment, which is usually the same! Yet this trick only works with
    the Inline-Assembler, to pass from/ to true PowerBASIC-Routines you
    will have to recopy this variable.

    Example:
            ! mov ax, &h1234
            ! mov Demo, ax
            ! mov bx, Demo
            ! retn

            Demo:
            ! dw 0

    Should you look at this thing with a Debugger, you will notice that
    PowerBASIC will add the Prefix &h2E (addressing using the Codesegment)
    in front of the access to the variable and the '!dw 0' field will hold
    the value &H1234.


    5.12. Creating 32Bit-Pointers
    -----------------------------
    Often 32Bit Pointers are needed for some Interrupt-Procedures to call
    old Interrupt-Handlers or Devicedrivers like CTVDSK/CT-VOICE and
HIMEM/
    MSCDEX. Because the creation of a 32Bit Pointer was described in a
    previous Chapter, here is the actual Syntax:

    Example:
            ! jmp dword Demo&
            ! jmp dword ptr Demo&
            ! call dword Demo&
            ! call dword ptr Demo&

    The pointers can also be taken from the Codesegment!


    5.13. Converting from REG to Inline-Assembler
    ---------------------------------------------
    The conversion from REG- to Inline-Assemblersources is also relatively
    simple. Instrad of the REG-Command, which buffers the Contents of the
    Processorregisters in an internal REG-Array, an access over the
Inline-
    Assembler causes a direct manipulation of the Processorregister. The
    REG-Command passes the REG-Values when CALL INTERRUPT is executed.
    Please not this difference and you will have not as many problems.
    You can translate all other commands 1:1:

    Example:
            REG 1, &h12345           -> ! mov ax, &h1234
            REG 2, &hFF              -> ! mov bl, &hFF
            REG 3, &h22 * 256        -> ! mov ch, &h22
            REG 4, &hAABB            -> ! mov dh, &hAA
                                        ! mov dl, &hBB
            REG 9, Demo%             -> ! mov es, Demo%
            CALL INTERRUPT &h21      -> ! int &h21
            Low?? = REG(1) AND 255   -> ! mov low??, al
            High?? = REG(1) \ 256    -> ! mov High??, ah


    5.14. Converting from A86 to Inline-Assembler
    ---------------------------------------------
    Usually a translation of A86-Sources can be done without problems.
    Remove the Stackborder and include the Assemblerlines into the Inline-
    Assembler. It will be best ig you create a FUNCTION call that passes
    the variables BYVAL, the rest is done by PowerBASIC.

    =======================================
    6. Hints for Pointers in PowerBASIC 3.2
    =======================================

    Shortindex:
    6.1. Pointers in general
    6.2. What are pointers, and what are they for?
    6.3. PowerBASIC-Pointers and dynamic strings
    6.4. PowerBASIC-Pointers and fixed length strings
    6.5. PowerBASIC-Pointer and FLEX-Strings
    6.6. PowerBASIC-Pointer and TYPE structures
    6.7. A little Demonstration (source)


    6.1. Pointers in general
    ------------------------
    Pointers in BASIC have been the cause for many discussions so far.
    PowerBASICS's Dynamic Memory-Managment has been an argument why
    Pointers in BASIC (if not impossible) don't make any sense. The
    following paragraphs will show that this is wrong. Dynamic Memory-
    Managment (which by the way is a real advantage of this language)
    and pointers are a possible combination.
    For the understanding of the follwing, knowledge of the interna of
    BASIC and DOS helps a lot


    6.2. What are pointers, and what are they for ?
    -----------------------------------------------
    Pointers do what their name says: they point. They allow interpreting
every
    single byte of your computers memory up to 1 Megabyte. All you have to
do
    is to assign any memory adress to the pointer. Pointers are useful to
get
    to areas of the memory that are outside of PowerBASIC's
Dynamic-Memory-
    Managment and they let you directly get hold of the Pointers that are
    given back by some DOS-Functions like:
        - Directory Table Area
        - Drive Parameter Block
        - DOS Info Block
        - PSP
        - Environment Block
        - and and and ...
    With pointers you can forget all those tiresome "old friends" like
    DEF SEG/POKE/PEEK or DEF SEG = PEEKI(...)!


    6.3. PowerBASIC-Pointers and dynamic strings
    --------------------------------------------
    String-Pointers to dynamic strings are defined in PowerBASIC with:

        DIM Pointer AS STRING PTR

     The Pointer is assigned as follows

        Pointer = VARPTR32(Demo1$)

    Example:
           
'***************************************************************
            '
            ' Demosource showing how to handle pointers and dynamic
strings
            '
           
'***************************************************************

            DIM Pointer1 AS STRING PTR   ' defining string pointer for
                                         ' dynamic strings
            Pointer1 = VARPTR32(Demo1$)  ' assign the pointer

            CLS
            PRINT "Adress:      Demo1$:       Pointer1:"

            Demo1$ = "123456"
            PRINT HEX$(VARPTR32(Demo1$)), Demo1$, @[EMAIL PROTECTED]
            Demo1$ = "654321"
            PRINT HEX$(VARPTR32(Demo1$)), Demo1$, @[EMAIL PROTECTED]
            Demo1$ = "!Test!"
            PRINT HEX$(VARPTR32(Demo1$)), Demo1$, @[EMAIL PROTECTED]
    6.4. PowerBASIC-Pointers and fixed length strings
    -------------------------------------------------
    String-Pointers to fixed strings are defined in PowerBASIC with:

        DIM Demo AS STRING * 6
        DIM Pointer AS STRING PTR * 6

    The Pointer is assigned as follows

        Pointer = VARPTR32(Demo$)

    Example:
           
'***************************************************************
            '
            ' Demo showing how to handle pointers and fixed length strings
            '
           
'***************************************************************

            DIM Demo2 AS STRING * 6        ' define string with fixed
length

            DIM Pointer2 AS STRING PTR * 6 ' define Pointer with fixed
length
            Pointer2 = VARPTR32(Demo2$)    ' assign the pointer

            PRINT
            PRINT
            PRINT "Adress:      Demo2$:       Pointer2:"

            Demo2$ = "123456"
            PRINT HEX$(VARPTR32(Demo2$)), Demo2$, @[EMAIL PROTECTED]
            Demo2$ = "654321"
            PRINT HEX$(VARPTR32(Demo2$)), Demo2$, @[EMAIL PROTECTED]
            Demo2$ = "!Test!"
            PRINT HEX$(VARPTR32(Demo2$)), Demo2$, @[EMAIL PROTECTED]
    6.5. PowerBASIC-Pointer and FLEX-Strings
    ----------------------------------------
    String-Pointers to FLEX-Strings are defined in PowerBASIC with:

        DIM Demo AS FLEX
        DIM Pointer AS FLEX PTR

    The Pointer is assigned as follows

        Pointer1 = VARPTR32(Demo1$)

    To use FLEX-Strings you have to use MAP before assigning the Pointer!!

    Example:
           
'***************************************************************
            '
            ' Demosource showing how to handle pointers and FLEX-Strings
            '
           
'***************************************************************

            DIM Demo3 AS FLEX            ' define string as FLEX!
            DIM Pointer AS FLEX PTR      ' define pointer as FLEX PTR!
            MAP Demo3$$ * 10             '
            FLEXCHR$ = "."

            Pointer = VARPTR32(Demo3$$)  ' assign the pointer

            PRINT
            PRINT
            PRINT "Adress:      Demo3$$:      Pointer:"

            Demo3$$ = "123456"
            PRINT HEX$(VARPTR32(Demo3$$)), Demo3$$, @[EMAIL PROTECTED]
            Demo3$$ = "654321"
            PRINT HEX$(VARPTR32(Demo3$$)), Demo3$$, @[EMAIL PROTECTED]
            Demo3$$ = "!Test!"
            PRINT HEX$(VARPTR32(Demo3$$)), Demo3$$, @[EMAIL PROTECTED]
    6.6. PowerBASIC-Pointer and TYPE structures
    -------------------------------------------
    String-Pointers to TYPE structures are defined in PowerBASIC with:

    TYPE Demo4_Struc                          ' define TYPE
            Demo5  AS BYTE
            Demo6 AS BYTE
    END TYPE

    The Pointer is assigned as follows

    DIM TypeDemo AS SHARED Demo4_Struc PTR

    You will find an example of pointers and TYPE structures in the
following
    Source.


    6.7. A little Demonstration (source)
    ------------------------------------
   
'************************************************************************
    '
    ' Handling the Video Ram with pointers in PowerBASIC 3.2
    '
    ' (c) Thomas Gohel
    '
    ' A little demonstration that pointers have really no(!!) problem with
    ' the internal memory-managment. For the successful use of Pointers
you
    ' need very good knowledge of the interna of PowerBASIC.
    '
    ' This demo abuses the video-ram as storage for strings and shows how
    ' PRINT commands modify the contents of the two pointers VIDEORAM and
    ' ZEICHEN.
    '
    ' This routine can be used for fast saving and restoring of the
complete
    ' video-ram:
    '
    '         @[EMAIL PROTECTED]
 = @[EMAIL PROTECTED]
    '
    ' will save the complete content of the first (Video)page to the
second
    ' page for later restauration.
    '
   
'************************************************************************

    TYPE Zeichen_Struc                       ' TYPE of a single sign
            Wert  AS BYTE
            Farbe AS BYTE
    END TYPE

    TYPE Screen_Struc                        ' TYPE for pages of the video
ram
            Page1 AS STRING * 4096           ' page 1
            Page2 AS STRING * 4096           ' page 2
            Page3 AS STRING * 4096           ' page 3
            Page4 AS STRING * 4096           ' page 4
    END TYPE

    DIM Zeichen AS SHARED Zeichen_Struc PTR  ' define the TYPE-structur
    DIM Videoram AS SHARED Screen_Struc PTR  ' as pointers

    Videoram = pbvScrnBuff                   ' Move TYPE-structur to the
Be-
                                             ' ginning of the video ram.
                                             ' PowerBASIC is
using/handling
                                             ' video ram as fixed memory
for
                                             ' strings now!  :-)))
    Zeichen  = pbvScrnBuff                   ' TYPE-Structur is to use the
                                             ' same memory-areas as PRINT
                                             ' and VIDEORAM

    SCREEN 0                                 ' set screen-mode
    CLS                                      ' clear screen

    PRINT "Dies ist ein Test"                ' normal PRINT on the
                                             ' screen
    A$=INPUT$(1)

    PRINT LEFT$(@[EMAIL PROTECTED]
)          ' show that the PRINT-command
                                             ' has filled our structur
                                             ' too !!
    A$=INPUT$(1)

    @[EMAIL PROTECTED]
 = @[EMAIL PROTECTED]
        ' save page1 to page2

    @[EMAIL PROTECTED]
  = 76                      ' now ZEICHEN is filled with
                                             ' a value. At the same time
                                             ' the change ist shown on the
    @[EMAIL PROTECTED]
 = 14                      ' screen and VIDEORAM is
                                             ' modified too !

    PRINT LEFT$(@[EMAIL PROTECTED]
)
    A$=INPUT$(1)

    @[EMAIL PROTECTED]
 = @[EMAIL PROTECTED]
        ' restore page1 frome page2


    Pointer_Speed_Test:

            PRINT STRING$(25*80,178);        ' filling the screen
            LOCATE 1, 14
            COLOR 11, 1
            PRINT "  -= STRING-Manipulation inside the";
            PRINT " Video RAM ! =-  "
            @[EMAIL PROTECTED]
 = @[EMAIL PROTECTED]
            COLOR 14, 1
            LOCATE 8,20: PRINT
"+----------------------------------------+"
            FOR i% = 9 TO 18
                LOCATE i%, 20
                PRINT          "|                                       
|"
            NEXT i%
            LOCATE 10, 22: PRINT "    Video RAM is handled as string"
            LOCATE 11, 22: PRINT "          "
            LOCATE 13, 22: PRINT "  -= Demo for the PowerBASIC-FAQ =- "
            LOCATE 19, 20
            PRINT             
"+----------------------------------------+"

            @[EMAIL PROTECTED]
 = @[EMAIL PROTECTED]
            FOR i% = 1 to 1000
                @[EMAIL PROTECTED]
 = @[EMAIL PROTECTED]
                @[EMAIL PROTECTED]
 = @[EMAIL PROTECTED]
            NEXT i%

            FOR i% = 1 TO 10
                FOR Durchlauf% = 1 TO 256
                    Zeichen = pbvScrnBuff
                    FOR Offset% = 1 TO 2048
                        IF @[EMAIL PROTECTED]
 > 32 THEN
                            DECR @[EMAIL PROTECTED]
                        END IF
                        Zeichen = Zeichen + 2
                    NEXT Offset%
                NEXT Druchlauf%
                @[EMAIL PROTECTED]
 = @[EMAIL PROTECTED]
            NEXT i%
   
'************************************************************************

    ===================================================
    7.  Hints in Connection with Turbo-C or Borland C++
    ===================================================

    Short overview:
    7.1.  The author
    7.2.  Why write/use external routines for PB3 in C
    7.3.  The correct memory model
    7.4.  Limitations by the PowerBASIC 3.x compiler/-linker
    7.5.  Passing Parameters
    7.6.  PowerBasic example
    7.7.  Corresponding C module
    7.8.  The assembler code, corresponding to the C module
    7.9.  Usage of routines from external C libraries
    7.10. Preparations if PB V2.1 is used


    7.1. The author
    ---------------
    The hints for "PowerBASIC in cooperation with C compilers like Turbo-C
or
    Borland C++ have been contributed to This FAQ by:

                Andras Hoeffken <ah@[EMAIL PROTECTED]
>
                Andras Hoeffken <2:2480/13.34 @[EMAIL PROTECTED]
 fidonet>
                Andras Hoeffken <130:1316/103 @[EMAIL PROTECTED]
 basnet-Germany>

    Very useful hints can also be found in the file CTOPB.FAQ contained in
the
    original PB Vs. 3.2 distribution.


    7.2. Why write/use external routines for PB3 in C
    -------------------------------------------------
    - C routines produce fast running code
    - for extremely fast code: first write a C source, then let the C
Compiler
      translate this source to ASM code (is done much faster as if one
would
      write ASM code directly, see example), finally optimize the ASM code
    - Routines from external C libraries can be used with PB


    7.3. The correct memory model
    -----------------------------
    For the generation of *.EXE files (e.g. by MASM or C + LINK) different
    memory models can be selected, e.g. Tiny, Small, Medium, Compact,
    Large, Huge, ...

    For the *.EXE files, generated by PowerBASIC, the following is valid
only:
            PowerBASIC 3.x - memory model = LARGE
            (PB uses 32-bit FAR pointers for both code- and datasegments)

    The Borland C compiler in his menu:
            Options / Compiler / Code Generation / Model
    has therefore to be set to the LARGE model.


    7.4. Limitations by the PowerBASIC 3.x compiler/-linker
    -------------------------------------------------------
    a) The PB3 linker can only link .OBJ modules, which have ONE data
segment,
       with a 2nd data segment or a DGROUP the PB3 linker refuses work and
       produces Errors. - C compilers in their default set-up always use
       several data segment names, which are combined i a DGROUP (this has
       certain advantages). For the cooperation with PB, the IDE of the
       C-Compilers in its menu:
                   Options / Compiler / Names
       must therefore be set up like:

           Code Segment: _TEXT          Bss Segment:      _DATA
           Code Group:                  Bss Group:
           Code Class:   TEXT           Bss Class:        DATA
           Data Segment: _DATA          Far Data Segment:
           Data Group:                  Far Data Group:
           Data Class:   DATA           Far Data Class:
           (the stars, originally present, MUST be erased!)

       Now, the C compiler produces only ONE data segment name and no more
a
           DGROUP !

    b) The PB3 linker (< Vs. 3.2) does not accept an "_" with segment
names
       (standard with C), therefore: use "$ALIAS" in the $LINK line
       (see example)!

    c) The PB3 compiler (< Vs. 3.2) does not accept "_" in names of
FUNCTIONS
       and SUBs (standard with C), therefore: use "$ALIAS" in DECLARE
lines
       (see example)!

    d) The PB3 compiler transfers parameters to functions and subs in the
       order "from right to left" (Pascal convention) and assumes, that
the
       external routine purges the stack before returning to PB. C
compilers
       work in the opposite way. Therefore: use "CDECL" in the DECLARE
lines
       (see example)!


    7.5. Passing Parameters
    -----------------------
    PB3 passes parameters to an external routine by 2 different ways:
        - using 'far pointers' ('by reference' or 'by copy')
        - by putting the values directly on the stack (BYVAL)

    The declarations in the C routines must be selected correspondingly!


    7.6. PowerBasic example
    -----------------------
    In the following .BAS program 2 routines show the mechanisms:
    - A: in the add-function "addab" (integer) "c=a+b" is calculated, then
         "x=c+1" is returned as the result of the function.
    - B: in the string-function "chst" the first character of a string is
         replaced by a "*".

    --- Cut ------------------------------------------------------------
    'PB3_TBC.BAS - linking Turbo C functions into PB3.x

    $ALIAS DATA AS "_DATA"  'assignment of one(!) segment name
    $LINK "pb3_tbc.obj"     'special C set-up without DGROUP!

    DEFINT A-Z
    DECLARE FUNCTION addab CDECL ALIAS "_addab" (a, BYVAL b, c)
    DECLARE SUB chst CDECL ALIAS "_chst" (word, word, integer)

    CLS: a = 7: b = 1: c = 0
    PRINT "c_before                =";c         'c=0
    x = addab (a, b, c)                         'A: c=a+b
    PRINT "c_after = a(7) + b(1)   =";c         'c=8
    PRINT "x = c_after + 1         =";x         'x=9

    a$ = "hallo"
    CALL chst (strseg(a$), strptr(a$), len(a$)) 'B: change string
    PRINT "changed string          = ";a$       'prints "*allo"
    END
    --- Cut End --------------------------------------------------------


    7.7. Corresponding C modul
    --------------------------
    --- Cut ------------------------------------------------------------
    /* Modul PB3_TBC.C  */

    #include <dos.h>          /* C library function (for strings) */
    static int d = 1;         /* d and e are put into the same data
segment */
    static int e;             /* d and e are NO  PB-variables */

    int addab(int far *a, int b, int far *c)
    {
        *c = *a + b;
         e = *c + d;
         return e;
    }

    void chst(unsigned far *stseg, unsigned far *stofs, int far *stlen)
    {
        char far *stdata;      /* pointer to the first string char */

        if (*stlen)            /* if string length > 0 */
        {
        stdata = (char far *) MK_FP(*stseg, *stofs); /* fetch the pointer
*/
        if (stdata)            /* if we have a valid string */
            *stdata = '*';     /* replace first character */
        }                      /* (do NOT overwrite the string length !)
*/
    }
    --- Cut End --------------------------------------------------------


    7.8. The assembler code, corresponding to the C module
    ------------------------------------------------------
    If someone is uncertain about the code, produced by the C compiler:
get
    the corresponding ASM code and look, how compact and fast the C
generated
    code is.

    To get the ASM code, shown below, first the above module PB3_TBC.C was
    compiled to PB3_TBC.OBJ (with the set-up of par. 7.4 !!), then with a
    disassembler for .OBJ-Files (OBJ2ASM.EXE) the following file
PB3_TBC.ASM
    was gained. (You can instead order the IDE of the C compiler to
produce
    equivalent ASM code, too. But with an external .OBJ disassembler, you
are
    quite better sure, what the PB3_TBC.OBJ module really contains)

    --- Cut ------------------------------------------------------------
    ;File PB3_TBC.ASM (disassembled from PB3_TBC.OBJ)

    _TEXT  SEGMENT BYTE PUBLIC 'CODE'
    _TEXT  ENDS

    _DATA  SEGMENT WORD PUBLIC 'DATA'
                                ;attention: no BSS segment, no DGROUP !!
    _DATA  ENDS

    PUBLIC _addab
    PUBLIC _chst

    _TEXT   SEGMENT
    assume cs: _TEXT
    assume ds: _DATA

    _addab:
    push   bp
    mov    bp,sp
    ; c = a + b:
    les    bx,dword ptr [bp+006h] ; a
    mov    ax,es:[bx]
    add    ax,[bp+00Ah]           ;   + b
    les    bx,dword ptr [bp+00Ch]
    mov    es:[bx],ax             ; c
    ;e = c + d:
    mov    ax,es:[bx]             ;c (line can be put out for
optimization)
    add    ax,$S1                 ;   + d
    mov    dx,seg _DATA
    mov    es,dx
    mov    es:$S2,ax              ; e
    ;return e:
    mov    ax,seg _DATA           ; (line can be put out for optimization)
    mov    es,ax                  ; (line can be put out for optimization)
    mov    ax,es:$S2              ; ax = e
    pop    bp
    retf

    _chst:
    push   bp
    mov    bp,sp
    sub    sp,+004h
    les    bx,dword ptr [bp+00Eh] ; len(a$)
    cmp    word ptr es:[bx],+000h ; nul?
    jz     $L3                    ; yes
    les    bx,dword ptr [bp+006h] ; strseg(a$) - segment
    mov    ax,es:[bx]
    les    bx,dword ptr [bp+00Ah] ; strptr(a$) - offset
    mov    dx,es:[bx]
    mov    [bp-002h],ax           ; own pointer
    mov    [bp-004h],dx
    mov    ax,[bp-004h]
    or     ax,[bp-002h]           ; pointer = 0?
    jz     $L3                    ; yes
    les    bx,dword ptr [bp-004h] ; points to first string char
    mov    byte ptr es:[bx],2Ah   ; overwrite char with '*'
    $L3:
    mov    sp,bp
    pop    bp
    retf

    _TEXT        ENDS

    _DATA        SEGMENT
    $S1     dw     00001h  ; initialized data
    $S2     dw     00000h  ; uninitialized data (here NOT in the
                           ; BSS segment!)
   _DATA        ENDS

    END
    --- Cut End --------------------------------------------------------


    7.9. Usage of routines from external C libraries
    ------------------------------------------------
    Although PB v3.x is much better adapted to C conventions than PB v2.1,
    it's mostly still NOT possible to immediately link .OBJ modules,
    corresponding to the normal C standard. Reason: C generates more than
    one data segment together with a DGROUP. To overcome this, one has to
use
    C or ASM source code and to re-compile/re-assemble these sources with
    corresponding to the aspects of par. 7.3 and 7.4a. There are 2
    possibilities:

    - With Borland C++ for the most runtime libraries the complete source
code
      is delivered with the standard distribution including instructions,
how
      to change the sources, and including MAKE files to re-generate own
      versions of the library modules.
    - If for an .OBJ module no source code is available, it's mostly
possible
      with small modules to get the corresponding ASM source code by using
an
      .OBJ-disassembler. Then, after having adapted the definitions of the
      data segments correctly to the PB3 conventions, it can be
re-assembled
      again.


    7.10. Preparations if PB V2.1 is used
    -------------------------------------
    The difference between PB v3.x and PB v2.1 is like follows:
    PB v2.1 does not know a "$ALIAS" instruction. AS PB v2.1 can not work
    with "_" (underscores), in the IDE of the C compiler additional
switches
    have to be changed:
    - with segment names (see par 7.4a) "_" are not allowed
    - in the menu "Options / Compiler / Advanced Code Generation" one has
to
      deactivate the switch "Generate underbars".

    PB v2.1 does not know the CDECL instruction. One therefore has to put
    instructions into the C source code, that the C functions have to be
    compiled corresponding to the PASCAL-conventions (this corresponds to
the
    PB-convention). For this, e.g in the example of par 7.6 and 7.7, the
    following (changed) lines have to be used:

        DECLARE FUNCTION addab (a, BYVAL b, c)
        DECLARE SUB chst (word, word, integer)

        int pascal addab(int far *a, int b, int far *c)
        void pascal chst(unsigned far *stseg, unsigned far *stofs,
                                                       int far *stlen)


    ================================================================
    8.  Hints about conversion of Sources from PDS to PowerBASIC 3.x
    ================================================================
    (from Mark Junker@[EMAIL PROTECTED]
 / mjs@[EMAIL PROTECTED]
)

    Generally you can say that PDS-Sources can be converted into PB3-
    Sources. Exceptions are Sources which access foreign libraries and
    use of dimensioned elements in a TYPE-Structure.


    So, the following does not allow a conversion:
        - Foreign libraries
          (like VESA-LIB and everything else there is out there...)

        - Dimensioned elements in a TYPE-Structure
          Example:
                  TYPE tTest
                          TestElement1         AS LONG
                          TestElement2(2 to 7) AS INTEGER
                          TestElement3         AS LONG
                  END TYPE
        - There may be no COMMON, but all variants of the COMMON SHARED-
          Command are allowed.
          Exception:
                  - When COMMON is used to pass parameters to a file
                    called by CHAIN.
                  - When it is irrelevant that the variables behind the
                    COMMON are available in all procedures.

        - Arrays with more than 8 Dimensions
        - REDIM PRESERVE is not flexible enough yet
        - More than 16 Parameters when calling a procedure

    When all of these things are not implemented, then the following
    things have to be changed while converting:

    Basic PDS:                       |PowerBASIC 3:
   
---------------------------------+---------------------------------------
    SSEG                             |STRSEG
    SADD                             |STRPTR
    SSEGADD                          |STRPTR32
                                     |STRPTR32 is only availble from PB3.2
on
    VARSEG/VARPTR                    |IMPORTANT: PB3 passes UNSIGNED
values,
                                     |PDS passes SIGNED values.
                                     |This can be changed using $OPTION
                                     |SIGNED OFF.
   
---------------------------------+---------------------------------------
    Offset of a file opened with OPEN|PB starts every file, you choose,
    starts with '1'!                 |at Zero (Standard) or at one. This
can
                                     |be changed with the following
command:
                                     |OPTION BINARY BASE 1
                                     |for the start at '1'
   
---------------------------------+---------------------------------------
    DIM SHARED VarName%              |This command can be converted in
                                     |two ways:
                                     |- DIM VarName%
                                     |  SHARED VarName%
                                     |- DIM VarName AS SHARED INTEGER
   
---------------------------------+---------------------------------------
    SHARED VarName() AS STRING*3     |Here we have the problem with
Strings
                                     |of fixed length, when they can't be
                                     |SHARED in the main program.
                                     |You may not make any Type-statements
                                     |('AS xxx') after SHARED.
                                     |   SHARED VarName as string
                                     |   will become: SHARED VarName$
                                     |   or: SHARED VarName :'in SUBs !
                                     |
                                     |You can SHARE
FIXED-LENGTH-STRING-Arrays
                                     |like this:
                                     |DIM VarName(MIN,DimNum) AS STRING*3
                                     |or
                                     |DIM VarName(MAX,DimNum) AS STRING*3
                                     |where 'DimNum' is the number of
                                     |Dimensions of the Array and the
number
                                     |must be entered in the program
directly.
   
---------------------------------+---------------------------------------
    COMMON SHARED /Block/ VarN%      |All three variants of the COMMON-
    COMMON SHARED VarN%