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.