BAPI Copyright 1992 - 2005, Stuart Udall version 16.16: June 19, 2005

 overview

 Note: a new version of this software is available BUT it's a port to PowerBASIC, and is no longer compatible with QBASIC. Does anyone still use QBASIC? Consider migrating if so...

Welcome to BAPI - a library of BASIC subroutines intended to simplify and accelerate the development of QBASIC programs. BAPI can read and write text files of any size, display popup alerts, questions and input forms, search for strings of text in files or other strings, and read and write INI files, among other things.

Inserting this library into any QBASIC program will allow the program to make use of all the functions of the library.

Programs written with the BAPI can run on DOS 5.0 or above, or Windows 3.1, 95, 98, 98SE, ME, NT, 2000, or XP. Minimum hardware requirements: 1Mb RAM, 80386 CPU, any video card. BAPI does not directly support mice, graphics, or sound (however, programs written with the BAPI can use QBASIC's graphics and sound functions no problem, and even work with inline assembler mouse drivers on the net).

background

QBASIC is a BASIC interpreter that came with all versions of DOS 5 and 6, and is usually shipped in the MS-DOS Tools directory on Windows CDs. It is a cut-down QuickBASIC, which in turn was the DOS-based forerunner to VisualBasic. QBASIC is very simple and small, however with some patience many things can be done with it. After several years of rewriting my user input and file management routines each time I made a new program, I standardised on a set of generic routines and variablenames. Over time this has evolved into the library presented. The library is called BAPI, an acronym for BASIC Application Programming Interface.

intended usage

This is not rocket science. Rocket scientists should head toward the booth with the Java signage. The library exists because I don't have time to learn a new programming language, I want to write programs quickly that work and that do what I want. I'm not writing word-processors or flight simulators... but my programs can read and write logfiles, webpages, scripts and sourcecode, for example. And combined with a BASIC compiler such as FirstBASIC, it's possible to create a working 80k EXE in a day, pretty blue windows, INI file and all!

BAPI software development kit

Included with BAPI is BAPISDK.EXE. This utility is designed to making working with BAPI easier. In particular, the SDK can:

• pre/postcompile a BAPI-based program: I use QBASIC to develop and edit my programs, however I use FirstBasic to compile to EXE. The FirstBasic editor is not so good; one limitation is that it can hold a file of 64k maximum. QBASIC files can be larger than that. This means you can write a program you can't compile, which is Bad. To address this, I have created a precompiler, which strips all whitespace, and all comments starting with a ' (which means REMs are not stripped). On average this strips around 20k from the source! The precompiler also adjusts the BAPI to take advantage of the larger memory space afforded by FirstBasic, and generally smoothes over the process of compiling a QBASIC program with FirstBasic. The SDK includes support for an EXE compressor, such as UPX, which automatically compresses the EXE produced by FirstBasic - OK, so there's not a huge point in compressing an 80k EXE, even at 2:1 average compression ratio, but waste not, want not, my Mum always told me - hi Mum!!! :-) Finally, the postcompilation process can publish the compressed EXE to a directory of your choice, in addition to the copy it saves in the current directory. This saves you having to copy the finished program from your development directory to your production directory.

• compare the BAPI from program A with the BAPI from program B

• upgrade the BAPI from program A with the BAPI from program B: You may find you end up with many different programs with many different tweaks in either your code or the BAPI (you can change almost any part of it). To manage this, BAPISDK can separate your code from the BAPI, and write each to separate files; the tool can also read these files and put the program back together again. But in between, you can extract a different BAPI from a different program, and substitute it when you reassemble your original program! In this way you can upgrade the BAPI without lots of copying and pasting.

• separate and amalgamate a program's BAPI and program-specific routines

• summarise a program's BAPI into an HTML report

 important bits

• requires Microsoft QBASIC 1.0 (1.1 reccommended)
• BAPI requires MS-DOS 5.0 or above (earlier versions untested)
• BAPISDK requires MS-Windows 9x, ME, NT, 2000 or XP
• BAPISDK compilation requires third-party compiler such as FirstBASIC
• the minimum hardware requirements for programs compiled with BAPI and FirstBASIC (including BAPISDK) are: 300Kb base memory, 512Kb RAM (XMS), 80386 CPU, any video card - if Windows is running these should be fine. If not, HIMEM.SYS must be loaded.
• BAPISDK EXE compression requires third-party EXE compressor such as UPX

• the following points are this program's terms and conditions of use:
1. This program is hereinafter known as "the Software".
2. The Software comes with no warranty and is used at your own risk.
3. The Software is not (and will never be) complete and as such may behave strangely.
4. The Software is the copyrighted property of the author.
5. The Software may be distributed freely.
6. The Software may NOT be incorporated into a commercial work without prior written permission from the author.
7. The Software is "donateware" - you can choose your amount, and pay with Paypal! Donating will encourage me to create more tools. If you do decide to donate, thankyou in advance; the form is here.

There is a feedback form here.

 installation
1. run the self-extracting archive
That's it. :-)

 configuration and startup

To use the BAPI, load the template included in the BAPI package into QBASIC, and add your code at the end. See this for more information regarding the structure of a BAPI-enabled program.

To use the SDK, simply run BAPISDK.EXE.

There are some default settings inside BAPISDK.INI; if this file doesn't exist, BAPISDK will create it.

 controls and methods

### BAPI function reference

* denotes required field
# denotes function is found in EXTRA.BAS

function
 abort 7 function index
purpose graceful abandoning of ship.
featureswill display errormessage if there is one; wait for keypress
 expects.. to contain.. a.err% error code a.msg$error message returns.. containing.. notes A table of runtime errors is here. ### INI how-to: general INI pointers • the INI file must be a text file (editable with Notepad) • the INI file must have the same filename as your program file (eg. yourprog.ini) • the INI file must have a .INI extension • the INI file must be in the current directory at runtime, unless on startup, p.ourvar$ contains an alternative location, and p.usevardir% is set; ... OR... the INI file can be pointed to by using as the FIRST parameter on the commandline /INI:, like this:
C:\>programname /INI:full_name_and_path\to_ini_file.ext


If the INI file is set via the commandline, the following notes apply:

1. long filenames, or filenames with embedded spaces, may not be used
2. the INI file can have any name and extension, and can be in any directory
3. this parameter is removed from the commandline once it is processed by the boot routine, and is thus invisible to BAPI-based programs. The name of the INI file is returned as the variable inifilename$. • any text after a semicolon (";") is considered a comment and is NOT loaded - except if p.noinistrip$ is set to true
• settings take the general format

setting=value

• don't use = or ; in settingnames
• settingnames are not case-sensitive
• the INI loader strips the variablenames from the left side of the equals sign; an INI entry elementname1=value1 is loaded into the array as simply value1
• the INI file has two parts - a main section and a module section (which can contain up to 100 modules)
• the main section is read automatically each time your program starts; the modules can also, as an option, be loaded automatically at startup
• data from the main section is stored in cfg$(numsettings%) where numsettings% is the number of settings loaded from the main section • modules can be used to contain sets of extra settings • modulenames are delimited by [square brackets] • modules end on the first blank line after the [modulename] • loaded module elements are placed into a two-dimensional array called inimod$() - each column of the array contains the contents of each module loaded
• each module can be referred to by its column number in the array; module 1 is the module contained in the first column. Thus, inimod$(1,3) contains element 3 of module 1; inimod$(3,5) contains element 3 of module 3
• the first row of each column of inimod$() contains the modulename; the second row contains the total number of loaded elements (including both structured and freeform elements). The other rows contain the elements themselves. Eg., [modulename] 6 value1 value2 value3  • to require the INI file, set p.needini%=1 in the program header ### INI how-to: loading modules automatically at startup The simplest way to load data from modules is to have the INI loader load them automatically at startup. If you don't do this, you'll need to load the module manually during execution, which can have advantages - see below. Note: modules loaded at boot are done so AFTER readuserini has executed - don't try and use a module element in readuserini, as it will be empty :) 1. write the INI file 1. choose a modulename, start a new line of INI file, at the first character position, type the modulename enclosed in square backets, eg: [modulename]  2. define elements for the module - these can be either freeformat or structured - a combination is acceptable. Freeformat is simply a list of lines of text. Structured are variables defined as such: elementname1=value1 elementname2=value2  2. add the code to the program 1. set p.loadmod%=1 in the program header - this tells the INI loader to load all modules in the INI file at boot 2. define the modulenames to load in readuserini. set the variable readim.s$ to contain a list of modulenames to load. this is a comma-delimited string, eg.,
[modulename1],[modulename2],[modulename3]


3. define the elementnames in readuserini. set the variable readim.e$to contain a list of elementnames to load. this is also a comma-delimited string, eg., elementname1,elementname2,elementname3  This step is optional. If readim.e$ is left blank, all elements will be loaded. If readim.e$is completed, elements named will be loaded into the array *first*, in the order they are listed in readim.e$. This permits a module of the format

[modulename]
elementname1=value1
elementname2=value2
elementname3=value3
extrasetting=rock
extrasetting=scissors
extrasetting=paper


The module(s) will then be loaded when the program starts up.

Loading modules automatically at startup is simpler, however loading modules manually during execution can conserve memory, and/or boost performance, allow you to repeatedly load different sets of options, and allow you to read settings from another INI file.

1. complete steps 1.1 and 1.2 as above

2. add the code to the program

1. tell the INI loader NOT to load all modules in the INI file at boot - set p.loadmod%=0 in the program header

2. define each modulename you intend to use in readuserini - set the variable readim.s$to contain a list of modulenames to load. this is a comma-delimited string, eg., [modulename1],[modulename2],[modulename3]  3. define the elementnames to load in readuserini. set the variable readim.e$ to contain a list of elementnames to load. this is a comma-delimited string, eg.,
elementname1,elementname2,elementname3


This step is optional. If readim.e$is left blank, all elements will be loaded. If readim.e$ is completed, elements named will be loaded into the array *first*, in the order they are listed in readim.e$. 4. At the appropriate point in your code, call the INI loader. Do this as such: GOSUB getmodele  See getmodele for more information. ### INI how-to: including a modulelist and moduledata in one INI file The modules must be loaded at execution, not at boot. Ensure that p.loadmod%=0. Attempting to load them at boot will not work. This is because the INI loader tries to load the module elements from the line immediately following the modulelist. For example, a modulelist might look as such: modulelist=[lsi],[mirror],[spacenet],[pickle-2],[test]  with each module being defined lower down in the INI file. The INI loader searches for the name of the module, and finds the modulelist line before it finds the module itself. It then attempts to load the module as usual, however because in reality it has only found the list of modules, not the module itself, the module is not loaded. ### INI how-to: processing a list of freeform elements Freeform elements are those found in a module but not defined in readim.e$

Working with these elements is complicated because the first two rows of the module's column in the inimod array are not elements, but the name and number of elements. So, to read any freeform elements from the inimod array, one must remember to allow for these...

• freeform elements start at inielenum% + 3
• freeform elements end at VAL(inimod$(modulenumber%,2)) + 4 ### BAPISDK usage notes • BAPISDK 11 has some speedups to make compilation faster. As well as a slightly reworked interface, there's a new 'quick compile' option which compiles the current target and exits, without prompting for any additional options, and without waiting for confirmation before exit. It will pause on an error, however. There's also a new commandline option, /qq - use this to call quick compile from the commandline. So you don't need to interact with BAPISDK at all! • Once BAPISDK calls Firstbasic or PowerBasic, don't edit the code while you're there, just compile and exit - it is a temporary copy that will be deleted when you exit! • BAPISDK requires that you leave three lines untouched, inside each program you write for use with it. These lines are used to define where the BAPI starts and stops, and where your code starts and stops. If you remove these lines, BAPISDK won't be able to process your program. The lines it requires left intact are: ' *** begin BAPI- ' * end BAPI * ' * begin program-specific subroutines  The above three lines are vital - edit them at your peril! :) • If using PowerBasic to compile, you may as well disable precompilation, since PowerBasic can handle programs larger than those handled by QBASIC. To disable precompilation, simply leave the precompile: option blank (it's on BAPISDK's 'compile program' menu). To enable it, enter yes in this field. Note: this option is only available with BAPISDK 9 or higher. Aside from the commandline used to start PowerBasic (set in BAPISDK's 'compile program' menu under compiler:), and the aforementioned precompilation tweak, no other changes are required to use BAPISDK with PowerBasic. • the SFX generator requires MAKESFX, however MAKESFX is no longer available. Therefore, do not use this function. Instead, use the SFX generator that is now built into WinRAR. ### BAPI 15 and below upgrade notes Note: references to BAPI 16 and BAPISDK 7 apply also to BAPI 16.1 and BAPISDK 8, and above. BAPISDK 7 new features: • will offer to recompile after a successful BAPI upgrade • can publish the compiled program to a production directory • support for EXE compressors such as UPX • the ability to create self-extracting archives • increased sourcecode compression during precompilation BAPISDK 7/BAPI 16 include some fine new features, however they unfortunately require you to make a small change to your sourcecode before BAPISDK will correctly upgrade programs written with BAPI 15 or below (although it will compile them OK). The change is simply moving the line that starts with "' *** begin BAPI" to a line immediately below the lines which define the name and version of the program (the variables p.name$, p.ver$, p.copy$ etc).

These lines should all be at the top of the sourcecode file. However in BAPI 15 and below, the "'*** begin BAPI" line was above the p.name$variables. It simply needs to be moved to below them. This change is to enable BAPISDK to migrate your program name, version, copyright info etc during a BAPI upgrade. BAPISDK 7 replaces everything below the "'*** begin BAPI" line. If you do not make this change prior to upgrading your BAPI with BAPISDK 7, you will lose your program info (eg. p.name$, p.ver$etc) during the upgrade. Here's an example of the required change being made. The first code segment is BEFORE manual editing. Note the begin line comes before all other lines. As of BAPI 16/BAPISDK 7, this is incorrect. ' *** begin BAPI-15 ' * mainline - set program variables, call boot, browse p.name$ = "weblog"
p.ver$= "1.0" p.copy$ = "(c) 1999-2000 Stuart Udall"
p.dev% = 1
p.needini% = 1
GOSUB boot
WHILE p.abort% = f%
...

Here is the same code, manually edited to be BAPISDK 7 readable:
p.name$= "weblog" p.ver$ = "1.0"

### reducing the BAPI memory footprint

QuickBASIC 4.5 and PDS 7.1 don't provide as much memory as FirstBasic does. Consequently, you must reduce the amount of memory BAPI uses if you wish to use it with QuickBASIC or PDS.

BAPI memory allocation is controlled by a small number of internal variables. Although making changes to any of these can reduce memory consumption, the three primary memory-hogs are p.size%, inimodmax%, and inielemax%.

There are two ways to control these variables, both of which are accomplished by editing the boot subroutine near the top of the BAPI. The first is to change the hardcoded numeric assignments made to either variable. For example, change p.size%=2000 to p.size%=1000 or p.size%=1500.

The second way is to change the multipliers used to increase the size of these variables when the BAPI runs in compiled mode. To change the multipliers, find the code in the boot routine that resizes the variables in question:

  p.size% = p.size% * 4: inimodmax% = inimodmax% * 4: inielemax% = inielemax% * 4

...and change one, two, or all three numeric values. The bigger the number, the more memory is used. These values are multiplied with the variables to determine the final size of the arrays the BAPI uses internally in compiled mode. Example change:
  p.size% = p.size% * 2: inimodmax% = inimodmax% * 2: inielemax% = inielemax% * 2


Although p.size% may at first be the obvious target, inimodmax% and inielemax% are actually multiplied together to form a two-dimensional array. If inimodmax% is set to 200 (allowing 200 modules in the INI) and inielemax% is also set to 200 (allowing 200 elements per module), that's 40000 data items allocated! In this case, reducing inimodmax% to 100 would only permit 100 modules in the INI, but would reduce INI memory allocation by half. If your program might only ever have five or ten modules, you can safely reduce this number.

 issues and limitations

• no support for STDIN/STDOUT redirection
• no support for graphics, sound or mice
• limited support for long filenames

 planned improvements

• add cycleoption ("true/false") to getform
• combine dialog and getform into a "common dialog" function