List of tables
Table 1. e.errlog Filename Hints
Table 2. im routines
Table 3. Image BBS Encoded Function Keys
Table 4. Input Line: Editor Control Bits
Table 5. Input Line: Password Entry Control Bits
Table 6. Array Numbers
Table 7. Image BBS Date Format
Table 8. Image BBS Date Decoding
Table 9. Interface Table Addresses
Table 10. Text editor calls
Table 11. BASIC Error Numbers
Table 12. Representation of a Sample Two-Dimensional Integer Array
Table 13. Sample “User Data” Struct Layout
Table 14. “User Data” Struct Data Storage
Table 15. Fields in Records
Table 16. Get Number From and Put Number Into Struct
Table 17. Parameters
Table 18. Scan Struct Commands
Table 19. Lightbar, page 1
Table 20. Lightbar, page 2
Table 21. Lightbar, page 3
Table 22. Lightbar, page 4
Table 23. Lightbar, page 5
Table 24. Lightbar, page 6
Table 25. Lightbar, page 7
Table 26. Lightbar, page 8
Table 27. e.data File Format
List of code snippets
i.SB: String Concatenation Example
Input Line: Setting Line Length and Prompt
Input Line: Setting Line Length, Default Text, Prompt and Edit Mode
Input Line: Setting Line Length, Default Text, Prompt and Allowing MCI & Graphics Characters
s.test file
i.read test file
im: Password Mask
im: Load Protocol File, Method 1
Example:
Get Character from Modem
Save and Restore Variable Pointers
i.IM/ecs: Save ECS Definitions to Disk
im: Position Terminal Cursor
im: Set Time with &,62
im: Display String on Console
i.IM: Position Terminal Cursor
i.GF: Scan Struct
i.UD: Scan For Older Upload Date than ld$
i.UD: Scan Numbers
i.GF: add menu item
i.IM: add menu item
i.IM: Use menu
checkflag.asm
Preface
Preliminary start on documentation. Feedback welcome! |
Welcome to the Image BBS 3.0 Programmer’s Reference Guide.
Image BBS has always been a versatile system, allowing a balance between the simplicity of operation and the power of customization with BASIC and ML programming. With the advent of Image BBS v3.0, the power of the system has increased greatly.
Nearly the entire BBS can be customized completely online without the need for programming knowledge. However, Image BBS v3.0 also provides for many powerful new programming tools not before available to the SysOp who desires complete customization of the BBS by changing the BASIC code.
This guide is designed to help such programmers use the Image Application Programming Interface (API) more productively. A lot of hard work has gone into this manual as it was created while the BBS was still being developed. Care was taken to document as much of the BBS as possible for just this purpose. We hope you find this useful in creating the next generation of Image BBS applications.
Happy programming!
—Jack Followay, Jr.; Larry Hedman, Al DeRosa, and Ryan Sherwood
Introduction
Welcome to the first official New Image BBS Programmer’s Reference Guide. While there was an unofficial guide released for Image v1.2, we hoped to give SysOps something they could trust when questions arose about v3.0. Nearly everyone who helped write Image v3.0 helped contribute to this guide. I would like to personally thank everyone who was involved, but if I’ve forgotten anyone please forgive me!
Al DeRosa (Bucko)
Larry Gartin (Wheelman)
Ray Kelm (Professor)
John Moore (Little John)
Ryan Powers (MonOp)
Bob Sisko (Iron Axe)
Ed Wilson (Fred Krueger)
And most of all, I’d like to thank our dear friend, Fred Dart, to whom we owe the very existence of Image v2.0. Without Fred, the project would have been lost forever. It is in his memory that we dedicate Image BBS v3.0.
How to Use This Guide
How to Get Help
Programming Image BBS 3.0
New Features
variable=usr(0)
function reads the stack pointer to display how much free space is on the processor stack.
BASIC Keyword Extensions
A few BASIC keywords have had additional parameters added to them.
load
Relocate Flag
Regular Commodore DOS uses the ,1
in load"filename",8,1
to mean “load this file to the load address stored in the file.”
In Image BBS, the relocate_flag has an expanded purpose—specifying the segment of memory to load a particular file to. A segment is the address which a file will load into, ignoring the file’s existing load address contained in the first two bytes of the file.
Currently, some segments are undefined. |
Segment | Purpose | Address | Example File |
---|---|---|---|
2 |
Protocol start |
|
|
7 |
Print mode table |
x |
|
8 |
Lightbar table |
x |
|
9 |
Alarm table |
x |
|
10 |
ASCII → Commodore translation table |
x |
n/a |
11 |
Commodore → ASCII translation table |
x |
n/a |
12 |
Network alarm table |
x |
|
Here are three different methods of accomplishing the same thing, loading the Punter file transfer protocol.
The first uses the enhanced load
function:
3000 dr=5:gosub 3:a$="++ punter":load dr$+a$,dv%,2 (1)
And the second relies more heavily on the Image ML, using the parameters set by BASIC:
3000 dr=5:gosub 3:a$=dr$+"++ punter":&,7,2 (2)
In both examples:
-
dr=5:gosub 3
takes an Image drive number (dr
, 1-6) to return the device (dv%
, e.g.10
) and drive prefix (dr$
, e.g.,0:
). Here, it returns the device and drive which your modules are stored on. -
a$="++ punter"
sets the filename toload
.
Next:
1 | Method 1: load dr$+a$,dv%,2 loads drive prefix dr$ plus filename a$ from device dv% to segment 2 ($c000 ) |
2 | Method 2: &,7,2 uses dr$ , a$ and dv% as defined by BASIC, but is shorter code |
The third (preferred) method calls a routine in im
:
3000 a$="punter":gosub 28
This method saves time in loading ++
files.
If the file specified in a$
is already in memory, the load process in line 29 is skipped.
It also is a shorter syntax for loading a protocol, saving memory in the BASIC program.
new
Line Range
new line_number
prepares to load
a new module by erasing lines from line_number
to the end of the program.
Example:
new 3000
erases lines 3000 to the end of all loaded modules.
Hexadecimal Values
Hexadecimal values (base 16) are prefaced with $
.
They can be used in poke
, peek
, sys
and &
commands.
poke $d004,$0c
is the equivalent of poke 53252,12
.
Binary Values
Binary values (base 2) are prefaced with %
and up to 8 bits can be specified.
Leading 0
s do not have to be specified.
Binary values can be used with the same BASIC keywords as above. Hexadecimal and binary can be combined, i.e.:
poke $d004,%00001100
is again the equivalent of poke 53252,12
.
Since only the lowest 4 bits are being set, the example can be shortened to:
poke $d004,%1100
If you want to do logical operations like and
or or
with the new binary or hexadecimal prefixes, the only keywords they work with are poke
, peek
, sys
, and &
.
Putting hexadecimal or binary prefixes after logical operators results in a ?syntax error
:
poke $d004,peek($d004) and %1100
Instead, assign %1100
to a variable first, then perform the logical operation using the variable:
c=%1100:poke $d004,peek($d004) and c
Programming Etiquette
Be nice. Write clean code. FIXME
Programming Theory
Static vs. Dynamic String Variables
There are two types of strings in BASIC: static and dynamic.
Static strings look like:
10 a$="hello":b$="there"
They are given a string descriptor (the address, length and type of string) which points within the BASIC program itself. Normally this isn’t a problem. However, when you load another module over the top of that string text, the string pointer still points to the same address, which by now could be overwritten by different code. Now when printed, the string variable could display random bytes of the new module. Often these bytes are BASIC tokens, or BASIC keywords reduced to a single byte to save memory and improve interpretation time.
There’s a way to get around this.
Dynamic strings are different: they’re created when two strings get concatenated together. You’ve probably looked through Image’s code and seen lines like:
3192 ... sy$="Su"+"b" ...
Why not just write sy$="Sub"
?
There is a reason for concatenating two strings together like this.
Strings created this way have string descriptors which are created from the top of BASIC, down toward the end of the BASIC program.
Each new string defined by concatenation creates a new string, moving the pointer to that string downwards, towards the end of your BASIC program—and your static strings.
This is the whole reason garbage collection exists—as more dynamic strings get defined, the pointer to the next free byte move toward the end of your program. If you define too many strings, you’ll eventually run out of space, triggering a garbage collection to erase the old definitions of strings to reclaim memory.
Image BBS uses a custom garbage collection routine, which is much faster than the one in standard Microsoft BASIC. |
But the long and the short of it: the string definition caused by, e.g.: sy$="S"+"ub"
lives outside your program’s code, higher in memory.
The text shouldn’t be overwritten by loading another module, which can sometimes cause strings to output bytes of your program.
Module Structure
When developing a module, bugs are certain to happen.
These bugs are logged to e.errlog
.
There are variables shown in the error log which can be handy to show which line or module the program was in when it crashed.
Filename Prefix | Starting Line | Variable Name | Label |
---|---|---|---|
|
3000 |
|
Program |
|
4000 |
|
Module |
|
60000 |
|
Sub-Module |
|
If your module spans from, say, lines 3000-4000
(or beyond), it would be a good idea to do something like:
pr$="i."+"test calls":p1$=pr$+""
to assign both pr$
(error lines 3000-) and p1$
(error lines 4000-) to the same string.
This avoids leaving garbage strings in e.errlog
because of the previously-mentioned “static string” issue.
If your module contains a collection of sub-modules, you might find it helpful to define in your main program something similar to:
3000 pr$="i."+"test calls"
And in your sub-module, define:
4000 p1$=pr$+".structs"
so that in the event of an error, e.errlog
reads:
Module: i.test calls
Sub Module: i.test calls.structs
Conversion and Backward Compatibility
Image v3.0 is a major change in design and programming style from previous versions. Your first reaction might be to assume that you can no longer use legacy modules created under Image v1.2a and below. However, nearly everything written under previous versions of Image can be made to run under v3.0. The easiest method for this is to run under “1.3 emulation.”
If modules are renumbered to start at line 3000, they can run under Image 3.0.
This mode greatly reduces available memory, but allows a program to make the same calls to im
that were available under Image 1.2a.
The best method for using legacy modules is to convert them to v3.0 compliant modules.
This section is provided to help you as you attempt to convert such modules. The v1.2a ←→ v3.0 cross-reference will be your best tool, but please take time to read the notes regarding making the modules truly Image v3.0 compliant rather than just “compatible.” You will want to take careful note of the theory and structure of a v3.0 compliant program, found in the Programming Etiquette section of this guide.
im
Subroutines
This chapter documents im
routines.
Some routines are simply needed too often by too many modules to justify placing them in every single module.
Subroutines are a programmer’s greatest friend.
The core im
file contains many subroutines which you will find basic to your application or module’s needs.
Be sure to read the Programming Etiquette section for help when deciding where to place a new routine you create.
⇒ Contributions by Jack “Rascal” Followay, Jr; Larry “X-Tec” Hedman, Jay “Hoy Brothers” Campey, and Ryan “Pinacolada” Sherwood.
v3.0 | v1.2, v2.0 | Purpose | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
Jump to main prompt at line 300. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
Position record pointer of the currently opened REL file on LFN 2 (it calls line There is a 1/10th-second delay (
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
Sets active system device/drive according to configured setup.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
Closes, then re-opens command channel (LFN 15) on the device/drive requested by setting the variable |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
Opens filename stored in |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
Read error channel of currently active device/drive.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
Uppercase input routine.
Waits for user input followed by a carriage return.
Stacked commands (
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
Wait for a keypress.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
Prints (strictly text) contents of |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
Position RELative file record pointer DOS command.
Same as line |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
Each user has a total of 19 flags stored in
The values of each flag are as follows:
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
Reset routine. Resets all system output to default parameters. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
Clear the screen and fall through to line |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
Outputs the SEQ file in |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
Update Board Activity Register (BAR) statistic This routine:
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
Print the value of |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Loads a
This routine then:
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
Opens REL file |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
Opens REL file |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
Opens E-Mail file for desired user.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
Opens REL file |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
Opens SEQ file
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
Opens REL file |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Loads
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Loads
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Loads
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
Loads
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
Prints |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
Writes file |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
Reads blocks free on device/drive |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Load and execute an |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Load and execute an i/ “mini-module” file beginning at line |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
Load and execute a
(Replaces 2.0’s |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Loads i.module from device, drive in |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Similar to 24, except uses |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Same as 28, except peculiar difference in approach of checking against |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
Wait for yes/no hotkey.
Otherwise, |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
Load The subroutine filename is added to a “module stack” so that if a |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
System prompt routine.
Not to be confused with line |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Check for logoff (O, or Q if at main prompt [
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Displays local/level
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
This routine is called by the prompt routine at line 200 to check for ECS commands. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
Main prompt entry routine.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Loads
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Reverts memory marker back to 1 ( |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Image 1.2 Emulation Mode.
Dimensions variables similar to Image v1.2 [ “Emulating” 1.2 is not the only use—this routine is helpful to save space and quickly |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
Check for |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
Check for |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
Prints up to the last 10 commands [stored in the history stack, |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
Update access level of user online. (Called by prompt routine at line 200). |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
If |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
Outputs a random macro from file |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
If an
|
sub.*
Module Jump Table
Files with a sub.
prefix contain routines which are used often, but to save memory and avoid code repetition, are separated from the main im
module.
sub.bar
This handles displaying the BBS’s Board Activity Register statistics.
sub.comm1
-
View or change last call date
-
View BBS caller activity log
-
Credit exchange: trade calls for time, credits, or vice-versa
sub.comm2
im |
Purpose |
---|---|
|
MT: Mini-Terminal |
From this point on, the line numbers follow Image 1.2/2.0 im specifications, plus 60000 (e.g., Image 2.0’s 1985 is renumbered to Image 3.0’s 61985 ).
|
im |
Purpose |
---|---|
|
a duplicate of |
|
Handle ECS commands |
|
format local or network node user IDs . if * if Returns: :: an$: entire string n0$: n1$: n2$: |
sub.display
sub.editor
sub.feedback
sub.handles
sub.info
sub.local
sub.menus
sub.misc
sub.misc2
sub.modem
sub.param1
sub.param2
sub.protos
sub.stack
sub.stats
sub.sysdos
This handles issuing DOS commands.
sub.turbo
This handles checking for, and enabling or disabling, the Creative Micro Designs SuperCPU.
&
Routines
&
is the command character which is BASIC’s interface to 70 machine language routines of Image BBS.
This section is undergoing discovery of what some routines are for and how they are used. |
&
: Image BBS Output
In BASIC, the print
keyword (or its abbreviation, ?
) displays text on the screen, as in:
print"Hello there!"
You can substitute &
in Image BBS to do the same thing:
&"Hello there!"
But unlike BASIC, after outputting this text, the cursor remains on the same line—there is no automatic carriage return printed.
It’s as if a semicolon (;
) was used after the print
statement above—this keeps the text all on one line:
print"Hello ";"there!";
vs. printing on two lines:
print"Hello"
print"there!"
To work around this, you can output a carriage return, which moves the cursor to the beginning of the next line.
On other terminals or operating systems, a carriage return moves the cursor to the beginning of the current line.
Sometimes an additional linefeed character is needed, which keeps the cursor in the current column, but moves the cursor down a row.
Hello there!
This stairstep-looking result is what printing looks like with only a linefeed, when the terminal needed both a carriage return and a linefeed. Probably not the desired result.
However, print
ing in Commodore BASIC—and our BBS in this example—doesn’t need a linefeed.
A carriage return is the equivalent of a carriage return plus linefeed.
&"Hello there!"+chr$(13)
chr$()
(read it as “character string”) is a function that outputs a character supplied in parentheses.
A carriage return is chr$(13)
.
So this snippet of code will output Hello there!
, then move the cursor to the beginning of the next line.
There is also a string variable defined in im
: r$=chr$(13)
(short for “return”).
This is a handy shortcut.
You can now code:
&"Hello there!"+r$
Using the r$ variable is actually an easy way to write data containing carriage returns to a SEQ file, as you’ll see later.
|
But there’s something even handier available.
Encoded Function Keys
Some special characters are difficult (or impossible) to type in BASIC. Or, they might cause problems while reading disk files. Therefore, they have been encoded using the reverse video letters seen while typing function keys when in Commodore’s “quote mode.”
This eliminates a few difficulties:
-
Entering special characters is made easier—instead of
chr$()
codes, you can just tap a function key in quote mode -
Some more simply written code (and BASIC itself) can truncate data when a
,
is encountered in a SEQ file—this character encoding eliminates that problem
Image BBS converts these special characters from their encoded form to readable characters when you:
-
use RD to read a SEQ file
-
use SB to read a post
-
Use WF to .Get, .Edit, and .Put a file back.
The image seq reader
utility used in BASIC also does this.
A new & command, &,15,2 , does the same thing when passed an$ , the string to translate.
|
As it relates to carriage returns, though, we can see in the following table:
Key | Quoted | Character | Key | Quoted | Character |
---|---|---|---|---|---|
f1 |
E |
, comma |
f2 |
I |
? question mark |
f3 |
F |
: colon |
f4 |
J |
= equal sign |
f5 |
G |
" quotation mark |
f6 |
K |
Return |
f7 |
H |
* asterisk |
f8 |
L |
^ up arrow |
Key is what you type on the Commodore 64 keyboard.
Quoted is what it looks like in “quote mode.”
Character is what the encoded character represents.
&
By Itself
This is a quick way to output the contents of a$
.
a$="Hello theref6":&
This outputs Hello there
and a carriage return.
We can take the previous example of:
&"Hello there!"+r$
and simplify it further with:
`&"Hello there!kbd:[f6]"`
Because of a quirk in the BASIC interpreter, you must follow a then clause with a colon before using the ampersand.
|
In other words, the following results in a ?syntax error
:
if b then &"hello"
This must be used instead:
if b then:&"hello"
BASIC Editing Modes
Quote Mode
In the BASIC editor, once the quote mark (Shift+2, ") is typed, color or cursor controls stop changing the cursor color or moving the cursor.
Instead, they start displaying reversed characters which stand for the color control, cursor control or symbol you are typing.
Once the text inside the quotes is print
ed, they perform their functions as if typed manually.
The Inst/Del key is the only cursor control not affected by “quote mode.”
Typing a second " exits quote mode, and allows you to use the cursor keys to edit the program line again.
See &,70 Position Terminal Cursor for how to easily move the terminal cursor within Image BBS, instead of using lots of cursor controls in quote mode.
|
Insert Mode
Insert mode is similar to quote mode, only for the number of spaces you insert with the Shift+Inst/Del key, the BASIC editor is in quote mode. Once the space inserted has been typed in, insert mode is exited.
Return gets out of quote and insert mode, and adds the current line into the BASIC program. |
Shift+Return gets out of quote and insert mode, but does not add the current line into the BASIC program.
Outputting Strings
String Literals
String Variables
Concatenation
Word-Wrap
A new feature of the text output routine is word-wrap. This is where a word which would extend past the right hand margin is moved to the following line instead.
The position to wrap words is usually 40 columns on the console, whatever the remote user’s screen width is, and 80 columns on the printer, if one is attached.
Setting the variable lp=1
and outputting text with &"…"
will enable word-wrap.
Setting lp=0
disables word-wrap, so words continue past the right margin.
Set Margins
The left and right margins can now be indented by up to 15 characters using two new MCI commands:
-
£m<x
(set left margin). This command causes every carriage return issued by Image BBS to be followed by x spaces, which indents text x spaces. The values for x are0
(to disable word-wrap), or1-9
, andj-o
(10-15). -
£m>x
(set right margin). This command causes the system to word wrap as if the user’s screen width was x characters less than it really is. It indents the text from the right side.
The use of £m<x
and £m>x
together allows you to make “block indents” of text that appear correct regardless of the user’s screen width.
MCI Commands
TODO
Outputting a string which itself contains MCI commands or MCI string variables will not work as expected, e.g.: |
c$="Hi":c%=3:z$="£$c £#3£#0£%c":&"£$z"
does not output z$
(£$c
outputs c$
, £#3
sets 3 leading characters, £#0
sets the fill character to 0
, and £%c
displays the value of c%
).
It outputs a literal
£$c £#3£#0£%c
Instead, do this:
c$="Hi":c%=3:z$="£$c £#3£# £%c":&z$
This outputs the expected
Hi 003
Outputting Numbers
Integers
Floating Point
Floating point values are not integers—the value could be fractional, and the decimal point could be in any position, hence the term “floating point.”
&str$(h)
-
Since
&h
isn’t supported to output the value ofh
, it must be converted to a string with thestr$()
function.
&str$(h) is still useful if the number of digits output is greater than 5, the limit of the MCI numeric output routine.
|
&str$(h)
worked under Image 1.2; it works here too, but there is a new MCI command in Image 3.0 to output single-letter floating point variables:
&"£!h"
-
Output the value of
h
.
To output a two-character variable name (e.g., xx
, c1
), you have some choices:
-
assign the two-character variable name to a single letter variable name, e.g.:
x=xx:&"Blocks free: £!x"
-
output the two-character variable using the
str$()
function:&"Number of days:"+str$(xx)
-
Output the value of
xx
.
&
Parameters Explained
&
commands from this point on have additional parameter(s) called by at least one number, followed by optional parameter(s).
These variables are denoted in italics.
&,call
-
This means that
&,
is required, but the value of call varies. Substitute the appropriate number in its place.
&,40
: perform garbage collection
&,call[,optional]
-
This means that, again,
&,call
is required. The value of call varies. However, the parameter [,optional] is not required. If it is supplied, there needs to be a,
and the appropriate parameter substituted in its place.
&,9,1
: display a$
in the 16-character programmable window
There are various sections which most commands use.
They outline BASIC setup (variables or poke
s) which need to be done before the &
call can be used.
- BASIC Setup:
-
Any
poke
s or BASIC variables which are used by the&
command are listed here. - Parameters:
-
Any extra information given after
&,x
, like strings or numbers, are listed here. - Returns:
-
Strings, numbers or arrays returned when the
&
command is finished are listed here. - Examples:
-
Examples of setup, the
&
call being used, and some typical results are listed here.
&,1
Input Line
&,1
accepts input from the user at a prompt.
It handles features including word wrap, MCI access, line length, and the ability to type graphics characters.
BASIC Setup:
poke 53252,line_length
limits the length of the input to line_length characters, 1-79.
p$
: text of the prompt shown before :
and input is accepted.
w$
: the default response to a prompt.
When using edit mode, if only Return is typed at a prompt, an$
is set to a null string (an$=""
).
The module can check for this and not update the original string.
An example is given below.
pl=0
: allow both lowercase and uppercase.
pl=1
: convert lowercase input to uppercase.
Parameters:
&,1,editor[,password]
Not all of these parameters are currently understood. |
editor
: editor flags:
Each bit controls a separate function of the input routine. Bits may be combined together to perform multiple functions.
Binary | Decimal | Purpose (if set) |
---|---|---|
|
1 |
disable typing graphics characters |
|
2 |
. or / on column one exits input |
|
4 |
disable prompt ( |
|
8 |
disable typing £ (the MCI command character) |
|
16 |
enable word-wrap |
|
32 |
enable edit mode |
|
64 |
ignore time remaining |
|
128 |
disable typing Delete on column one to exit input |
Returns:
Variable | Purpose |
---|---|
|
1 |
peek() |
Purpose |
---|---|
|
0: normal exit 1: Delete, . or / typed on column 1 2: Left 3: Loss of carrier, or time expired ( |
Explanations:
TODO: demonstrations of each mode in i.test calls
- Edit mode
-
The prompt (
p$
) is displayed, and the default response (w$
) is displayed. Then, the prompt (p$
) is displayed again, and one of three choices can be made:-
Return accepts the default (
w$
) -
a new string can be typed
-
the current string can be edited using Ctrl key shortcuts
-
password
: password flags:
Binary | Decimal | Purpose |
---|---|---|
|
1 |
password mask enabled for output [uses mask character in |
|
2 |
no output |
Returns:
an$
: text typed at the prompt.
Examples:
TODO: write examples for each option.
poke 53252,10:p$="Name":&,1
poke 53252,10
: Set the input length to 10 characters.
p$="Name"
: Set the prompt to Name:
.
&,1
: Allow user input, and return string in an$
.
poke 53252,20:w$=na$:p$="Handle":&,1,32:if an$<>"" then na$=an$
poke 53252,20
: Set the input length to 20 characters.
w$=na$
: Assign the user’s handle (na$
) to w$
(the prompt’s default).
p$="Handle"
: Set the prompt to Handle:
.
&,1,32
: Setting bit 5 (a value of 32) enables edit mode.
This displays the prompt, the original text (w$
), and re-displays the prompt.
Editing control keys can be used to change the input.
Editing mode looks like this:
Handle: PINACOLADA Handle: _
The string typed in response to a prompt is returned in an$
.
if an$<>"" then na$=an$
: Just typing Return (to accept the default, w$
) sets an$
to a null string.
If something else was typed (an$<>""
), assign na$
to what was typed (an$
).
poke 53252,30:p$="New Prompt":&,1,9:if an$<>"" then po$=an$
poke 53252,30
: Set the input length to 30 characters.
p$="New Prompt"
: Set the prompt to New Prompt:
.
&,1,9
: Setting bits 3 and 0 (a value of 8 + 1) allow MCI and graphics characters to be entered.
&,2
Disk File Input
Input data from an open disk file.
This routine inputs a maximum of 80 characters into a$
.
Parameters:
&,2,lfn[,bytes]
lfn
: logical file number.
A logical file number (LFN) relates the open
, close
, cmd
, get#
, input#
and print#
statements to each other.
LFNs help distinguish multiple files from each other. They associate the commands being used with the filename opened which uses the same LFN.
The LFN is the first number in an open
statement, e.g. open 2,10,2
.
The LFN value ranges from 1 to 255. LFN 15 is usually reserved for the DOS command channel.
The only restriction is that you can’t re-open
a LFN that is already open
, or you get the error ?file open error
.
bytes
: number of bytes to get from file (1-80).
Carriage returns are ignored.
Returns:
a$
: bytes from file
Example:
data (1)
----+----+----+----+----+----+ (2)
1 | a regular string |
2 | a 30-character string, used to demonstrate &,2,2,25 |
3000 dr=1:a$="s.test file,s,r":gosub 4 (1)
3002 if e% then:&:goto 3100 (2)
3004 &,2,2:& (3)
3006 &,2,2,25:& (4)
3100 close 2:goto 300 (5)
1 | dr=1 : set the Image drive to 1 (the System drive).
a$="s.test file,s,r" : set the System disk filename prefix to s. , the main filename to test file , specifies s for a SEQuential file, and r for reading the file.
gosub 4 : open a$ for the device and drive assigned to the System drive. |
2 | If there is a DOS error (e.g. file not found ), this line intercepts it.
e% : the DOS error number.
if e% implies if e%<>0 (if e% does not equal zero; i.e., a non-zero result means an error occurred).
a$ : the DOS error string.
& : display the DOS error string in a$ .
goto 3100 : close the disk channel instead of getting data from a non-existant file. |
3 | &,2,2 : using logical file #2, get a line of data from the disk.
The data is returned in a$ .
& : output a$ . |
4 | &,2,2,25 : using logical file #2, get a line of data from the disk—but stop at 25 characters, instead of getting the entire line.
The data is returned in a$ .
& : output a$ . |
5 | close 2 : close disk file.
goto 300 : go to main prompt. |
Using input#2,a$
when the disk file contains a string hello,there
returns only hello
in a$
.
When used with input#
, ,
is a delimiter which truncates (cuts off) the data after the ,
.
You can prefix the string with "
on disk to get around that.
But most likely, you want to read hello
and there
into two separate variables.
input#2,a$,b$
does that, resulting in a$="hello"
and b$="there"
.
&,3
Read File from Disk
Read a file from disk. An optional speed parameter can be specified for reading movie files, which adds an appropriate slowdown based on the value.
Parameters:
&,3,lfn[,speed]
lfn
: logical file number
,speed
: speed (1
-20
for movie file read. 1
=faster, 20
=slower)
&,4
Get Byte from Modem
This returns the character received from the modem in peek(780)
.
This routine does no ASCII translation, and no high bit stripping; it gets the character directly from the RS232 routines.
Returns:
x=peek(780)
reads the character from the RS232 routines.
If no character is received from the modem, peek(780)=0
.
&,5
Get Version
Get the version information embedded in the BBS ML.
Returns:
lp
: major/minor (1.3)
a%
: revision (1)
a$
: date ("12/29/91 1:18p"
)
&,6
Password Input
Sets the input length to 14, and displays a definable mask character rather than the actual characters typed. The text typed is returned in plain (non-masked) text.
Parameters:
poke 17138,mask
: display mask character instead of the user’s input
You could do poke 17138,asc("X")
to set the mask character to X
.
Returns:
an$
: password in plain text
Example:
263 &"Password: ":&,6:if an$<>ep$ then:&"Incorrect Password."
&"Password: "
: Display the prompt Password:
.
&,6
: Allow password entry, displaying the mask character instead of the text actually typed.
if an$<>ep$ then:&"Incorrect Password."
: if an$
(the entered text) is not equal to (<>
) ep$
(a password set on an Extended Command Set command), display the message.
&,7
Load File
Loads a module into memory.
Parameters:
a$
: the drive number and filename (e.g., "0:i.module"
)
Syntax:
&,7,device[,segment]
Segments are pre-defined addresses that a module will load to, regardless of the file’s first two bytes which define its load address.
Not all segments are currently defined.
Segment | Purpose |
---|---|
2 |
Protocols or blocks of ML |
7 |
Print mode table |
8 |
Lightbar text |
9 |
Alarm table |
10 |
ASCII-to-Commodore translation table |
11 |
Commodore-to-ASCII translation table |
12 |
Print mode table |
29 ml$="++ "+a$:a$=dr$+ml$:&,7,dv%,2:goto 5
This line loads an ML protocol (++
file).
ml$="++ "+a$
Assign ml$
the ++
prefix for error reporting purposes.
a$=dr$+ml$
Concatenate dr$
(the current drive prefix) and ml$
(discussed above) into a$
.
&,7,dv%,2
Do a module load using device dv%
into segment 2 (the protocol address, 49152
or $c000
).
goto 5
Check for a DOS error.
&,8
Disk Directory
Display either:
-
an entire disk directory at once, from the directory header to the
blocks free.
message -
a line of information at a time (calling it multiple times will get the directory header, each file’s block count, filename, filetype, splat and lock status, and the
blocks free.
count)
Parameters:
&,8,lfn,flag
lfn
: logical file #
flag
: [0
=entire directory | 1
=single line]
Returns:
flag=0
: Displays entire directory
flag=1
: a$
: single line of disk directory information
3000 dr=1:gosub 3:open 2,dv%,0,"$"+dr$+"*":get#2,a$,a$ (1) 3002 &,8,2,0:close 2:goto 300 (2)
1 | dr=1:gosub 3 : get device of s. disk.
open 2,dv%,0,"$"+dr$+"*" : open the directory as a file. The secondary address must be 0 to instruct the drive to return the disk directory as a BASIC-formatted series of lines, displayable by this routine. $0:* : Use the wildcard pattern * (all files). get#2,a$,a$ : discard the load address information. |
2 | &,8,2,0 : Use lfn#2 to get the entire disk directory (0 ). close 2 : close lfn#2. goto 300 : go to main prompt. |
&,9
Bottom Variable
Output variables to 16-character status window.
Parameters:
&,9[,x]
: x=variable number to display, 0-49:
Variable | Variable | Variable | Variable | Variable |
---|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Examples:
&,9[,0]
: output an$
to status window
&,9,1
: print a$
to status window
&,9,2
: print b$
to status window
&,9,3
: output tr$
to status window
&,9,4
: output d1$
to status window
&,10
Terminal Mode
C=+Ctrl leaves terminal mode
&,11
Clear Array
Clear array #x.
Number | Array | Purpose |
---|---|---|
0 |
|
Text editor: lines entered |
1 |
|
|
2 |
|
|
3 |
|
|
4 |
|
|
5 |
|
|
6 |
|
|
7 |
|
|
8 |
|
|
9 |
|
|
10 |
|
Access levels |
11 |
|
Subops |
Example:
&,11
-
Clear
tt$()
array.
&,12
New User
Non-abortable file read.
&,13
arbit
A function reserved to arbitrate port use in multi-port Lt.Kernal hard drive setups.
This is currently being researched. |
&,14
Dump Array
Write array elements to an already-open file, using logical file #2.
&,14,array
-
Output from 1 to however many elements were
dim
ensioned for array. &,14,array,end
-
Output elements of array from 1-end.
See Array Numbers for the arrays which correspond to array. |
&,15
Convert an$
This group of functions perform various conversions on the string contained in an$
.
Related string conversion functions can be found at &,65 convert.
|
&,15
Convert Date
Convert an 11-digit Image BBS-formatted date into a long date string.
an$=d1$:&,15:&an$
→ displays verbose date
-
an$=d1$
: Put current 11-digit date (d1$
, e.g.60429218427
) intoan$
-
&,15
: Convert 11-digit date to a long date string, e.g.Thu Apr 29, 2021 4:29 P
and assign that toan$
-
&an$
: Outputan$
Image BBS Date Format
Image BBS uses an 11-digit string to represent a time and date.
The format is w yr mo dt hr mi
.
Extra spaces between the numbers have been added for ease of reading, but are not used in the actual string. |
Position | Abbreviation | Purpose | Range |
---|---|---|---|
1 |
|
weekday |
|
2-3 |
|
year |
|
4-5 |
|
month |
|
6-7 |
|
date |
|
8-9 |
|
hour |
|
10-11 |
|
minute |
|
The current time and date is stored in the string d1$
, which is continually updated by the ML.
Here is a sample definition of d1$
:
"22105178944"
Let’s break down how the string is encoded.
Position | Value | Purpose | Meaning |
---|---|---|---|
1 |
|
weekday |
|
2-3 |
|
year |
|
4-5 |
|
month |
|
6-7 |
|
date |
|
8-9 |
|
hour |
|
10-11 |
|
minute |
|
As the table above shows, this string stands for Mon May 17, 2021 9:44 PM
.
You can also output Ctrl+d or chr$(4) in an & statement to convert an 11-digit date/time string to a long date/time string.
Both these statements output the same string as above:
|
-
a$="22105178944":&"Ctrl+d"+a$
-
a$="22105178944":&chr$(4)+a$
Outputting the date and time this way also outputs the user’s time zone.
&,15,1
Title Case
Changes an all uppercase string to mixed case.
an$="THE CHIEF":&,15,1:&an$
→ The Chief
&,15,2
Decode Function Keys
Decodes quoted function key characters into readable equivalents.
i.t
-
an$="hostf3port":&,15,2:&"£v7f6"
→host:port
&,15,3
and &,15,4
These point to, and are the same as, &,15,2
.
&,15,5
newdate
Some sort of hour (?) conversion.
Syntax:
an$="wyymmddhhmm":&,15,5:&"Ctrl+d"+an$
This function is currently being researched. |
&,15,6
Scan String
Scan an$
for the first occurrence of a specified character.
You can specify the character to scan for in one of two ways:
-
x, the PETSCII value of the character
-
use the
asc("x")
function, which returns the ASCII (or PETSCII) value of character x
If the specified character is found in an$
, split it into two strings:
-
an$
now ends before the specified character was found -
a$
begins after the specified character was found to the end of the string
If the specified character is not found in an$ , a$="" , a null string.
|
312 &,15,6,140:uu$=an$:an$=a$
140 =f8, Image ^
|
352 &,15,6,133:d2%=val(an$):d1%=a:dr=.:dv%(.)=d1%:dr%(.)=d2%
133 =f1, Image ,
|
&,16
sys49152
Perform sys 49152
.
Usually this is used in a file transfer protocol for performing a file copy, upload, or download.
Parameters:
&,16
[,sub-function]
Following &,16
with a sub-function number (e.g., &,16,2
) calls a sub-function of the module through a jump table.
Refer to Protocols for more information and listings of jump tables. |
&,17
sys49155
Perform sys 49155
as shown above.
&,18
Set Screen Mode
This command turns the screen mask on (enabling split screen mode) or off (enabling full-screen mode). The bottom status line (showing the date and time, status indicators, and the time remaining for a user’s call) is always present, regardless of mode.
Parameters:
&,18,0
: Turn the screen mask off, enabling full screen mode (24 lines for viewing caller activity).
&,18,1
: Turn the screen mask on, enabling split screen mode (16 lines for viewing caller activity).
The 9 lines of the screen mask show:
-
the lightbar interface
-
system, caller, protocol or network transfer information depending on the BBS’s mode
-
the modem I/O windows,
M=
free memory, andL=
BASIC line number currently executing
&,19
Get Version
This function did something different in Image 1.2, but was removed.
It points to &,5
Get Version to maintain the numbering of the &
calls.
&,20
Read from Interface Table
Reads a byte from the interface table.
This is meant to possibly eventually replace peek()
ing memory locations.
While the functionality is there, it is limited, but can be expanded in the future.
Parameters:
&,20,index,command
index
: position in table (see table)
command
: [0
=put in a%
| 1
=return in accumulator, peek(780)
]
Index | peek() |
Hexadecimal | Purpose |
---|---|---|---|
0 |
|
|
Input line length |
For now, refer to Pokes and Memory Locations to see the list of poke
s you may use.
&,21
Write to Interface Table
Writes a byte to the interface table.
This is meant to possibly eventually replace poke
ing memory locations.
While the functionality is there, it is limited, but should be expanded in the future.
Parameters:
index
: see Interface Table Addresses for more information
value
: the value you would normally poke
into a memory location
Example:
&,21,0,20
Set input line length to 20 characters.
&,22
Wait x Tenths of a Second
This waits for any interval from .1 second to 25.5 seconds, in 1/10-second steps.
Parameters:
x
= 1-255
&,22,10 (1)
&,22,200 (2)
1 | Wait 1 second (10 10ths of a second) |
2 | Wait 20 seconds (20 10/10ths of a second) |
&,23
Get Character from Modem
3000 &,23:c=peek(780):if c<>32 then 3000 (1)
1 | Get character from modem.
Save in c .
Loop until the caller hits Space [chr$(32) ]. |
&,23 doesn’t stop and wait for input, unlike the £g1 MCI command.
If no character is received from the connected user, peek(780)=0 .
|
&,24
xchrout1
This following routine is used by Image BBS machine language itself; there is little reason to call it from BASIC. |
This is an output character routine that should be used when writing ML routines which need to output a character to the user.
&,25
Sound
Produce 4 separate sounds, optionally repeating the sound a specified number of times.
Parameters:
&,25,sound[,repeat]
sound=
&,25,0 beep &,25,1 ding &,25,2 higher pitched ding &,25,3 gong sound from CCGMS (a terminal program)
repeat=
Number of times to repeat: [0
: Stop repeat | 1-254
: Repeat count | 255
: infinite]
&,26
ecschk
This is currently being researched. |
&,27
Save Variable Pointers
This saves pointers that tell BASIC where variables and arrays start and end.
When modules introduce arrays not already defined in im
, the variable pointers can be restored with &,28
.
This erases unnecessary variables after they’re done being used.
FIXME
Creating New Arrays
If you define any new arrays in a module, be sure not to consume unnecessary memory after you end the module.
You can do this by using the &,27
(array pointer save) and &,28
(array pointer restore) calls.
Image 1.2 had just one level of variable pointer save and restore. Image 1.3 and above adds multiple levels of save and restore with an additional parameter.
3000 &,27,2 (1)
3002 dim u%(10,20) (2)
...
3010 &,28,2:goto 300 (3)
1 | save current variable pointers, and create variable pointer level 2 |
2 | create new array |
3 | &,28,2 : restore level 2 array pointers (this frees up memory used by the array but preserves level 1 system variables still needed by the BBS). goto 300 : go to main prompt. |
TODO: I would like a diagram of array pointers, creating new arrays, restoring old pointers here.
The main prompt restores level 1 array pointers and already does a &,28,1 there.
|
If you substitute &,27,1
for &,27,2
and &,28,1
for &,28,2
in the above code, line 300 will redo &,28,1
.
This causes a ?redim’d array error in 306
(i.e., redimensioned array error; an array can’t be dim
ensioned twice).
&,28
Restore Variable Pointers
FIXME
These following 8 routines are used by Image BBS machine language themselves; there is little reason to call them from BASIC. |
&,29
usevar
Get contents of a variable. This is the routine to call to read the value of a variable from ML.
Prerequisite:
ldx
variable_number ; variable to access.
(Refer to variable table FIXME.)
Returns:
$61
: Start of buffer holding the variable contents.
&,30
putvar
Assign a value to a variable.
This stores the contents of the buffer at $61
into a variable.
Prerequisite:
ldx
variable_number ; variable to access.
(Refer to variable table FIXME.)
Returns:
$61
: Start of buffer holding the variable contents.
&,31
zero
This stores the floating point equivalent of 0
in the buffer starting at $61
.
&,32
minusone
This stores the floating point equivalent of -1
in the buffer starting at $61
.
&,33
getarr
Get descriptor (length and pointer) for an element of tt$(x)
.
Prerequisite:
ldx
element ; element to access.
Returns: $61
: Start of buffer holding the descriptor.
&,34
putarr
&,35
getln
&,36
putln
&,37
trapon
Enable error-trap routine. BASIC run-time errors will be caught, and redirected to the BBS error handler at line 2000.
&,38
trapoff
Disable error-trap routine.
BASIC run-time errors will not be caught, and will crash like in regular BASIC, halting the program and putting you back at the ready.
prompt.
This following routine is used by Image BBS machine language itself; there is little reason to call it from BASIC. |
&,39
prtln
Prints the array element tt$()
contained in the .x
register.
&,40
forcegc
Perform a garbage collection (freeing RAM by erasing unused strings).
While the garbage collection is being performed, G
shows in the status indicator area on the bottom status line.
FG also performs garbage collection if you are in pseudo-local mode.
&,41
setbaud
This command changes the bits per second (BPS) rate.
Do not change the BPS rate while someone is online. This only changes the rate of Image BBS transmitting data; the modem cannot match speeds except while offline. |
Parameters:
Parameter | BPS rate |
---|---|
|
300 |
|
not used |
|
1200 |
|
2400 |
|
4800 |
|
9600 |
|
19200 |
|
38400 |
To utilize speeds higher than 2400 BPS, you must have a SwiftLink, Turbo232 or compatible high-speed RS232 cartridge connected to the expansion/cartridge port of your Commodore 64. |
&,42
ECS Commands
This group of commands are used for interfacing the Extended Command Set (ECS) with BASIC. There are sub-commands to:
-
load and save the command set
-
search for and update individual commands
-
goto
orgosub
line numbers inim
, or modules
&,42
Check for ECS Command
This checks whether the command passed in an$
is a valid ECS command.
Example:
226 f4=.:a%=zz:b%=2^ac%:&,42:if a% then ef$=b$:ep$=a$:ec=a%:ec%=b%:goto 261
BASIC Setup:
an$
: command the user typed
a%
: Local Mode flag (zz
)
b%
: access level
Returns:
a%
: [0
: not found in ECS table | n
: ECS command #n
]
a$
: password
b$
: ECS flags
b%
: credits to use command
&,42,1
Goto Line in ECS Command
This will goto
a particular line in im
contained in the ECS command, if its goto/gosub
flag is set to goto
.
In this respect, it is similar to &,66
: calculated GOTO
.
Parameter:
a%
: line number to goto
Example:
268 a%=asc(ef$+nl$)+256*asc(mid$(ef$,2,1)+nl$):&,42,1
From an ECS flags string ef$
, a%
holds the line # to goto
, using &,42,1
.
&,42,2
Get ECS Definitions From RAM
Example:
4004 &,42,2:n=a%:goto 4034
Returns:
a%
: number of ECS definitions in memory
&,42,3
Put ECS Definition Into RAM
Add/replace the ECS definition in tt$(n)
to the list currently in memory.
Parameter:
tt$(n)
: command definition
&,42,3,number
: the command number in the ECS to add/replace
Examples:
4010 tt$(n+1)=chr$(0):&,42,3,n+1:return
n
: the current count of ECS commands
Assign an empty command [chr$(0)
is a null byte] to the next command [tt$(n+1)
].
&,42,3,n+1
: Add the empty command in [tt$(n+1)
] to the ECS.
&,42,4
Load ECS Definitions from Disk
Load ECS definitions from a disk file.
Parameters:
a$
: filename
dv%
: device #
Example:
3106 a$=dr$+"e.ecs.main":&,42,4
Load the ECS definitions in e.ecs.main
from disk.
&,42,5
Save ECS Definitions to Disk
Save ECS definitions to a disk file.
Parameters:
a$
: filename
dv%
: device #
BASIC Setup:
Line 4016 is the root example, lines 4010 and 4018 are provided for context. |
4010 tt$(n+1)=chr$(0):&,42,3,n+1:return (1)
4016 &"Save To Disk{f6:2}":gosub 4010:gosub 4018:gosub 19:a$=dr$+a$:&,42,5:tz=0:return (2)
4018 dr=3:a$="e.ecs.main":return (3)
1 | Set end of ECS command list. |
2 | gosub 4010 : see callout 1.
gosub 4018 : see callout 3.
gosub 19 : scratch existing e.ecs.main file.
&,42,5 : Save ECS definitions to disk.
tz=0 : Clear “file modified” flag. |
3 | assign dr=3 (Image drive) to the Etcetera disk, and a$="e.ecs.main" , the ECS filename. |
These following 9 routines are used by Image BBS machine language themselves; there is little reason to call them from BASIC. |
&,43
chatchk
Checks for presence of the Cht
left check mark.
&,44
trace
Checks for presence of the Trc
left check mark.
&,45
prtvar
Prints a variable with MCI enabled.
&,46
prtvar0
Prints a variable with MCI disabled.
&,47
carchk
Checks for the presence of a Carrier Detect signal.
Returns:
0
: carrier present, or local mode
1
: carrier dropped
2
: timeout
&,48
getkbd
Check console keyboard for a keypress. This can also be also used from BASIC.
Returns:
peek(198)
: Character typed
&,48 does not stop and wait for input, unlike the £g1 MCI command.
If no character is typed on the keyboard, peek(198)=0 .
|
FIXME: verify this
&,49
getmod
Gets a character from the modem, with ASCII translation.
&,50
outscn
Output a character to the BBS console.
&,51
outmod
Outputs character in accumulator [peek(780)
] to modem.
&,52
Lightbar Interface
This is how to read the status of lightbar checkmarks, change checkmarks’ status, and move the “lit” portion to a specific location.
Parameters:
&,52,position,option
&,52,$hexadecimal,option is allowed.
|
Example: Turn off Trc
left: &,52,$18,0
(&,52,24,0
decimal).
option=0
: clear checkmark at position
option=1
: set checkmark at position
option=2
: toggle checkmark at position
option=3
: read status of position, return in a%
(0
=off, 1
=on)
option=4
: move lightbar to position
Option 5 does the same thing in ML as option 4 does in BASIC.
&,53
Logoff
This following routine is used by Image BBS machine language itself; there is little reason to call it from BASIC. |
-
Resets various flags:
-
chat page counter
-
sound repeat counter
-
-
clears status line indicators
Example:
3074 &,53
&,54
Text Editor Interface
The editor can be entered in different ways, depending on the value of mode.
Line 60100 of sub.editor
uses &,54,a
.
The values of a and the purpose for entering the editor are as follows:
Line | Variable | Purpose |
---|---|---|
|
|
Normal entry, empty buffer |
|
|
Buffer not cleared |
|
|
Extended editor command |
When a
is equal to 0, this is the "normal" entry point into the editor with an empty buffer.
When a
is equal to 1, entry into the editor does not clear the buffer.
When a
is equal to 2, entry into the editor is the point that would be used in an extended command if the command that was typed was not a recognized command.
How to use the editor in your BASIC programs is described later in “The Editor.”
These following 2 routines are used by Image BBS machine language themselves; there is little reason to call them from BASIC. |
&,55
output
&,56
chatmode
&,57
relread
Reads records from an open RELative file until the character ^
is encountered.
Parameters:
&,57,lfn
lfn
: logical file number
&,58
setalarm
Parameters:
&,58,hour,minute
hour
: hour
minute
: minute
&,59
farerr
Cause a specified BASIC error to happen.
Parameter:
&,59,1,error
Example:
&,59,1,14
Cause error 14
, ?illegal quantity error
.
Number | Error | Number | Error |
---|---|---|---|
1 |
TOO MANY FILES |
16 |
OUT OF MEMORY |
2 |
FILE OPEN |
17 |
UNDEF’D STATEMENT |
3 |
FILE NOT OPEN |
18 |
BAD SUBSCRIPT |
4 |
FILE NOT FOUND |
19 |
REDIM’D ARRAY |
5 |
DEVICE NOT PRESENT |
20 |
DIVISION BY ZERO |
6 |
NOT INPUT FILE |
21 |
ILLEGAL DIRECT |
7 |
NOT OUTPUT FILE |
22 |
TYPE MISMATCH |
8 |
MISSING FILE NAME |
23 |
STRING TOO LONG |
9 |
ILLEGAL DEVICE NUMBER |
24 |
FILE DATA |
10 |
NEXT WITHOUT FOR |
25 |
FORMULA TOO COMPLEX |
11 |
SYNTAX |
26 |
CAN’T CONTINUE |
12 |
RETURN WITHOUT GOSUB |
27 |
UNDEF’D FUNCTION |
13 |
OUT OF DATA |
28 |
VERIFY |
14 |
ILLEGAL QUANTITY |
29 |
LOAD |
15 |
OVERFLOW |
30 |
BREAK |
&,60
Structures
Structures (or structs for short) allow you to access and manipulate the memory used by arrays at machine language speeds.
See the Structures chapter for more information.
&,61
poscrsr
Move the terminal cursor to a specified column and row on the screen.
Parameters:
&,61,column,row
0,0 is the top left corner of the screen.
|
4004 &,38:&,61,.,8:print"&,37:goto300:":end
&,61,0,8
: position the cursor at column 0, row 9. print
recovery information if the BBS crashes.
&,62
Set Time
Set BBS clock.
Parameters:
&,62,
hour, minute
hour
: hour
minute
: minute
Example:
3182 &,62,h,m
These following 3 routines are used by Image BBS machine language themselves; there is little reason to call them from BASIC. |
&,63
inline1
&,64
convstr
&,65
convert
Another group of related string conversion functions, there are sub-functions to convert:
-
names (?)
-
disk data
-
special characters to Image-encoded function keys, and
-
check special characters.
Related string conversion functions can be found at &,15 Convert an$ .
|
&,66
Calculated goto
goto
line number held in a%
.
If you have 13 4-digit goto
targets on a line, this can save a fair amount of RAM (and BASIC interpretation time).
BASIC Setup:
a%
: line number to goto
Instead of writing this (which uses 73 bytes):
Spaces between line number targets have been added for clarity’s sake. |
on a% goto 3000, 3100, 3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900, 4000, 4100, 4200, 4300
The same thing can be written like so (which uses 19 bytes):
a%=3000+a%*100:&,66
Based on the value of a%
(including 0
), &,66
will goto
lines starting at 3300 in increments of 100 (0
=3000, 1
=3100, 2
=3200, 3
=3300, etc.)
&,66,1
Calculated gosub
gosub
line number held in a%
.
If you have 13 4-digit gosub
targets on a line, this can save a fair amount of RAM (and BASIC interpretation time).
Example:
Instead of writing this (which uses 73 bytes):
on a% gosub 3000,3100,3200,3300,3400,3500,3600,3700,3800,3900,4000,4100,4200,4300
The same thing can be written like so (which uses 38 bytes):
a%=abs(val(an$)):if a%<15 then a%=3100+a%*50:&,66,1
Based on the value of a%
(including 0
), &,66,1
will gosub
lines starting at 3100
, in increments of 50 (0
=3100, 1
=3150, 2
=3200, 3
=3250, etc).
a%=3:a%=3100+a%*50:&,66,1
would gosub 3250
.
&,67
copyrite
&,68
struct
Certain sub-functions of &,60
are re-directed here.
&,69
Display String on Console
This function will not draw PETSCII graphics characters properly. |
Parameters:
&,69,column,row,text,color
column
: 0-39
row
: 0-24
Upper left of the screen starts at column 0, row 0. |
text
: can be a string (a$
), literal text ("Hi there!"
), or a combination of both ("Hi there, "+a$+"!"
)
color
: is 1-15
for un-reversed colors.
(0
, black, is excluded—this is the same numbering as MCI colors.)
For reversed colors, add $80
(or 128
decimal).
$8x
is reverse color x ($81
or 129
is reverse white, $8f
or 142
is reverse light gray).
Example:
13 &,69,4,21,left$(" "+cm$+"{21 spaces}",22),$8c
-
&,69,4,21
: position string at column 5, row 22
-
left$(" "+cm$+"{21 spaces}",22)
: format the string so it’s left-justified in the 22-characterArea
window
-
,$8c
: draws the string in reverse ($8
) in color$c
(decimal 13, light green)
The module sub.display is a good example of using &,69 .
|
&,70
Position Terminal Cursor
Parameters:
&,70,column,row
Upper left corner of the screen is 0,0 .
|
column
: 0-39
row
: 0-24
3350 ... &,70,.,n/2+8.5:&"{white}"
Structures
8/1/2022: Documentation under heavy development and discovery. Feedback welcome. |
Structures (or structs for short) allow you to access and manipulate the memory used by arrays at machine language speeds.
Programmed properly, structs save RAM compared to having multiple string and numeric arrays defined to, say, hold information about a U/D library:
-
filename and filetype
-
the block size
-
times downloaded
-
upload date and last download date
You can now hold all this information within a single struct array, performing:
-
searches
-
sorts
-
filtering the list of files based on a substring match
-
and more.
You can store multiple types of data in a single struct—each category is stored in a separate “column” called a field--and perform operations on the data using &,60
or &,68
, and various sub-commands.
Performing a struct search operation is much faster than searching through an array in BASIC with a for…next
loop.
Static Arrays
The arrays are considered static because, like static strings embedded in BASIC text (such as a$="hello"
), the size of individual fields can’t change once the struct is defined.
Currently there’s no option to resize a struct without first copying data to another struct (accomplished with &,60,10 Copy Record).
|
There are functions to:
-
put and get strings, and Image BBS-style 11-digit dates
-
sort and filter data
-
test and collect information from the struct, then put the results in another array
-
copy pieces of information from one part of the struct to another
-
load and save structs
FIXME more functions
Elements are the individual “boxes” in the array that data is held in.
Strings can be stored in either a floating point array [like a()
or b()
], or an integer array [like a%()
or b%()
].
-
Two bytes of a string’s text can be stored per element of an integer array
-
Five bytes of a floating point array, or 4 bytes… FIXME
Record (0,x) | |||
---|---|---|---|
Field (0,0) |
|
|
|
Field (1,0) |
|
|
|
Field (2,0) |
|
|
|
It is suggested that you use numeric instead of string arrays, since this will allow you to both access the elements as numeric data, as well as put and get strings.
Floating point arrays use 5 bytes per element. Integer arrays use 2 bytes per element. When deciding to use structs, you should determine what types of data you will need to store, and how much memory that data will require.
As a running example, let’s design a struct to hold a user’s ID#, handle, and password. A module will be written to store, edit, and retrieve data to/from this struct.
-
The ID is an integer type (never > 32767), requiring 2 bytes.
-
The handle can be up to 20 characters.
-
The password can be up to 15 characters.
Since the integers store in 2 bytes, the total number of bytes needed is 37 (2 + 20 + 15). Thirty-seven bytes would require either:
-
19 integer elements (2 bytes per element × 19 elements = 38 bytes)
or
-
8 floating point elements (5 bytes per element × 8 elements = 40 bytes).
Now that you have the basic concept of the struct, let’s look in a little more detail. Here is a byte-by-byte map of the struct we designed.
Element Position | Byte Position | Data | Type | Bytes Used |
---|---|---|---|---|
Element 0 |
Bytes 00-01 |
ID# |
Integer |
2 bytes |
Element 1 |
Bytes 02-21 |
Handle |
String |
20 bytes |
Element 11 |
Bytes 22-36 |
Password |
String |
15 bytes |
Element 18½ |
Byte 37 |
unused |
n/a |
1 byte |
Element |
|
|
|
|
|
|
|
|
|
|
|
Byte Pos |
|
|
|
|
|
|
|
|
|
|
|
Data |
ID# |
Handle (20 bytes) |
|||||||||
Bytes |
|
|
|
|
|
|
x x |
x x |
x x |
x x |
x x |
Element |
|
|
|
|
|
|
|
|
|
Byte Pos |
|
|
|
|
|
|
|
|
|
Data |
Password (15 bytes) |
unused |
|||||||
Bytes |
|
|
|
|
x x |
x x |
x x |
x |
unused |
Because the unused byte 37 is not on an even element boundary (the previous element is an odd number of bytes), it cannot be used. |
Since the ID# is an integer anyway, it would be best to use an integer array. The definition would look like this:
dim u%(18)
Remember that arrays start at element 0! There are 19 bytes in this struct, 0-18. |
Of course, you may want to store more than one of these records in memory.
To do so, you would need a 2-dimensional array.
(Suppose that x is the number of records you want.)
This would change the dim
statement to:
dim u%(18,x-1)
Some New Terminology
To refer to data in a struct, and hopefully reduce confusion about “elements” and “bytes,” the following terminology will be used:
-
The first number in the array notation is the field number (like a field within a record of a RELative file). It’s reccommended to be an even number since integers occupy at least two bytes.
-
The second number is the record number. When the size of the struct is
dim
ensioned, you use this value to address individual records within the struct.
Record and field are specified in what most people and programs would consider reverse order (in a database, a record is composed of fields of information). Sorry, there’s no way around this (that we’re aware of). |
TODO: a visualization of fields in a record.
u%(field,record) |
Fields 0-1 | Field 2 | Field 3 | Field 4 | |
---|---|---|---|---|---|
Record 0 [ |
— configuration information — |
||||
Record 1 |
a |
b |
c |
d |
e |
Record 2 |
f | g |
h |
i |
j |
|
Record 3 |
k | l |
m |
n |
o |
Record 0 , field 0 [e.g., u%(0,0) ] is often used to hold the number of records in the struct.
Record 0 may hold additional information in other fields during the lifetime of the struct.
|
Using Structs
Now down to the important part: how to use all of this!
The struct system is called with either &,60,sub-function,…
or &,68,sub-function,…
.
There are currently 14 sub-functions supported by the struct routines. They are documented below.
Numeric Values and Structs
The array used with structs is either an integer or floating point type. To put numeric values into—or get numeric values from—a struct requires no special struct calls.
You may use code similar to the following examples:
Get value | Put value |
---|---|
|
|
Integer arrays can store values from -32768 to 32767 .
|
&,60,0
Put String
Copies a specified string variable (up to a specified length) into a field of a record of a struct.
&,60,0,
length, struct%(field, record), string$
length: the maximum string length to put into the record.
struct%(field, record): the struct name, field and record you’re putting the string into.
string$: the string variable name to assign the struct data to.
&,60,0,20,u%(1,1),na$
-
Put a string:
&,60,0,20,u%(1,1),na$
-
of up to 20 bytes:
&,60,0,20,u%(1,1),na$
-
from the
u%()
array (field 1, record 1):
&,60,0,20,u%(1,1),na$
-
into the string variable
na$
:
&,60,0,20,u%(1,1),na$
TODO: test if putting string longer than length into struct is truncated—it should be.
?type mismatch error
: if the parameter string$ is not a string variable FIXME
&,60,1
Get String
This copies data from a struct into a specified string variable.
&,60,1,
length, struct%(field, record), string$
The parameters length, struct%(field, record), and string$ are the same as Put String
above.
&,60,1,20,u%(11,2),a$
In our earlier example user data struct, to access the third user’s password, you would do this:
&,60,1,20,u%(11,2),a$
Parameter | Purpose |
---|---|
|
Get a string… |
|
of at most 20 bytes… |
|
from the array |
|
into the string variable |
&,60,2
Load Struct from Disk
Loads the specified struct on disk into an array.
&,60,2,0,
struct%(field, record), filename$, device
&,60,2,0,
: Required parameters.
struct%(field, record),: FIXME
filename$,: FIXME
device: FIXME
Assign the variable dr
to the Image drive number desired, and gosub 3
.
This returns device (dv%
).
(For our example, we’ll set dr=6
, since u.
files live on Image drive 6.)
dr=6:gosub 3
This also returns the drive prefix, dr$
.
&,60,2,0,u%(0,0),dr$+"u.handles",dv%
-
Load a struct:
&,60,2,0,u%(0,0),dr$+"u.handles",dv%
The 0 is believed to be a necessary but ignored parameter.
|
-
Use the
u%()
array (load to record0
, field0
):
&,60,2,0,u%(0,0),dr$+"u.handles",dv%
You do not have to load the file at the start of the array.
The starting record and field are specified in the array notation.
This example loads the file u.handles into the u%() array, starting at the beginning of the array (0,0) .
It could load starting at (0,5) — record 5 , field 0 — or anywhere else you want, as long as it is within the bounds of the struct’s dim ensions.
|
-
Use the drive prefix
dr$
, plus the fictitious"u.handles"
filename:
&,60,2,0,u%(0,0),dr$+"u.handles",dv%
-
dv%
is the device number to load the struct from:
&,60,2,0,u%(0,0),dr$+"u.handles",dv%
&,60,3
Save a Struct to Disk
This saves a struct to a specified disk file.
&,60,3,0,
struct%(field, record), filename$, device
TODO use include::
from &,60,2
setup
&,60,3,0,
struct%(field, record), bytes, filename$, device
The parameters struct%(field, record), bytes, filename$, and device are the same as in previous commands.
The starting record and field numbers to save are specified by the numbers in the array notation.
&,60,3,0,u%(0,0),38*3,dr$+"u.handles",dv%
The starting record and field is specified with (as above) u%(0,0)
.
-
Save a struct:
&,60,3,0,u%(0,0),3*38,dr$+"u.handles",dv%
-
The starting element is specified with struct%(field, record):
&,60,3,0,u%(0,0),3*38,dr$+"u.handles",dv%
-
bytes: the number of bytes the struct occupies is the number of records multiplied by the bytes per record. In our example, 3 records × 38 bytes:
&,60,3,0,u%(0,0),3*38,dr$+"u.handles",dv%
-
drive prefix
dr$
+ filename (the theoreticalu.handles
):
&,60,3,0,u%(0,0),3*38,dr$+"u.handles",dv%
-
device
dv%
, set bygosub 3
before the struct save call
&,60,4
Put Date
Put an 11-digit date string into a struct (converted from 6 bytes as stored in Binary Coded Decimal).
&,60,4,0,
struct%(field, record), string$
struct%(field, record): struct name, record and field to store date in
string$: the 11-digit date string (either a literal string or string variable?) FIXME
?illegal quantity error
if the date string is not 11 digits
an$="10412208234":&,60,4,0,u%(3,0),an$
TODO: Explain example.
&,60,5
Get Date
Convert a 6-digit Binary Coded Decimal (BCD) date string (as shown above) to the 11-digit format as shown above.
&,60,5,0,
struct%(field, record), string$
Parameter | Purpose |
---|---|
|
Get date call. |
|
struct name, field, record… |
string$ |
…string variable to hold the converted 11-digit date and time |
&,60,5,0,u%(0,1),an$:&,15:&an$
-
&,60,5,0,
: Get a date string… -
u%(0,1),
: …from the structu%()
, field1
, record0
… -
an$:
…intoan$
. -
&,15
: Convertan$
into a long date string. -
&an$
: Display the long date string.
TODO: finish the output
&,60,6
Scan Struct
Scan through a field in a struct, testing whether various conditions are true on variables. If the condition is true, perform an operation on another field in the struct.
&,60,6,
num, command, a%(a,b), b%(a,b), size, bits, test
3166 a%=0:if s%(0,0) then:&,60,6,s%(0,0),0,s%(0,1),s%(1,1),80,1,2^ac%
Statement | Variable | Purpose |
---|---|---|
|
n/a |
There is an implied |
|
n/a |
scansum |
|
num |
for the record count |
|
command |
|
|
s%(field, record) |
starting flags element |
|
s%(field, record) |
starting object element |
|
size |
each record is 80 bytes wide |
|
bits |
set bit 1 on … if command returns zero? FIXME |
|
test |
access level |
4106 &,60,6,x1%(0,0),0,x1%(0,1),x1%(1,1),36,4096,2^ac%
4108 &,60,6,x1%(0,0),5,x1%(0,1),x1%(0,1),36,8192,f
4110 &,60,6,x1%(0,0),7,x1%(0,1),x1%(0,1),36,16384,id
num
: # of fields in the struct to scan
bits
: the bits to set if test is true
flag%(field, record)
: the struct name, record and field on which to set bits
if test
is true.
record may be a dummy parameter, more tests needed. |
scan%(field, record)
: struct name, record and field to scan
size
: record size in bytes
command
: command number as listed in this table:
Num | Command | Add If Result |
---|---|---|
0 |
2 byte |
not equal to |
1 |
2 byte |
equal to |
2 |
2 byte |
less than ( |
3 |
2 byte |
greater than or equal to ( |
4 |
date |
date is less than ( |
5 |
date |
date is greater than or equal to ( |
- Num
-
Command number
- Command
-
How to compare the two objects:
-
and
does a logical and with the bits FIXME -
cmp
compares values
-
- Add If Result
-
Add this record (field?) to the FIXME only if object meets the command’s criteria
test: the object to test for (apparently can be either a variable or a number, maybe the byte number?)
This is still being researched. |
The following code scans the U/D directory for entries which have an upload date older than ld$
, setting bits $4f
on ud%(3,1)
(if the entry matches?):
3950 &,60,6,rn,$4f,ud%(0,1),ud%(3,1),60,4,ld$:b%=a%
rn
: highest record number to scan in the directory struct
$4f
: (%0100 1111
in binary) FIXME still researching the purpose of this
ud%(0,1)
: FIXME
ud%(3,1)
: Upload date
60
: record is 60 bytes wide
4
: date comparison, <
(less than)
ld$
: the comparison object (last call date).
Can apparently be a string name, or number of an array?
a%
: count of fields the comparison returns as matching test
.
b%(a,b)
: the array containing the comparisons matching test
.
&,60,7
Sort Struct
Sort a string array (only two-dimensional?). Does not work with numeric arrays.
&,60,7,0,
a$(a, b), start
a$(a,b): String array to sort
start: Element to start sorting at?
4016 for i=1 to 8:&".":&,60,7,0,a$(p+1,i),n-p:next:p=n-10
&,60,8
Scan Numbers
Scan through a specified field in a struct for non-zero values.
a%
returns how many non-zero values there are.
The list of non-zero values are returned in the specified array.
&,60,8,
number, size, access, struct%(field, record), result%(1), start
number
: number of records to scan
size
: size of the record, in bytes
access
: access level to filter results by (in bits?)
struct%(field, record)
: the struct, record and field to scan
result%(1)
: the single-dimension array to put the results in.
1
seems to be a dummy parameter: ignored, but necessary to be interpreted as a valid array reference.
start
: record to start scanning at
4112 &,60,8,x1%(0,0),36,8192+16384,x1%(0,1),x2%(1),1:x2%(0)=a%
-
&,60,8
: Scan Numbers sub-command -
rn
: Scan throughrn
records -
60
: the struct is 60 bytes per record -
a
: filter by access levela
-
ud%(0,1)
: look in theud%(field=0, record=1)
(field 0=“don’t care?”) -
f%(x)
: put non-zero results in thef%()
array -
1
: Start at record 1.
More research needed.
8192+16384 exceeds the expected access levels of 0-9 (values 1-1023).
|
3310 &,60,8,rn,60,a,ud%(0,1),f%(1),1:f%(0)=a%
FIXME: order of params changed — this is Jack’s struct UD
-
&,60,8
: Scan Numbers sub-command -
rn
: Scan throughrn
records -
60
: the struct is 60 bytes per record -
a
: filter by access levela
-
ud%(0,1)
: look in theud%(field=0, record=1)
(field 0="don’t care?") -
f%(x)
: put non-zero results in thef%()
array -
1
: Start at record 1.
a%
: number of results returned, 0
=none.
a%(a)
: one-dimensional array of results, from a%(1—a)
&,60,9
Scan Sum
&,60,9,
number, size, struct%(field, record)
number
: number of records to scan
size
: size of record, in bytes
struct%(field, record)
: (field=“don’t care”? FIXME), record to scan
This function call documentation is incomplete. |
None yet.
a%
: FIXME: total of values in struct?
&,60,10
Copy Record
Copy one record from one struct to a record in another struct.
&,60,10,
size, a1(a, b), a2(a, b)
size
: size of record
a1%(a,b)
: source struct a1%()
, record b
and field a
a2%(a,b)
: destination struct a2%()
, record b
and field a
4694 if x<>fb%(.,.) then for a=x to fb%(.,.)-1:&,60,10,60,fb%(.,a+1),fb%(.,a):next (1)
1 | if x<>fb%(0,0) : if x does not equal the number of records in the struct [fb%(0,0) ], then copy record a+1 to record a in a loop. |
&,60,11
Scan for String
Scan struct for a string present in a specified field and record. Put results in another specified struct, field and record?
&,60,11,
num, size, op, str, a1%(a,b), a2%(b), start
num
: number of records to scan
size
: size of record
op
: operation:
-
0
specifies a regular compare (a string literal) -
1
specifies a pattern to match. Here you can use two wildcard characters (like Commodore DOS):-
f2 (in quote mode: I) is equal to ?, which specifies any character in its place
-
f7 (in quote mode: H) is equal to *, which specifies any characters from this point to the end of the string
-
str
: FIXME: string variable/string literal to scan for?
a1%(a,b)
: source struct a1%(), record b, field a, to scan
a2%(b)
: target 1-dimension array a2%(), dummy element b, to put results into
start
: record to start scanning from
No info yet.
None yet.
&,60,12
Game Scan
Unknown purpose.
&,60,12,
count, size, a$, a%(a,b), b$
count
: how many records to scan?
size
: size of the record to scan
a$
: a string to search for?
a%(a,b)
: a%()
: struct name, a
: field and b
: record to scan
b$
: ?
None yet.
&,60,13
Text Read
Not sure yet. Read a file into a struct?
&,60,13,
number, reclen, scan(), bits, text(), strlen
number,: count of lines to read?
reclen,: record length?
scan(),: ?
bits,: ?
text(),: ?
strlen: ?
None yet.
Variables
Within Image BBS, there are certain variables which can be considered “reserved.” This does not mean that you cannot use them, per se, but that they can only be used for specific purposes:
-
Some variables may be used any time, but have a specific purpose.
-
Some variables can be used with certain subsystems, but not with others.
-
Some variables may be used anywhere, but change continually.
This is explained in detail in the following paragraphs.
An example of a variable used for a specific purpose is na$
.
This variable is used to print the handle of the user online.
Storing something for a module in this variable would cause an undesirable effect (modifying the user’s handle).
Basically, these types of variables are used to control system statistics and are best left alone, only to be used to output information.
Some variables are used as interfaces between the BASIC and ML, an example being pl
.
Setting pl
to 0
will cause all user input to be in the form of upper- and lowercase characters.
When you set pl
in BASIC, it causes the ML input routines to accept both uppercase and lowercase characters.
The main variables that can be used sometimes are arrays.
Depending on which subsystem you are in, the arrays may or may not be in use.
If they are not in use, it is safe to use them.
The only exceptions to this is st()
, dv%()
and tt$()
.
-
st()
holds the Board Activity Register stats; changing the values of this array should be reserved for updating the BAR stats. -
dv%()
is the system device designator. Altering this will change the device accessed by the system. -
tt$()
cannot be used in a module that calls the editor, unless you want to edit existing text in that array. All text stored in the editor is put intott$()
.
Some variables are intended to continually change.
These include variables that will print text to the screen and modem, as well as variables that form links between the BASIC and ML portions of the program.
Examples are a$
and an$
:
-
When used in conjunction with
&
, the value ofa$
will be printed to the screen and modem. -
All responses entered at a prompt will be stored in
an$
.
These variables have a set purpose, but are intended to change.
Variable
This is the variable’s name.
Type
BBS
: this is a BBS statistic or BBS-maintained variable, it could be saved to e.data
.
User
: this is a user statistic, saved to u.config
.
Use?
indicates you can assign a value to it within your own modules.
indicates the variable is maintained by either the BBS ML or BASIC modules. User data corruption or other unwanted side-effects may occur if this variable is reassigned.
means the variable may be used in some circumstances, but not in others.
Purpose
An explanation of what the variable does.
Integer
Variable | Type | Use? | Purpose |
---|---|---|---|
|
|||
|
BBS |
User access level, Read: Get user’s access level. Write: Set user’s access level. |
|
|
Access flag? |
||
|
BBS |
Old access level (“Access Old”).
If |
|
|
User |
Last call carrier drop flag. |
|
|
User |
Computer type: |
|
|
User |
Calls today. |
|
|
BBS |
Currently active device number. |
|
|
BBS |
Currently active drive/LU number. FIXME: duplicate? |
|
|
BBS |
Currently active drive/LU number. FIXME: duplicate? |
|
|
User |
Downloads allowed per day. |
|
|
User |
Downloaded blocks. |
|
|
BBS |
Default color for text. |
|
|
BBS |
ASCII value of keypress? |
|
|
User |
Line length (width of the user’s screen in columns) |
|
|
BBS |
Minute of the day: |
|
|
BBS |
Prime Time: Minutes allowed during prime time. |
|
|
BBS |
Prime Time: Starting hour. |
|
|
BBS |
Prime Time: Ending hour. |
|
|
BBS |
Prime Time: Active flag |
|
|
User |
Total calls to the system by the user online |
Floating Point
Variable | Type | Use? | Purpose |
---|---|---|---|
|
BBS |
AutoMaint flag. |
|
|
BBS |
BBS boot drive device number, used only during initialization. |
|
|
BBS |
Temporary blocks free count. |
|
bu |
|||
|
BBS |
Total calls to the BBS. |
|
|
User |
Amount of credits the user has. |
|
|
BBS |
Line number an error has occurred on. |
|
|
User |
Expert mode flag: |
|
|
BBS |
Image |
|
|
BBS |
BBS reservation: |
|
|
BBS |
BBS reservation: |
|
|
BBS |
BBS reservation: |
|
le |
Lines in text editor x10 |
||
lf |
User |
Linefeed flag. |
|
|
BBS |
Read: Use: Disable or enable word-wrap for |
|
nc |
BBS |
Edit with IM |
Credits given to new user. |
|
User |
Graphics mode. |
|
|
BBS |
Network transfer flag: |
|
|
BBS |
General Files directory stack depth counter. |
|
|
User |
Prompt Mode flag: |
|
|
|||
|
BBS |
||
|
BBS |
||
|
BBS |
||
|
BBS |
Pseudo-local mode flag: |
Strings
b$
-z$
are work variables used throughout the BBS by different subsections.
They are available for use and may be read and written freely.
Some specific information about certain variables is outlined below.
Variable | Type | Use? | Purpose |
---|---|---|---|
|
BBS |
Output text using General-purpose work variable. |
|
|
BBS |
Access group information, including 4 control characters and access group name. (Also MCI variable |
|
|
BBS |
A horizontal line 2 characters less than the user’s screen width. (Also MCI variable |
|
|
|||
|
BBS |
Character input from
(Also MCI variable |
|
|
BBS |
Boot drive partition/LU number.
Used once in |
|
|
BBS |
BBS name. (Also MCI variable |
|
|
used once in |
||
|
BBS |
Chat mode entry message. |
|
|
BBS |
Chat mode exit message. |
|
|
BBS |
|
|
|
BBS |
2-character system identifier, sometimes shown with user ID. (Also MCI variable |
|
|
BBS |
Copy of |
|
|
BBS |
Current Message, displayed in the (Sometimes used for debugging information in |
|
|
BBS |
User’s computer type, displayed in 16-character programmable window using |
|
|
BBS |
Current time and date information in 11-digit format, updated by BBS ML. (Also MCI variable |
|
|
BBS |
Time and date of last logoff, or Library name at entry. (Also MCI variable |
|
|
BBS |
Handle of last user on the system. (Also MCI variable |
|
|
BBS |
Name of current ML protocol in memory. (Also MCI variable |
|
|
BBS |
True last call date of user online in 11 digit format. (Also MCI variable |
|
|
BBS |
Logoff time of last user. |
|
|
BBS |
System identifier + user ID number |
|
|
BBS |
Currently active drive/LU number + |
|
|
BBS |
ECS command flags. |
|
|
BBS |
ECS command password. |
|
|
BBS |
Programmable function key definitions.
Strings must end in null byte ( |
|
|
User |
Real first name of user online. |
|
|
User |
20-character string which determines the user’s status flags. |
|
|
BBS |
16 hexadecimal digits: |
|
|
BBS |
Current |
|
|
BBS |
Modem initialization string. |
|
|
BBS |
Access level + handle of the sysop. |
|
|
User |
|
|
|
|||
|
BBS |
System reservation: password. |
|
|
User |
Last call date of user in 11-digit format. Used to determine whether a message is new or not. |
|
|
User |
Real last name of user online. |
|
|
|||
|
BBS |
Logon time of user online in 11-digit format. |
|
|
BBS |
Filename of current ML module in memory. |
|
|
BBS |
More prompt text: |
|
|
BBS |
modem setup? |
|
|
BBS |
Handle of current caller. (Also MCI variable |
|
|
BBS |
Null character [ |
|
|
BBS |
Last network sort time/date in 11-digit format. |
|
|
BBS |
Current prompt text. |
|
|
BBS |
|
|
|
BBS |
|
|
|
User |
E-mail address of current user online. (Also MCI variable |
|
|
BBS |
Text for system main level prompt. |
|
|
BBS |
System password (change with |
|
|
BBS |
Name of current |
|
|
|||
|
User |
Password of current online user |
|
|
BBS |
Quotation mark [ |
|
|
BBS |
Return character [ |
|
|
User |
Real name of user online ( (Also MCI variable |
|
|
|||
|
BBS |
Current subsystem active. |
|
|
BBS |
C= Time-of-day clock |
|
|
Time zone |
||
|
BBS |
Reserved for command stacking. |
|
|
User |
User flags. |
|
|
Command stacking string. |
||
|
Word-wrap input. |
||
|
BBS |
System drive/LU designators FIXME? |
|
|
only during boot-up or config |
String Arrays
Variable | Type | Use? | Purpose |
---|---|---|---|
|
BBS |
Text of computer types. |
|
|
BBS |
User command history stack. |
|
|
BBS |
|
|
|
BBS |
General File directory names stack. GF section remembers which menu level you were at after quitting a module. |
|
|
BBS |
Text entered into text editor. This array can be used in modules not using the text editor. |
Floating Point Arrays
Variable | Type | Use? | Purpose |
---|---|---|---|
|
BBS |
Blocks free on system disks. |
Image 1.2 Arrays
Image 1.2 Arrays
bb$(31)
dt$(31)
ed$(61)
nn$(61)
a%(61)
c%(61)
d%(61)
e%(31)
f%(61)
ac%(31)
so%(31)
POKEs and Memory Locations
poke
s control various flags maintained by the Image BBS machine language (ML).
Decimal | Hex | ML Label | BASIC Variable | Purpose |
---|---|---|---|---|
|
|
Time limit |
||
|
|
|
|
Terminal width in columns. |
|
|
|
n/a |
Number of lines output.
If the More Prompt is enabled, compare |
|
|
|
|
Terminal height in rows. |
|
|
|
n/a |
Time set flag.
|
|
|
n/a |
Password mask character. |
|
|
|
|
n/a |
Control input line length. |
poke s could go away in the future, in favor of an interface table.
This replaces using a memory location with a number in the interface table.
|
Instead of using poke 53252,22
, the call would be similar to &,21,0,22
.
Refer to the &,20
: Read from Interface Table or &,21
: Write to Interface Table commands for more information.
Machine Language Entry Points
Here is a listing of ML modules and their entry points.
This section is currently undergoing research. |
Protocols
&,16,4,x
: getflag
sub.protos
: This returns the value of defflag
from the protocol.
Its purpose is currently unknown.
&,16,5,x
: getflag
This sets the value of defflag
from the protocol.
Its purpose is currently unknown.
++ index
This module handles the u.config
(user log) and u.weedinfo
(user weed info) files.
Function | Description | Entry | Exit |
---|---|---|---|
|
|
LFN #2 for the REL file channel must be LFN #15 for the command channel must be
|
If If |
|
|
|
|
|
|
|
n/a |
|
|
n/a |
n/a |
|
|
|
n/a |
|
|
|
n/a |
|
|
|
|
|
This allows fields other than the first one to be indexed. |
|
n/a |
|
|
|
|
++ post
The ++ post
protocol supports querying which protocol is loaded in memory via &,16,255
.
This returns the protocol number in a%
.
This is useful to prevent unnecessary load
ing if the protocol is already in memory.
++ punter
Function | Purpose | Returns |
---|---|---|
|
multi-download |
|
|
multi-upload |
|
|
multi-download + header |
|
|
multi-upload + header |
|
|
setflag |
|
|
getflag |
(are these flags whether the protocol supports multi-file transfers?) |
++ reader
This module can display PRG files.
Function | Purpose | Returns |
---|---|---|
|
Detokenize BASIC file, use column width |
Graphic Menu
The ML module ++ menu2
handles adding menu items, hotkeys, displaying the menu and passing the menu item selected back to BASIC.
&,16,0
:
Add menu item
Parameters:
&,16,0,?,menu%(field, record),"hotkey(s)","prefix_text?","menu_item_text"
?
: 42
: draw two-column menu
menu%(field,record)
: struct to put menu text in
hotkey(s)
: One (B) or two (/B) keys to type to select this menu item
prefix_text
:
menu_item_text
: Text the user sees for this menu item.
Example:
3518 if pf>1 then:&,16,0,42,q%(0,n),"/B","Op ","Return to Previous Menu":n=n+1
3008 &,16,.,34,m%(.,1),"A","","Macros Editor"
Returns:
a%
: which item was selected
&,16,1
: Add string
Parameters:
Unknown.
&,16,2
: Use menu
Parameters:
&,16,2, _?_, _menu%(field,record)_, _item_count?_, _?_, _?_, _menu_height?_, _?_, _?_, _?_
Examples:
3350 &,16,2,34,m%(.,1),n,17,2,n/2+.5,2,6,.:lm=a%+1:&,70,.,n/2+8.5:&"{white}":return
Returns:
a%
: item number selected
&,16,3
: ?
Lightbar Reference
Lightbar Numbering
Title |
|
|
|
|
|
|
|
|
Decimal |
00 01 |
02 03 |
04 05 |
06 07 |
08 09 |
10 11 |
12 13 |
14 15 |
Hex |
$00 01 |
02 03 |
04 05 |
06 07 |
08 09 |
0a 0b |
0c 0d |
0e 0f |
Title |
|
|
|
|
|
|
|
|
Decimal |
16 17 |
18 19 |
20 21 |
22 23 |
24 25 |
26 27 |
28 29 |
30 31 |
Hex |
$10 11 |
12 13 |
14 15 |
16 17 |
18 19 |
1a 1b |
1c 1d |
1e 1f |
Title |
|
|
|
|
|
|
|
|
Decimal |
32 33 |
34 35 |
36 37 |
38 39 |
40 41 |
42 43 |
44 45 |
46 47 |
Hex |
$20 21 |
22 23 |
24 25 |
26 27 |
28 29 |
2a 2b |
2c 2d |
2e 2f |
Title |
|
|
|
|
|
|
|
|
Decimal |
48 49 |
50 51 |
52 53 |
54 55 |
56 57 |
58 59 |
60 61 |
62 63 |
Hex |
$30 31 |
32 33 |
34 35 |
36 37 |
38 39 |
3a 3b |
3c 3d |
3e 3f |
Title |
|
|
|
|
|
|
|
|
Decimal |
64 65 |
66 67 |
68 69 |
70 71 |
72 73 |
74 75 |
76 77 |
78 79 |
Hex |
$40 41 |
42 43 |
44 45 |
46 47 |
48 49 |
4a 4b |
4c 4d |
4e 4f |
Title |
|
|
|
|
|
|
|
|
Decimal |
80 81 |
82 83 |
84 85 |
86 87 |
88 89 |
90 91 |
92 93 |
94 95 |
Hex |
$50 51 |
52 53 |
54 55 |
56 57 |
58 59 |
5a 5b |
5c 5d |
5e 5f |
Title |
|
|
|
|
|
|
|
|
Decimal |
96 97 |
98 99 |
100 101 |
102 103 |
104 105 |
106 107 |
108 109 |
110 111 |
Hex |
$60 61 |
62 63 |
64 65 |
66 67 |
68 69 |
6a 6b |
6c 6d |
6e 6f |
Title |
|
|
|
|
|
|
|
|
Decimal |
112 113 |
114 115 |
116 117 |
118 119 |
120 121 |
122 123 |
124 125 |
126 127 |
Hex |
$70 71 |
72 73 |
74 75 |
76 77 |
78 79 |
7a 7b |
7c 7d |
7e 7f |
Lightbar Interface: &,52
BASIC &,52
Commands
&,52,position,mode
position
ranges from 0-127 decimal ($00-$7f hexadecimal--&,52,$30,0
, for example, is allowed).
mode
is 0-4 as used by BASIC.
|
clear checkmark at position |
|
set checkmark at position |
|
toggle checkmark at position |
|
read checkmark at position, return status in |
|
move “lit” portion of lightbar to position 0-72 [FIXME: or 1-73?] |
Assembly Example
FIXME
Mode 5 is reserved for use by ML routines, and is the equivalent of &,52,x,3
in BASIC. ldx
with the flag to check, jsr chkflags
, and the result (0 or 1) is returned in .a
.
ldx #$04 ; lightbar flag number
jsr chkflag ; returns flag status (0=off, 1=on) in .a
bne flag_on
beq flag_off
Memory Map
Author: Ray Kelm
During boot (contents of the ML file):
Memory range | Purpose |
---|---|
|
wedge code |
|
editor code |
|
garbage collector |
|
ECS code |
|
struct code |
|
|
|
|
|
|
Everything after this point is the same as the next section.
While running:
Memory range | Purpose |
---|---|
|
RS232 driver |
|
RS232 input buffer |
|
RS232 output buffer |
|
BASIC wedge |
|
temporary screen data |
|
|
|
|
|
array pointers |
|
days per month |
|
unused |
|
sounds |
|
net alarms |
|
ASCII to CBM translation table |
|
CBM to ASCII translation table |
|
|
|
|
|
|
|
alarm table |
|
date buffer |
|
|
|
|
|
|
|
|
|
unused |
|
|
|
editor execution location (swapped in when needed) |
|
BASIC program area |
|
BASIC ROM / Image ML routines in RAM |
|
“Protocol” block for loadable ML code |
|
swapper area |
|
interface page |
|
buffer page |
|
??? |
|
I/O memory |
|
Character ROM |
|
editor swap location (code is here when waiting to run) |
|
KERNAL ROM / Image ML “swap” code in ROM |
|
garbage collector swap module |
|
ECS swap module |
|
Struct swap module |
|
Swap1 swap module |
|
Swap2 swap module |
|
Swap3 swap module |
File Formats
Introduction
To show when options are mutually exclusive (there can be only one option chosen from a group), the following notation is used:
[ option 1 | option 2 | option 3 ]
means that of the three options presented, option 1 or option 2 or option 3 is saved in that position in the file.
e.data
e.data
is a RELative file containing BBS configuration information, as well as BBS statistics.
The record size is 31 bytes.
Record | Variable | Purpose | Possible Values |
---|---|---|---|
1 |
|
Total calls to the system |
— |
2-3 |
— |
unused |
— |
4 |
— |
one-time caller weed cutoff, in months |
|
5-11 |
— |
unused |
— |
12 |
|
Highest user account # +1 |
|
13-16 |
— |
unused |
|
17 |
|
Last caller handle |
|
18 |
|
Sub-board password for non-RELedit systems |
|
19 |
— |
Date/time of last user logoff |
|
20 |
|
Prime Time info |
Time allowed per call, Prime Time start, Prime Time end |
21 |
|
System Reservation Password |
[
|
22-30 |
— |
unused |
|
31 |
— |
Next available user account # |
|
32 |
— |
RS232 Interface Type |
[ |
33-34 |
— |
unused |
|
35 |
|
Date/time of last log reset |
|
36 |
— |
unused |
|
37 |
|
Clock set device |
[ |
38 |
|
Lt.Kernal device number |
|
39 |
— |
Autoweed cutoff, in months |
|
40 |
|
Default text color |
|
41 |
|
Printer secondary address |
|
42 |
|
Printer line feeds |
[ |
43 |
— |
Password mask character(s) |
|
44 |
— |
Log start date |
|
45 |
|
BBS time zone abbreviation/hour offset |
e.g., |
46 |
— |
unused |
|
47 |
|
BBS name |
|
48 |
|
Entering chat message |
|
49 |
|
Exiting chat message |
|
50 |
— |
Netsub ID |
increments by 1 when net post/response made |
51 |
|
BBS identifier |
e.g., |
52 |
— |
System device, drive |
For records 52-57, devices and drives are in separate fields of each record (stored as two lines separated by a carriage return). |
53 |
— |
E-Mail device, drive |
|
54 |
— |
Etcetera device, drive |
|
55 |
— |
Directory device, drive |
|
56 |
— |
Module device, drive |
|
57 |
— |
User device, drive |
|
58 |
|
Credits for new user |
s.m.protos
This is a file which describes the file transfer protocols available to a user.
1 1234567890
punter00 Punter punter20 Image 1.3 Punter xmodem01 Xmodem/CRC punter10 Relaxed Punter xmodem11 Relaxed Xmodem/CRC copier00 Copier
Offset | Purpose | Variable name |
---|---|---|
|
|
|
|
x |
|
|
x |
|
|
x |
unused |
|
Protocol display name |
|
nm.P.count
nm.P.count
stores dates, times and tracking numbers of netsub messages sent out from your board.