ISAM REFERENCE Version 2.10 February 3, 1995 (C) Copyright Psion PLC 1990-95 All rights reserved. This manual and the programs referred to herein are copyrighted works of Psion PLC, London, England. Reproduction in whole or in part, including utilization in machines capable of reproduction or retrieval, without express written permission of Psion PLC, is prohibited. Reverse engineering is also prohibited. The information in this document is subject to change without notice. Psion and the Psion logo are registered trademarks, and Psion, Psion MC, Psion HC, Psion Series 3, Psion Series 3a and Psion Workabout are trademarks of Psion PLC. TopSpeed is a registered trademark of Clarion Software Corporation. IBM, IBM XT and IBM AT are registered trademarks of International Business Machines Corp. Microsoft and MS-DOS are registered trademarks of Microsoft Corporation. Apple and Macintosh are registered trademarks of Apple Computer Inc. VAX and VMS are registered trademarks of Digital Equipment Corporation. Brief is a registered trademark of Underware Inc. Psion PLC acknowledges that some other names referred to are registered trademarks. Ea Se eee Contents OO eee DV TREODUCHON os. cre ciacsesdcztestsavis besksace sabteeentce ce ic thee es ca i 1 OVER VICW Pres cite ccc vapciu part tetne sacra see trt narescet em vennescattes’ ieitins dike one vessdaice 1 MPS TSAIM NR ALY wigiie ven tersestode Gaavaaabsiavenssniavedincy ss wersaye Secseevoearcceucokiacheeks 1 DBF IGS aed drauu gar tha nis det ane oe di dewey oenueatgtiad tenes Grateiunew ne ules honttcat Nt 2 PICS arsdeecceantd veunasarcwacmecuransoisnagteusias seve canueee paises ioc Seales: Staab ected 2 NUMBER OR FECORES oo ceca. ailoc feel awesseopeissavvapiaveréuecs taibesctbiacteesGshealdleccs 2 Bethe ee ES: 3550 sins wands cocuesuestn fa catpeiaaile Uened tamale noes davik ov caus tstdewonc wie orasc oe 2 BIOCK DUNERIMG i cnac acces anstyes cuyinassuestiea Madeausccauan innate es ded cuhaesiontiecses ee 2 ICY CES CHE OM ernst ceceatecsatovissanasdelsadendsastaccs dbversducenccesageiner foxtevente osha. 2 DIZELOMBaEG MNOS ic ascaveusdacsadeacensetarasrsuaiiooievdediduamesbestiuree eicanacaniclncs 3 Interface to the ISAM library.............sscssssscecceccssseccccessccccusessceseeceecscccesees 3 BOAO NG ION Esai neecestans avsseccnensaguatvcsewaseoss iiaceebataoaeetsvaeeickecuicenicet 3 Creating am (SAM :OB)OCE si. 5cc.iscsnssasteecisadeiWevevasevisesss aide keaseaeavedeaesiseeécck 4 Calling (ISAM MUNCLONS 4.iscissye2sedoacasuedsaseerdeweesecedansdssesesahuocdcvercecsa covers 4 Destroying the ISAM object..............sssssssccssssscceceseccccenesecsececsueecceceuces 4 UV PUG ASE: si seca lane vcuuwetded osanes des adynnsvauseuremettleauon secon Meraeloecate cic ccs 4 EXAMPIG PROGQHANTS « wosascredececslsoueiaavecadatheuade nee nckass ws aeer sea tee laieclbeccsseecaninl 5 Building a complete (dense) index.............cssssscccsssssccssssecececsesseueceneesees 5 Building a selective (sparse) index .............csssescccssecccsasscececcescccecceseeese 7 @ ISOM FUNCTIONS sve sestes seo choc 05 Secudeutce se buscdvscaudbasduvacbecvuaceacnnssd sata lice hedabeseae ek 9 GE MSN al MU MCHONS vases connec cu seiisenladeubuaycatedonsouauueedisoves ss cusSaceavlncsiea oo licetaas 9 Initialise an ISAM object (O_IS_INIT)...........ssssssecesscscccceecececccaueseccesecees 9 Destroy an ISAM object (O_IS DESTROY) ............ccccecsesessessssecececeesesees 10 Set the field definition (O_IS SET FIELDDEF) .............cccccsscccccesesseuseneees 10 Get the field definition (O_IS_GET_FIELDDEF) Sevestecdaied sida oeeRhuecdacvesieekeest 11 Set the key definition (O_IS SET _KEYDEPF) .............ccccsscsssseecccceeesecccuees 11 Get the key definition (O_IS_GET KEYDEP).............ccccsesssseccccesesessueecees 13 Put a value into a field (fom IS PUT CSRIEUD) 5 in sbavecsuedessscecdsscssevesceccetestacies 13 Get a value from a field (Oi IS GET GEIBUID). cccsisanseescecincsacoansovsseosantoeecs 13 Get the type of a field (0 _[S GET TYPE) au incnetecnrenecmestntsesetireecuoeroeieces 14 Get the address of the record buffer (0. IS GET_RBUP)..............cccccesees 14 Set the radix for number conversion (0 _| AS “SET RADIX) eiseaaiWwanstanvasettaxns 14 Set the text format for DOUBLES (O_ IS SET _ RADIX) daacaduece sbaveteveeauasaess 14 Add ancventry (O° 1S ADD) ssccs er cecccais sts Sons Cissvepwes doves sevavievec bevdeccecetovecess 14 Erase an entry (O IS ERASE).......ccsssccsssssccssscsssscsssssscersonecsececesssessens 14 Update an entry (O_IS_UPDATE)..............cccsseceeseccccsscceccercecseuececeeevecs 15 ata HIG FUMCNONS tise ssranii scp aes terebeeaiasdaxedtagd touted aleuumcvensuenteccteeccni dfs 15 Open a data file (O_IS DOPEN)..............ccccsssccssstceseconsesccenseneccessceeeesce 15 Flush data file buffers {0 IS DFELUSH) ic scctsacsckiv cesta dtsnsberscxevseovacdescs vases 15 Get sizeof data Tile (0! IS SIZE) 0. sis.ssccsstersssivacnssavenerenesassieccdeieedsc se 15 Read first data record (O_IS DFIRST)...........cccccssescsessescecstessecsccescesscs 15 Read next data record (O_ Is” DN EXT) idavedeves dense de deeocsedeeses csavadetectictis 16 Index file FUNCTIONS ...........ccccvesseccccccscccoretsnscseresstesceetaccsecesconsevscececeecceccee 16 Open: aniimdex: (OISIOREN) esl 5Ge inf Gscws toecsshasasinea sau celeeesadeneaaceeer ghee ecs 16 Close an index (O_ [SISO SEP cicaesterncaveastyt.temadlen eae basal ea, 16 Flush index file buffers (OCIS MBLUSH) 5 secs fea iee sicnadeavesseidebdeecnedeaathersoes 17 Set and get index flags (O_ Is” SIREAGS)ocacsetets cates docuisicdvsntsevese Sensesheons 17 Specify a filter method (O_ is PANELISTS estbiadt 2s coe bt os ssi hind vaneatee tocnaeannee: 17 Specify a duplicates method (om ISSIDUP) 23. oss tacdesrvceacs vavanand each catceeeivee 18 Bulle an: index: (OIS | IRONED). s.0 ies idcubeeexdssvacecanederecvesacadecaverlinetlccacesecs 18 Build an index from sorted data (OMS *IQBUIED) 2. cits seccovedecesssaciceeees ecees 18 Add an index entry (O_ ISBIA DD) Seth nett se create ante ata, «St ee 19 ISAM REFERENCE i Erase an index entry (O_IS_IERASE).............cssscsssscccevscorsvecesesecesscconees 19 Erase all index entries (O_ is wa IERASEALL) wok. ssscscccecatintees .cmresceterreeees 19 Get the number of index entries (OBISTIGOUNT) ciciiniressccnteecces ceStesceieees 20 Get size of an index file (O_IS | ISIZE) T Sawa case cdces salyseuieess se coe acbeascMeereeneeee 20 Find a record using an index (ORISAIFIND) 6.25.0 c.uscucsstih ce ee cee: 20 Read next indexed record (O_ is_ _INEXT) G Saline deen ve sovaatedaw asus eoeeeieteceeanete 21 Read previous indexed record (O4 ISSIBACK) & ia. cckscc codes cei acteatettectseoes 21 Read first indexed record (O_IS IFIRST) Le teet eats te cectatrauacat et ecetscaseeereones 21 Read last indexed record (O_ 1s ILAST) SCOOT TET ESTE EC CCLEER SET eee 21 Read current indexed record (O_ ISSIGURRENT) oa cs escscaseisdccccscenstesceuests« 21 CHAPTER 1 INTRODUCTION SSS_—— SSS ee eae ee a ee ey Overview This manual describes the Indexed Sequential Access Method (ISAM) dynamic library for SIBO machines (HC, $3, S3a and MC). The ISAM library provides a powerful set of functions for rapid and efficient access of Database files (DBF files). Such files consist of multiple records containing one or more structured fields. They can be created, maintained and accessed from OPL programs and database applications on the HC, S3, S3a and MC (see the Database Files chapter of the PLIB Reference manual). The ISAM library uses B-tree index files to provide rapid and efficient indexed and sequential access to DBF files. It is the most widely used form of index file simply because it is the most efficient general method of accessing database files. In brief, B-tree index files minimise the number of disk accesses per retrieval - manipulating data already in memory is much faster than accessing the disk - whilst ensuring a well balanced index i.e. no one retrieval requires an inordinately large number of disk accesses (for details see for example Structures, by Michael J.Folk and Bill Zoellick, published by Addison-Wesley Publishing Company). The ISAM library The ISAM library functions provide the following: = Fast record retrieval on a key. For example a DBF file can be searched for all records containing the key "Smith". = Very little degradation of the speed of retrieval as the number of records increases - even large DBF files can be manipulated with relative ease. = Sequential access to records that are ordered by the key (that is, next, back, first and last). For example a record with key "Smalley" that precedes a current record with key "Smith" can be rapidly found using the 0_I1s_1BACK function. = The ability to see a selection of the records in the file (by constructing a selective or Sparse index). For example all records containing the key "Smith" can be viewed. = Access to record fields with automatic conversion from numbers to text (and vice-versa) if required. = The ability to make powerful key definitions that facilitate access ordered on combinations of up to eight fields. For example all records with key fields "Smith" and "Slough" can be found with "Smith" given the higher priority. = The opening of up to 31 index files for a DBF file at any one time. For example, a DBF file containing customer details can have two indexes, one for searching on customer occupation and related details and the other for searching on customer location and related details. = The adding, erasing, and updating of records with the appropriate updating of all associated index files carried out automatically thus greatly facilitating the task of maintaining an index. ISAM REFERENCE SSS SS ee ee ee er Ty DBF files Fields The following field types are available: BYTE, UBYTE, WORD, UWORD, LONG, ULONG, DOUBLE, STRING. However, if compatibility with existing OPL or PLIB DBF functions is required, the field types must be restricted to: WORD, LONG, DOUBLE, STRING Number of records The maximum number of records that can be handled by the PLIB DBF functions is 65534. However, in ISAM the maximum is 2147483647. SSS SSS a a a ee ea eee B-tree index files The ISAM library uses B-tree index files to provide much more powerful indexed and sequential access to DBF files than would otherwise be possible. In general B-tree index files should not be constructed or maintained on a Flash SSD. There is however no reason not to read an index file from Flash SSD. Block buffering B-tree index files are block structured files having a block size of 1SAM_BLOCK_SIZE (512) bytes (in the literature these blocks are sometimes referred to as pages - the terms are interchangeable). Index files are read using a least-recently-used (LRU) block buffering scheme - blocks that are repeatedly accessed are kept in memory (typically these are blocks near the root of the B-tree index). LRU block buffering has such an impact on the performance of the B-tree algorithm that it is not reasonable to do without it. The ISAM library implements a fixed-size LRU block pool per process regardless of the number of open index files. The size is fixed by calling the ISAM function o_1s_1Nn1T and specifying zero causes the default of 20 blocks (10K bytes) to be used. If more than one ISAM object is created, the same block pool is used; if a new size is specified in 0_!s_INIT, it is ignored if there are any index files still open. The new size is used once all of the original index files are closed. The LRU block pool is implemented in an external memory segment and does not, therefore, detract from the process data segment. The segment name will be BLKSnnnn.BLK where nnnn is the process ID in hex. Key description A key consists of up to eight fields with the constituent fields prioritised according to their order - the first having the highest priority - subject to an overall maximum key size of 64 bytes. For example, keys can be constructed from eight pous-e fields or, as a further example, the first 63 characters of a single text field (stored as a leading byte count string). The field types: BYTE, UBYTE, WORD, UWORD, LONG, ULONG and DOUBLE are compared numerically whereas STRING fields are compared lexically using a given number of characters at a given offset from the start. The comparison is subject to a programmer defined collation table. The specification of the key is stored in the header of the B-tree index file and the structure is defined by ISAM_KEYDEF: 1 INTRODUCTION ——___-__—————_-—j typedef struct € WORD field; /* Field number for key */ UBYTE type; /* Type of field in key */ UBYTE flags; /* TSAM_FIELDFLAG_ASCEND or ISAM_FIELDFLAG_DESCEND */ UBYTE offset; /* Offset for start of comparison */ UBYTE len; /* Number of characters to compare */ WORD convert; /* Convert flag or collate table */ > ISAM_KEY_FIELD; typedef struct € WORD nKeyFields; /* Number of key fields following... */ ISAM_KEY_FIELD keyField[ISAM_MAX_KEYFIELDS]; > ISAM_KEYDEF; The convert field can take one of the following values: ISAM_CONVERT_NOFOLD ISAM_CONVERT_FOLD ISAM_CONVERT_UPPER ISAM_CONVERT_LOWER which range from 0 - 3, or it can be the address of a user defined 256 byte collate table. The priority for the field comparisons is the order they are specified with the first one having highest priority. Size of B-tree files The size of a B-tree file depends upon the key size; therefore, it is good practice to keep the key as compact as possible. A worst-case B-tree file is only 50% full so the maximum size of a B-tree file is approximately: 2*(number of records)*(key length + 6) For example, an index file with an eight byte key for a 1000 record file would require approximately 28K bytes of storage. However, under typical use, a B-tree will be approximately 67% full and with the ISAM_MINIMISE flag set (see the o_Is_IFLAGs function) this is increased to approximately 86%. Note also that B-trees built from sorted data using 0_1S_1QBUILD or O_IS_IQADD are significantly more compact, typically 98% or over for large numbers of records. SSS SaaS Se eee eee eee eee ee Interface to the ISAM library The ISAM library is written using object-oriented programming (OOP). A class hierarchy has been implemented such that OOP programmers can subclass the library to handle record files other than DBF files and to use index files other than B-tree files. Most of the ISAM functions can be called using conventional C (using the PLIB p_send OF p_entersend functions) and the library is compatible with any combination of CLIB and PLIB libraries. The rest of this section describes how to use the ISAM library from conventional C. In any program using ISAM, the following steps will be involved: = Load the ISAM DYL. = Create an ISAM object = Call the ISAM functions = Destroy the ISAM object Loading the DYL The ISAM library is supplied as one file 1sam.pYL. Before any ISAM functions can be called, this must be loaded. This will get a category handle which is needed for an ISAM object to be created. The loading must be done in one of two ways depending on whether it has been linked into a multiple DYL file (normally an executable) or not. ISAM REFERENCE ® If not linked to a multiple DYL file, the PLIB function p_toad! ib must be used, for example: HANDLE isamCat; p_loadl ib("ISAM.DYL", &isamCat, TRUE); will load 1sam.pyt from the current directory and write the category handle to isamCat. = If linked to a multiple DYL, the two PLIB functions p_opent ib and p_loadfilelib must be used, for example, if ISAM.DYL has been linked as the first DYL in an executable: HANDLE isamCat; VOID *chan; chan=NULL; if (p_openlib(&chan,DatCommandPtr)==0) p_loadfilelib(chan,0,&isamCat, TRUE); p_close(chan); will load IsaM.bYL from the current executable and write the category handle to isamCat. Creating an ISAM object Once the ISAM library has been loaded, an ISAM object can be created. The class of the object required is defined in isam.g as c_ptTbBF, which is an ISAM object using B-trees to access DBF files (ISAM may be subclassed to produce objects accessing other types of file). The PLIB functions p_newlibh or f_newl ibh can be used to create the object, for example: VOID *pIsam; plsam=p_newl ibh(isamCat,C_BIDBF); Since there is always some initialisation to be carried out, it is generally more convenient to use the PLIB function f_newlibhsend, for example: VOID *plsam; plsam=f_newl ibhsend( isamCat,C_BTDBF,O_IS_INIT,4096,0); will create an ISAM object and then call the function 0_1s_INIT to initialise a record buffer of 4096 bytes and the default index buffer (see the ISAM Functions chapter for the details of the 0_1s_1NIT function). Calling ISAM functions The ISAM functions are called by sending a message to an ISAM object using the PLIB functions p_send OI p_entersend. The messages are defined in isam.g and take the form 0_1s_xxx where xxx is the name of the function. Since all ISAM functions which can fail return zero for success or leave with a negative error number, p_entersend can easily be used to catch the error or p_send can be used if the error handling is done at a higher level. For example: INT c; if ((c=p_entersend4(plsam,O_IS_DOPEN, "TEST .DBF",P_FOPEN))<0) p_printfC"Open data file failed with error %d",c); catches the error whereas: p_send4(plsam,O_1S DOPEN, "TEST .DBF",P_FOPEN); passes any error to a higher level. Destroying the ISAM object The ISAM function 0_1s_DEsTROY will close the data file and all open index files and free all memory used and does not leave or return errors. However, since data is buffered, it could fail. Carefully written applications should therefore make sure that all data has been flushed and any error dealt with before calling 0_I1s_DEsTROY. The functions 0_1s_DFLUSH and 0_IS_IFLUSH must be used. Typical use There are many ISAM functions available; here is a sample in the order that they are typically used: = Create and initialise an ISAM object, use PLIB function f_newl ibhsend. 1 INTRODUCTION SS eee = Set the field definition for the data file, use 0_1S_SET_FIELDDEF. = Open or create a data file, use 0_1S_DOPEN. = Set the key definition for an index file, use 0_1S_SET_KEYDEF. = Open or create one or more index files, use 0_1S_I0PEN. = Build an index file, use 0_Is_IBUILD. = Add or erase records, use 0_IS_ADD Or 0_IS_ERASE. = Access ordered data with keys, use 0_IS_IFIND Or 0_IS_INEXT etc. = Flush buffers, use o_1s_DFLUSH and 0_IS_IFLUSH. = Destroy the ISAM object, use 0_1S_DESTROY. Example programs Note that the following two examples do not include complete error handling. Building a complete (dense) index This program creates a DBF file called ExaMPLE.oBF with one field of type Lone and appends 100 random numbers to it. It then creates and builds an index file called Ex1.BTx of these numbers in ascending order. Note that in the argument list for the setFieldDef and setkeyDef subroutines, the TopSpeed C compiler understands the three dots to indicate an undefined number of arguments of undefined type. #include #include #include #include #include GLREF_C TEXT *DatCommandPtr; LOCAL_C HANDLE isamCat; LOCAL_C VOID *plsam; LOCAL_C VOID pErrCUBYTE *mess, INT err) ¢ UBYTE buf (E_MAX_ERROR_TEXT_SIZE]; p_errs(&buf [0] ,err); P_printf("%s failed - %s",mess, &buf [0] ); p_getch(); p_exit( TRUE); } LOCAL_C VOID loadIsam(VOID) € INT c; TEXT dylname[P_FNAMESIZE]; p_fparse("ISAM.DYL", &dylname[0} ,NULL); if ((c=p_loadl ib(&dylname [0] , ,&isamCat, TRUE) )<0) pErr("Load ISAM.DYL",c); } LOCAL_C VOID createlsam(VOID) { plsam=f_newl ibhsend(isamCat,C_BTDBF,O_IS_INIT,4096,0); > LOCAL_C VOID setFieldDef(INT nFields,...) { p_send4(plIsam,0_IS_SET_FIELDDEF,nFields,&nFields+1); _- Oro ISAM REFERENCE LOCAL_C VOID setKeyDef(INT nKeyFields,...) € p_send4(pIsam,O_IS_SET_KEYDEF ,nKeyFields, &nKeyFields+1); > LOCAL_C VOID openData(TEXT *name,UINT mode) € INT c; if ((c=p_entersend4(pIsam,0_IS_DOPEN,name,mode))<0) pErr("Open data file",c); > LOCAL_C INT openIndex(TEXT *name,UINT mode) { INT ¢; if ((c=p_entersend4(pIsam,O_IS_IOPEN,name,mode) )<0) pErr("Open index file",c); return(c); > GLDEF_C VOID main(VOID) { ULONG seed; LONG lL; INT nRecords; INT indexid; INT i; loadIsam(); createlIsam(); setFieldDef(1,ISAM_FIELDTYPE_LONG); openData( "EXAMPLE .DBF",P_FREPLACE |P_FUPDATE); seed=0L; nRecords=100; p_printf("Generating %u records",nRecords); for (i=0;i p_printf ("Building index"); setKeyDef(1,0, 1SAM_FIELDTYPE_LONG, ISAM_FIELDFLAG_ASCEND); index Id=open!I ndex("EX1.BTX", P_FREPLACE |P_FUPDATE); p_send3(pIsam,O_IS_IBUILD, indexId); p_printf("Sorted data:"); p_send3(pIsam,O_IS_IFIRST, indexId); for (i=0;i p_send2(pIsam,O_IS_ DESTROY); p_getch(); p_exit(0); > 1 INTRODUCTION SS See Building a selective (sparse) index The following routine opens the DBF file called ExaMPLE DBF which was created in the previous example. It then creates and builds an index file called ex2.8Tx of those numbers which are divisible by ten in ascending order. LOCAL_C VOID divi0¢VOID) { LONG Ll; INT indexId; INT eof; createlsam(); openData("EXAMPLE.DBF",P_FOPEN); p_printf("Build index of numbers divisible by 10"); setKeyDef(1,0, ISAM_FIELDTYPE_LONG, ISAM_FIELDFLAG_ ASCEND); indexId=openIndex("EX2.BTX", P_FREPLACE|P_FUPDATE); eof=p_send2(pIsam,O_IS_DFIRST); while (eof==FALSE) € p_send5(pIsam,O_IS_GET_FIELD,0,&1,1SAM_FIELDTYPE_LONG); if (¢1%10)==0) p_send3(pisam,O_IS_IADD, indexId); eof=p_send2(plIsam,0_IS_DNEXT); > p_printf("Sorted data:"); eof=p_send3(plsam,0_IS_IFIRST, indexId); while (eof==FALSE) € p_send5(pIsam,0_IS_GET_FIELD,0,&l,ISAM_FIELDTYPE_LONG); p_printt¢("%ld",L); eof=p_send3(pIsam,O_IS_INEXT, indexId); > p_send2(pIsam,0_IS_DESTROY); > CHAPTER 2 ISAM FUNCTIONS ISAM functions are called using either p_send or p_entersend to the ISAM object created with (for example) the PLIB function p_newlibh. Most functions which can fail will return zero or a positive number for success or leave with a negative error number, giving the caller the option of catching the error using p_entersend or leaving the error handling to a higher level by calling p_send. Functions that can generate E_FILE_EoF (for example, 0_1S_INEXT), will return this negative error rather than leave. All functions can be called from standard C but o_1s_IFILTER and 0_1S_IpuP are only applicable when using object oriented programming (OOP). There are three types of functions: = General functions s Data file functions = Index file functions SSS a a a a ae eee General functions This section describes functions to perform the following: = Initialise and destroy an ISAM object. = Define and read the field definition for a data file. = Define and read the key definition for an index file. = Read and write data to the record buffer. ® Set the format for conversion of numbers to text. = Add, erase and update records in the data file with appropriate updates to all associated index files. SINT eee VOID p_send4(VOID *pIsam, O_IS_INIT, INT rBufSize, INT iBufBlocks); Initialise the ISAM object with a record buffer of length raufLen and an index buffer in an external memory segment with isufBlocks blocks (a block is 1SAM_BLOCK_sIZE (512) bytes long). If iBufBlocks is zero, the default number of blocks, 8L_DEFAULT BLOCKS (20) is used. Performs the following initialisation: = Allocates rbufLen bytes for the record buffer. = Sets the field definition to the default of 32 string fields. = Sets the key definition to the default of the first eight characters of the first string field. ISAM REFERENCE TO = Sets the radix for number conversion to the default of 10. = Sets the format for doubles converted to text to the default of p_pTOB_GENERAL with a width of 20 and a decimal point character of '.'. rBufLen sets the size of the record buffer and must be in the range 1SAM_MIN_RECORD_BUFFER (512) to ISAM_MAX_RECORD_BUFFER (16384). If it is not, p_panic will be called. The record buffer is used to read records from the data file and must be at least as long as the longest record to be read. A length of ISAM_MAX_RECORD_LENGTH+2 (4096) is guaranteed to be large enough for all records. When an index file is being built, data is read from the file in blocks as large as the record buffer; the bigger the buffer, the faster the build will be. iBufBlocks must be less than or equal to ISAM_MAX_SEG_BLOCKS (1024). Any value greater than this will cause p_panic to be called. Leaves with E_GEN_NOMEMoRY if there is insufficient memory to initialise everything. Typically, this function would be called when the object is created and can be combined into one call using (for example) the PLIB function f_newl ibhsend: plsam=f_newl ibhsend( isamCatNum, C_BTDBF,O_IS_INIT,4096,0); This will create an ISAM object and initialise it with a record buffer of 4096 bytes and the default number of index buffer blocks. Creating an ISAM object is explained further in the Introduction chapter. VOID p_send2(VOID *pIsam, O_IS_DESTROY); Destroy the ISAM object. The data file and all open index files are closed and all memory is freed. Note that if more than one ISAM object is created in the same process, the external segment memory used for buffering the indexes is shared and will only be freed when the last ISAM object is destroyed. O_IS_DESTROY can fail due to one or more write operations but will always succeed in destroying the ISAM object (freeing all memory used). No error is ever returned and the function will not leave. Carefully written applications avoid this problem by using o_1s_pFLUSH and 0_IS_IFLUSH, to flush all buffered data (and taking appropriate action if this fails) before destroying the object without risk of failure. INT p_send4(VOID *pisam, O_IS_SET_FIELDDEF, INT nFields, VOID *pArgs); Set the field definition to contain nFietds with types in the list at pargs. This field definition will be used when a data file is created. Alternatively pargs can point to an ISAM_FIELDDEF structure containing the field definition while nfields is passed as zero. The ISAM_FIELDDEF structure is defined in isam.g as: typedef struct € WORD nFields; UBYTE type[ISAM_MAX_DEFINED_FIELDS] ; > ISAM_FIELDDEF For example: LOCAL_C VOID defineFields(VOID) € ISAM_FIELDDEF fieldDef; fieldDef .nFields=2; fieldDef.type[0]=ISAM_FIELDTYPE_WORD; fieldDef.typel1]=ISAM_FIELDTYPE_LONG; p_send4(pisam,0_IS_SET_FIELDDEF,0,&fieldDef); > SS ee SS ee 10 2 ISAM FUNCTIONS —_ See is equivalent to: LOCAL_C VOID setFieldDef(INT nFields,...) € p_send4(pIsam,O_IS_SET_FIELDDEF ,nFields,&nFields+1)); > LOCAL_C VOID defineFields(VOID) € setFieldDef(2,1SAM_FIELDTYPE_WORD, ISAM_FIELDTYPE_LONG); > and both define the field structure of the data file to be two fields, the first a woRD field, the second a LONG. The maximum number of fields that can be specified is 1SAM_MAX_DEFINED_FIELDS (32) and each field type must be one of the following types: ISAM_FIELDTYPE_BYTE for a signed Byte field. ISAM_FIELDTYPE_UBYTE for an unsigned usyTE field. ISAM_FIELDTYPE_WORD for a signed worp field. ISAM_FIELDTYPE_UWORD for an unsigned uworp field. ISAM_FIELDTYPE_LONG for a signed tone field. ISAM_FIELDTYPE_ULONG for an unsigned uLonc field. ISAM_FIELDTYPE_DOUBLE for a DOUBLE field. ISAM_FIELDTYPE_STRING for a leading byte count string field. More fields than are specified in the field definition can be accessed, but they are always assumed to be of type ISAM_FIELDTYPE_STRING. Note that this specifies the field types to be used in the actual data file; however, conversion to and from I1SAM_FIELDTYPE_STRING is performed automatically by the functions 0_1S_PUT_FIELD and O_IS_GET_FIELD. See the descriptions of these two functions for further details. Similarly, index files may specify field types which differ from those specified for data file fields. The field types will be converted automatically, provided the conversion is to or from ISAM_FIELDTYPE_STRING. See the description of 0_1$_SET_KEYDEF. Retums zero if successful or leaves with &_GEN_ARG if the given field definition is invalid. ISAM_FIELDDEF *p_send2(VOID *pIsam, O_IS GET_FIELDDEF); Get the current field definition, returning a pointer to an 1SAM_FIELDDEF structure. INT p_send4(VOID *plsam, O_IS_SET_KEYDEF, INT nKeyFields, VOID *pArgs); Set the key definition (to be used for the next created index file) to contain nkeyFields with the parameters for each key field specified in the list at pArgs. This key definition will be used for the next index file created. Alternatively pArgs can point to an ISAM_KEYDEF structure containing the key definition while nFields is passed as zero. The 1SAM_KEYDEF structure is defined in isam.g by: 11 ISAM REFERENCE typedef struct € WORD field; /* Field number for key */ UBYTE type; /* Type of field in key */ UBYTE flags; /* ISAM_FIELDFLAG_ASCEND or ISAM_FIELDTYPE_DESCEND */ UBYTE offset; /* Offset for string comparison */ UBYTE len: /* Length for string comparison */ WORD convert; /* Convert flag or collate table */ } ISAM_KEY_FIELD; typedef struct € WORD nkKeyFields; ISAM_KEY_FIELD keyField[ISAM_MAX_KEYFIELDS]; } ISAM_KEYDEF; For example: LOCAL_C VOID defineKey(VOID) € ISAM_KEYDEF keyDef; keyDef .nKeyFields=2; keyDef .keyField[0] .field=3; keyDef .keyField[0] . type=ISAM_FIELDTYPE_STRING; keyDef .keyField[0] . flags=1SAM_FIELDFLAG_ASCEND; keyDef .keyField[0] .offset=0; keyDef .keyField[0] . Len=8; keyDef .keyField[0] .convert=1SAM_CONVERT_NOFOLD; keyDef .keyField[1] .field=1; keyDef.keyField[1] . type=ISAM_FIELDTYPE_LONG; keyDef .keyField[1] .flags=1SAM_FIELDFLAG_ASCEND; p_send4(pIsam,O_IS_SET_KEYDEF ,0,&keyDef); 3 is equivalent to: LOCAL_C VOID setKeyDefCINT nKeyFields,...) {€ p_send4(pIsam,0_IS_SET_KEYDEF ,nKeyFields, &nKeyFields+1); > LOCAL_C VOID defineKey(VOID) € setKeyDef(2,3, 1SAM_FIELOTYPE_STRING, ISAM_FIELDFLAG_ASCEND,0,8,1SAM_CONVERT_NOFOLD, 1, TSAM_FIELDTYPE_LONG, ISAM_FIELDTYPE_ASCEND); > The fields: offset, len and convert must only be supplied if the type is 1SAM_FIELDTYPE_STRING. The key definition is subject to the following validation: The number of key fields must be in the range 1 to 1SAM_MAX_KEYFIELDS (8). The field number for each key field must be in the range 0 to 1SAM_MAX_RECORD_FIELDS (4094). The type of each key field (the type actually stored in the index file) must be valid and must be either the same as the type specified in the current field definition or be a conversion from or to an ISAM_FIELDTYPE_STRING, The length of a key produced by this definition must be no greater than ISAM_MAX_KEY_LENGTH (64). Returns the length of a key resulting from this definition if successful or leaves with €_GEN_aRG if the key definition is invalid. 12 2 ISAM FUNCTIONS ISAM_KEYDEF “p_send3(VOID *plsam, O_IS_GET_KEYDEF, INT indexId); Get the key definition for the index indexid, returning a pointer to an 1SAM_KEYDEF structure. The value indexid is returned when an index is opened (see 0_1S_I10PEN below). INT p_send5(VOID “plsam, O_IS_PUT_FIELD, INT field, VOID *pData, INT type); Put the data at address pata into the record buffer at field number given by field. If any preceding fields have not been set, they will be automatically set to contain zeros. The type parameter is the type of the data pointed to by pdata. If type is ISAM_FIELDTYPE_STRING, the data at pData must be in the form of a leading byte string. If type is different from that specified for field number field (as reported by 0_IS_GET_FIELDDEF) and either of these two types is ISAM_FIELDTYPE_STRING, the field data will be converted between numeric and string types as necessary according to the current radix (as set by 0_IS_SET_RADIX). For example, if the field definition is set to 32 strings and the current radix is decimal (the defaults), the following code will put the value "31" into field zero in the record buffer as a leading byte count string. WORD value; value=31; p_send5(pIsam,0_IS_PUT_FIELD,0,&value, ISAM_FIELDTYPE_WORD); Returns zero if successful or leaves with one of the following negative error numbers: E_FILE_RECORD the assignment to the field would make the total record length greater than ISAM_MAX_RECORD_LENGTH (4094) or the size of the buffer specified in 0_1S_INIT. E_GEN_ARG the type conversion required is not to or from ISAM_FIELDTYPE_STRING. E_GEN_FAIL the type conversion failed because the string could not be recognised as a number. E_GEN_OVER the type conversion failed because the number is out of range. INT p_sendS(VOID *pisam, O_IS_GET FIELD, INT field, VOID *pData, INT t e@); - eT YP! Get the data from field in the record buffer into the buffer at poata. The type parameter is the type of the data required at ppata. If type is ISAM_FIELDTYPE_STRING, the data will be written to poata in the form of a leading byte string. If type is different from that specified for field number field (as reported by 0_IS_GET_FIELDDEF) and either of these two types is 1SAM_FIELDTYPE_STRING, the field data will be converted between numeric and string types as necessary according to the current radix (as set by 0_IS_SET_RADIX). For example, if the field definition is set to 32 strings (the default), the following code will get the value from field 10 in the record buffer and convert it to a LONG. LONG lValue; p_send5(pIsam,O_IS_GET_FIELD,10,&lValue, ISAM_FIELDTYPE_LONG); Retums zero if successful or leaves with one of the following negative error numbers: E_GEN_ARG the type conversion required is not to or from 1SAM_FIELDTYPE_STRING. E_GEN_FAIL the type conversion failed because the string could not be recognised as a number. £_GEN_OVER the type conversion failed because the number is out of range. 13 INT p_send3(VOID *pIsam, O_IS_GET_TYPE, INT field); Return the actual type of field in the data file. This provides the same functionality as calling 0_1s_GET_FIELDDEF and then inspecting the required field. It is included for convenience. ISAM_RECORDBUF *p_send2(VOID *plsam, 0_IS_GET_RBUF); Get the actual address of the record buffer allocated in 0_1s_1NIT, returning a pointer to an ISAM_RECORDBUF structure. This struct is not defined in any header file - users of this method function should declare the struct in their own code as: typedef struct { WORD Len; /* Length of record */ UBYTE data[2]; /* len bytes of data... */ } ISAM_RECORDBUF; This function is provided to allow direct access to the current record in the buffer, if needed. Typically, it will be more convenient to use 0_IS_GET_FIELD and ©_IS_PUT_FIELD. VOID p_send3(VOID “pIsam, C_IS_SET_RADIX, INT radix); Set the base radix for number conversion to radix. By default this is set to 10. VOID p_send3(VOID *pIsam, O_IS_SET_DFORMAT, P_DTOB *dFormat); Set the format for pousLEs converted to text to be that specified by dFormat. INT p_send2(VOID *pIsam, O_IS_ADD); Add the record currently in the record buffer to the data file and attempt to add entries to all open index files which do not have 1SAM_FLAG_MANUAL set (see 0_IS_IFLAGS). One or more of the index files may refuse to actually add the entry for any of the following reasons: = A filter method returns FALSE (see 0_1S_IFILTER). = The entry matches an existing entry in the index and a duplicate method returns FALSE (see O_IS_IDUP). " The entry matches an existing entry in the index and I1SAM_FLAG_ALLOWDUP is not set (see O_IS_IFLAGS). but no error will be given. Returns FALSE if successful or leaves with one of the negative errors returned by the PLIB function p_write. s INT p_send2(VOID *pIsam, O_IS_ ERASE); Erase the record currently in the record buffer from the data file and from all open index files which do not have ISAM_FLAG_MANUAL set (see O_IS_IFLAGS). The record buffer must contain a record read by a successful call to one of the following functions: O_IS_DFIRST, O_1S_DNEXT, O_IS_IFIND, O_IS_INEXT, O_IS_IBACK, O_IS_IFIRST, O_IS_ILAST, O_IS_ICURRENT. SSS SS Se ee eee 14 2 ISAM FUNCTIONS —. EES Retums FALSE if successful or €_FILE_EoF if the current record is end-of-file or leaves with one of the negative errors retumed by the PLIB function p write. INT p_send2(VOID *pisam, O_IS_ UPDATE); Replace the record which was read by a successful call to one of the following functions: 0_1s_DFIRST, O_IS_DNEXT, O_IS_IFIND, O_IS_INEXT, O_IS_IBACK, O_IS_IFIRST, O_IS_ILAST, O_IS_ICURRENT, by the new contents of the record buffer in the data file and all open index files which do not have 1SAM_FLAG_MANUAL set (see O_IS_IFLAGS). Returns FALSE if successful or €_FILE_Eor if the current record is end-of-file or leaves with one of the negative errors returned by the PLIB function p_write. SS ea en ee eS] Data file functions This section describes functions to perform the following: = Open or create a data file. = Flush the buffers used for the data file. = Get the current size of the data file. = Sequentially read the data file. INT p_send4(VOID *plsam, O_IS_DOPEN, TEXT *name, UINT mode); Open a data file specified by the zero terminated file specification name. The mode parameter is the same as for the PLIB function p_open(P_FSTREAM). If P_FCREATE OF P_FREPLACE is specified, the data file is created with the current field definition (see 0_1S_SET_FIELDDEF). If an existing data file is opened, the current field definition is set to that of the file opened. Only one data file can be opened per ISAM object. If an attempt is made to open more than one, P_panic will be called. Retums zero if successful or leaves with one of the negative errors returned by p_open(P_FSTREAM). INT p_send2(VOID *pisam, O_IS_DFLUSH); Flush al! data written to the data file and write the file's modification date. Returns zero if successful or leaves with one of the negative errors returned by the PLIB function P_write. See the PLIB function p_iow(P_FFLUSK) for further details on flushing. Sra INT p_send3(VOID *pIsam, O_IS DSIZE, LONG *size); Write the size (in bytes) of the open data file to size. Retums zero if successful or leaves with one of the negative errors returned by the PLIB function p_seek. INT p_send2(VOID *plsam, O_IS_DFIRST); Read the first record in the data file into the record buffer. 15 ISAM REFERENCE Returns zero if successful or £_FILE_EoF if there are no records or leaves with one of the negative errors returned by the PLIB function p_read. Read the next record in the data file into the record buffer. Should be used in conjunctions with o_1s_DFIRST to provide sequential access to the data file records in the order they are stored without the need for an index file. Returns zero if successful or E_FILE_EOF if the current record is the last record in the file or leaves with one of the negative errors returned by the PLIB function p_read. a a a a a a ed Index file functions This section describes functions to perform the following: = Open or create an index file. = Flush the buffers used for the index file. ® Build a complete (dense) index file from a sorted or unsorted data file. = Build an index for a selection of records (sparse) by one of two mechanisms: 1) Specify a function which will be called during the building of the index (OOP only). 2) Add and erase entries from the index directly. = Get the size and number of entries in an index. = Provide fast indexed access to records in the data file from a given index and match key. = Provide sequential access to records in the data file in the order defined by an index. The function 0_I1S_IOPEN returns an indexId which is then passed as a parameter to other index functions. INT p_send4(VOID *pIsam, O_IS_IOPEN, TEXT “name, UINT mode); Open an index file specified by the zero terminated file specification name. The mode parameter has the same meaning as for the PLIB function p_opencP_FSTREAM), except that P_FAPPEND should not be specified. If P_FCREATE or P_FREPLACE is specified, the data file is created with the current key definition (see 0_1S_SET_KEYDEF above). If an existing index file is opened (with a mode of P_FOPEN, optionally ored with P_FUPDATE) its key definition can be obtaining using 0_1s_GET_KEYDEF. Note that the key definition is stored in the index file itself and cannot be changed once the index file has been created. Retums an indexid from 1 to 31 if successful or leaves with one of the negative errors returned by P_open(P_FSTREAM) Or E_GEN_FAIL if an attempt is made to open more than 31 indexes. INT p_send3(VOID *plsam, O_IS_ICLOSE, INT indexId); Close the index specified by indexid and return zero. 0_IS_ICLOSE can fail due to one or more write operations but will always succeed in closing the channel (the indexid should not be used subsequently). No error is ever returned and the function will not leave. Carefully written applications avoid this problem by using 0_!s_IFLUSH to flush all buffered data (and taking appropriate action it this fails) before closing the channel without risk of failure. 16 2 ISAM FUNCTIONS INT p_send3(VOID *plsam, O_IS_IFLUSH, INT indexld); Flush all buffers used for index indextd and write the index file's modification date. Returns zero if successful or leaves with one of the negative errors returned by the PLIB function p_write. See the PLIB function p_iow¢P_FFLUSH) for further details on flushing. INT p_sendS(VOID *plsam, O_IS_IFLAGS, INT indexId, INT mask, INT value); Modify the flag bits given by mask to the state (set or clear) given by value in index indextd. Returns the new value of the flags; passing mask as Zero just reads the current flag settings. The flags available are: ISAM_FLAG_ALLOWDUP allow duplicate entries in the index. If this flag is set, duplicate entries will be added when the index is built using 0_I1s_BUILD or 0_IS_QBUILD or when entries are added with 0_1S_ADD or 0_IS_IADD. 1SAM_FLAG_MANUAL the index will not be automatically updated by calls to the general functions 0_1S_ADD, O_IS_ERASE or 0_IS_UPDATE. The index functions 0_1S_1ADD and O_IS_IERASE must be used to add or erase entries explicitly; typically, it is used to build an index to a selection of records only (a sparse index). ISAM_FLAG_MINIMIZE Minimize the storage requirement of the index by altering the way keys are inserted. The index is not compressed when the flag is set but any future additions to the index are inserted using the minimize algorithm. With the flag set, the actual insertion will be slower but the index produced will be smaller and hence a greater portion of it can be held in internal buffers which means finding the insertion point is faster. Whether it is worth setting this flag is clearly application dependent and the best way to decide is by trial and error. The flag can be set or cleared at any stage without harming the index structure. By default, all the above flags are not set. Note that these settings are stored in the index file but can be modified at any time. For example, if 1SAM_FLAG_ALLOWDUP is not set, it does not necessarily mean there are no duplicate entries in the index. It just means that the current intention is to not add duplicates. Example testId=p_send4(pIsam,0_IS_IOPEN, "TEST. INX", P_FREPLACE|P_FUPDATE); p_send5(pIsam,O_IS_IFLAGS, testId, ISAM_FLAG_ALLOWDUP, ISAM_FLAG_ALLOWDUP); creates an index file in which duplicate entries will be allowed. _ Specify a filter method VOID p_sendS(VOID *pIsam, O_IS_IFILTER, INT indexid, VOID *pObj, INT method); This function is only applicable when using object oriented programming (OOP). Specify the object at p0bj to be called with method whenever entries are added to index indextd, to facilitate the building of an index to a selection of records (a sparse index). The method is called with a pointer to the key that is being inserted and the address of a LoNG which is the data file reference. The method must return FALSE if the entry should be omitted from the index or TRUE if it should be added. To remove the filter method, pobj must be passed as NULL. 17 ISAM REFERENCE pil VOID p_send5(VOID *plsam, O_IS_IDUP, INT indexId, VOID *pObj, INT method); This function is only applicable when using object oriented programming (OOP). Specify the object at pobj to be called with method whenever a duplicate entry is added to index indexId. The method is called with a pointer to the key that is being inserted and the address of a Lonc which is the data file reference. The method must return FALSE if the duplicate entry should be omitted from the index or TRUE if it should be added anyway. There is no regard for the setting of the flag 1SAM_FLAG_ALLOWDUP in either case, ie the method called has higher priority. To remove the duplicates method, pobj must be passed as NULL. INT p_send3(VOID *plsam, O_IS_IBUILD, INT indexId); Build the index specified by indexid using its key definition to extract keys from the records in the data file. If the data file is already ordered by the key for this index, 0_1s_1aBuILD should be used to build the index much faster. The index is always built from scratch; any existing index entries are erased first. Returns FALSE if the complete build was successful and there were no duplicate entries; returns TRUE if successful but there were duplicates or leaves with one of the negative errors returned by the PLIB function p_write in which case all entries made so far will be erased. Duplicate entries The value TRUE, returned by 0_1$_IBUILD is simply to inform the caller that one or more keys extracted from the data during the build were identical. It does not, however, indicate whether more than one copy of the key has been stored in the index or not. This is controlled by the following: = Ifa duplicates method has been specified by 0_1s_1pup, its return value of TRUE or FALSE determines whether to insert or not. (This is applicable to OOP only.) = If there is no duplicates method, the setting of the flag 1SAM_FLAG_ALLOWDUP is used. INT p_send3(VOID *plIsam, O_IS_IQBUILD, INT indexId); Build the index specified by indexid using its key definition to extract keys from the records in the (sorted) data file. For this function to work, the records in the data file must be in the correct order defined by the key definition for this index. There are two advantages of this function over 0_Is_1BUILD: 1) It is much faster for a large number of records. So much faster, in fact, that it is often quicker to sort the data file (using, for example, a quick-sort algorithm) and then call 0_1s_1aBuILb to build an index than to call 0_1s_1BUILD with an unsorted data file. 2) The index file produced will generally be smaller (more compressed) than that produced using O_1S_IBUILD. Note that if the flag ISAM_FLAG_MINIMIZE is set before the call to 0_IS_QBUILD, an even smaller index file will be produced at a small cost to the time taken (see the 0_1S_IFLAGS function, above). The index is always built from scratch, so any existing index entries are erased first. Returns FALSE if the complete build is successful or leaves with one of the negative errors returned by the PLIB function p write in which case all entries made so far will be erased. Note that there is no checking for duplicate entries as there is with the o_1s_1BUILD function. 18 2 ISAM FUNCTIONS INT p_send3(VOID *plsam, O_IS_IADD, INT indexId); Add an entry to the index indexid using its key definition to extract a key from the record currently in the record buffer. The entry is added to the given index only, unlike the function 0_1s_app which adds entries to all appropriate indexes automatically. This provides, therefore, the mechanism for building and maintaining a selective (sparse) index: = Read records into the record buffer using, for example, 0_1S_DNEXT, Or O_IS_IFIND, 0_IS_INEXT with another index. = Selectively add entries to this index if certain conditions are met. This method of building an index will typically be slower than building a sparse index by calling O_IS_IBUILD Or 0_IS_IQBUILD after specifying a filter method but does not require OOP. If the entries are to be added in key order, the function 0_1s_1aapp should be used to add the entries faster. Retumis FALSE if successful or TRUE if successful but the entry is a duplicate or leaves with one of the negative errors returned by the PLIB function p_write. The decision whether to add a duplicate entry is made in exactly the same way as with 0_IS_IBUILD. INT p_send4(VOID *pIsam, O_IS_IQADD, INT indexId, INT finish); Add an entry to the index indexid in order using its key definition to extract a key from the record currently in the record buffer. The entries must be added in the correct order given by the key for this index and the parameter finish should be passed as FALsE for all entries except the last entry, when it should be passed as TRUE. The index should contain no entries before the first 0_1s_1aapp is called. The advantages of this function over 0_1s_1apD are the same as 0_IS_IQBUILD over O_IS_IBUILD. Returms FALSE if successful or leaves with one of the negative errors returned by the PLIB function P_write. Note that there is no checking for duplicate entries as there is with the 0_1s_1app function. 1S_IEF INT p_send3(VOID *pIsam, O_IS_IERASE, INT indexId); Erase an entry from the index indexid, which corresponds to the record currently in the record buffer. The entry is erased from the given index only, unlike the function 0_1s_ERASE which erases entries from all appropriate indexes automatically. This provides, therefore, the mechanism for maintaining a selective (sparse) index. Returns FALSE if successful or TRUE if there is no entry in the index which corresponds to the record in the record buffer or leaves with one of the negative errors returned by the PLIB function p_write. INT p_send3(VOID *pisam, O_IS_IERASEALL, INT indexId); Erase all entries in the index indextd. Returns zero if successful or leaves with one of the negative errors returned by the PLIB function p_write. 19 INT p_send4(VOID *pIsam, O_IS_ICOUNT, INT indexId, LONG *count); Write the number of entries in the open index file indexId to count. Returns zero if successful or leaves with one of the negative errors returned by the PLIB function p_seek. INT p_send4(VOID *pIsam, O_IS_DSIZE, INT indexId, LONG *size); Write the size (in bytes) of the open index file indexid to size. Returns zero if successful or leaves with one of the negative errors returned by the PLIB function p_seek. INT p_send4(VOID *pisam, O_IS_IFIND, INT indexId, VOID **pArgs); Find an entry in the index indexid which matches the key generated by the arguments at pargs and read the corresponding record from the data file into the record buffer. pArgs is the address of an array of pointers to key fields to be matched, terminated by NULL if fewer key fields are supplied than are specified in the key definition for this index. Returns the following: FALSE if a matching entry is found and the corresponding record is read into the record buffer. TRUE if no match is found and the record corresponding to the following index entry is read into the buffer. E_FILE_EOF if no match is found and there is no following index entry (no record is read into the record buffer). or leaves with a negative error returned from the PLIB function p_read. For example: LOCAL_C INT findEntryCINT indexId,...) { return(p_send4(pisam,O_IS_IFIND, indexId, &indexId+1)); > LOCAL_C VOID find(VoID) { UBYTE str[16]; LONG lL; L=99999L ; str [0J=3; str[ij="A'; str[2]="B'; str(3]='C'; if (findEntry(index1,&l,&str [0] ,NULL)==FALSE) p_printf ("Found") ; else p_printf("Not found"); > will search index’ for the first entry with field zero equal to 999991 and field one equal to asc. Note that the field types passed must be the same as those specified in the key definition of the index. If there is more than one entry in the index which matches the given fields, 0_1s_IFIND will always read the first one. To read any others, use 0_IS_INEXT. 20 2 ISAM FUNCTIONS INT p_send3(VOID *pIsam, O_IS_INEXT, INT indexId); Read the record corresponding to the next entry in index indexid into the record buffer. Returns zero if successful or £_FILE_EoF if the current index entry is the last one or leaves with one of the negative errors returned by the PLIB function p_read. If two or more indexes are open at the same time, this method function may return E_FILE_EOF erroneously. If you use two or more indexes simultaneously, you should access this method via a utility function of the following form: GLDEF_C INT DoInext(VOID *pIsam, INT indexId) € INT ret; ret=p_send3(pIsam,O_IS_INEXT, indexId); if (ret==E_FILE_EOF) { p_send3(pIsam,0_IS_IBACK, indexId); p_send3(pIsam,O_IS_INEXT, indexId); ret=p_send3(pIsam,O_IS_INEXT, indexId); > return(ret); > INT p_send3(VOID *plsam, O_IS_IBACK, INT indexId); Read the record corresponding to the next entry in index index!d into the record buffer. Retums zero if successful or €_FILE_E0F if the current index entry is the first one or leaves with one of the negative errors returned by the PLIB function p_read. INT p_send3(VOID *pIsam, O_IS_IFIRST, INT indexId); Read the record corresponding to the first entry in index indexid into the record buffer. Returns zero if successful or €_F1L€_EOF if there are no entries in the index or leaves with one of the negative errors returned by the PLIB function p_read. INT p_send3(VOID *pIsam, O_IS_ILAST, INT indexId); Read the record corresponding to the last entry in index indexid into the record buffer. Returns zero if successful or €_F1LE_E0F if there are no entries in the index or leaves with one of the negative errors returned by the PLIB function p_read. INT p_send3(VOID *pIsam, O_IS_ICURRENT, INT indexId); Read the record corresponding to the current entry in index indexid into the record buffer. Retums zero if successful or €_F1LE€_E0F if the current index entry is set to end-of-file or leaves with one of the negative errors returned by the PLIB function p_read. 21 INDEX IS ADD 14 -18 DESTROY 10 DFIRST 15 “DFLUSH 15 ERASE 14 GET FIELD 13 GET_FIELDDEF 11 GET_KEYDEF 13 GET_RBUF 14 GET_TYPE 14 “IADD 19 “IBACK 21 IBUILD 18 ICLOSE 16 “ICOUNT 20 “ICURRENT 21 “IDUP 18 IERASE 19 “IERASEALL 19 TIFILTER 17 “IFIND 20 IFIRST 21 IFLAGS 17 “IFLUSH 17 ILAST 21 “INEXT 21 INIT 9 “IOPEN 16 “IQADD 19 “IOBUILD 18 “ISIZE 20 “PUT FIELD 13 "SET_DFORMAT 14 SET_FIELDDEF 10 ~SET_KEYDEF 11 "SET_RADIX 14 "UPDATE 15 1111919919191 9, 92,9, 9,2,2,9,9,9,9,2,9,9,9,0,9,0.0 FIAVAIIRAA AAD ADD BADAADARARA DADO RBBB AAD D