Changes in Halcyon 3.05: 22 Jul 93 - Fixed problem with detecting a read-only file. In the Assign method, FileMode is set to ReadOnly if the read only file attribute is set in the file. If a network file, SharedDenyWrite is also set. 24 Jul 93 - Modified Find to go to the end of file if no match. This makes it compatible with the dBase Find procedure. 24 Jul 93 - Modified Find to call object^.FindNear. Now, the file will be positioned at the record with the next greater key if no match and the search did not go to end of file. The programmer can call Found to see if there was a match, and dEOF to see if the file is positioned at the end of file (true), or at the next greater key (false). 25 Jul 93 - Improved the speed of setting indexes in the Select method. Replaced routine to do a sequential search for the index key with record number matching the current number. New routine Finds matching record key and then confirms the record number matches. Provides significant reduction in time required. 25 Jul 93 - Improved the speed of switching indexes in the IndexOrder method. Replaced routine to do a sequential search for the index key with record number matching the current number. New routine Finds matching record key and then confirms the record number matches. Provides significant reduction in time required. 28 Jul 93 - Added the following call to allow user formula expression processing for indexes: Procedure SetFormulaProcess(UserRoutine1 : FormulaProc; UserRoutine2: XtractFunc); Assigns two user-supplied routines to process formulas to be built and used by index files. This call replaces the default DefFormulaBuild and DefFormulaXtract with the programmer's own routine via a call to SetFormulaProcess. 28 Jul 93 - Added program GS_BUILD.PAS to automatically build the TPUs for all units. 02 Aug 93 - Fixed problem in the Use command that did not clear the Object pointer when the used file changed. This was no problem except when the area was cleared (Use('')), and then Use'd again. Since the object pointer in the table was invalid, an error occured. 07 Aug 93 - Fixed Skip method to properly load the first record or the ending record in the file if the skip count resulted in a skip distance that caused access beyond file limits. 07 Aug 93 - Added statement to clear IOResult before attempting to make an IO call. If IOResult is non-zero when a command is issued, it is possible the routine will get that result code instead of the valid result. ADDED EXAMPLE PROGRAMS program TestBrow; DBase Browser TESTBROW.PAS Copyright (c) Richard F. Griffin 20 July 1993 102 Molded Stone Pl Warner Robins, GA 31088 ------------------------------------------------------------- This program demonstrates how dBase files may be browsed using Griffin Solutions units. The program opens a dBase file and proceeds to browse the file. Pressing F1 displays a list of commands available. The browse methods are in unit GSXT.BRO. Description: Procedure StartBrowse(lincnt, linwidth: integer); Initializes browse activity. The lincnt argument is the number of lines that can be displayed on screen. The linwidth argument is the line size to be displayed on screen. Must be called before any other command. Procedure ResetBrowse; Resets the browse function by releasing memory. Must be called to close the browse activity. Function GetBrowseHeader(bline: word): string; Returns the portion of the header line starting at bline for the maximum length that can be displayed on screen. Function GetBrowseLine(linnum, bline: word): string; Returns the portion of the data record to be displayed starting at bline position within the string array of the record. The function will return a string of the length that can be displayed on screen. Linnum is the row to be selected, based on the record's relative position in the display window. UpdateBrowse must be called initially to select the range of records to be displayed. Function GetBrowseRecord(linnum: integer): longint; Returns the physical record number for the record at linnum. Linnum is the row to be selected, based on the record's relative position in the display window. UpdateBrowse must be called initially to select the range of records to be displayed. Function GetBrowseBar(bline: word): string; Returns a separator line to be placed between the header and data records. This line is created by scanning the portion of the header line starting at bline for the maximum length that can be displayed on screen. If the position in the header contains the value in broSeparator, then the value from broIntersect is inserted in the line, otherwise the value in broHorizontal is inserted. Procedure MoveBrowseLeft(var posn: word); Used to compute the scroll position for a scroll left. Decrements posn by 1. It then tests to see if posn is less than 1 and sets it to 1 if it is less. This value is used by other calls to identify the starting scroll position for GetBrowseLine and GetBrowseHeader. Procedure MoveBrowseRight(var posn: word); Used to compute the scroll position for a scroll right. Increments posn by 1. It then tests to see if posn is greater than (length of the record - max line that can be displayed), and adjusts to that length if greater. This prevents scrolling beyond the length of the record. The value returned in posn is used by other calls to identify the starting scroll position for GetBrowseLine and GetBrowseHeader. Procedure RenewBrowseLine(linnum: word); Rereads the physical record for the record displayed at linnum. Linnum is the row to be selected, based on the record's relative position in the display window. UpdateBrowse must be called initially to select the range of records to be displayed. This routine needs to be called if a record is updated during the browse activity. Procedure TabBrowseLeft(var posn: word); Used to compute the scroll position for a tab left. Decrements posn to the start of the previous field, unless already at field 1. This value is used by other calls to identify the starting scroll position for GetBrowseLine and GetBrowseHeader. Procedure TabBrowseRight(var posn: word); Used to compute the scroll position for a tab right. Increments posn to the start of the next field. It then tests to see if posn is greater than (length of the record - max line that can be displayed), and adjusts to that length if greater. This prevents scrolling beyond the length of the record. The value returned in posn is used by other calls to identify the starting scroll position for GetBrowseLine and GetBrowseHeader. Procedure UpdateBrowse(action: longint); Retrieves records from the database file based on the command in action. Valid commands are: broLnDn, broLnUp, broTop, broBttm, broPgDn, and broPgUp. It retrieves as many records as is necessary to fill the number of lines specified in the StartBrowse command. -------------------------------------------------------------------------------} program TestFind; DBase File Index Find TESTFIND.PAS Copyright (c) Richard F. Griffin 24 July 1993 102 Molded Stone Pl Warner Robins, GA 31088 ------------------------------------------------------------- This program demonstrates how dBase files may use the Find call. -------------------------------------------------------------------------------} program TestFrm1; Formula Routine TESTFRM1.PAS Copyright (c) Richard F. Griffin 27 July 1993 102 Molded Stone Pl Warner Robins, GA 31088 ------------------------------------------------------------- The Formula routine in HALCYON only handles straight field names. However, the power of using objects is how simple it becomes to modify an ancestor object. The following code, taken from demo program GSDMO_06.PAS, shows creating a child object with a virtual method Formula. This method will be called anytime a formula is needed for an index action from anywhere within the ancestor object(s). In this example, the PAYMENT field is converted to a string of nine characters with two decimal places. The BIRTHDATE field is then converted to a display format (YY/MM/DD) and appended to the string. The string is then returned as the formula's result. The IndexOn command must contain the correct formula; for example: "IndexOn('DEMOFRM1','STR(PAYMENT,9,2)+DTOC(BIRTHDATE)')", so it will be stored properly in the index header for use by other programs such as dBase, FoxPro, Clipper, etc. Description: Added the following call to allow user formula expression processing for indexes: Procedure SetFormulaProcess(UserRoutine1 : FormulaProc; UserRoutine2: XtractFunc); Assigns two user-supplied routines to process formulas to be built and used by index files. This call replaces the default DefFormulaBuild and DefFormulaXtract with the programmer's own routine via a call to SetFormulaProcess. The Formula routine in HALCYON only handles straight field names. However, the SetFormulaProcess allows a user- supplied routine to be called anytime a formula is needed for an index action from anywhere within the ancestor object(s). Two routines must be provided. UserRoutine1 is a routine that parses the expression and translates into paramaters are understood by UserRoutine2. UserRoutine2 is called everytime a index key is to be extracted from a record. In this example, substrings of the first five positions of the LASTNAME and FIRSTNAME fields are combined in a string that is then returned as the formula's result. The IndexOn command must contain the correct formula; for example: IndexOn('DEMOFRM2', 'SUBSTR(LASTNAME,1,5)+SUBSTR(FIRSTNAME,1,5)'); so it will be stored properly in the index header for use by other programs such as dBase, FoxPro, Clipper, etc. ($F+) Function UFormula(st:string;var fmrec:GSR_FormRec): boolean; var FldCnt : integer; begin if (fmrec.FAlias = 'TESTFRM2') then (Correct Index?) begin (set extract table) UFormula := true; for FldCnt := 0 to 32 do fmrec.FPosn[FldCnt] := 0; fmrec.FType := 'C'; (Character key) fmrec.FDcml := 0; fmrec.FSize := 10; (5 chars from LASTNAME & FIRSTNAME) end else UFormula := true; end; Function UFormXtract(var st:string;fmrec:GSR_FormRec):boolean; begin if (fmrec.FAlias = 'TESTFRM2') then (Correct index?) begin UFormXtract := true; st := SubStr(FieldGet('LASTNAME'),1,5) + SubStr(FieldGet('FIRSTNAME'),1,5); end else UFormXtract := false; end; ($F-) . . . Select(1); Use('GSDMO_01'); SetFormulaProcess(UFormula, UFormXtract); . . To return to the default, simply use: SetFormulaProcess(DefFormulaBuild, DefFormulaXtract); Note that the assigned procedure must use far calls ($F+). Also note that SetFormulaProcess should not be called until a file has been assigned to the selected file area through Use. If no file has been assigned, Error 1008, Object is not initialized in file area, will halt the program. See TESTFRM1.PAS and TESTFRM2.PAS for demonstrations of this function. -------------------------------------------------------------------------------} program TestFrm2; Formula Routine TESTFRM2.PAS Copyright (c) Richard F. Griffin 27 July 1993 102 Molded Stone Pl Warner Robins, GA 31088 ------------------------------------------------------------- The Formula routine in HALCYON only handles straight field names. However, the power of using objects is how simple it becomes to modifiy an ancestor object. The following code, taken from demo program GSDMO_06.PAS, shows creating a child object with a virtual method Formula. This method will be called anytime a formula is needed for an index action from anywhere within the ancestor object(s). In this example, substrings of the first five positions of the LASTNAME and FIRSTNAME fields are combined in a string that is then returned as the formula's result. The IndexOn command must contain the correct formula; for example: IndexOn('DEMOFRM2','SUBSTR(LASTNAME,1,5)+SUBSTR(FIRSTNAME,1,5)'); so it will be stored properly in the index header for use by other programs such as dBase, FoxPro, Clipper, etc. -------------------------------------------------------------------------------} program TestPick; DBase File Lister TESTPICK.PAS Copyright (c) Richard F. Griffin 20 July 1993 102 Molded Stone Pl Warner Robins, GA 31088 ------------------------------------------------------------- This program demonstrates how dBase records may be selected using pick menus in Griffin Solutions units. See SHOWOFF.PAS for additional examples. --- WILL NOT RUN UNDER WINDOWS --- -------------------------------------------------------------------------------} program TestSch1; DBase Key Field Locator TESTSCH1.PAS Copyright (c) Richard F. Griffin 14 July 1993 102 Molded Stone Pl Warner Robins, GA 31088 ------------------------------------------------------------- This program demonstrates how key strings may be located in dBase files. If the GSDMO_01.DBF file does not exist, the program will display a a message that the file was not found and to run GSDMO_01 to make the file. Upon execution, the program sets the size of the cache file to a maximum of 64512 bytes. It will then ask for a LASTNAME field key to find. Enter any portion of the string. The search routine is in GSXT_SCH.PAS Description: Procedure is called as follows: Result := SearchDBF(s, FNum, fromtop) Where: s = The string to search for FNum = The record field to search fromtop = Boolean true to start from the top of the file, false to continue from the current record. Result = Starting position of the found string in the field, or zero if the string is not found. The file in the selected file (using GSOBShel) will be searched for the record field that matches the string s. Records will be read through whatever filters are set (deleted records ignored, etc.). When a match is found the starting location within the field is returned and the file is positioned with the matching record as the current record. If no match, zero is returned and the current record is positioned to the initial position as when the call was made. NOTE THAT THIS TEST IS NOT CASE SENSITIVE!! See TESTSCH1.PAS and TESTSCH2.PAS for an example of how to use the routine. -------------------------------------------------------------------------------} program TestSch2; DBase Key Field Locator TESTSCH2.PAS Copyright (c) Richard F. Griffin 14 July 1993 102 Molded Stone Pl Warner Robins, GA 31088 ------------------------------------------------------------- This program demonstrates how status may be checked while running key string searches in dBase files. This example is an extension of the status reporting example that was demonstrated in GSDMO_17.PAS. If the GSDMO_17.DBF file does not exist, the program will display a a message that the file was not found and to run GSDMO_17 to make the file. The program opens a dBase file and will ask for a LASTNAME field key to search for. Enter any portion of the string. During the search, the current record being searched is reported. -------------------------------------------------------------------------------}