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.