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

—thanks to jam and X-Tec for editing help

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

$c000

++ punter

7

Print mode table

x

e.printmodes

8

Lightbar table

x

e.lightdefs

9

Alarm table

x

e.alarms

10

ASCII → Commodore translation table

x

n/a

11

Commodore → ASCII translation table

x

n/a

12

Network alarm table

x

nm.times

Example 1. Loading a Protocol

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 to load.

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 0s 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
Parsing Limitations

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

Module Structure

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

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.

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.

& 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.

Boring Background: CR/LF, CR, LF?

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, printing 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:

Table 1. Image BBS Encoded Function Keys
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 chr$(13)

f7

H

* asterisk

f8

L

^ up arrow

& 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!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:

if b then &"hello" (will not work)

if b then:&"hello" (must be used instead)

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 printed, 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 (left margin) This MCI command causes every carriage return issued by Image BBS to be followed by x spaces, which indents text x spaces. The values for x are 0 (to disable word-wrap), or 1-9, and j-o (10-15).

  • £m>x (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

bla

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$ (which outputs c$, £#3 sets 3 leading characters, £#0 sets the fill character to 0, and 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 of h, it must be converted to a string with the str$() function. This 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 using an MCI command.

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.

&,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, needs , and the appropriate parameter substituted in its place.

There are various sections which most commands use. They outline BASIC setup (variables or pokes) which need to be done before the & call can be used.

BASIC Setup:

Any pokes 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.

TODO double check this:

pl=0: convert lowercase input to uppercase.

pl=1: allow both lowercase and 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.

Bits Decimal Purpose (if set)

%00000001

1

disable typing graphics characters

%00000010

2

. or / on column one exits input

%00000100

4

disable prompt (p$)

%00001000

8

disable typing £ (the MCI command character)

%00010000

16

enable word wrap

%00100000

32

enable edit mode

%01000000

64

ignore time remaining

%10000000

128

disable typing Delete on column one to exit input

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:

These haven’t been tested, just going by what Ray said
Bits Decimal Purpose

%00000001

1

password mask enabled for output

[uses character in peek(17138)]

%00000010

2

no output

Returns:

an$: text typed at the prompt.

Examples:

TODO: write examples for each option.

poke 53252,10:p$="Name":&,1 (1)
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$ (1)

Handle: PINACOLADA
Handle: _
1 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. 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$ (1)
1 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.

Logical File Numbers

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:

s.test file
data (1)
----+----+----+----+----+----+ (2)
1 a regular string
2 a 30-character string, used to demonstrate &,2,2,25
i.read test file
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, ignoring a carriage return. The data is returned in a$. &: output a$.
5 close 2: close disk file. goto 300: go to main prompt.
Example 2. BASIC Pitfall

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 input length to 14, and uses an input mask. The mask character is displayed, rather than the real character typed.

Parameters:

poke 17138,mask: display this character instead of the user’s input

Example:

&,6: Allow password entry, displaying the mask character set by the poke above.

Returns:

an$: password in plain text


&,7 Load File

Loads a module into memory.

Parameters:

a$: the drive number and filename (e.g., "0:i.module")

Syntax:

&,7,device[,segment]


&,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

Display Entire s. Disk Directory
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

0 an$

10 tt$

20 nl

30 a%

40 f1$

1 a$

11 na$

21 ul

31 b$

41 f2$

2 b$

12 rn$

22 qe

32 dv%

42 f3$

3 tr$

13 ph$

23 rq

33 dr$

43 f4$

4 d1$

14 ak$

24 ac%

34 c1$

44 f5$

5 d2$

15 lp

25 ef

35 c2$

45 f6$

6 d3$

16 pl

26 lf

36 co$

46 f7$

7 d4$

17 rc

27 w$

37 ch$

47 f8$

8 d5$

18 sh

28 p$

38 kp%

48 mp$

9 ld$

19 mw

29 tr%

39 c3$

49 mn%

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.

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 dimensioned for array.

&,14,array,end

Output elements of array from 1-end.

See [array-table] for the arrays which correspond to array.

&,15 Convert an$

This group of functions perform various conversions on the string contained in an$.

&,15 Convert Date

an$=d1$:&,15:&an$ → displays verbose date

  1. an$=d1$: Put current 11-digit date (d1$, e.g. 60429218427) into an$

  2. &,15: Convert 11-digit date to a long date string, e.g. Thu Apr 29, 2021  4:29 P and assign that to an$

  3. &an$: Output an$

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.
Table 2. Image BBS Date Format
Position Shortcut Purpose Range

1

 w

weekday

1=Sun…​7=Sat

2-3

yr

year

00…​99 (the year within the century, 20xx, is displayed using &,15)

4-5

mo

month

01…​12

6-7

dt

date

01…​31

8-9

hr

hour

00…​11 (12:00 AM, midnight—​11:00 AM, 1 hour until noon)

80…​92 (12:00 PM, noon—​11:00 PM, 1 hour until midnight)

10-11

mi

minute

00…​59

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.

Table 3. Image BBS Date Decoding
Position Value Purpose Meaning

1

 2

weekday

Mon

2-3

21

year

2021

4-5

05

month

May

6-7

17

date

17

8-9

89

hour

 9:00 PM (9=hour, plus 80=PM)

10-11

44

minute

44

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$


&,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

Split on space, two ways
  1. an$="Hello world":&,15,6,32

This splits "Hello world" at chr$(32) (Space), resulting in an$="Hello" and a$="world".

  1. an$="Hello world":&,15,6,asc(" ")

This splits "Hello world" at the ASCII value of Space (32), resulting in an$="Hello" and a$="world".

After the split, the two strings look like this:

an$="Hello"

chr$(32)

a$="world"

If the specified character is not found in an$, a$="", a null string.
im

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.

Jump tables are useful for giving assembly language routines entry points that don’t change. In other words, if a particular routine changes in size, that would shift all the addresses to jump to around from that point forward.

You probably don’t want to search for all the BASIC sys references to the changed addresses throughout your code. Instead, just change the address that the jump table entry points to, and you can keep the BASIC sys address that calls the routine the same (stable).

Each of these instructions in a fictitious protocol assembly-language jump table take 3 bytes:

jmp $c009 ; sys 49152 sub-function 0 (&,16)

jmp $c0a5 ; sys 49155 sub-function 1 (&,16,1, also the equivalent of &,17)

jmp $c147 ; sys 49158 sub-function 2 (&,16,2)

Refer to Protocols for more information.

&,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, and L= 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)]

Table 4. Interface Table Addresses
Index peek() Hexadecimal Purpose

0

53252

$d004

Input line length

For now, refer to Pokes and Memory Locations to see the list of pokes you may use.


&,21 Write to Interface Table

Writes a byte to the interface table. This is meant to possibly eventually replace pokeing 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

Example:
&,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 dimensioned 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

&,41,0

300

&,41,1

not used

&,41,2

1200

&,41,3

2400

&,41,4

4800

&,41,5

9600

&,41,6

19200

&,41,7

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 or gosub line numbers in im, or modules

&,42 Check for ECS Command

This checks whether the command passed in an$ is a valid ECS command.

Example:

im
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:

im
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:

i/IM.ecs
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:

i/IM.ecs
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:

im
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 #

Preparation:


 xxxx a$="e.ecs.main":dr=5:gosub 19 (1)
---
1 set system drive to the Etcetera disk. gosub 19: scratch existing e.ecs.main file

Example:

i/IM.ecs
4016 ... a$=dr$+a$:&,42,5:return

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:

im:
3074 &,53

&,54 Text editor interface

&,54,0	don't preserve text in tt$() array
&,54,1	re-enter main
&,54,2	re-enter, not command

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 a record from a RELative file.


&,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.

Table 5. Error Numbers
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) are

See the Static Arrays (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.
im
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:

im:
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


&,66 Calculated goto

goto line number held in a%. If you have 14 4-digit goto targets on a line, this can save a fair amount of RAM (and BASIC interpretation time).

Parameter:

a%: line number to goto

Example:

Instead of writing:

on a% goto 3000,3100,3200,3300,3400,3500,3600,3700,3800,3900,4000,4100,4200,4300 (79 bytes)

The same thing can be written like so:

a%=3000+a%*100:&,66 (19 bytes)

Based on the value of a% (including 0), &,66 will goto lines starting at 3300 in increments of 100 (0=3300, 1=3400, 2=3500, 3=3600, etc.)


&,66,1 Calculated gosub

gosub line number held in a%. If you have 14 4-digit gosub targets on a line, this can save a fair amount of RAM (and BASIC interpretation time).

i.test structs:

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

text: a$, "Hi there!", or "Hi there, "+a$+"!"

color: is 1-15 for un-reversed colors. For reversed colors, add $80 (or

Upper left of the screen starts at column 0, row 0.

Example

&,69,4,21,left$(" "+cm$+"{21 spaces}",22),$8c
  1. &,69,4,21 position string at column 5, row 22

  1. left$(" "+cm$+"{21 spaces}",22): format the string so it’s left-justified in the 22-character Area window

  1. ,$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.

Parameters:

Upper left corner of the screen is 0,0.

column: 0-39

row: 0-24

color: 1-15, same as the MCI colors (black, 0, is excluded). $8x is reverse color x ($81 is reverse white, $8f is reverse light gray).

Question

Will this plot stuff to the screen mask area when in full screen mode? I’m pretty sure it does.

&,70 Position Terminal Cursor

Parameters:

&,70,column,row

Upper left corner of the screen is 0,0.

column: 0-39

row: 0-24

i.IM
&,70,.,n/2+8.5:&"{white}"
Fancy Title
Question for the Ages:

What is the difference between &,61 (poscrsr) and &,70 (cursposn)?

Static Arrays (Structures)

Structures (or structs) allow you to treat the memory used by arrays as blocks of memory. You can store multiple types of data in this memory, and perform operations on the data using &,60 and various sub-commands. This is much faster than a BASIC for…​next loop.

There are functions to:

  • put and get strings, and Image-formatted 11-digit dates

  • sort and filter data

  • collect information from one structure, and put the results in another array

  • load and save structures

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 or integer array. Two bytes per element of the string text can be stored per element of an integer array.

Table 6. Representation of Sample 2D Integer Array

x%(0,0)

x%(0,1)

x%(0,2)

x%(1,0)

x%(1,1)

x%(1,2)

x%(2,0)

x%(2,1)

x%(2,2)

It is suggested that you use numeric type arrays, since this will allow you to access the elements as numeric data, as well as put and get strings.

Floating point arrays (like a() or b()) use 5 bytes per element. Integer arrays (like a%() or b%()) use 2 bytes per element. When deciding to use structures, 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 structure to hold a user’s ID#, handle, and password. A module will be written to store, edit, and retrieve data to/from this structure.

  • 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 structure, let’s look in a little more detail. Here is a byte-by-byte map of the structure we designed.

Table 7. Sample Structure layout
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

Table 8. Structure Data Storage

Element

u%(0,0)

u%(0,1)

u%(0,2)

u%(0,3)

u%(0,4)

u%(0,5)

u%(0,6)

u%(0,7)

u%(0,8)

u%(0,9)

u%(0,10)

Byte Pos

00 01

02 03

04 05

06 07

08 09

10 11

12 13

14 15

16 17

18 19

20 21

Data

ID#

Handle (20 bytes)

Bytes

0 1

P I

N A

C O

L A

D A

x x

x x

x x

x x

x x

Element

u%(0,11)

u%(0,12)

u%(0,13)

u%(0,14)

u%(0,15)

u%(0,16)

u%(0,17)

u%(0,18)

Byte Pos

22 23

24 25

26 27

28 29

30 31

32 33

34 35

36

37

Data

Password (15 bytes)

unused

Bytes

P A

S S

W O

R D

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 structure, 0-18.

Of course, you may want to store more than one of these structures in memory. To do so, you would need a 2-dimensional array. This would change the dim statement to:

dim u%(18,x-1)

(Suppose that x is the number of structures you want.)

To refer to bytes in a structure:

  • the first number in the array notation is the record number (like a field of a record in a RELative file)

  • the second number is the field number (or byte number).

Record 0, field 0 (e.g., u%(0,0)) is often used to hold the number of elements in the structure.

Now down to the important part: how to use all of this! The structure system is called with either &,60,x,…​ or &,68,x,…​.

There are currently 14 sub-functions supported by the structure routines. They are documented below.

Numeric Values and Structures

The array used with structures is either an integer or floating point type. To put numeric values into—​or get numeric values from—​a structure requires no special structure calls.

You may use code similar to the following examples:

Table 9. Get number from and put number into structure
Get value Put value

f=a%(3,3)

a%(3,3)=20

Integer arrays can store values from -32768 to 32767.

&,60,0 Put String

Copies a specified string variable of a fixed length into a field in a structure.

Syntax

&,60,0,length,struct(record,field),string$

length: the maximum string length to put into the record.

array(): the array name assigned to the structure you’re reading the string from.

string$: the string name to read the structure data into.

Example
&,60,0,20,u%(1,1),na$
  1. Put a string:

&,60,0,20,u%(1,1),na$

  1. of 20 bytes:

&,60,0,20,u%(1,1),na$

  1. from the u%() array (record 1, field 1):

&,60,0,20,u%(1,1),na$

  1. into the string variable na$:

&,60,0,20,u%(1,1),na$

TODO: show putting string longer than length into struct, is it truncated?


&,60,1 Get String

This copies a string from a structure into a specified string variable.

Syntax:

&,60,1,length,struct(field,record),string$

The parameters length, struct(field,record), and string$ are the same as Put String above.

Example:

&,60,1,20,u%(11,2),a$
  1. Get a string

&,60,1,20,u%(11,2),a$

  1. of 20 bytes

&,60,1,20,u%(11,2),a$

  1. from array u% (element 11, byte 2)

&,60,1,20,u%(11,2),a$

  1. into a$.

&,60,1,20,u%(11,2),a$

In our earlier example user data structure, to access the third user’s password, you would:

  1. get a string:

&,60,1,20,u%(11,2),a$

  1. of 20 bytes:

&,60,1,20,u%(11,2),a$

  1. from the u% array (element 11, byte 2):

&,60,1,20,u%(11,2),a$

  1. into the string variable a$:

&,60,1,20,u%(11,2),a$


&,60,2 Load structure from disk

Loads the specified structure on disk into an array.

Syntax:

&,60,2,0,struct(field,record),filename$,device

Example:

&,60,2,0,u%(0,0),dr$+"u.handles",dv%
You do not have to load the file at the start of the array.

&,60,2,0,u%(0,0),dr$+"u.handles",dv%

  1. Load a structure:

&,60,2,0,u%(0,0),dr$+"u.handles",dv%

The 0 is believed to be a necessary but ignored parameter.
  1. Use the u%() array (element 0, byte 0):

&,60,2,0,u%(0,0),dr$+"u.handles",dv%

  1. Use the drive prefix dr$, plus the fictitious "u.handles" filename:

&,60,2,0,u%(0,0),dr$+"u.handles",dv%

  1. dv% is the device number to load the structure from:

&,60,2,0,u%(0,0),dr$+"u.handles",dv%


&,60,3 Save a structure to disk

This saves a structure to a specified disk file.

Parameters:

&,60,3,0,struct%(record,field),bytes,filename$,device

The parameters struct%(record,field), bytes, and filename$ are the same as in previous commands.

device should be gotten with (since u. files live on Image drive 6):

dr=6:gosub 3

to get the drive prefix, dr$, and device, dv%.

Example:

&,60,3,0,u%(0,0),3*38,dr$+"u.handles",dv%

The starting record and field numbers to save are specified by the numbers in the array notation. The number of bytes should be calculated by:

bytes per record × number of records (38 bytes × 3 records in the example).

Don’t forget: records start at 0!

The starting field and record is specified with (as above) u%(0,0).

  1. Save a structure:

&,60,3,0,u%(0,0),3*38,dr$+"u.handles",dv%

  1. The starting element is specified with array():

&,60,3,0,u%(0,0),3*38,dr$+"u.handles",dv%

  1. bytes: the number of bytes per structure, multiplied by the number of structures (3 structures × 38 bytes in the example):

&,60,3,0,u%(0,0),3*38,dr$+"u.handles",dv%

  1. drive prefix dr$ + filename (the theoretical u.handles):

&,60,3,0,u%(0,0),3*38,dr$+"u.handles",dv%


&,60,4 Put Date

Put an 11-digit date into a structure (stored in Binary Coded Decimal).

Syntax

&,60,4,0,array(a,b),string$

array(a,b): array name(a=starting structure, b=starting byte)

string$: the 11-digit date string

Example
an$="10412208234":&,60,4,0,u%(3,0),an$
Details: Binary Coded Decimal

Structs store an 11-digit date in 3 bytes using Binary Coded Decimal (BCD) format. Two decimal digits are stored per byte, using the high and low nybbles (i.e., two 4-bit halves of an 8-bit number).

an$="10412208234":&,60,4,0,u%(0,1),an$

Element

u%(0,1)

u%(0,2)

u%(0,3)

unused

Binary

%0001 %0000

%0100 %0001

%0010 %0010

%0000 %1000

%0010 %0011

%0100

%xxxx

Decimal

1      0

4      1

2      2

0      8

2      3

      4

    x


&,60,5 Get Date

Get an 11-digit date from structure. The date is stored in Binary Coded Decimal (BCD) format as shown above.

Parameters:

&,60,5,0,array(a,b),string$

array(rec,field): array name(record,field)

string$: string name

Example
&,60,5,0,u%(0,1),an$:&,15:&an$
  1. &,60,5,0,u%(0,1),an$: Get a date from the struct into an$.

  2. &,15: convert an$ into a long date string.

  3. &an$: display the long date string.


&,60,6 Scan Structures

Scan through a field in a structure, testing whether various conditions are true on variables. If the condition is true, perform an operation on another field in the structure.

Syntax:

&,60,6,num,command,a%(a,b),b%(a,b),size,bits,test

i.GF
a%=0:if s%(0,0) then:&,60,6,s%(0,0),0,s%(0,1),s%(1,1),80,1,2^ac%
i.MM.load
&,60,6,x1%(0,0),0,x1%(0,1),x1%(1,1),36,4096,2^ac%
&,60,6,x1%(0,0),5,x1%(0,1),x1%(0,1),36,8192,f
&,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%(record,field): the field on which to set bits if test is true.

record may be a dummy parameter, more tests needed.

scan%(rec,field): field to scan

size: record size in bytes

command: command number:

Table 10. Scan Struct Commands

0

2 byte and, <>0

1

2 byte and, ==0

2

2 byte cmp, <

3

2 byte cmp, >=

4

date cmp, <

5

date cmp, >=

test: the object to test for (apparently can be either a variable or a number, maybe the byte number?)

Example: i.UD from Image 2.0

The following code scans the U/D directory for entries which have an upload date older than ld$, (setting $4f on ud%(0,1) if the entry matches):

3950 &,60,6,rn,$4f,ud%(0,1),ud%(3,1),60,4,ld$:b%=a%

&,60,6: scan struct

rn: record number, how many structures to scan in the directory

$4f: %01001111 in binary, FIXME still researching the purpose of this

ud%(0,1): FIXME

ud%(3,1): Upload date

60: record size, in bytes

4: date comparison, < (less than)

ld$: last call date (the comparison object). Can apparently be a string name, or number of an array?

Returns:

a%: count of fields the comparison returns as matching test.

b%(a,b): the array containing the comparisons matching test.


&,60,7 Sort Structure

Sort a string array (only multi-dimensional?). Does not work with numeric values.

Syntax:

&,60,7,0,a$(a,b),start?

Example:

i/lo/tt maint:

&,60,7,0,a$(p+1,i),n-p


&,60,8 Scan Numbers

Scan through a specified field in a structure for non-zero values. a% holds how many non-zero values there are. The list of non-zero values is put in a specified array.

Parameters:

&,60,8,number,size,access,struct%(record,field),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?)

i/MM.load

&,60,8,x1%(0,0),36,8192+16384,x1%(0,1),x2%(1),1:x2%(0)=a%

More research needed. This value exceeds the expected access levels of 0-9 (values 1-1023).

struct%(record,field): the 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

i.UD:
&,60,8,rn,60,a,ud%(0,1),f%(1),1:f%(0)=a%
  1. &,60,8: Scan Numbers sub-command

  2. rn: Scan through rn records

  3. 60: the struct is 60 bytes per record

  4. a: filter by access level a

  5. ud%(x,1): look in the ud%(x,1) (x="don’t care") record

  6. f%(x): putting non-zero results in the f%() array

  7. 1: Start at record 1.

Returns: a%: number of results returned. 0 if none.

a%(a): one-dimensional array of results, from a%(1) to a%(a%)


&,60,9 Scan Sum

Purpose

Syntax:

&,60,9,number,size,struct%(record,field)

number: number of records to scan

size: size of record, in bytes

struct%(x,field): (record x="don’t care"), field to scan

This function call documentation seems incomplete.

Example:

None yet.

Returns:

a%: FIXME: total of values in record?


&,60,10 Copy Structure

Copy one record to another.

Syntax:

&,60,10,size,a1(a,b),a2(a,b)

size: size of record

a1(a,b): source record

a2(a,b): destination record

Example:

i/IM.logon
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 structure [fb%(0,0)], then copy record a+1 to record a in a loop.

&,60,11 Scan for String

Scan structure for a string present in a specified array.

Parameters:

&,60,11,num,size,op,str,a1(a,b),a2(b),start

num: number of records

size: size of record

op: FIXME: array number in table?

str: FIXME: string/string literal to scan for?

a1(a,b): source record to scan

a2(b): target 1-dimension array to put results into

start: record to start scanning from

Example:

None yet.

Table 11. Arrays used by Scan String
Number Array Purpose

1

tt$()

editor text array

2

bb$()

3

dt$()

4

ed$()

5

nn$()

6

a%()

7

c%()

8

d%()

9

e%()

10

f%()

11

ac%()

access info

12

so%()

subops


&,60,12 Game Scan

Purpose

Parameters:

&,60,12,count,size,a$,a%(a,b),b$

count:

size: size of the record to scan

a$:

a%(a,b):

b$:

Example:

None yet.


&,60,13 Text Read

Purpose:

Syntax: &,60,13,number,reclen,scan(),bits,text(),strlen

"menu.s" is source for "++ 2" (cursor menu) (from source, bytes in struct) ; 0 - # entries ; 1 - item type character ;2,3- item value ;4,5- credits to charge ;6,7- access ;8-39 - text