BAPI/CC Copyright 2005 - 2009, Stuart Udall version 1.00: February 6, 2009

 overview next section top of page

Welcome to BAPI/CC - a library of PowerBASIC Console Compiler (PBCC) subroutines intended to simplify and accelerate the development of PBCC programs. BAPI/CC 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, read and write INI files, and connect to SMTP, FTP, HTTP and MySQL servers, among other things.

Including this library into any PBCC program will allow the program to make use of all the functions of the library.

Programs written with BAPI/CC can run on Windows 9x/NT/2000/XP.

BAPI/CC is a port of my BAPI QBASIC library to PBCC. BAPI/CC leverages the Windows-based nature of PBCC and can thus utilise STDIN/STDOUT, long filenames, gigabytes of RAM, etc.

If you're familiar with BAPI, take a look at the changes between BAPI and BAPI/CC. If you're porting BAPI code to BAPI/CC, check out the porting how-to. Also available are general notes on porting QBASIC code to PBCC.

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. It's possible to create a working 200k EXE in a day, pretty blue windows, INI file and all!

Note: BAPI/CC is not at all related to SAP's Business API.

 important bits next section top of page

• requires PowerBASIC Console Compiler 4.0 or higher

• 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 next section top of page
1. run the self-extracting archive
That's it. :-)

 configuration and startup next section top of page

To use BAPI/CC, include it into your program. An example of a minimalist BAPI/CC-enabled program is below.

' * compiler control statements
#Include "\dev\bapicc\bapicc.inc" ' use BAPI/CC

' * begin mainline
Function PBMain () As Long

' initialise program settings
p_name$= "galgen" p_ver$ = "0.11"
p_copy$= "(c) 2002-2009 Stuart Udall" ' pass control to BAPI/CC Call mainline If a_err% > 0 Then Function = a_err% ' return errorlevel End If End Function ' * end mainline ' * begin program-specific subroutines ' * readuserini: get and set any program-specific settings Sub readuserini ' define your variables here End Sub ' * user interface Sub userface ' insert your core loops here End Sub  This code first includes the library, then creates the PBMain() function (required in each PBCC program). It then sets a few BAPI/CC settings and calls mainline, a BAPI/CC subroutine that initialises BAPI/CC. When mainline exits, PBMain() exits also, and the program closes. The two subroutine stubs visible are readuserini and userface. readuserini is used to define variables used by your code, and load INI settings from file. userface is where the bulk of your code goes, this is where you display data onscreen, get user input, read/write files, branch to your own subroutines, etc. As many additional subroutines as required can be added below userface. Note: BAPI/CC initialisation is not complete until AFTER readuserini has exited. This means, for example, it's not possible for readuserini to call dialog (a BAPI/CC messagebox routine) to display errors. To display errors encountered by readuserini, call dialog with code in the userface.  controls and methods next section top of page ### function reference * denotes required field  mainline 16 call boot, browser, restart or exit abort 7 graceful abandoning of ship. addmenu 1 adds menu items to the menu array anykey 3 wait for keypress, return it appendfile 4 append a line to a text file auth 3 gets a password from the user boot 16 pre-define environment, arrays, load DOS vars, INI file changeini 3 changes the value of an INI setting in the INI file copyblock 4 copy a range of lines from one file to another file copymove 3 copy or move a file from one location to another csv2dim 3 parse a comma-separated-string into tmp array deltree 1 silently deletes a directory tree dialog 9 display alert/question dialog box, get keypress/answer; log to file dim2csv 1 parse the tmp array into a CSV-delimited string drawbox 9 draw a box onscreen epochdate 1 converts dates in MM-DD-YYYY format to/from unix epochtime findrule 2 returns rule number, given rule name findsetting 3 returns value of a specified setting in INI file findss 5 find the next or previous occurence of a substring in a string findssarray 3 find the next occurence of a substring in infile array freespace 4 returns volume label, total space and free space on the specified volume getaltkey 2 returns ASCII character from alt-keycode getdate 6 returns epochday, and date in "Month Daynumber, 4DigitYear" format getdaynum 1 returns number of days since year start, or since prespecified date getdosvar 1 returns value of specified DOS environment variable getform 9 get multiple data items from user in dialog box getHTTP 1 download a file with HTTP getmodele 5 retrieve all elements from a module in memory or in INI file getNTLMinfo 1 returns NT Lan Manager configuration getosver 2 returns operating system and version getrand 6 generate a unique 16-digit string and tempfilename getregkey 3 retrieve a registry key from Windows' registry hex2dec 1 converts a hexadecimal number to decimal hostlookup 1 resolve a host either by name or by IP ifexist 8 detect the presence of a file or directory on disk ifinmod 3 find an element in a module in memory nukebox 1 erase current dialog box openforappend 1 opens a file for appending, with full errorhandling printfile 1 print a file on a printer progress 6 display progress indicator, with optional dualbar putFTP 1 upload a file with FTP readdir 16 obtain directory contents from FAT-16, FAT-32, NTFS or UNC volumes readfile 7 read a range of lines from a text file into infile array refresh 1 restores the screen to a virgin state runfromdir 1 run a DOS command from within a specified directory runlongcmd 5 run a DOS commandline up to 255 characters long, returns errorlevels safekill 1 deletes file, with errorhandling scanfile 5 find the next or previous occurence of a string in a text file sendmail 4 send an email with SMTP showline 3 displays a formatted line onscreen showlistbox 1 displays a table of data onscreen, allows selection showmenu 4 display scrollable menu, wait for cursor-based selection, parse user response showmsg 10 display or erase statusbar showtitle 2 display titlebar sift 1 check for char, convert if found split 4 chop a string in two at first, next, previous or last delimiter, or character position SQLinsert 1 add a record into an SQL database SQLdelete 1 remove a record from an SQL database SQLquery 2 query an SQL database SQLupdate 1 change a record in an SQL database strip 2 strip leading/trailing spaces from a string, and any sub-ASCII 32 characters table2csv 1 convert a MySQL table to a CSV file tail 1 returns the last line of a text file template 3 generates a file from a template and a datasource testint 1 tests that a number stored as a string is less than 32767 trunc 1 returns a number with x decimal points unix2dos 2 convert a LF-terminated file to CR/LF URLdecode 1 convert a string from URL-encoded format to ASCII URLencode 1 convert a string to URL-encoded format from ASCII writebuf 4 buffered write to text file writefile 16 write a range of lines to a text file from infile array; can backup and/or append function  mainline 16 function index purpose set program variables, call boot, browser, restart or exit features  expects.. to contain.. p_name$ * name of program p_ver$* program version number p_copy$ copyright information p_abort% 0=continue execution without reinitialisation; 1=end execution, displaying error in a_msg$if it exists p_noini% flag to ignore INI file (1=ignore, 0=don't (default)) p_needini% flag to require INI file (1=require, 0=don't (default)) p_loadmod% flag to load [modules] at boot (1=load, 0=don't (default)) p_ininoclear% flag to retain INI file in memory after boot (1=retain, 0=don't (default)) p_needwin% flag to require execution under Win32 or Win9x (0=don't require Win32 (default); 1=require Win32; 2=require Win9x) p_ourvar$ environment variable to load p_needvar% flag to require environment variable (0=don't require variable (default); 1=require variable) p_usevardir% flag to use the environment variable as a path to the INI file (0=don't (default); 1=use variable as INI directory) p_quiet% flag to suppress signon screen (1=suppress, 0=don't (default)) p_debug% flag to enable debug mode (1=debug, 0=normal (default)) p_debugstep% flag to 1=enable step-by-step debug mode (1=step-by-step, 0=don't (default)) returns.. containing.. DOS errorlevel a number designating a runtime error (0=no error)
notes
• to return an errorlevel to a script, allow the mainline routine to exit with a_err% set to the errorlevel to return
• setting p_debugstep%=1 without also setting p_debug%=1 will have no effect
• p_abort% is set true by the boot routine if an error occurs, and would not normally be used outside this context

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. function  addmenu 1 function index purpose adds menu items to the menu array features  expects.. to contain.. addm_p$ the item text (the text that is displayed in the menu itself) addm_m$the item description (the text that is displayed on the statusbar when the cursor is on the menu item) addm_d$ the item key (the value that is returned if this item is selected) addm_refresh% if set, sets the m_items% to 0 (this has the effect of deleting the old menu, however, the old menu items are not actually erased, they are still in the array) returns.. containing.. m_items% incremented m_p$() populated m_m$() populated m_d$() populated notes • this routine is for use with showmenu, and simplifies adding/removing items to/from a large menu, in that the programmer does not have to increment m_items% manually function  anykey 3 function index purpose wait for user keypress, return keypress and keycode features  expects.. to contain.. s_msg$ string to display in status bar returns.. containing.. keyb$key pressed by user kb_code% keycode of key pressed by user notes • if the user presses an extended key (eg. Alt-B), the keycode returned will have 500 added to it function  appendfile 4 function index purpose append a line to a text file featuresif the file does not exist, it will be created  expects.. to contain.. appef_name$ * name of file to append to appef_s$string to append returns.. containing.. appef_err$ error message (if appropriate)
notes

function
 auth 3 function index
purpose gets a password from the user
featurescan ask for re-entry to confirm
 expects.. to contain.. auth_verify% if set to 1, the messagebox presented will say "verification" instead. However no verification is performed. It is up to the calling application to call auth twice, the second time with auth_verify set, and compare the passwords itself. returns.. containing.. auth_pw$the password entered notes • All text entered in the auth field is starred out. function  boot 16 function index purpose pre-define environment, arrays, load DOS vars, INI file featuressets up screen, tests critical variables, detects operating system, recovers DOS environment variables, sets TEMP directory, reads INI file  expects.. to contain.. readim_s$ a comma-separated list of modules to load from the INI file readim_e$a comma-separated list of elements to load from each module returns.. containing.. p_bapi$ BAPI/CC's internal revision level p_abort% 1=error during boot; 0=no error a_msg$error message (empty if none) p_temp$ name of temporary directory for use by this program p_os% operating system the program is executing under: 0=unknown; 1=DOS; 2=Win9x; 3=WinNT4; 4=Win2000; 5=WinME; 6=WinXP getos_ver$operating system the program is executing under (descriptive string) p_ourvarval$ value of environment variable set by p_ourvar$p_ourdir$ directory set by p_ourvar$(if p_usevardir% is true) p_cmd$ commandline used to call the program (if available) inifilename$full name and path of INI file (if available) numsettings% number of settings read from main section of INI file (if available) cfg$(x,numsettings%) two-dimensional array containing settings from main section of INI file (if available)
notes
• boot also sets a number of internal variables, and allocates memory to the various arrays (such as infile, lst, tmp, etc)
• boot also runs the readuserini subroutine, and loads the INI file (in that order)
• the values returned by the INI loader are the same to those output by getmodele
• click here for more infomation about readim_s$, readim_e$, numsettings% and INI files
• the internal revision level is useful for determining the BAPI revision used to compile a particular EXE: view the EXE and search on "revision" or simply "rev" - the first match should be the BAPI/CC revision number

function
 changeini 3 function index
purpose changes the value of an INI setting in the INI file
featureswill create an INI file if it does not exist; will add the setting if it does not exist**
 expects.. to contain.. ini_target$* name of setting to change ini_module$ name of module containing this setting (blank to disable module support) ini_change$* value of new setting returns.. containing.. cini_err$ error message (blank if none)
notes
• preserves comments no the INI line, if there are any
• ** auto-creation of settings is not supported if the setting is in a module. You must create a blank setting= line.
• the name of the INI file is determined by BAPI/CC.

function
 copyblock 4 function index
purpose copy a range of lines from one file to another file
features
 expects.. to contain.. copyb_source$* file to copy from copyb_target$ * file to copy to copyb_start% row upon which to start copying (0 for start of file) copyb_stop% row upon which to stop copying (0 for 'until end') copyb_noflush% 0=flush enabled; 1=don't flush when end-of-block or end-of-file is reached lst$() array containing strings to insert as a header into target header_length% * number of rows of strings to export from list array as header (0 to disable) writf_append% 1=append to target file; 0=overwrite (default) writf_backup% 1=create .BAKfile before write; 0=don't (default) returns.. containing.. copyb_bytes! number of bytes copied copyb_err$ error message (blank if none)
notes
• this routine will overwrite the contents of the infile array
• if the target does not exist, it will be created
• if the target already exists, it will be overwritten, unless writf_append% is true

function
 copymove 3 function index
purpose copy or move a file from one location to another
featurescan copy or move across UNC paths, drives and directories
 expects.. to contain.. mf_from$name of file to move mf_to$ name of file to move to mf_movefile% 0=copy file (default); 1=move file mf_checkfirst% 0=overwrite if target exists; 1=make backup, prompt to overwrite or abort if target exists mf_cycle% 1=silently affirm .BAKfile overwrite prompt; 0=prompt before overwriting .BAKfile (default) returns.. containing.. movef_err$error message (blank if none) notes function  csv2dim 3 function index purpose converts a comma-separated-string to an array features  expects.. to contain.. c2d_s$ * string to convert c2d_d$delimiter string - if not set, defaults to , (a comma) c2d_undelimit% if set to 1, will strip the first and last character from each data item (useful for stripping 'quotes' around dataitems) c2d_quoted% if set to 1, enables "string quoted" dataitems (embedded commas permitted) c2d_quotemark$ quote delimiting character - if not set, defaults to " (a double-quote, ASCII 34) returns.. containing.. c2d_found% number of detected items tmp$() array containing each detected item as a separate row notes • as the delimiting character can be set, this routine is not confined to processing CSV data. The routine could be used to break a sentence into an array, by changing the delimiting character to a space (ASCII 32). function  deltree 1 function index purpose silently deletes a directory tree features  expects.. to contain.. delt_name$ the name of the directory to delete returns.. containing.. delt_err$result string (blank if none) notes • supports W9X and W2K and above function  dialog 9 function index purpose show alert/question, get keypress/answer; log to file featurescan also display buttons; can log messages to file; updates statusbar; returns action  expects.. to contain.. d_title$ the title of the dialog box d_msg$the string to display in the dialog box q_msgs% number of lines of multiline prompt to display q_msg$() array containing multiline prompt lines d_type% 0=message box (OK only); 1=question (Yes/No); 2=message but don't wait for keypress; 3=log only, no screen output; 4=screen only, no log output d_buttons% number of buttons to display (0=no buttons) d_b_l$() array containing button labels d_b_h%() array containing character position of label to highlight and capitalise d_b_c$() array containing character to return if user presses this button p_logging% 0=don't log messages; 1=log messages to errorlog p_errlog$name of logfile - by default, this is p_name$ plus ".log" p_auto% automatic mode; 0=display messages; 1=don't display, only log to file d_flag$this string is inserted at the beginning of the logfile entry. If empty, it is set to ! (exclamation mark) returns.. containing.. d_b_pressed$ character value of pressed button (empty if not pressed) action% 0=NO; 1=YES (if dialog was a question)
notes
• if d_title$is empty, a default is supplied • if d_type%=4 (screen only) but p_auto%=1 (automode enabled) then automode will take precedence • if q_msgs% contains a value, d_msg$ is discarded, and the contents of q_msg$() are displayed instead • the contents of q_msg$() are not logged to disk, even if logging is enabled.

function
 dim2csv 1 function index
purpose parse the tmp array into a CSV-delimited string
features
 expects.. to contain.. tmp$() array containing each item as a separate row d2c_num% number of items to convert d2c_d$ delimiter string - if not set, defaults to , (a comma) returns.. containing.. c2d_s$converted string notes • as the delimiting character can be set, this routine is not confined to processing CSV data. The routine could be used to break an array into a sentence, by changing the delimiting character to a space (ASCII 32). function  drawbox 9 function index purpose draw a box onscreen, with optional title, note, status, content, buttons, getconfirmation, anykey and vanish features  expects.. to contain.. b_strings% number of lines of text to display b_str$() array containing lines of text to display b_title$title of box b_note$ subtitle of box s_msg$text to display in statusbar b_h% height of box (in characters) b_len% length of box (in characters) b_xpos% x-position of upper-left-hand corner of box b_ypos% y-position of upper-left-hand corner of box b_text_for_col% the foreground colour of the text in the box d_buttons% number of buttons to display (0=no buttons) d_b_l$() array containing button labels d_b_h%() array containing character position of label to highlight and capitalise d_b_c$() array containing character to return if user presses this button b_wait% wait for keypress (0=don't wait (default), 1=wait) b_confirm% get confirmation (0=don't (default), 1=wait for Y or N) returns.. containing.. d_b_pressed$ character value of pressed button (empty if not pressed) action% 0=NO; 1=YES (if dialog was a question)
notes

function
 epochdate 1 function index
purpose converts dates in MM-DD-YYYY format to/from unix epochtime
features autodetects whether a date or an epochtime is to be converted, and returns the opposite of what was supplied
 expects.. to contain.. ed_source$the date (in MM-DD-YYYY format) or epochtime to convert returns.. containing.. ed_converted$ converted date (either an epochtime, or in MM-DD-YYYY format)
notes
• Currently requires EPOCHDAY.EXE

function
 findrule 2 function index
purpose returns rule number, given rule name
features
 expects.. to contain.. findr_name$name of module to find returns.. containing.. findr_num% number of found of module notes • do not supply [square brackets] around the modulename function  findsetting 3 function index purpose returns value of a specified setting in INI file features  expects.. to contain.. lookin$ * name of setting to query returns.. containing.. cfgval$value of setting (blank if not found) notes • this routine is usually used in readuserINI; it's not used anywhere else by BAPI/CC function  findss 5 function index purpose find the next or previous occurence of a substring in a string features  expects.. to contain.. lookin$ * string to search lookfor$* string to search for foundat% * starting position (0 for beginning or end) f_last% 0 = search from beginning of string; 1 = search from end of string returns.. containing.. foundat% starting character position of found substring in string (0 if not found) notes function  findssarray 3 function index purpose find the next occurence of a substring in infile array features  expects.. to contain.. infile$() * array of strings infilelines% * length of array of strings lookfor$* string to search for findsa_y% * row in array to start searching on (0 for start) returns.. containing.. findsa_y% row in array containing string (0 if not found) findsa_x% starting character position of string in row containg string (0 if not found) notes • ensure that infilelines% does not become corrupted between when the file is loaded, and when findssarray is called • improve: search backwards? function  freespace 4 function index purpose returns volume label, total space and free space on the specified volume features compatible with Windows 9x/ME/2K/XP/2K3 and mapped network volumes (NT4 not supported)  expects.. to contain.. frees_driveletter$ the letter of the drive to work with frees_sizeinmegs% return size in megabytes (Mb) (0=no (default); 1=yes) returns.. containing.. frees_vol$the volume label frees_total&& total space on the volume, in megabytes frees_size&& free space on the volume, in megabytes frees_err$ result string (blank if none)
notes

function
 getaltkey 2 function index
purpose returns ASCII character from alt-keycode
features
 expects.. to contain.. alt_code% * raw extended keycode returns.. containing.. alt_key$letter of keypress notes function  getdate 6 function index purpose returns date in "Month Daynumber, 4DigitYear" format features also returns the number of days since January 1, 1900  expects.. to contain.. getdate_this$ date to process (in mm-dd-yyyy format) returns.. containing.. epochday! number of days since January 1, 1900 ourdate$date in "Month Daynumber, 4DigitYear" format, eg., September 21, 2000 notes • Leave getdate_this$ blank to process the current date
• Y2K compliant
• epochday does not return correct values for dates prior to 1582 AD

function
 getdaynum 1 function index
purpose returns the number of days since year start, or since a pre-specified date
features
 expects.. to contain.. getday_date$date to process (in mm-dd-yyyy format) returns.. containing.. getday_num% number of days since the date specified notes • Leave getday_date$ blank to return the number of days since the beginning of the current year
• Y2K compliant
• does not return correct values for dates prior to 1582 AD

function
 getdosvar 1 function index
purpose returns value of specified DOS environment variable
features
 expects.. to contain.. getvar_name$* name of variable to query returns.. containing.. getvar_val$ value of variable (blank if not found)
notes

function
 getform 9 function index
purpose get multiple data items from user in dialog box
featurescursor key-based editing; insert/overtype; scrolling if input overlength; simulated cursor; titlebar; footerbar; blank field if first key is backspace; filters non-displayable characters; auto-positioning and sizing dialog box; displays buttons with hi-lit alt-keys
 expects.. to contain.. g_title$contents of title g_note$ contents of note g_items% number of input items on form g_focus% default selected item g_automin% minimum size for any input field * g_p$(n) prompt for item n g_m$(n) status line for item n g_d$(n) default setting for item n g_c%(n) default cursor position for item n g_l%(n) length of on-screen input field g_lmax%(n) maximum length of input g_hide%(n) enable/disable output masking (1=ON, 0=OFF) g_buttons% number of buttons on form g_b_l$(n) label for button n g_b_c$(n) character returned by button n g_b_h%(n) character position in label to highlight returns.. containing.. g_abort% 1 = user aborted; 0 = did not abort g_i$(n) response from user for item n g_b_pressed$character of pressed button (empty if none pressed) g_c_y% form item selected when form exited notes • set g_c%(n) to -1 to have the cursor default to the end of the input field • set g_lmax%(n) to -1 to use max input size for field (250 characters) • set g_l%(n) to -1 to autosize the length of the input field • to set the above three automatically, plus the hide setting to OFF, for each menu item, place a value in g_automin%. * If g_automin% contains a value, the settings in g_c%(n), g_l%(n), g_lmax%(n) and g_hide%(n) will be ignored • hiding is not possible when autosizing • cursor position 0 is the first character of the input field • improve: true/false fieldtype • uses: getaltkey (and others..) function  getHTTP 1 function index purpose download a file with HTTP features  expects.. to contain.. gh_url$ the URL of the file to download gh_destfile$the name of the file to save the downloaded file as gh_quiet% suppress CURL output (1=suppress, 0=don't (default)) returns.. containing.. gh_error% result status (1=error; 0=no error) gh_result$ result string (returned on success as well as failure)
notes
• Currently requires CURL.EXE

function
 getmodele 5 function index
purpose retrieve all elements from a module in memory or in INI file
features
 expects.. to contain.. getmod_file$* the name of the file containing the module to load getmod_name$ * the name of the module to load - this will be one of the modules listed in readim_s$getmod_num% * the column number of the module array to fill with module data p_noinistrip% default is 0 (false/off); if set to 1 (true/on), the INI loader will not strip comments or whitespace from the elements as they are loaded returns.. containing.. inimod$() two-dimensional array containing loaded values inimodnum% number of modules loaded inielenum% number of structured elements loaded orphanele% number of orphaned elements loaded inioverflow% set TRUE if number of loaded elements exceeded available module memory space (in this case, the as many elements as possible are loaded). getmod_err$error message if unable to open INI file notes • the INI loader will overwrite any existing data in the column with new data from the module being loaded • for more information on inimod$(), modules and INI files, see general INI pointers
• the side-effect of using p_noinistrip% is that any comments in the INI file will be interpreted. For this reason, avoid using comments in INI files used by programs with p_noinistrip% enabled. The only exception is at the end of [modulenames], where ; comments are still permitted (and ignored) if p_noinistrip% is enabled.

function
 getNTLMinfo 1 function index
purpose returns NT Lan Manager configuration
features
 expects.. to contain.. returns.. containing.. net_cname$the name of this computer net_uname$ the name of the currently logged-in user net_wgroup$the name of the workgroup this computer is a member of net_domain$ the name of the domain this computer is a member of
notes
• these settings are used for Windows-based networking, such as file-and-print sharing

function
 getosver 2 function index
purpose returns operating system and version
features
 expects.. to contain.. returns.. containing.. p_os% OS detected: 0=unknown; 1=DOS; 2=Win9x; 3=WinNT; 4=Win2000; 5=WinME; 6=WinXP getos_ver$version string returned by operating system notes function  getrand 6 function index purpose generate a unique 16-digit string and filename featurescan return string as a tempfilename; can prepend a prespecified string to the generated string  expects.. to contain.. gr_prefix$ if provided, getrand will prepend this string to the beginning of the generated string it returns. gr_seq% if set to 1, getrand will allocate filenames in a sequential, rather than pseudo-random manner. gr_forceshort% if set to 1, getrand will return an 8-character string, instead of 16 characters. returns.. containing.. uniquename$string of 16 random numbers uniquetemp$ fully qualified drive:\path\filename.tmp (uses p_temp$variable allocated by boot) notes • The use of gr_prefix$ is recommended, as it reduces the chances of a tempfile collision.
• Use gr_seq% if there's a chance more than one unique string will be generated per second. The pseudo-random algorithm (which is based on the time of day) is in fact designed for this, but prolonged testing on fast computers has revealed it's simply not random enough. gr_seq% answers this problem by forcing the unique strings to increment in sequence. It is thus suitable for generating a large number of unique strings very quickly.

function
 getregkey 3 function index
purpose returns the contents of a specified Windows registry key
features
 expects.. to contain.. getrk_key$* name of registry key to query getrk_decode% flag to decode directory key (0=no (default), 1=yes) getrk_read% flag to read key (0=no (default), 1=yes) returns.. containing.. getrk_file$ name of file containing key (blank if decoding is enabled) getrk_val$data associated with value within key (blank if key not found, or if reading or decoding are disabled) getrk_err$ error message (blank if no error)
notes
• If getrk_decode% is specified, the directoryname is decoded and the keyfile deleted.
• If getrk_read% is specified, the key is read and the keyfile deleted.
• getrk_decode% and getrk_read% cannot be used together. getrk_decode% will execute if both settings are enabled.
• If neither getrk_decode% or getrk_read% are specified, the key is not analysed, the keyfile is not deleted by getregkey, and the name of the keyfile is returned in getrk_file$. This file must be deleted later by your program - it is not deleted automatically, and will cause a "tempfiles left in tempdir" error on exit if not deleted. function  hex2dec 1 function index purpose converts a hexadecimal number to decimal features  expects.. to contain.. h2d_in$ * string containing number to convert returns.. containing.. h2d_out! the input number, expressed in decimal
notes

function
 hostlookup 1 function index
purpose resolve a host either by name or by IP
features autodetects whether a name or an IP address is to be resolved, and returns the opposite of what was supplied
 expects.. to contain.. hostl_address$the hostname or IP address to resolve returns.. containing.. hostl_resolved$ the resolved hostname or IP address
notes
• supports IPv4 only

function
 ifexist 8 function index
purpose detect the presence of a file or directory on disk
featureswill use default drive and/or directory if not supplied
 expects.. to contain.. ifexist_name$* filename to test for returns.. containing.. ifexist_found% 1=file exists; 0 if not exists ifexist_name$ fully-qualified path to file ifexist_err$error message (if any) notes • fully supports wildcards function  ifinmod 3 function index purpose to see whether a given string is contained within a given module featuresThis search can look for partial match, or an exact match, for the first x number of characters in the string. This search only looks for the first match at present.  expects.. to contain.. ifinm_num% * module number to search ifinm_s$ * string to search for ifinm_left% 1=enable exact match from left; 0=match anywhere in string (default) ifinm_exact% 1=enable exact match; 0=permit a match on a substring (default) returns.. containing.. ifinm_found% set TRUE if the string was found within the elements of the module ifinm_foundin$the string the match was found in ifinm_foundat% the row the match was found in notes • If ifinm_exact% is set true, ifinmod checks whether the supplied string *exactly* matches any string in the module (it's still case-INsensitive, however). Previously, it matched exactly from the left ("starts with.."), or matched anywhere ("contains.."). function  nukebox 1 function index purpose erase current dialog box features  expects.. to contain.. returns.. containing.. notes function  openforappend 1 function index purpose opens a file for appending, with full errorhandling features  expects.. to contain.. appeof_name$ the name of the file to open appeof_handle% the filehandle to use returns.. containing.. appeof_err$error (if any, blank if none) notes • Note: this routine does not close the file, it only opens it. If many lines of text are being appended to the same file, leaving a file open for appending, instead of opening and closing it for each append, is more efficient. The calling routine must close the file itself, however. function  printfile 1 function index purpose print a file on a printer features  expects.. to contain.. printf_name$ the name of the file to print printf_printer$the name of the printer to print on returns.. containing.. printf_err$ result string (blank if none)
notes
• currently supports HTML files only
• the printer name must match the printer as seen in the control panel, for example, "HP Laserjet 5M" (don't include the quotes)
• this routine pops up Windows' Print dialog box, which requires a click of OK before the print is done. To automate this, a program such as WKIX32 is needed, to send the Enter key to the Print dialog box.

function
 progress 6 function index
purpose show progress bar onscreen
featurescan display a second progress bar underneath
 expects.. to contain.. p_done% percentile complete p_showdone% 0=don't show; 1=show percentile complete in the progress bar p_update% 0=draw whole box; 1=draw only progress bar (faster) p_updatefreq% 0=draw every %; >0=update at that frequency p_dualbar% 0=single progress bar only; 1=draw dual progress bars p_dualdone% percentile of second progress bar complete p_reset% 0=don't reset; 1=reset all progress counters returns.. containing..
notes
• update will draw the box, but only if it has not already been drawn
• p_updatefreq% is used to update the display only every x%. For example, setting p_updatefreq% to 5 would update the display when the percentage complete was 5%, 10%, 15% and so on. This results in a chunkier bar movement, but usually speeds program execution (due to reduced screen updates).
• p_reset% is used to tell the routine to reset its counters and begin a new progress bar. This is required if repeatedly using the routine with the p_updatefreq% parameter set to on. p_reset% will be automatically set to FALSE when the bar is reset.

function
 putFTP 1 function index
purpose upload a file with FTP
features
 expects.. to contain.. pf_ftpserver$the hostname of the FTP server to use (eg. ftp.yourdomain.com) pf_targetdir$ the fully-qualified path to upload to (eg. /htdocs/) pf_sourcefile$the name of the file to upload pf_username$ the name of the user to log in as pf_pw$the password to use returns.. containing.. pf_error% result status (1=error; 0=no error) pf_result$ result string (returned on success as well as failure)
notes
• Currently requires CURL.EXE

function
purpose obtain directory contents from FAT-16, FAT-32, NTFS or UNC volumes
featuresif not supplied, will resolve default drive and/or directory
 expects.. to contain.. readd_name$name of directory to read readd_noinfo% if set to 1, enables high-speed mode returns.. containing.. readd_name$ fully qualified path to target directory readd_files% number of files and directories in target directory dirinfo$(n) CSV-formatted array of file information readd_err$ error message, if any - blank if no error
notes
• the format of dirinfo array is drive:,\full\path\name,filename,extension,date,time,size
• fully supports wildcards
• high-speed mode does not return file date/time/size, but also doesn't display a "File Not Found" error on empty directories (unlike low-speed mode)

function
purpose read a range of lines from a text file into infile array
featureswill set buffer overflow flag if file is too big for available memory
 expects.. to contain.. readf_name$* name of file to read readf_start% * line in file to start reading from (0 for start) readf_length% * number of lines to read (0 for all) returns.. containing.. infile$() array containing lines read infilelines% number of lines read readf_bytes! number of bytes read readf_size! total size of file readf_err$error message (blank if none) readf_bufstat% 0=complete file in RAM; 1=partial file in RAM readf_bufline% line at which RAM filled (0 if complete file in RAM) notes function  refresh 1 function index purpose restores the screen to a virgin state features  expects.. to contain.. returns.. containing.. notes • this routine restores the screen to its state when the program starts - a blank screen with the titlebar across the top function  runfromdir 1 function index purpose runs specified command from within a specified directory features  expects.. to contain.. runf_dir$ * directory to execute command within runf_cmd$* command to execute returns.. containing.. runf_err$ errormessage (if any)
notes
• The command is started minimised and execution waits until the command exits before it resumes.
• Calls to runfromdir under NT4 with will fail unless START.EXE is in the path.

function
 runlongcmd 5 function index
purpose runs specified commandline
featurescommandline can be longer than the QBASIC limit of 127 characters - up to 255 characters; also returns errorlevel
 expects.. to contain.. longcmd$* commandline to execute rl_quiet% attempt to suppress all output (0=no (default), 1=yes) rl_newwin% run this command in a new window (0=no (default), 1=yes) rl_newwinshow% minimise new window (0=no (default), 1=yes) rl_nowait% don't wait for this command to finish before continuing (0=wait (default), 1=don't wait) returns.. containing.. longcmd_err% errorlevel returned from command notes • Starting processes in their own window usually provides more memory to the child process. • rl_newwin% is not available under Windows NT4, as that operating system has no START.EXE command by default. It is possible to pass a START command directly to runlongcmd by placing it in the command string longcmd$. However if the system executing the program is Windows NT, the function will fail (for the same reason - START.EXE not included). The same is also true if using START with a SHELL command under NT4 - it won't work. Either place START.EXE on the system (and in the path) or don't use it, if under NT4. The BAPI provides the operating system type in the variable p_os%.
• Calls to runlongcmd under NT4 with rl_newwin% enabled will be executed, but in the same window as the calling process.
• rl_newwinshow% does nothing if rl_newwin% is set to 0

function
 safekill 1 function index
purpose deletes file, with errorhandling
features
 expects.. to contain.. safef_name$the name of the file to delete returns.. containing.. safef_err$ result string (blank if none)
notes

function
 scanfile 5 function index
purpose find the next or previous occurence of a string in a text file
features
 expects.. to contain.. scanf_name$* name of file to scan lookfor$ * string to search for scanf_start% * line upon which to start searching (0 for first line) scanf_stop% * line upon which to stop searching (0 to search whole file) scanf_last% 0=find next occurence of string; 1=find previous occurence of string returns.. containing.. foundin$line containing found string (blank if not found) foundline% line number of found string (0 if not found) scanf_err$ error message (blank if no error) scanf_size! total size of scanned file (o if not found) scanf_bytes! bytes scanned before string was found (0 if not found)
notes

function
 sendmail 4 function index
purpose send an email with SMTP
features
 expects.. to contain.. sm_messagefile$the name of the file containing the message body sm_recipient$ the email address to send the message TO sm_subject$the string to place in the subjectline of the email sm_fromaddr$ the email address to send the message FROM sm_replyto$the email address the recipient should reply to sm_smtpserver$ the hostname of the SMTP server to use sm_cc$the email address to CC (carbon-copy) the message to (optional) sm_attach$ a list of files to attach to the email, separated by commas (optional) sm_htmlflag% set to true to enable HTML mail (specify the filename in sm_messagefile$as usual) sm_alttext$ the file to contain non-HTML (alternate) text (optional/HTML only) sm_embedlist$a list of files to embed in the email, separed by commas (optional/HTML only) returns.. containing.. sm_error% result status (1=error; 0=no error) sm_result$ result string (returned on success as well as failure)
notes
• Currently requires BLAT.EXE

function
 showline 3 function index
purpose displays a formatted line onscreen
featurescan also erase the line
 expects.. to contain.. showl_l% the screenline upon which output is to appear (Y) showl_t% the tabline (column position) upon which the data is to appear (X) showl_promptx% the tabline (column position) upon which the prompt is to appear (X) (default=1, first column) showl_datacol% the foreground colour of the displayed data (default=15, bright white) showl_p$the prompt to display showl_d$ the data to display showl_x% if set to 1, the line specified in showl_l% will be erased returns.. containing..
notes
• output is in the form prompt: [data]
• valid numbers for showl_datacol% range between 1 and 15

function
 showlistbox 1 function index
purpose displays a table of data onscreen, allows selection
features
 expects.. to contain.. lst$() array containing the data to display, in CSV format lb_listitems% the number of items in the array lb_pagestart% the line number where the list starts lb_pageend% the line number where the list ends lb_fieldnames$ the names of the fields to display, in CSV format lb_fieldlengths$the lengths of the fields to display, in CSV format lb_actionitem% the item upon which to place the cursor lb_datastyle% the format of the data in lst$(); 0=CSV, 1=TSV lb_startat% the line of data upon which to place the cursor returns.. containing.. lst$() contents of table, in TSV format lb_action% keypress (1=Esc; 2=enter; 3=delete; 4=question mark; 5=spacebar; 6=insert) lb_actionitem% the line number of the item upon which to perform the returned action lb_exitat% the line of data upon which the cursor was on, when the routine exited notes • this routine is a bit developmental.. ;) function  showmenu 4 function index purpose display scrollable menu, wait for cursor-based selection, parse user response featuresautosizing, returns selection, updates status  expects.. to contain.. m_title$ contents of title m_items% number of list items on menu m_maxlines% maximum number of list items to display m_focus% default selected item m_p$(n) prompt for item n m_m$(n) status line for item n m_d$(n) unique listitem ID d_buttons% number of buttons to display (0=no buttons) d_b_l$() array containing button labels d_b_h%() array containing character position of label to highlight and capitalise d_b_c$() array containing character to return if user presses this button returns.. containing.. m_abort% 1 = user aborted; 0 = did not abort m_focus% number of item selected m_action$ unique listitem ID of selected response from user d_b_pressed$character value of pressed button (empty if not pressed) notes • If the number of list items exceeds m_maxlines%, or if the number of list items is too large to fit onscreen, a scrollbar will appear. Excess items can be accessed by scrolling down the menu with the cursor keys. function  showmsg 10 function index purpose display or erase statusbar features  expects.. to contain.. s_msg$ string to display in status bar s_nuke% toggle to erase statusbar instead (1=erase, 0=don't (default)) returns.. containing..
notes
• the statusbar is displayed on the bottom line of the screen

function
 showtitle 2 function index
purpose display titlebar
features
 expects.. to contain.. p_name$* name of program p_ver$ * program version number p_copy$copyright information returns.. containing.. notes • the titlebar is displayed on the top line of the screen function  sift 1 function index purpose convert all instances of a given string in a given string to another given string features  expects.. to contain.. sift_s$ * string to sift sift_c$* string to convert from sift_to$ string to convert sifted characters to returns.. containing.. sift_s$sifted string notes • if sift_to$ is left blank, then sift will delete the nominated string (sift_c$) from the string, replacing it with nothing. This will change the length of the string. • sift can sift either single or multiple characters. • if sift_to$ is a different length to sift_c$, then the returned string will be of a different length. function  split 4 function index purpose chop a string in two at first, next, previous or last delimiter, or character position features  expects.. to contain.. split_s$ * string to split split_d$delimiter to find (may be more than one character) split_last% 0 = search from start; 1 = search from end split_start% character position to start search at split_c% character position to split at returns.. containing.. split_l$ left half of split string split_r$right half of split string notes • if both a delimiter and a character position are provided, the string will be split at the character position, and will not be searched for the delimiter. • this routine does NOT return the delimiting characters themselves, or the character at the character position, in EITHER split_l$ or split_r$- it is discarded. function  SQLdelete 1 function index purpose remove a record from an SQL database features  expects.. to contain.. sd_path$ the full path to the MySQL client sd_user$the database username sd_pw$ the database password sd_host$the database server address sd_db$ the database containing the record sd_table$the table containing the record sd_keyfield$ the field name used to identify the record sd_value$the field value used to identify the record returns.. containing.. sd_err$ result string (blank if none)
notes
• currently requires the MySQL client, MYSQL.EXE

function
 SQLinsert 1 function index
purpose add a record to an SQL database
features
 expects.. to contain.. si_path$the full path to the MySQL client si_user$ the database username si_pw$the database password si_host$ the database server address si_db$the database containing the record si_table$ the table containing the record si_items% the number of fields twod$(x,y) 2D array of fieldnames and fieldvalues, x=1 for fieldnames, x=2 for fieldvalues, y=field number returns.. containing.. si_err$ result string (blank if none)
notes
• currently requires the MySQL client, MYSQL.EXE

function
 SQLquery 2 function index
purpose query an SQL database
features
 expects.. to contain.. sq_path$the full path to the MySQL client sq_user$ the database username sq_pw$the database password sq_host$ the database server address sq_db$the database to contain the record sq_table$ the table to contain the record sq_keyfield$(optional) the field name searched for a match (if not provided, all records in the table are returned) sq_value$ the query string to match on sq_query$the query string to match on - if provided, causes a LIKE search instead of an exact match search; in this case, sq_value$ is ignored returns.. containing.. sq_err$result string (blank if none) sq_results% number of results lst$() results (in TSV format)
notes
• if sq_keyfield$is provided, either sq_value$ or sq_query$must also be provided • currently requires the MySQL client, MYSQL.EXE function  SQLupdate 1 function index purpose change a record in an SQL database features  expects.. to contain.. su_path$ the full path to the MySQL client su_user$the database username su_pw$ the database password su_host$the database server address su_db$ the database containing the record su_table$the table containing the record su_items% the number of fields su_keyfield$ the field name used to identify the record su_value$the field value used to identify the record twod$(x,y) 2D array of fieldnames and fieldvalues, x=1 for fieldnames, x=2 for fieldvalues, y=field number returns.. containing.. su_err$result string (blank if none) notes • currently requires the MySQL client, MYSQL.EXE function  strip 2 function index purpose strip leading/trailing spaces from a string, and sub-ASCII 32 characters features  expects.. to contain.. strip_s$ * string to strip returns.. containing.. strip_s$stripped string notes • improve: strip any character function  table2csv 1 function index purpose convert a MySQL table to a CSV file features  expects.. to contain.. sq_path$ the full path to the MySQL client sq_user$the database username sq_pw$ the database password sq_host$the database server address sq_db$ the database containing the table to export sq_table$the table to export t2c_name$ the file to export to returns.. containing.. t2c_err$result string (blank if none) notes • warning: this routine overwrites the lst and infile arrays • currently requires the MySQL client, MYSQL.EXE function  tail 1 function index purpose returns the last line of a text file features  expects.. to contain.. tail_file$ the name of the file containing the template returns.. containing.. tail_line$the contents of the last line notes • Currently requires DTAIL.EXE function  template 3 function index purpose generates a file from a template and a datasource features  expects.. to contain.. template_file$ the name of the file containing the template template_output$the name of the file to contain the generated output lst$() array containing dataitems, in the format itemname=itemvalue returns.. containing.. template_err$result string (blank if none) notes • currently, a maximum of 50 dataitems are supported • the template must contain variables assigned like this: $$variable .. this must be on a new line, in the first column.. and the lst() array must be populated with itemnames that match the variablenames (but not including the$$) function  testint 1 function index purpose tests that a number stored as a string is less than 32767 features  expects.. to contain.. testint_s$ * string containing number to query returns.. containing.. testint_ok% 0=number greater than 32767; 1=number less than or equal to 32767
notes

function
 trunc 1 function index
purpose returns a number with x decimal points
features
 expects.. to contain.. trunc_num! * number to truncate trunc_points% * number to decimal points to truncate to returns.. containing.. trunc_s$the number truncated to the required number of decimal places notes function  unix2dos 2 function index purpose convert a LF-terminated file to CR/LF features  expects.. to contain.. u2d_source$ the name of the file to convert u2d_target$the name of the file to contain the converted text returns.. containing.. u2d_err$ result string (blank if none)
notes

function
 URLdecode 1 function index
purpose convert a string from URL-encoded format to ASCII
features
 expects.. to contain.. URLdecode_s$the string to convert returns.. containing.. URLdecode_d$ the converted string
notes
• this routine decodes from URL- or percent-encoded format - see http://en.wikipedia.org/wiki/Url_encode

function
 URLencode 1 function index
purpose convert a string to URL-encoded format from ASCII
features
 expects.. to contain.. URLencode_s$the string to convert returns.. containing.. URLencode_d$ the converted string
notes
• this routine encodes into URL- or percent-encoded format - see http://en.wikipedia.org/wiki/Url_encode

function
 writebuf 4 function index
purpose buffered write to text file
features
 expects.. to contain.. writf_name$* name of file to write to writb_s$ string to write (empty will write a blank line) writb_init% 0=don't initialise (default); 1=initialise buffer and write first portion of file to disk writb_flush% 0=don't flush (default); 1=flush buffer to disk writb_head% number of lines already in infile array to write as start of file (0 to disable) infile$() array of strings to write as start of file lst$() array containing strings to insert as a header into target header_length% * number of rows of strings to export from list array as header (0 to disable) writf_append% 1=append to target file; 0=overwrite (default) writf_backup% 1=create .BAKfile before write; 0=don't (default) returns.. containing.. writb_err$error message (blank if none) notes • the file will not be closed until the buffer is flushed • a header in the lst$() array will precede a header in the infile$() array when written to file • How to use: 1. initialise the buffer:  writf_name$ = outputfilename$writf_append% = t% writf_backup% = f% writb_init% = t% writb_head% = 0 header_length% = 0 Call writebuf  2. write to the buffer (repeat this until the file is ready to be closed):  writb_s$ = outputstring$Call writebuf flush the buffer writb_flush% = t% Call writebuf  function  writefile 16 function index purpose write a range of lines to a text file from infile array, with optional backup and append featureswill create file if it does not exist; can append or overwrite, can make .BAKfiles  expects.. to contain.. writf_name$ * name of file to write writf_start% * line in infile array to start writing from (0 for start) writf_stop% * line in infile array to stop writing at infile$() array containing strings to write lst$() array containing strings to insert as a header into target header_length% * number of rows of strings to export from list array as header (0 to disable) writf_append% 1=append to target file; 0=overwrite (default) writf_backup% 1=create .BAKfile before write; 0=don't (default) writf_cycle% 1=silently affirm .BAKfile overwrite prompt; 0=prompt before overwriting .BAKfile (default) returns.. containing.. writf_err$error message (blank if none) notes ### general-purpose scratch arrays BAPI/CC defines a number of arrays, for the purpose of data sharing between your program and itself, and also for general use. These are as follows: namesize set bydescription infile$()p_size%holds files read into memory by readfile; holds the data to be written by writefile; is scanned by findssarray; is used by changeINI, writebuf, table2csv
lst$()p_size%holds data to display for listbox; holds header data to write for writefile; holds template data; holds SQL query results tmp$()p_size%holds exploded data for CSV2dim; used by various routines as a scratch array
twod$()inielemax%a two-dimensional scratch array used by SQLinsert and SQLupdate Care must be taken when storing data in these arrays, as it may be either used, or overwritten, by various BAPI/CC routines. However, with a little skill, manipulating the contents of these arrays in between calls to BAPI/CC functions permits the making of very precise changes to the data being processed, often with a minimal amount of arbitrary code. see also: memory usage ### debug mode A verbose troubleshooting mode is available, to assist in development and debugging. Many routines now have debug code built-in; setting p_debug%=1 activates it. Define this along with your p_name$, p_ver$settings at the top of your program, before the BAPI/CC mainline is called. Whilst in debug mode, the API will operate normally, however "fancy" screen functions (such as showline, showmsg and dialog) instead produce "simple" output consistent with the rest of the debug mode. This stops cursor positioning calls scrambling the debug output. showmenu and getform work as usual, however (this can get messy onscreen). Also available is a "step-by-step" debug option, p_debugstep%. Setting this to true causes BAPI/CC to request a keypress at various stages of execution, if p_debug%=1 is also set. This allows you to step through startup and execution, to ensure everything is working as intended. Note: debug messages may be truncated to fit on one line. ### 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 true; ... OR... the INI file can be pointed to by using as the FIRST parameter on the commandline, 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, or manually during execution
• modulenames are delimited by [square brackets]
• modules end on the first blank line after the [modulename]
• the names of modules to load are defined by you in the variable readim_s$• the names of elements to load are defined by you in the variable readim_e$
• free-format elements (with no name) can also be loaded
• data from the main section is stored in cfg$(numsettings%) where numsettings% is the number of settings loaded from the main section • 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 • if you have problems, try temporarily setting p_debug%=1 and p_debugstep%=1 (in the program header) - this will show debug information ### INI how-to: writing an INI file 1. open a new file using a text editor (such as Notepad) 2. choose a modulename, start a new line of INI file, at the first character position, type the modulename enclosed in square backets, eg: [modulename]  3. 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  4. save the file as programname.ini where programname matches the name defined in p_name$, in the same directory as your BAS and EXE files.

Note: a different name and location can be used, however the full path and name of the INI file will need to be provided on the commandline in that case.

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.

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
2. set p_loadmod%=1 in the program header - this tells the INI loader to load all modules in the INI file at boot
3. 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]  4. 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, in the order they appear in the INI file. They will be treated as orphans/freeform elements in this case. If readim_e$ is completed, elements named will be loaded into the array *first*, in the order they are listed in readim_e$. Any other elements found in the module will be loaded into the array last, in the order they appear in the INI file, and treated as orphans/freeform elements. [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. ### INI how-to: loading modules manually during execution 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. write the INI file 2. tell the INI loader NOT to load all modules in the INI file at boot - set p_loadmod%=0 in the program header 3. 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]

4. 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, in the order they appear in the INI file. They will be treated as orphans/freeform elements in this case.

If readim_e$is completed, elements named will be loaded into the array *first*, in the order they are listed in readim_e$. Any other elements found in the module will be loaded into the array last, in the order they appear in the INI file, and treated as orphans/freeform elements.

5. At the appropriate point in your code, call the INI loader. Do this as such:
GOSUB getmodele


### 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: working with orphans/freeform elements

Orphans/freeform elements are those found in a module but not defined in readim_e$. Orphans/freeform elements are NOT stripped of any leading settingname (unlike structured elements). For instance, a element which appears in an INI module like this: amalgamate=dancetrax,[dead links]  Will be loaded verbatim (unchanged) into inimod, IF "amalgamate" is NOT listed in readim_e$. If, however it is a structured element (that is, if "amalgamate" IS listed in readim_e$), it will be loaded into inimod like this: dancetrax,[dead links]  Freeform elements need not have a leading settingname at all. A list of email addresses, for example, if included as a module in an INI file, can be loaded as freeform elements. Freeform elements can be loaded automatically at startup, or manually during execution. Processing freeform 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

### reserved file handles

These filehandles are used internally by the BAPI, and should not be used by your programs.

If you attempt to use one of these reserved filehandles, you may hang your program, lose data, or experience other abnormal program behavior.

handleused by
254scanfile
252writefile
251appendfile
250writebuf
249copyblock
248getmodele
247unix2dos
246template
245tail
244SQLquery
243epochdate
242runlongcmd
241template
240freespace

### runtime error codes

These messages may appear during program execution, and result in immediate termination of the program.

They are produced by the abort routine.

codemeaning
1TEMP environment variable not set

add the line SET TEMP=directoryname to your AUTOEXEC.BAT and reboot - where directoryname is a directory to be used for tempfiles.

2temporary directory [directoryname] inaccessible

The directory specified by the TEMP environment variable cannot be accessed - does it exist, and are permissions granted?

3function [functionname] missing parameter [parametername]

A call was made to a BAPI function without supplying a required parameter.

4[unused]

The program's INI file is required, and is missing from the current directory.

6this program requires Win32

The program must be executed under a 32-bit Windows environment (eg. Windows 95, 98, 98SE, ME, NT4, 2000 or XP).

7tempfiles left in [directoryname]

The program has failed to clean up its tempfiles.

8this program requires Win9x

The program must be executed under a Windows 9x environment (eg. Windows 95, 98 or 98SE).

9unable to write to logfile [logfilename]

Is the path to the logfile valid? Are permissions granted?

10environment variable not set [variablename]

Is the variable set in AUTOEXEC, or in the shell environment?

11unique temp counter overflow

Your program attempted to create more than 9999999 tempfiles.

### internal variables

 p_size% the maximum length of the infile, directory, list, and tmp arrays. p_cfgsize% the maximum number of settings permitted in the main section of the INI file. p_cfgsize% this setting is also multiplied by 2 to determine the maximum number of DOS environment variables to be cached. d_max% the maximum height of a dialog box. On a 25-line screen, it's 21 lines. inimodmax% the maximum number of modules permitted in the INI file. inielemax% the maximum number of elements permitted in each module of the INI file. p_errlog\$ the name of the logfile (if any). p_bufsize% the size in bytes of the readfile/writefile buffer.

### memory usage

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 BAPI/CC's code. 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 next section top of page

• no direct support for graphics, sound or mice

 planned improvements next section top of page

• not listed here

 revision history next section top of page

These routines are an enhanced port of my BAPI QBASIC library.

 September 2005 version 0.01 initial port from QBASIC March 2006 version 0.02 numerous fixes and repairs 2007 - 2008 version 0.03 numerous new routines and tweaks February 2009 version 1.00 ported and improved documentation; public release