PART 2
HOW TO WRITE A VIEWSTORE UTILITY
by Mark Colton, author of VIEW, VIEWSHEET AND VIEWSTORE
XOSBGE
XOSBGE is equivalent to OSBGET, except that ViewStore error handling is
enabled.
On entry: See filing system manual for OSBGET.
On exit: VS error occurred; error code in A.
VC no error; see filing system manual for
results.
XOSBPU
XOSBPU is equivalent to OSBPUT, except that ViewStore error handling is
enabled.
On entry: see filing system manual for OSBPUT.
On exit: VS error occurred; error code in A.
VC no error; see filing system manual for
results.
XOSCLS
XOSCLS is equivalent to OSFIND with A=0, in order to close a file.
ViewStore error trapping is also enabled.
On entry: Y contains handle of file to be closed.
On exit: VS error occurred; error code in A.
VC file closed successfully.
X,Y undefined.
XOSGBP
XOSGBP is equivalent to OSGBPB, except that ViewStore error handling is
enabled.
On entry: See filing system manual for OSGBPB.
On exit: VS error occurred; error code in A.
VC no error; see filing system manual for
results.
CALUTI
CALUTI is provided to allow utilities to call other programs stored in
utility file format. The SELECT utility, which is provided with ViewStore,
uses this call to call the SORT program when it is required. Parameters can
be passed between the programs using temporaries, or other memory space.
The CALUTI call can be thought of as the logical equivalent of the Basic
CHAIN statement. The utility should exit under the prefix given for
utilities; CALUTI applies the utility prefix to the name given
automatically. If the utility is not found, the "Insert utility disc and
hit a key" message will be generated, and ViewStore will wait until a key is
pressed before continuing.
On entry: A contains low byte of address of name of
utility to be loaded. Name must be
terminated by Carriage Return.
Y contains high byte of address of name of
utility to be loaded.
TEMP14 contains the address of the first byte of
free memory that the utility being loaded is
to use. This will normally be the same
value as passed to the initial utility.
On exit: VS error occurred; error code in A. Otherwise,
control is passed to the new utility.
Floating Point
Unfortunately, a discussion of floating point is outside the scope of this
document. However, certain of the key routines in a floating point package
are in the ROM itself, and entry points to these routines are provided.
The REPORT utility which is provided with ViewStore uses these routines, and
implements many more inside itself. The routine most obviously missing from
this set is a routine to output a floating point number in ASCII. If you
wish to do this, you will have to work out how to do it yourself.
I can refer you to the "Advanced Basic Rom User Guide", published by the
"Cambridge Microcomputer Centre", which contains useful information about
the floating point package in Basic, and how it works. The floating point
in ViewStore works in the same way.
Remember that there is no need to understand floating point to write a
utility, since the date in ViewStore files is stored in ASCII format, not as
floating point numbers. Use of floating is only necessary when you wish
your utility to provide floating point arithmetic.
The two accumulators, FWRK and FACC are in zero page. If you are not using
the floating point package in your utility, you can use the zero page
allocated to the accumulators for your own purposes.
FONE Sets FACC to value of one.
FTENFX Multiplies FACC by 10 (not normalised).
FTENGQ Divides FACC by 10 (not normalised).
FADDWI Adds FACC and FWRK; answer in FACC, not rounded.
FTENX Multiplies mantissa by 10.
FRDDK Reads in ASCII number to FACC. Low byte of address of
string in A; high byte of address of string in Y.
FTST Tests number of FACC and sets flags.
FNEG Swaps sign of number in FACC.
FCLR Sets FACC to zero.
FADDW Adds FACC and FWRK; answer in FACC, rounded.
FDIVA Divides FACC by FWRK; answer in FACC.
FMULX Multiples FACC by FWRK; answer in FACC.
General
These routines are an assortment of useful subroutines for which entry
points are provided.
GETDEC Get a decimal number.
KINCH Flush keyboard buffer, and get an input character.
MULPLY Multiply two single byte integers.
OUTDEC Output a decimal number.
PSTRNG Output a string.
RELLIN Read a line of input.
SKPCBL Skip blanks.
GETDEC
GETDEC reads a number as an ASCII string and converts it into binary. The
maximum size of a binary number that it can return is two bytes. No errors
are generated for overflows; GETDEC will return the bottom sixteen bits of
an arbitrarily large number.
On entry: TEMP06 points to start of string.
Y gives offset from beginning of string to
start of ASCII number; no leading blanks
allowed.
On exit: A contains low byte of number.
X contains high byte of number.
Y is updated to point to the non-numeric
character that terminated the number.
EQ no number was found; A,X,Y undefined.
KINCH
Call this routine to get a character of input from the keyboard. The
keyboard buffer is flushed first. ESCAPEs are detected and acknowledged
automatically, using the OSBYTE 126 call, and the Carry flag indicates
whether ESCAPE was detected.
On entry: No entry conditions.
On exit: CC A contains input character.
CS ESCAPE was detected.
MULPLY
MULPLY multiplies two eight bit numbers together, giving a sixteen bit
result:
On entry: A contains an 8-bit number.
Y contains an 8-bit number.
On exit: A contains the low byte of the result.
Y contains the high byte of the result.
CS if Y is non-zero (the result is greater than
255).
X preserved.
OUTDEC
Call OUTDEC to output a sixteen bit decimal number to the VDU.
On entry: X contains the low byte of the number.
Y contains the high byte of the number.
On exit: A,X,Y undefined.
PSTRNG
PSTRNG outputs a string in-line with the code to the VDU. The string must
be delimited with a null, zero byte.
For example: JSR PSTRNG
EQUS "This will be output to the VDU"
EQUB 0
On entry: Immediately following the JSR call, there is a
string delimited with a null. The string must
not be more then 256 characters long, including
the delimiter.
On exit: A,Y undefined.
X preserved.
RELLIN
RELLIN reads a line of input, and puts it into LINBUF. The input is
terminated with a Carriage Return or an ESCAPE. The OSWORD 0 call is used
to get the input. TEMP06 is left pointing to the beginning of LINBUF, and Y
gives the offset to the first non-space character in LINBUF.
On entry: No entry parameters.
On exit: LINBUF contains the line of input; maximum 256
characters.
TEMP06 points to LINBUF.
CMDPAR gives offset from TEMP06 to the first
non-space character.
CS ESCAPE terminated input.
SKPCBL
SKPCBL skips spaces in a line of input, terminated by a Carriage Return.
On entry: TEMP06 points to beginning of input string.
CMDPAR gives offset from start of string to start
skipping spaces.
On exit: CMDPAR gives offset to first non-space character
after initial value.
A contains first non-space character.
EQ hit CR at end of line, before non-space
character was found.
The Index System
The ViewStore ROM contains a set of routines for creating and maintaining
index files. These are used internally by code in the ROM, and also by the
INDEX utility. They are very powerful and could be used by extra utilities
to great effect.
You will be familiar with the way the ViewStore itself uses the index
system. A utility could use indexes side by side with the ROM, or it could
build and maintain indexes for its own purpose.
In a ViewStore index file, you can store a "key", and associate with the key
a pointer value, 4 bytes in size. They key can be any string of ASCII
characters, and the pointer value any four byte integer, but usually the
pointer value is used to remember a record file address.
The characters that make up an index key must be between the values 32 and
254, inclusive. Since the alphabetical value of numbers and dates is not
the same as the value we generally wish these data types to have (that is
numbers in numerical order, and dates in age order), the ASCII number and
date fields as they are stored in ViewStore data files must be converted
into another form before being sent to the index system. A routine, ADJVAL,
is provided to do this. Remember, if you are building or altering an index
file, to use the ADJVAL routine on the key.
The index system uses a technique akin to that of IBM's ISAM (indexed
sequential access method) and VSAM (virtual sequential access method)
systems.
Nearly all the calls to alter an index file are made through one routine,
with a reason code: ISAM.
ISAM uses some workspace in the language workspace area. If you're not
using the index system, the utility can use this workspace for its own
purposes.
ADJVAL Routine to adjust values of different key types.
CCRTIX Create an index file.
GETIXN Return index name for a given field number.
IDXSCH Search for an index, given a field name.
ISAM General entry point to ISAM package.
ADJVAL
This routine is called before sending a key to ISAM for an operation. It
adjusts the value of number and date fields into "index format", ready for
ISAM.
If you give it a date value to adjust, it will check the validity of the
date as it is processing the value. An error code is returned if a problem
is found with the date; in this case the value left in the buffer will be
legal, but will be an incorrect conversion from the date that you supplied.
On entry: X has field number of field being adjusted.
LINBUF has field value to be adjusted, delimited
with an end of field marker.
On exit: LINBUF contains adjusted field value.
CS error was found in date value.
CRTIX
CRTIX is used to create a new index file. You must supply the name of the
file, and the number of bytes of disk space that you wish to reserve for the
file. If a file with the name that you have exists already, it will be
overwritten.
The maximum amount of space that you can reserve is 65535 bytes.
On entry: FBLOCK has filename of file that you wish to create,
with PREFIX already inserted.
A contains keysize of file.
X contains low byte of number of bytes to
reserve.
Y contains high byte of number of bytes to
reserve.
On exit: VC file created OK.
VS error occurred; error code in A.
GETIXN
GETIXN extracts the name of the index for a particular field from the format
file, and places it in FBLOCK, with the index prefix automatically inserted.
On entry: X contains the field number of the field for
which you require the index name.
On exit: CC no error; name is in FBLOCK with prefix.
CS error occurred; error code is in A.
IDXSCH
Given a field name specification (which may include the wildcards "?" and
"*"), IDXSCH looks for a field with this name, and checks whether this field
has an index switched on.
On entry: LWORK contains field name to search for, which may
contain wildcards.
A contains field number of field to start
searching from.
On exit: CC field found OK; X contains number of field
found.
CS no field found; error code in A.
ISAM
ISAM is the routine that you call to perform operations on an index file.
The reason code of the operation you wish to perform is loaded into A. A
summary of reason code values is given at the end in table 4.
All calls to ISAM update the Carry and Overflow flags. The carry flag
indicates whether an "internal" error occurred - such as "No key found".
The Overflow flag indicates when a filing system error occurred - such as
"Disk fault". A list of internal ISAM errors is given in table 5. Note
that you can't call the error reporting routine REPERL with an internal ISAM
error code; the internal code is only for checking within a program.
Key values are passed to ISAM in LINBUFl 4 byte pointer values are passed in
REG1. ISAM can handle a maximum of nine indexes open at one time. The
maximum size of a key is 105 bytes.
Indexed sequential files have the two features that you can locate a
particular key by giving its value, and that you can also read up and down
the index in key order. ISAM works by having a "position". Certain calls
set the file "position", some move the position up and down, and some calls
destroy the position altogether. The "Search" call sets the file position;
the "Next" and "Previous" calls move the position, and the "Insert" and
"Delete" calls destroy the position.
If you execute a "Next", or a "Previous" call on an index file with no
position, the index is said to be set at the beginning.
The A, X and Y registers are all undefined after a call to ISAM.
Reason code Effect
A=ISMFLO Tell ISAM that file is open.
Before you make this call, you should have opened the file
with the filing system. This call just informs ISAM that
you have opened the file, and tells it to reverse some
workspace for the file.
On entry: Y contains handle of already opened
file, as returned by the filing
system.
On exit: The file position is reset.
VS file already open; internal error
code in A.
CS internal error occurred; internal
error code in A.
A=ISMSCH Search for key in index.
This call attempts to find the key in LINBUF in the index
that you specify. If no key is found, the index is still
"positioned", and you can use the "Get next key" and "Get
previous key" calls. A subsequent "Get next key" call
after a key was not found, returns the next highest value
key that is in the index.
On entry: Y contains the handle of the file.
LINBUF contains key to search for.
On exit: VS filing system error occurred; error
code in A.
CS key not found; internal error code in
A.
The file position is set.
REG1 contains pointer value of key, if
found.
A=ISMINS Insert key into index.
This call inserts the key in LINBUF into the index file.
On entry: Y contains the handle of the file.
LINBUF contains the key to insert.
REG1 contains pointer value to be
associated with the key.
On exit: The file position is reset.
VS filing system error occurred; error
code in A.
CS index is full; internal error code
in A.
A=ISMNXT Return next sequential key.
This call returns the pointer value of the next sequential
key, from the current file position.
On entry: Y contains the file handle.
On exit: VS filing system error occurred; error
code in A.
CS At end of file; internal error code
in A.
The file position is advanced by
one.
REG1 contains the pointer value
associated with the key.
A=ISMDEL Delete key from index.
This call deletes the specified key and associated pointer
value from the index file.
On entry: Y contains the file handle.
On exit: The file position is reset.
VS filing system error occurred; error
code in A.
CS Key not found; internal error code
in A.
REG1 contains the pointer value
associated with the key.
A=ISMCLS Close file.
This call closes the file; it both calls the filing system
to close the file, and closes the file within ISAM as well.
This is slightly different from the ISMOPN call, which
requires the filing system open call to be separate.
On entry: Y contains the file handle.
On exit: VS filing system error occurred; error
code in A.
A=ISMPRE Return previous key in index file.
This call returns the pointer value of the previous
sequential key in the index, from the current file position.
On entry: Y contains the file handle.
On exit: VS filing system error occurred; error
code in A.
CS Beginning of file; internal error
code in A.
The file position is moved back by
one.
REG1 contains the pointer value
associated with the key.
Printer Control Routines
The printer control routines handle the printer driver for the utility. A
printer driver must be loaded from ViewStore Command Mode before calling the
utility, or the default printer driver in the ROM is used.
Highlights can be sent to the printer driver from a utility, but there is no
provision for handling of the printer options byte or microspacing.
Highlights begin at 128 for highlight 1.
A utility can test the state of the printer by examining the location
PRNFLG. If bit 7 of PRNFLG is set, then the printer is switched on. If bit
6 of PRNFLG is set, then the printer is not actually on, but waiting: a
call to PRNON will switch on the printer.
The printer should be switched off before reporting errors.
ASKPRN Ask about printer.
PRNON Switch waiting printer on.
PRNOFF Switch printer off.
PSCOUTT Send character to printer/screen vector.
ASKPRN
This routine prompts the user with the question "Screen or Printer (S,P)?".
According to the response, bit 6 of PRNFLG is updated to indicate whether
the printer is waiting. If bit 6 is set, a subsequent call to PRNON by the
utility will switch on the printer.
On entry: No entry conditions.
On exit: PRNFLG Bit 6 set if printer is waiting; clear if
screen is to be used.
A,X,Y undefined.
PRNON
If the printer is waiting, that is bit 6 of PRNFLG is set, a call to PRNON
will switch it on, calling the printer on routine in the printer driver.
On entry: No entry conditions.
On exit: A,X,Y undefined.
PRNOFF
If the printer is switched on, a call to PRNOFF will switch it off.
On entry: No entry conditions.
On exit: PRNFLG Bit 7 clear. Bit 6 unaltered.
A,X,Y undefined.
PSCOUT
This routine vectors characters either to the screen or the printer,
depending which is enabled. A utility which wishes to use the printer
optionally should send all output to this routine, and in conjunction with
the ASKPRN, PRNON and PRNOFF calls, output can be directed by the user of
the utility to the screen or printer, depending on his answer to the ASKPRN
question.
PSCOTT automatically strips off trailing spaces from printer output.
On entry: A contains character to be printed. Highlight
codes begin at 128 for highlight 1.
On exit: A,X,Y preserved.
Summaries
Table 1 - Routines and Addresses
Routine Address Temporaries Altered
PSCOTT &802A
KINCH &802D
PRNON &8030 10
PRNOFF &8033 10
ISAM &8036 01,02,03,04,05,06,08,10,14
FONE &8039
FTENFX &803C
FTENFQ &803F
FADDW1 &8042
FTENX &8045
GETXFL &8048 04,05,06,06,11
INIIMF &804B 00,04,05,06,07,10,11,12
CMPFLD &804E 01,02,03,04,05
RELLIN &8051 06,07,08
FRDDK &8054 04,05,10
FTST &8057
FNEG &805A
FCLR &805D
FADDW &8060
FDIVA &8063 LWORK
FMULX &8066
REPERL &8069 04,05,06,07,10,11,12
SETDPS &806C
GETFRC &806F 04,05,06,07,11
OUTDEC &8072 04,10,11
NXTIMF&8075 03,04,05,10
SCHFLD &8078 02,03,04,05,06,07,11
CHKEOR &807B
CHKEOF &807E
PSTRNG &8081 12
MULPLY &8084 05,10
GETDEC &8087 05,10
ADJVAL &808A 01,02,03,04,05,06,07,10,11
CALUTI &808D 03,04,05,06,07,08,09,10,11,12,LWORK
SKPCBL &8090
STXPRE &8093 05
MOVFBK &8096
MOVNAY &8099
CHKDIR &809C 05
SETDIR &809F 04,05
OSHCAL &80A2
CRTIX &80A5
GETKYW &80A8 02,04,05,06,07,10,11
IDXSCH &80AB
GETIXN &80AE
GETWID &80B1 04,05,06,07,10,11
CALSBN &80B4 04,05,06,07,10,11
SIZFLD &80B7
GETFLD &80BA 04,05,06,07,11
SCHFLN &80BD 02,03,04,05,06,07,11
ASKPRN &80C0 06,07,08,12
OPFILE &80C3
XOSCLS &80C6
XOSBGE &80C9
XOSBPU &80CC
XOSGBP &80CF
XOSARG 780D2
Table 2 - Field Numbers of the Header
DIFDES 1 Description
DIFDSM 2 Display mode S/C
DIFRCS 3 Record size
DIFCAP 4 Capacity
DIFIDX 5 Index field
DIFSCM 6 Screen Mode
Table 3 - Field Numbers of the Format File
RFFFNA 1 Name
RFFWID 2 Width
RFFTYP 3 Type
RFFPOX 4 X screen position
RFFPOY 5 Y screen position
RFFALS 6 Scroll Y/N
RFFDCP 7 Decimal places
RFFRLO 8 Low limit
RFFRHI 9 High limit
RFFIDX 10 Index Y/N
RFFKYW 11 Key width
RFFIXN 12 Index name
RFFPRO 13 Prompt
RFFVLS 14 Value list
Table 4 - ISAM Commands
ISMFLO 0 open file
ISMSCH 1 search
ISMINS 2 insert key
ISMNXT 3 next key
ISMDEL 4 delete key
ISMCLS 5 close file
ISMPRE 6 previous key
Table 5 - ISAM Internal Errors
ISEFLO 0 file already open
ISEKXP 1 beginning of file for previous key
ISELSK 2 end of file for next key
ISEKXI 3 key already exits
ISENKF 4 no key found
Table 6 - Memory Layout
ViewStore variables available for read by the utility
VWSLIM &B memory limit
FILMOD &44 editing file or not
PRNFLG &47 printer flag
XSSAVE &48 stack save for filing system
SSAVE &49 stack save for ISAM & FP
CURCHN &4A intermediate file channel
EFILE &4B main file channel
REG1 &4C 4-byte register
Temporaries
TEMPFD &50 single byte temporaries
TEMPFE &51
TEMPFF &52
TEMP00 &53
TEMP01 &54
TEMP02 &55
TEMP03 &56
TEMP04 &57
TEMP05 &58
TEMP06 &59 two byte temporaries
TEMP07 &5B
TEMP08 &5D
TEMP09 &5F
TEMP10 &61
TEMP11 &63
TEMP12 &65
TEMP13 &67
TEMP14 &69
VWSSTZ &6B start of zero page workspace
FACCS &6B floating point accumulator
FACCXH &6C
FACCX &6D
FACCMA &6E
FACCMB &6F
FACCMC &70
FACCMD &71
FACCMG &72
FWRKS &73 floating point work accumulator
FWRKXH &74
FWRKX &75
FWRKMA &76
FWRKMB &77
FWRKMC &78
FWRKMD &79
FWRKMG &7A
VWSXTZ &7E start of free if using FP
OSFARA &500 OSFILE/OSHCAL work area
LWORK &50D work area - 16 bytes
FBLOCK &563 filename work area - 27 bytes
VWSSTL &5D3 start of language workspace
LINBUF &5DC line buffer/ISAM key buffer (256 bytes)
VWSXTL &6DC language workspace after LINBUF
VWSITL &799 start of language workspace if using ISAM.
Table 7 - Offsets for Prefixes
DATPRE 0 data prefix
FMTPRE &E format prefix
IDXPRE &1C index prefix
SRTPRE &2A sort prefix
UTIPRE &38 utility prefix
Table 8 - Offsets for Filenames
EFLNAM &1B data file name
FFLNAM &2B format file name
PRNAME &35 printer name
UTINAM &42 utility name
ARGNAM &4F name work area
Table 9 - Error Codes
MEMERR 1 not enough money
MISERR 2 mistake
NEMERR 3 no end marker
BDFERR 4 bad file
ENDERR 5 end of data
NUMERR 6 not numeric
RANERR 7 range error
VLSERR 8 value not in list
TBGERR 9 overflow
REAERR 10 read error
RTBERR 11 record too big
BDIERR 12 bad directory
BDNERR 13 bad name
FLNERR 14 field not found
FNOERR 15 file not open
TMFERR 16 too many files
SKFERR 17 stack overflow
NOFERR 18 no index field
DATERR 19 bad date
NFSERR 20 no fields on screen
BDMERR 21 bad mode
ESCERR 22 escape
NDSERR 23 normal display
FDSERR 24 format edit disabled
DMOERR 25 data mode only
BPRERR 26 bad prefix
DCPERR 27 too many places
FNIERR 28 field not indexed
BDPERR 29 bad pointer
BFSERR 30 bad FS
FNXERR 127 x not found
Table 10 - File Format
&9 end of field marker
&D end of record marker
&1 end of file marker
&3 space character
&2 deleted character
&0 file pad character
Each Field in the record is terminated by an end of field marker.
Each record in the field is terminated by an end of record record.
The file is terminated by an end of file marker.
Any expansion space in a record is represented by multiple space characters
after the last end of field marker, but before the end of record marker.
A deleted record is represented by multiple deleted characters followed by
an end of record marker.
Any padding space between the end of file marker and the physical end of
file is filled with file pad characters.