home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / OPBONUS.ZIP / FBROWSE.LZH / FBROWSE.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1990-09-20  |  57.2 KB  |  1,945 lines

  1. {$R-,S-,I-,V-,B-,F+,O+,A-}
  2.  
  3. {$I OPDEFINE.INC}
  4.  
  5. {*********************************************************}
  6. {*                   FBROWSE.PAS 5.06                    *}
  7. {*       Copyright (c) TurboPower Software 1990.         *}
  8. {*                 All rights reserved.                  *}
  9. {*********************************************************}
  10.  
  11. unit FBrowse;
  12.   {-CommandWindow-based data file browser for B-Tree Filer}
  13.  
  14. interface
  15.  
  16. uses
  17.   Dos,
  18.   OpInline,
  19.   OpString,
  20.   OpRoot,
  21.   OpCrt,
  22.   {$IFDEF UseMouse}
  23.   OpMouse,
  24.   {$ENDIF}
  25.   OpCmd,
  26.   OpDos,
  27.   OpFrame,
  28.   OpWindow,
  29.   {$IFDEF UseDrag}                      {!!.06}
  30.   OpDrag,                               {!!.06}
  31.   {$ENDIF}                              {!!.06}
  32.   Filer,
  33.   VRec;
  34.  
  35.   {$I FBROWSE.ICD}  {configuration data}
  36.  
  37. const
  38.   {option codes}
  39.   fbScrollByPage   = $00000001; {scroll by page?}
  40.   fbMousePage      = $00000002; {clicking on scroll bar scrolls by page}
  41.   fbDrawActive     = $00000004; {Draw and Process leave selected item visible}
  42.   fbUseReadLock    = $00000008; {use read locks while building pages?}
  43.   fbAutoScale      = $00000010; {scale scroll bar based on low/high keys?}
  44.   fbForceUpdate    = $00000020; {force the screen to be updated}
  45.   fbFlushKbd       = $00000040; {flush keyboard buffer at boundaries}
  46.   fbBellOnFlush    = $00000080; {ring bell when flushing?}
  47.   fbBuildOnKey     = $00000100; {build function needs only the key}
  48.  
  49.   fbLockPending    = $10000000; {internal flags}
  50.   fbForceRedraw    = $20000000;
  51.   fbIsNet          = $40000000;
  52.   fbInProcess      = $80000000;
  53.  
  54.   DefFBrowserOptions : LongInt = fbMousePage+fbDrawActive+fbAutoScale+fbUseReadLock;
  55.   BadFBrowserOptions : LongInt = fbLockPending+fbForceRedraw+fbIsNet+fbInProcess;
  56.  
  57.   DefRetriesOnLock : Integer = 50;
  58.  
  59. type
  60.   ItemRowsArray = array[1..1] of StringPtr; {variably sized}
  61.   ItemRowsPtr = ^ItemRowsArray;
  62.   ItemRec =
  63.     record
  64.       irKey  : IsamKeyStr;
  65.       irRef  : LongInt;
  66.       irLen  : Word;
  67.       irRows : ItemRowsPtr;
  68.     end;
  69.   ItemRecArray = array[1..100] of ItemRec; {size is arbitrary}
  70.  
  71. type
  72.   FBrowserPtr = ^FBrowser;
  73.   BuildItemProc =
  74.     procedure (Row : Byte; var DatS; Len : Word; RecNum : LongInt;
  75.                Key : IsamKeyStr; var S : string; FBP : FBrowserPtr);
  76.   SpecialTaskProc =
  77.     procedure (RecNum : LongInt; Key : IsamKeyStr; FBP : FBrowserPtr);
  78.   FilterFunc =
  79.     function (RecNum : LongInt; Key : IsamKeyStr; FBP : FBrowserPtr) : Boolean;
  80.   UpdateProc =
  81.     procedure (FBP : FBrowserPtr);
  82.   RefreshFunc =
  83.     function (FBP : FBrowserPtr) : Boolean;
  84.  
  85.   FBrowser =    {browser for fixed-length record Fileblocks}
  86.     object(CommandWindow)
  87.       {----------------------------Procedure pointers}
  88.       fbPreMove,                  {called before each user-generated command}
  89.       fbTask : SpecialTaskProc;   {user-defined special task hook}
  90.       fbBuildItem : BuildItemProc; {user-supplied function to build an item}
  91.       fbUpdate : UpdateProc;      {called on each screen update}
  92.       fbFilter : FilterFunc;      {record filter}
  93.       fbRefresh : RefreshFunc;    {called to determine if screen refresh needed}
  94.       {----------------------------Fileblock stuff}
  95.       fbIFB : IsamFileBlockPtr;   {file block pointer}
  96.       fbDatPtr : Pointer;         {pointer to record buffer}
  97.       fbKeyNum : Integer;         {key number}
  98.       fbLowKey : IsamKeyStr;      {low key}
  99.       fbHighKey : IsamKeyStr;     {high key}
  100.       fbCurKey : IsamKeyStr;      {current key}
  101.       fbCurRef : LongInt;         {current record number}
  102.       fbRetries : Integer;        {# of retries in case of a lock error}
  103.       {----------------------------Window stuff}
  104.       fbItemRecs : ^ItemRecArray; {array of item records}
  105.       fbMaxItems : Byte;          {maximum items per window}
  106.       fbMaxRows : Byte;           {maximum rows per window}
  107.       fbRowsPerItem : Byte;       {number of rows for each item}
  108.       fbMaxCols : Word;           {maximum columns per row}
  109.       fbCurItem : Byte;           {current item}
  110.       fbColOfs : Word;            {horizontal scrolling factor}
  111.       fbFirstCol : Word;          {first column in memory}
  112.       fbOptions : LongInt;        {option flags}
  113.       fbHDelta : Byte;            {columns to jump--horizontal scroll}
  114.       fbVDelta : Byte;            {rows (items) to jump--vertical scroll}
  115.     {$IFDEF UseAdjustableWindows}
  116.       {----------------------------Other window stuff}
  117.       fbLastHeight : Byte;        {window height on last UpdateContents call}
  118.       {$IFDEF UseScrollBars}
  119.       fbLastWidth : Byte;         {window width on last UpdateContents call}
  120.       {$ENDIF}
  121.     {$ENDIF}
  122.     {$IFDEF UseScrollBars}
  123.       {----------------------------Scroll bar stuff}
  124.       fbBDelta : Byte;            {columns to jump--horizontal scroll (bar)}
  125.       fbScaleLow : Word;          {scroll bar scale--fbLowKey}
  126.     {$ENDIF}
  127.       {----------------------------Colors}
  128.       fbItemColor : Byte;         {unselected items}
  129.       fbItemMono : Byte;
  130.       fbSelColor : Byte;          {selected items}
  131.       fbSelMono : Byte;
  132.       fbDummy   : record end;     {marks end of data fields}
  133.       {....methods....}
  134.       constructor Init(X1, Y1, X2, Y2 : Byte;
  135.                        IFBPtr : IsamFileBlockPtr;
  136.                        KeyNum : Integer;
  137.                        var DatS;
  138.                        MaxRows, RowsPerItem : Byte;
  139.                        MaxCols : Word);
  140.         {-Initialize with default window options}
  141.       constructor InitCustom(X1, Y1, X2, Y2 : Byte;
  142.                              var Colors : ColorSet;
  143.                              Options : LongInt;
  144.                              IFBPtr : IsamFileBlockPtr;
  145.                              KeyNum : Integer;
  146.                              var DatS;
  147.                              MaxRows, RowsPerItem : Byte;
  148.                              MaxCols : Word);
  149.         {-Initialize with custom window options}
  150.       destructor Done; virtual;
  151.         {-Deallocate item records}
  152.       procedure ProcessSelf; virtual;
  153.         {-Process browse commands}
  154.       {...}
  155.       procedure fbOptionsOn(OptionFlags : LongInt);
  156.         {-Activate multiple options}
  157.       procedure fbOptionsOff(OptionFlags : LongInt);
  158.         {-Deactivate multiple options}
  159.       function fbOptionsAreOn(OptionFlags : LongInt) : Boolean;
  160.         {-Return True if all specified options are on}
  161.       {...}
  162.       function GetFileBlockPtr : IsamFileBlockPtr;
  163.         {-Get pointer to associated fileblock}
  164.       function GetKeyNumber : Integer;
  165.         {-Get current index key number}
  166.       function GetCurrentItem : Byte;
  167.         {-Get number of currently highlighted item}
  168.       function GetCurrentCol : Word;
  169.         {-Get column currently displayed at left edge of window}
  170.       function GetFirstCol : Word;
  171.         {-Get first column of data to be loaded into memory}
  172.       procedure GetCurrentKeyAndRef(var Key : IsamKeyStr; var Ref : LongInt);
  173.         {-Retrieve current key and record number}
  174.       procedure GetCurrentRecord(var DatS; var DatLen : Word);
  175.         {-Retrieve current record}
  176.       function GetItemString(Item, Row : Byte) : string; virtual; {!!.06}
  177.         {-Get string corresponding to specified Row of specified Item}
  178.       {...}
  179.       procedure SetCurrentRecord(Key : IsamKeyStr; Ref : LongInt);
  180.         {-Set the current record}
  181.       procedure SetKeyRange(LowKey, HighKey : IsamKeyStr);
  182.         {-Set subrange of valid keys}
  183.       procedure SetKeyNumber(KeyNum : Integer);
  184.         {-Switch index keys}
  185.       procedure SetRetries(Retries : Integer);
  186.         {-Set number of times to retry on read operations}
  187.       {...}
  188.       procedure SetNormAttr(Color, Mono : Byte);
  189.         {-Set attribute for unselected items}
  190.       procedure SetSelectAttr(Color, Mono : Byte);
  191.         {-Set attribute for selected items}
  192.       {...}
  193.       procedure SetHorizScrollDelta(Delta : Byte);
  194.         {-Set columns to jump when scrolling horizontally}
  195.       procedure SetVertScrollDelta(Delta : Byte);
  196.         {-Set rows (items) to jump when scrolling vertically}
  197.       {$IFDEF UseScrollBars}
  198.       procedure SetHorizScrollBarDelta(Delta : Byte);
  199.         {-Set columns to jump when scrolling horizontally (scroll bar)}
  200.       {$ENDIF}
  201.       {...}
  202.       procedure SetBuildItemProc(BIF : BuildItemProc);
  203.         {-Set procedure to build an item}
  204.       procedure SetFilterFunc(FF : FilterFunc);
  205.         {-Set record filtering function}
  206.       function IsFilteringEnabled : Boolean; virtual;
  207.         {-Return True if filtering is enabled}
  208.       procedure SetSpecialTaskProc(STP : SpecialTaskProc);
  209.         {-Set user-defined special task hook}
  210.       procedure SetPreMoveProc(PMP : SpecialTaskProc);
  211.         {-Set user-defined procedure to call before each command}
  212.       procedure SetScreenUpdateProc(SUP : UpdateProc);
  213.         {-Set user-defined procedure to call on each screen update}
  214.       procedure SetRefreshFunc(RF : RefreshFunc);
  215.         {-Set routine called to determine if screen refresh is needed}
  216.       {...}
  217.       procedure CharHook; virtual;
  218.         {-Called each time a regular character is entered by user}
  219.       procedure CursorLeft; virtual;
  220.         {-Called to process the ccLeft command}
  221.       procedure CursorRight; virtual;
  222.         {-Called to process the ccRight command}
  223.       procedure ScreenUpdate; virtual;
  224.         {-Called on each screen update; when current item/column changes}
  225.       procedure PreMove; virtual;
  226.         {-Called just prior to getting each keyboard command}
  227.       procedure DrawItem(Item : Byte; Highlight : Boolean); virtual;
  228.         {-Draw the specified (relative) Item of the browse window}
  229.       procedure BuildOneItem(Item : Byte; Locked : Boolean); virtual;
  230.         {-Convert specified item to a string}
  231.       procedure BuildOneRow(Row : Byte; var DatS; Len : Word; RecNum : LongInt;
  232.                             Key : IsamKeyStr; var S : string); virtual; {!!.06}
  233.         {-Convert specified row of specified item to a string}          {!!.06}
  234.       function RecordFilter(RecNum : LongInt; Key : IsamKeyStr) : Boolean; virtual;
  235.         {-Return True if this record should be displayed}
  236.       procedure SpecialTask; virtual;
  237.         {-Special task hook}
  238.       function NeedRefresh : Boolean; virtual;
  239.         {-Do we need to refresh the display?}
  240.       procedure GetRecord(Ref : LongInt; var DatS; var Len : Word); virtual;
  241.         {-Low-level routine to read a specific record}
  242.     {$IFDEF UseStreams}
  243.       constructor Load(var S : IdStream);
  244.         {-Load a file browser from a stream}
  245.       procedure Store(var S : IdStream);
  246.         {-Store a file browser in a stream}
  247.     {$ENDIF}
  248. {.Z+}
  249.       {+++ internal methods +++}
  250.     {$IFDEF UseScrollBars}     {!!.06}
  251.       procedure Draw; virtual; {!!.06}
  252.     {$ENDIF}                   {!!.06}
  253.       procedure GotError(ErrorCode : Word; ErrorMsg : string); {!!.06}
  254.       procedure UpdateContents; virtual;
  255.       procedure fbCheckLoadedColumns;
  256.       procedure fbReadLock(Lock : Boolean);
  257.       procedure fbNextKeyPrim(var Ref : LongInt; var Key : IsamKeyStr);
  258.       procedure fbSearchKeyPrim(var Ref : LongInt; var Key : IsamKeyStr);
  259.       procedure fbPrevKeyPrim(var Ref : LongInt; var Key : IsamKeyStr);
  260.       procedure fbFindKeyPrim(var Ref : LongInt; var Key : IsamKeyStr;
  261.                               NFSD : Integer);
  262.       procedure fbNextKey(var Ref : LongInt; var Key : IsamKeyStr);
  263.       procedure fbSearchKey(var Ref : LongInt; var Key : IsamKeyStr);
  264.       procedure fbPrevKey(var Ref : LongInt; var Key : IsamKeyStr);
  265.       procedure fbFindKey(var Ref : LongInt; var Key : IsamKeyStr;
  266.                           NFSD : Integer);
  267.       function  fbKeyInBounds(var Key : IsamKeyStr) : Boolean;
  268.       procedure fbScrollItemRecs(Delta, LastItem : Integer);
  269.       procedure fbBuildCurPage(Desired : Byte);
  270.       function  fbLastValidItem : Byte;
  271.       procedure fbGotoItem(Item : Byte);
  272.       function  fbDisplayItems : Byte;
  273.       function  fbOnePage(LessOne : Boolean) : Integer;
  274.       procedure fbLineUp;
  275.       procedure fbLineDown;
  276.       procedure fbPageUp;
  277.       procedure fbPageDown;
  278.       procedure fbFlushKeyboard;
  279.       procedure fbScrollVert(ScDelta, HiDelta : Integer);
  280.       procedure fbScrollHoriz(Delta : Integer);
  281.       procedure fbFirstRec;
  282.       procedure fbLastRec;
  283.       procedure fbEmptyItemRec(I : Byte);
  284.       procedure fbEmptyBrowScreen;
  285.       function  fbCurRecExists : Boolean;
  286.       procedure fbPositionCursor;
  287.     {$IFDEF UseAdjustableWindows}
  288.       procedure fbAdjustDisplay(NewH, OldH : Byte);
  289.     {$ENDIF}
  290.     {$IFDEF UseScrollBars}
  291.       procedure fbSetupForScrollBars;
  292.       procedure fbUpdateScrollBars(DoVert : Boolean);
  293.     {$ENDIF}
  294.     {$IFDEF UseMouse}
  295.       procedure fbGotoRelPos(P : LongInt);
  296.       function  fbProcessMouseCommand : Boolean;
  297.     {$ENDIF}
  298. {.Z-}
  299.     end;
  300.  
  301.   VBrowserPtr = ^VBrowser;
  302.   VBrowser =   {browser for variable-length record Fileblocks}
  303.     object(FBrowser)
  304.       procedure GetRecord(Ref : LongInt; var DatS; var Len : Word); virtual;
  305.         {-Low-level routine to read a specific record}
  306.     end;
  307.  
  308.   {-------------------------------------------------------}
  309.  
  310.   function NullFilterFunc(RecNum : LongInt; Key : IsamKeyStr;
  311.                           FBP : FBrowserPtr) : Boolean;
  312.     {-Do-nothing record filtering function}
  313.  
  314.   function NullRefreshFunc(FBP : FBrowserPtr) : Boolean;
  315.     {-Do-nothing refresh function}
  316.  
  317.   function RefreshAtEachCommand(FBP : FBrowserPtr) : Boolean;
  318.     {-Check for need to refresh before each command if no keystrokes pending}
  319.  
  320. const
  321.   RefreshPeriod : Word = 18*5;
  322.  
  323.   function RefreshPeriodically(FBP : FBrowserPtr) : Boolean;
  324.     {-Check for need to refresh every RefreshPeriod clock ticks}
  325.  
  326. {$IFDEF UseStreams}
  327. {.Z+}
  328.   procedure FBrowserStream(SPtr : IdStreamPtr);
  329.     {-Register all types needed for streams containing file browsers}
  330.   procedure VBrowserStream(SPtr : IdStreamPtr);
  331.     {-Register all types needed for streams containing file browsers}
  332. {.Z-}
  333. {$ENDIF}
  334.  
  335. var
  336.   {$IFDEF UseDrag}                      {!!.06}
  337.   FBrowserCommands : DragProcessor;     {!!.06}
  338.   {$ELSE}                               {!!.06}
  339.   FBrowserCommands : CommandProcessor;
  340.   {$ENDIF}                              {!!.06}
  341.  
  342.   {=======================================================================}
  343.  
  344. implementation
  345.  
  346. const
  347.   ScaleHigh = 32768;
  348.  
  349.   {$I FBROWSE.IN1}     {mouse, scroll bars, streams, refresh/filter functions}
  350.  
  351.   constructor FBrowser.Init(X1, Y1, X2, Y2 : Byte;
  352.                             IFBPtr : IsamFileBlockPtr;
  353.                             KeyNum : Integer;
  354.                             var DatS;
  355.                             MaxRows, RowsPerItem : Byte;
  356.                             MaxCols : Word);
  357.     {-Initialize with default window options}
  358.   begin
  359.     if not FBrowser.InitCustom(X1, Y1, X2, Y2,
  360.                                DefaultColorSet, DefWindowOptions,
  361.                                IFBPtr, KeyNum, DatS,
  362.                                MaxRows, RowsPerItem, MaxCols) then
  363.       Fail;
  364.   end;
  365.  
  366.   constructor FBrowser.InitCustom(X1, Y1, X2, Y2 : Byte;
  367.                                   var Colors : ColorSet;
  368.                                   Options : LongInt;
  369.                                   IFBPtr : IsamFileBlockPtr;
  370.                                   KeyNum : Integer;
  371.                                   var DatS;
  372.                                   MaxRows, RowsPerItem : Byte;
  373.                                   MaxCols : Word);
  374.     {-Initialize with custom window options}
  375.   var
  376.     I, J, M, N, C : Word;
  377.   begin
  378.     {in case we fail...}
  379.     fbItemRecs := nil;
  380.  
  381.     {force wUserContents on}
  382.     SetLongFlag(Options, wUserContents);
  383.  
  384.     {make sure the Fileblock is indexed}
  385.     if IFBPtr^.NrOfKeys = 0 then begin
  386.       InitStatus := epFatal+ecNoIndex;
  387.       Fail;
  388.     end;
  389.  
  390.     {initialize the window}
  391.     if not CommandWindow.InitCustom(X1, Y1, X2, Y2, Colors, Options,
  392.                                     FBrowserCommands, ucFBrowser) then
  393.       Fail;
  394.  
  395.     {calculate rows, columns, etc.}
  396.     if RowsPerItem = 0 then
  397.       RowsPerItem := 1;
  398.     if MaxRows = 0 then
  399.       MaxRows := Height;
  400.     fbMaxRows := MaxRows;
  401.     fbMaxItems := MaxRows div RowsPerItem;
  402.     {make sure window is high enough}
  403.     if (Height < RowsPerItem) or (fbMaxItems = 0) then begin
  404.       InitStatus := epFatal+ecWinTooSmall;
  405.       Done;
  406.       Fail;
  407.     end;
  408.     {$IFDEF UseAdjustableWindows}
  409.     {set the limits to use when resizing the window}
  410.     SetSizeLimits(wMinW, MaxWord(wMinH, RowsPerItem), wMaxW, wMaxH);
  411.     {$ENDIF}
  412.     fbRowsPerItem := RowsPerItem;
  413.     if MaxCols = 0 then
  414.       MaxCols := Width;
  415.     fbMaxCols := MaxCols;
  416.  
  417.     {initialize data fields}
  418.     fbOptions := DefFBrowserOptions;
  419.     if IsNetFileBlock(IFBptr) then
  420.       SetLongFlag(fbOptions, fbIsNet)
  421.     else
  422.       ClearLongFlag(fbOptions, fbIsNet);
  423.     fbIFB := IFBPtr;
  424.     fbKeyNum := 1;
  425.     fbDatPtr := @DatS;
  426.   {$IFDEF UseAdjustableWindows}
  427.     fbLastHeight := fbDisplayItems;
  428.     {$IFDEF UseScrollBars}
  429.     fbLastWidth := Width;
  430.     {$ENDIF}
  431.   {$ENDIF}
  432.     fbColOfs := 0;
  433.     fbFirstCol := 1;
  434.     fbCurItem := 1;
  435.     fbCurRef := 1;
  436.     fbHDelta := 1;
  437.     fbVDelta := 1;
  438.   {$IFDEF UseScrollBars}
  439.     fbBDelta := 10;
  440.   {$ENDIF}
  441.     @fbTask  := nil;
  442.     @fbBuildItem := nil;
  443.     fbFilter := NullFilterFunc;
  444.     @fbPreMove := nil;
  445.     @fbUpdate := nil;
  446.     fbRefresh := NullRefreshFunc;
  447.     fbRetries := DefRetriesOnLock;
  448.  
  449.     {set colors}
  450.     fbItemColor := Colors.TextColor;
  451.     fbItemMono := Colors.TextMono;
  452.     fbSelColor := Colors.SelItemColor;
  453.     fbSelMono := Colors.SelItemMono;
  454.  
  455.     {select hidden cursor}
  456.     SetCursor(cuHidden);
  457.  
  458.     {assume that we're out of memory}
  459.     InitStatus := epFatal+ecOutOfMemory;
  460.  
  461.     {allocate the item records array}
  462.     M := Word(fbMaxItems)*SizeOf(ItemRec);
  463.     if not GetMemCheck(fbItemRecs, M) then begin
  464.       Done;
  465.       Fail;
  466.     end;
  467.  
  468.     {initialize the array}
  469.     FillChar(fbItemRecs^, M, 0);
  470.  
  471.     {allocate the string pointers}
  472.     M := MinWord(MaxCols, 255)+1;
  473.     N := RowsPerItem*SizeOf(Pointer);
  474.     for I := 1 to fbMaxItems do
  475.       with fbItemRecs^[I] do begin
  476.         if not GetMemCheck(irRows, N) then begin
  477.           Done;
  478.           Fail;
  479.         end
  480.         else begin
  481.           FillChar(irRows^, N, 0);
  482.           for J := 1 to RowsPerItem do
  483.             if GetMemCheck(irRows^[J], M) then
  484.               {initialize the string}
  485.               FillChar(irRows^[J]^, M, 0)
  486.             else begin
  487.               Done;
  488.               Fail;
  489.             end;
  490.         end;
  491.       end;
  492.  
  493.     {set key number and default key range}
  494.     SetKeyNumber(KeyNum);
  495.     SetKeyRange('', '');
  496.  
  497.     {clear InitStatus}   {!!.06}
  498.     InitStatus := 0;     {!!.06}
  499.   end;
  500.  
  501.   destructor FBrowser.Done;
  502.     {-Deallocate row records}
  503.   var
  504.     I, J : Word;
  505.   begin
  506.     if fbItemRecs <> nil then begin
  507.       {deallocate individual item records}
  508.       for I := 1 to fbMaxItems do
  509.         with fbItemRecs^[I] do
  510.           if irRows <> nil then begin
  511.             {deallocate the individual strings}
  512.             for J := 1 to fbRowsPerItem do
  513.               FreeMemCheck(irRows^[J], MinWord(fbMaxCols, 255)+1);
  514.  
  515.             {deallocate the array of strings}
  516.             FreeMemCheck(irRows, fbRowsPerItem*SizeOf(Pointer));
  517.           end;
  518.  
  519.       {deallocate the item records array}
  520.       FreeMemCheck(fbItemRecs, fbMaxItems*SizeOf(ItemRec));
  521.     end;
  522.  
  523.     {call ancestor's destructor}
  524.     CommandWindow.Done;
  525.   end;
  526.  
  527.   procedure FBrowser.GotError(ErrorCode : Word; ErrorMsg : string); {!!.06}
  528.     {-To be called when an error occurs}
  529.   begin
  530.     fbReadLock(False);
  531.     CommandWindow.GotError(ErrorCode, ErrorMsg);
  532.   end;
  533.  
  534.   procedure FBrowser.fbOptionsOn(OptionFlags : LongInt);
  535.     {-Activate multiple options}
  536.   begin
  537.     SetLongFlag(fbOptions, OptionFlags and not BadFBrowserOptions);
  538.   end;
  539.  
  540.   procedure FBrowser.fbOptionsOff(OptionFlags : LongInt);
  541.     {-Deactivate multiple options}
  542.   begin
  543.     ClearLongFlag(fbOptions, OptionFlags and not BadFBrowserOptions);
  544.   end;
  545.  
  546.   function FBrowser.fbOptionsAreOn(OptionFlags : LongInt) : Boolean;
  547.     {-Return true if all specified options are on}
  548.   begin
  549.     fbOptionsAreOn := (fbOptions and OptionFlags = OptionFlags);
  550.   end;
  551.  
  552.   procedure FBrowser.SetNormAttr(Color, Mono : Byte);
  553.     {-Set attribute for unselected items}
  554.   begin
  555.     fbItemColor := Color;
  556.     fbItemMono := MapMono(Color, Mono);
  557.   end;
  558.  
  559.   procedure FBrowser.SetSelectAttr(Color, Mono : Byte);
  560.     {-Set attribute for selected items}
  561.   begin
  562.     fbSelColor := Color;
  563.     fbSelMono := MapMono(Color, Mono);
  564.   end;
  565.  
  566.   procedure FBrowser.SetBuildItemProc(BIF : BuildItemProc);
  567.     {-Set function to build an item}
  568.   begin
  569.     fbBuildItem := BIF;
  570.   end;
  571.  
  572.   procedure FBrowser.SetFilterFunc(FF : FilterFunc);
  573.     {-Set record filtering function}
  574.   begin
  575.     fbFilter := FF;
  576.     SetLongFlag(fbOptions, fbForceUpdate);
  577.   end;
  578.  
  579.   procedure FBrowser.SetSpecialTaskProc(STP : SpecialTaskProc);
  580.     {-Set user-defined special task hook}
  581.   begin
  582.     fbTask := STP;
  583.   end;
  584.  
  585.   procedure FBrowser.SetPreMoveProc(PMP : SpecialTaskProc);
  586.     {-Set user-defined procedure to call before each command}
  587.   begin
  588.     fbPreMove := PMP;
  589.   end;
  590.  
  591.   procedure FBrowser.SetScreenUpdateProc(SUP : UpdateProc);
  592.     {-Set user-defined procedure to call on each screen update}
  593.   begin
  594.     fbUpdate := SUP;
  595.   end;
  596.  
  597.   procedure FBrowser.SetRefreshFunc(RF : RefreshFunc);
  598.     {-Set routine called to determine if screen refresh is needed}
  599.   begin
  600.     fbRefresh := RF;
  601.   end;
  602.  
  603.   procedure FBrowser.SetHorizScrollDelta(Delta : Byte);
  604.     {-Set columns to jump when scrolling horizontally}
  605.   begin
  606.     fbHDelta := Delta;
  607.   end;
  608.  
  609.   procedure FBrowser.SetVertScrollDelta(Delta : Byte);
  610.     {-Set rows (items) to jump when scrolling vertically}
  611.   begin
  612.     fbVDelta := Delta;
  613.   end;
  614.  
  615. {$IFDEF UseScrollBars}
  616.   procedure FBrowser.SetHorizScrollBarDelta(Delta : Byte);
  617.     {-Set columns to jump when scrolling horizontally (scroll bar)}
  618.   begin
  619.     fbBDelta := Delta;
  620.   end;
  621. {$ENDIF}
  622.  
  623.   function FBrowser.GetFileBlockPtr : IsamFileBlockPtr;
  624.     {-Get pointer to associated fileblock}
  625.   begin
  626.     GetFileBlockPtr := fbIFB;
  627.   end;
  628.  
  629.   function FBrowser.GetKeyNumber : Integer;
  630.     {-Get current index key number}
  631.   begin
  632.     GetKeyNumber := fbKeyNum;
  633.   end;
  634.  
  635.   function FBrowser.GetCurrentItem : Byte;
  636.     {-Get number of currently highlighted item}
  637.   begin
  638.     GetCurrentItem := fbCurItem;
  639.   end;
  640.  
  641.   function FBrowser.GetCurrentCol : Word;
  642.     {-Get column currently displayed at left edge of window}
  643.   begin
  644.     GetCurrentCol := fbColOfs+1;
  645.   end;
  646.  
  647.   function FBrowser.GetFirstCol : Word;
  648.     {-Get first column of data to be loaded into memory}
  649.   begin
  650.     GetFirstCol := fbFirstCol;
  651.   end;
  652.  
  653.   function FBrowser.GetItemString(Item, Row : Byte) : string;
  654.     {-Get string corresponding to specified Row of specified Item}
  655.   begin
  656.     GetItemString := fbItemRecs^[Item].irRows^[Row]^;
  657.   end;
  658.  
  659.   procedure FBrowser.GetCurrentKeyAndRef(var Key : IsamKeyStr; var Ref : LongInt);
  660.     {-Retrieve current key and record number}
  661.   begin
  662.     Key := fbCurKey;
  663.     Ref := fbCurRef;
  664.   end;
  665.  
  666.   procedure FBrowser.GetCurrentRecord(var DatS; var DatLen : Word);
  667.     {-Retrieve current record}
  668.   var
  669.     RT : Integer;
  670.   begin
  671.     if fbCurRef = 0 then
  672.       DatLen := 0
  673.     else begin
  674.       RT := 0;
  675.       repeat
  676.         GetRecord(fbCurRef, DatS, DatLen);
  677.         Inc(RT);
  678.       until (RT >= fbRetries) or (IsamErrorClass <> 2);
  679.     end;
  680.   end;
  681.  
  682.   procedure FBrowser.SetCurrentRecord(Key : IsamKeyStr; Ref : LongInt);
  683.     {-Set the current record}
  684.   var
  685.     I, DI : Word;
  686.   begin
  687.     if Key < fbLowKey then begin               {!!.06}
  688.       Key := fbLowKey;                         {!!.06}
  689.       Ref := 1;                                {!!.06}
  690.     end                                        {!!.06}
  691.     else if Key > fbHighKey then begin         {!!.06}
  692.       Key := fbHighKey;                        {!!.06}
  693.       Ref := MaxLongInt;                       {!!.06}
  694.     end;                                       {!!.06}
  695.  
  696.     {is it already displayed?}
  697.     DI := fbDisplayItems;
  698.     if fbItemRecs^[1].irRef <> 0 then
  699.       for I := 1 to DI do
  700.         with fbItemRecs^[I] do
  701.           if (irRef = Ref) and (Key = irKey) then begin
  702.             if I <> fbCurItem then
  703.               fbGotoItem(I);
  704.             Exit;
  705.           end;
  706.  
  707.     {set current item, etc.}
  708.     if Ref <> fbCurRef then
  709.       if Key > fbCurKey then
  710.         fbCurItem := DI
  711.       else
  712.         fbCurItem := 1;
  713.     fbCurKey := Key;
  714.     fbCurRef := Ref;
  715.  
  716.     {mark the screen as empty}
  717.     fbEmptyBrowScreen;
  718.  
  719.     {update the screen if the window is current}
  720.     if IsCurrent then
  721.       UpdateContents;
  722.   end;
  723.  
  724.   procedure FBrowser.SetKeyRange(LowKey, HighKey : IsamKeyStr);
  725.     {-Set subrange of valid keys}
  726.   begin
  727.     if HighKey >= LowKey then
  728.       if not LongFlagIsSet(fbOptions, fbInProcess) then begin
  729.         fbLowKey := LowKey;
  730.         fbHighKey := PadCh(HighKey, #$FF, SizeOf(fbHighKey)-1);
  731.         fbCurKey := fbLowKey;
  732.         {$IFDEF UseScrollBars}
  733.         fbScaleLow := $FFFF;
  734.         {$ENDIF}
  735.         fbEmptyBrowScreen;
  736.       end;
  737.   end;
  738.  
  739.   procedure FBrowser.SetKeyNumber(KeyNum : Integer);
  740.     {-Switch index keys}
  741.   begin
  742.     if not LongFlagIsSet(fbOptions, fbInProcess) then
  743.       if (KeyNum > 0) and (KeyNum <= fbIFB^.NrOfKeys) then begin
  744.         fbKeyNum := KeyNum;
  745.         SetKeyRange('', '');
  746.       end;
  747.   end;
  748.  
  749.   procedure FBrowser.SetRetries(Retries : Integer);
  750.     {-Set number of times to retry on read operations}
  751.   begin
  752.     fbRetries := Retries;
  753.   end;
  754.  
  755.   procedure FBrowser.BuildOneRow(Row : Byte; var DatS; Len : Word;    {!!.06}
  756.                                  RecNum : LongInt; Key : IsamKeyStr;
  757.                                  var S : string);
  758.     {-Convert specified row of specified item to a string}
  759.   begin
  760.     if @fbBuildItem <> nil then
  761.       fbBuildItem(Row, DatS, Len, RecNum, Key, S, @Self);
  762.   end;
  763.  
  764.   procedure FBrowser.BuildOneItem(Item : Byte; Locked : Boolean);
  765.     {-Convert specified item to a string}
  766.   var
  767.     S : string;
  768.     SLen : Byte absolute S;
  769.     R : Word;
  770.     Ref : LongInt;
  771.   begin
  772.     with fbItemRecs^[Item] do begin
  773.       for R := 1 to fbRowsPerItem do
  774.         irRows^[R]^ := '';
  775.       {if @fbBuildItem <> nil then begin}                {!!.06}
  776.       if Locked then
  777.         Ref := -1
  778.       else begin
  779.         Ref := irRef;
  780.         if not LongFlagIsSet(fbOptions, fbBuildOnKey) then begin
  781.           GetRecord(irRef, fbDatPtr^, irLen);
  782.           case IsamErrorClass of
  783.             0..1 : {ok};
  784.             2    : Ref := -1;
  785.             else begin
  786.               GotError(epFatal+ecIsamError, emIsamError);
  787.               Exit;
  788.             end;
  789.           end;
  790.           IsamClearOK;
  791.         end;
  792.       end;
  793.  
  794.       for R := 1 to fbRowsPerItem do begin
  795.         BuildOneRow(R, fbDatPtr^, irLen, Ref, irKey, S); {!!.06}
  796.         if (ClassifyError(cwGetLastError) = etFatal) or  {!!.06}
  797.            (IsamErrorClass > 2) then                     {!!.06}
  798.           Exit;                                          {!!.06}
  799.         SLen := MinWord(SLen, MinWord(fbMaxCols, 255));
  800.         irRows^[R]^ := S;
  801.       end;
  802.       {end;}                                             {!!.06}
  803.     end;
  804.   end;
  805.  
  806.   procedure FBrowser.DrawItem(Item : Byte; Highlight : Boolean);
  807.     {-Draw the specified (relative) Item of the browse window}
  808.   var
  809.     S : String;
  810.     SLen : Byte absolute S;
  811.     Attr : Byte;
  812.     R, FRow, LRow, Start, I, W : Word;
  813.     {$IFDEF UseMouse}
  814.     SaveMouse : Boolean;
  815.     {$ENDIF}
  816.   begin
  817.     {calculate first and last rows}
  818.     FRow := Succ(Pred(Item) * fbRowsPerItem);
  819.     if (Item = 0) or (FRow > Height) then
  820.       Exit;
  821.     Inc(FRow, Pred(wYL));
  822.     LRow := FRow+Pred(fbRowsPerItem);
  823.  
  824.     {$IFDEF UseMouse}
  825.     HideMousePrim(SaveMouse);
  826.     {$ENDIF}
  827.  
  828.     {get the string}
  829.     W := Width;
  830.     if Item > fbMaxItems then begin
  831.       Attr := ColorMono(wTextColor, wTextMono);
  832.       for R := FRow to LRow do
  833.         FastFill(W, ' ', R+Pred(wYL), wXL, Attr);
  834.     end
  835.     else begin
  836.       if Highlight then
  837.         Attr := ColorMono(fbSelColor, fbSelMono)
  838.       else
  839.         Attr := ColorMono(fbItemColor, fbItemMono);
  840.  
  841.       {calculate starting column for the text we want}
  842.       Start := Succ(fbColOfs)-Pred(fbFirstCol);
  843.  
  844.       for I := 1 to fbRowsPerItem do begin
  845.         {extract the appropriate substring}
  846.         S := Copy(GetItemString(Item, I), Start, W); {!!.06}
  847.  
  848.         {adjust the string as necessary}
  849.         if SLen < W then begin
  850.           FillChar(S[SLen+1], W-SLen, ' ');
  851.           SLen := W;
  852.         end;
  853.  
  854.         {draw the string}
  855.         FastWrite(S, FRow+Pred(I), wXL, Attr);
  856.       end;
  857.     end;
  858.  
  859.     {$IFDEF UseMouse}
  860.     ShowMousePrim(SaveMouse);
  861.     {$ENDIF}
  862.   end;
  863.  
  864.   procedure FBrowser.fbPositionCursor;
  865.     {-Position the cursor at the start of the current item}
  866.   begin
  867.     {calculate first and last rows}
  868.     GotoXY(1, Succ(Pred(fbCurItem) * fbRowsPerItem));
  869.   end;
  870.  
  871.   function FBrowser.RecordFilter(RecNum : LongInt; Key : IsamKeyStr) : Boolean;
  872.     {-Return True if this record should be displayed}
  873.   begin
  874.     RecordFilter := fbFilter(RecNum, Key, @Self);
  875.   end;
  876.  
  877.   function FBrowser.IsFilteringEnabled : Boolean;
  878.     {-Return True if filtering is enabled}
  879.   begin
  880.     IsFilteringEnabled := @fbFilter <> @NullFilterFunc;
  881.   end;
  882.  
  883.   function FBrowser.fbDisplayItems : Byte;
  884.     {-Number of items to be displayed}
  885.   var
  886.     Rows : Byte;
  887.   begin
  888.     if fbMaxRows <= Height then
  889.       Rows := fbMaxRows
  890.     else
  891.       Rows := Height;
  892.     fbDisplayItems := Rows div fbRowsPerItem;
  893.   end;
  894.  
  895.   procedure FBrowser.fbCheckLoadedColumns;
  896.     {-Make sure the right columns are loaded into memory}
  897.   var
  898.     I, CO, LCN, LCH : Word;
  899.     NewFC : Integer;
  900.   begin
  901.     {nothing to do unless max columns > 255}
  902.     if fbMaxCols <= 255 then
  903.       Exit;
  904.  
  905.     {calculate last column that we need loaded}
  906.     LCN := fbColOfs{+1} + Width{-1};
  907.  
  908.     {calculate last column that we have}
  909.     LCH := fbFirstCol+254;
  910.  
  911.     {do we have the right columns loaded?}
  912.     CO := Succ(fbColOfs);
  913.     if (CO < fbFirstCol) then begin
  914.       NewFC := LCN-254;
  915.       if NewFC < 1 then
  916.         NewFC := 1;
  917.     end
  918.     else if (LCN > LCH) then
  919.       {make current column the first one loaded--we're scrolling right}
  920.       NewFC := CO
  921.     else
  922.       {nothing to do}
  923.       Exit;
  924.  
  925.     {rebuild the current page}
  926.     fbFirstCol := NewFC;
  927.     fbBuildCurPage(fbCurItem);
  928.   end;
  929.  
  930. {$IFDEF UseScrollBars}    {!!.06}
  931.   procedure FBrowser.Draw;
  932.     {-Reset scroll bars if fbForceUpdate is set}
  933.   begin
  934.     if LongFlagIsSet(fbOptions, fbForceUpdate) then
  935.       fbScaleLow := $FFFF;
  936.     CommandWindow.Draw;
  937.   end;
  938. {$ENDIF}
  939.  
  940.   procedure FBrowser.UpdateContents;
  941.     {-Redraw the complete browse window}
  942.   var
  943.     I, DI, FRow : Word;
  944.     Attr : Byte;
  945.     HOK : Boolean;
  946.     MaxCO : Integer;
  947.     {$IFDEF UseMouse}
  948.     SaveMouse : Boolean;
  949.     {$ENDIF}
  950.   begin
  951.     {check for pending errors}
  952.     if cwGetLastError <> 0 then
  953.       Exit;
  954.  
  955.     {build current page if necessary}
  956.     if LongFlagIsSet(fbOptions, fbForceUpdate+fbLockPending) then begin
  957.       fbBuildCurPage(fbCurItem);
  958.   {$IFNDEF UseAdjustableWindows}
  959.       {make sure the right columns are loaded into memory}
  960.       fbCheckLoadedColumns;
  961.     end;
  962.   {$ELSE}
  963.     end
  964.     {adjust display if window has been resized}
  965.     else begin
  966.       DI := fbDisplayItems;
  967.       if DI <> fbLastHeight then begin
  968.         fbAdjustDisplay(DI, fbLastHeight);
  969.         fbLastHeight := DI;
  970.       end;
  971.     end;
  972.  
  973.     if cwGetLastError = 0 then
  974.       IsamClearOK
  975.     else
  976.       Exit;
  977.  
  978.     {see if we need to adjust column offset}
  979.     MaxCO := fbMaxCols-Width;
  980.     if MaxCO < 0 then
  981.       MaxCO := 0;
  982.     fbColOfs := MinWord(fbColOfs, MaxCO);
  983.  
  984.     {make sure the right columns are loaded into memory}
  985.     fbCheckLoadedColumns;
  986.  
  987.     {$IFDEF UseScrollBars}
  988.     {we'll need to reset scroll bars if width changed}
  989.     DI := Width;
  990.     if DI <> fbLastWidth then begin
  991.       {request a reset}
  992.       fbScaleLow := $FFFF;
  993.       fbLastWidth := DI;
  994.     end;
  995.     {$ENDIF}
  996.   {$ENDIF}
  997.  
  998.     {clear update and redraw flags}
  999.     ClearLongFlag(fbOptions, fbForceUpdate+fbForceRedraw);
  1000.  
  1001.     {$IFDEF UseMouse}
  1002.     HideMousePrim(SaveMouse);
  1003.     {$ENDIF}
  1004.  
  1005.     {draw one page}
  1006.     HOK := LongFlagIsSet(fbOptions, fbDrawActive+fbInProcess);
  1007.     DI := fbDisplayItems;
  1008.     for I := 1 to DI do
  1009.       DrawItem(I, (I = fbCurItem) and HOK);
  1010.  
  1011.     {pad remainder of window with blank lines}
  1012.     FRow := Succ(DI * fbRowsPerItem);
  1013.     Attr := ColorMono(wTextColor, wTextMono);
  1014.     for I := FRow to Height do
  1015.       FastFill(Width, ' ', I+Pred(wYL), wXL, Attr);
  1016.  
  1017.     {$IFDEF UseScrollBars}
  1018.     {update scroll bars}
  1019.     fbUpdateScrollBars(True);
  1020.     {$ENDIF}
  1021.  
  1022.     {call user-written screen update routine}
  1023.     ScreenUpdate;
  1024.  
  1025.     {update child windows, if any}
  1026.     StackWindow.UpdateContents;
  1027.  
  1028.     {$IFDEF UseMouse}
  1029.     ShowMousePrim(SaveMouse);
  1030.     {$ENDIF}
  1031.   end;
  1032.  
  1033.   procedure FBrowser.fbEmptyItemRec(I : Byte);
  1034.     {-Empty the specified item record}
  1035.   var
  1036.     J : Word;
  1037.   begin
  1038.     with fbItemRecs^[I] do begin
  1039.       irKey := '';
  1040.       irRef := 0;
  1041.       for J := 1 to fbRowsPerItem do
  1042.         irRows^[J]^ := '';
  1043.       irLen := 0;
  1044.     end;
  1045.   end;
  1046.  
  1047.   procedure FBrowser.fbEmptyBrowScreen;
  1048.     {-Mark the browser screen as being empty}
  1049.   var
  1050.     I : Word;
  1051.   begin
  1052.     {clear all the item records}
  1053.     if fbItemRecs^[1].irRef <> 0 then
  1054.       for I := 1 to fbMaxItems do
  1055.         fbEmptyItemRec(I);
  1056.  
  1057.     {force complete screen update}
  1058.     SetLongFlag(fbOptions, fbForceUpdate+fbForceRedraw);
  1059.     ClearLongFlag(fbOptions, fbLockPending);
  1060.   end;
  1061.  
  1062.   procedure FBrowser.SpecialTask;
  1063.     {-Special task hook}
  1064.   begin
  1065.     if @fbTask = nil then
  1066.       cwCmd := ccNone
  1067.     else with fbItemRecs^[fbCurItem] do begin
  1068.       fbTask(irRef, irKey, @Self);
  1069.       if IsamErrorClass > 1 then
  1070.         GotError(epFatal+ecIsamError, emIsamError);
  1071.     end;
  1072.   end;
  1073.  
  1074.   function FBrowser.NeedRefresh : Boolean;
  1075.     {-Do we need to refresh the display?}
  1076.   begin
  1077.     NeedRefresh := fbRefresh(@Self);
  1078.   end;
  1079.  
  1080.   procedure FBrowser.PreMove;
  1081.     {-Called just prior to getting each keyboard command}
  1082.   begin
  1083.     if @fbPreMove <> nil then
  1084.       with fbItemRecs^[fbCurItem] do begin
  1085.         fbPreMove(irRef, irKey, @Self);
  1086.         if IsamErrorClass > 1 then
  1087.           GotError(epFatal+ecIsamError, emIsamError);
  1088.       end;
  1089.   end;
  1090.  
  1091.   procedure FBrowser.CharHook;
  1092.     {-Called each time a regular character is entered by user}
  1093.   begin
  1094.   end;
  1095.  
  1096.   procedure FBrowser.CursorLeft;
  1097.     {-Called to process the ccLeft command}
  1098.   begin
  1099.     fbScrollHoriz(-fbHDelta);
  1100.   end;
  1101.  
  1102.   procedure FBrowser.CursorRight;
  1103.     {-Called to process the ccRight command}
  1104.   begin
  1105.     fbScrollHoriz(+fbHDelta);
  1106.   end;
  1107.  
  1108.   procedure FBrowser.ScreenUpdate;
  1109.     {-Called on each screen update; when current row/column changes}
  1110.   begin
  1111.     if @fbUpdate <> nil then begin
  1112.       fbUpdate(@Self);
  1113.       if IsamErrorClass > 1 then
  1114.         GotError(epFatal+ecIsamError, emIsamError);
  1115.     end;
  1116.   end;
  1117.  
  1118.   function FBrowser.fbKeyInBounds(var Key : IsamKeyStr) : Boolean;
  1119.     {-Return True if fbLowKey <= Key <= fbHighKey}
  1120.   begin
  1121.     fbKeyInBounds := (Key >= fbLowKey) and (Key <= fbHighKey);
  1122.   end;
  1123.  
  1124.   procedure FBrowser.fbScrollItemRecs(Delta, LastItem : Integer);
  1125.     {-Scroll the item records up or down by Delta items}
  1126.   var
  1127.     I, J, N : Integer;
  1128.     IRP : ItemRowsPtr;
  1129.   begin
  1130.     N := SizeOf(ItemRec)*Pred(LastItem);
  1131.     if Delta < 0 then
  1132.       for I := 1 to Abs(Delta) do begin
  1133.         IRP := fbItemRecs^[1].irRows;
  1134.         MoveFast(fbItemRecs^[2], fbItemRecs^[1], N);
  1135.         fbItemRecs^[LastItem].irRows := IRP;
  1136.         fbEmptyItemRec(LastItem);
  1137.       end
  1138.     else
  1139.       for I := 1 to Delta do begin
  1140.         IRP := fbItemRecs^[LastItem].irRows;
  1141.         MoveFast(fbItemRecs^[1], fbItemRecs^[2], N);
  1142.         fbItemRecs^[1].irRows := IRP;
  1143.         fbEmptyItemRec(1);
  1144.       end;
  1145.   end;
  1146.  
  1147.   procedure FBrowser.fbReadLock(Lock : Boolean);
  1148.     {-Set or clear a read lock on the current Fileblock}
  1149.   var
  1150.     RT : Integer;
  1151.   begin
  1152.     if fbOptionsAreOn(fbUseReadLock+fbIsNet) then begin       {!!.06}
  1153.       if Lock = fbIFB^.NSP^.ReadLocked then                   {!!.06}
  1154.         Exit;                                                 {!!.06}
  1155.       RT := 0;
  1156.       repeat
  1157.         if Lock then
  1158.           ReadLockFileBlock(fbIFB)
  1159.         else
  1160.           UnLockFileBlock(fbIFB);
  1161.         Inc(RT);
  1162.       until IsamOK or (RT >= fbRetries);
  1163.     end;
  1164.     IsamClearOK;
  1165.   end;
  1166.  
  1167.   procedure FBrowser.fbBuildCurPage(Desired : Byte);
  1168.     {-Build the current page}
  1169.   label
  1170.     ExitPoint;
  1171.   var
  1172.     I, J, DI  : Integer;
  1173.     Ref : LongInt;
  1174.     Key : IsamKeyStr;
  1175.   begin
  1176.     DI := fbDisplayItems;
  1177.     fbEmptyBrowScreen;
  1178.  
  1179.     {read-lock the file if desired}
  1180.     fbReadLock(True);
  1181.  
  1182.     Ref := fbCurRef;
  1183.     Key := fbCurKey;
  1184.     fbFindKey(Ref, Key, 1);
  1185.     case IsamErrorClass of
  1186.       0 : if not fbKeyInBounds(Key) then begin
  1187.             Ref := fbCurRef;
  1188.             Key := fbCurKey;
  1189.             fbFindKey(Ref, Key, -1);
  1190.             if not IsamOK then begin
  1191.               GotError(epFatal+ecNoKeysFound, emNoKeysFound);
  1192.               goto ExitPoint;
  1193.             end;
  1194.           end;
  1195.       1 : if IsamError = 10250 then begin
  1196.             Ref := fbCurRef;
  1197.             Key := fbCurKey;
  1198.             fbFindKey(Ref, Key, -1);
  1199.             if not IsamOK then begin
  1200.               GotError(epFatal+ecNoKeysFound, emNoKeysFound);
  1201.               goto ExitPoint;
  1202.             end;
  1203.           end
  1204.           else begin
  1205.             fbNextKey(Ref, Key);
  1206.             if not IsamOK then begin
  1207.               GotError(epFatal+ecNoKeysFound, emNoKeysFound);
  1208.               goto ExitPoint;
  1209.             end;
  1210.           end;
  1211.       2 :
  1212.         with fbItemRecs^[1] do begin
  1213.           SetLongFlag(fbOptions, fbLockPending);
  1214.           irRef := Ref;
  1215.           irKey := Key;
  1216.           BuildOneItem(1, True);
  1217.           fbCurItem := 1;
  1218.           GotError(epWarning+ecFileBlockLocked, emFileBlockLocked);
  1219.           ClearErrors;
  1220.           goto ExitPoint;
  1221.         end;
  1222.       else
  1223.         GotError(epFatal+ecIsamError, emIsamError);
  1224.         goto ExitPoint; {!!.06}
  1225.     end;
  1226.  
  1227.     I := Desired;
  1228.     while (I >= 1) and fbKeyInBounds(Key) and (IsamErrorClass = 0) do begin
  1229.       with fbItemRecs^[I] do begin
  1230.         irRef := Ref;
  1231.         irKey := Key;
  1232.         BuildOneItem(I, False);
  1233.         if ClassifyError(cwGetLastError) = etFatal then {!!.06}
  1234.           goto ExitPoint;                               {!!.06}
  1235.       end;
  1236.       Dec(I);
  1237.       if (I > 0) and (IsamErrorClass = 0) then begin
  1238.         fbPrevKey(Ref, Key);
  1239.         if IsamErrorClass > 1 then begin
  1240.           GotError(epFatal+ecIsamError, emIsamError);
  1241.           goto ExitPoint;
  1242.         end;
  1243.       end;
  1244.     end;
  1245.     if I > 0 then begin
  1246.       fbScrollItemRecs(-I, fbDisplayItems);
  1247.       Dec(Desired, I);
  1248.     end;
  1249.     if fbItemRecs^[1].irRef = 0 then begin
  1250.       GotError(epFatal+ecNoKeysFound, emNoKeysFound);
  1251.       goto ExitPoint;
  1252.     end;
  1253.     if Desired = 0 then
  1254.       Desired := 1;
  1255.     if Desired < DI then begin
  1256.       fbFindKey(fbCurRef, fbCurKey, 1);
  1257.       if IsamErrorClass > 1 then begin
  1258.         GotError(epFatal+ecIsamError, emIsamError);
  1259.         goto ExitPoint;
  1260.       end;
  1261.       if IsamErrorClass = 0 then begin
  1262.         fbNextKey(Ref, Key);
  1263.         I := Succ(Desired);
  1264.         while (I <= DI) and fbKeyInBounds(Key) and (IsamErrorClass = 0) do begin
  1265.           with fbItemRecs^[I] do begin
  1266.             irRef := Ref;
  1267.             irKey := Key;
  1268.             BuildOneItem(I, False);
  1269.             if ClassifyError(cwGetLastError) = etFatal then {!!.06}
  1270.               goto ExitPoint;                               {!!.06}
  1271.           end;
  1272.           Inc(I);
  1273.           if (I <= DI) and (IsamErrorClass = 0) then
  1274.             fbNextKey(Ref, Key);
  1275.         end;
  1276.       end
  1277.       else
  1278.         I := Desired;
  1279.  
  1280.       if Desired > I then
  1281.         fbCurItem := I
  1282.       else
  1283.         fbCurItem := Desired;
  1284.     end
  1285.     else
  1286.       fbCurItem := Desired;
  1287.  
  1288.     with fbItemRecs^[fbCurItem] do begin
  1289.       fbCurRef := irRef;
  1290.       fbCurKey := irKey;
  1291.     end;
  1292.  
  1293.     ClearLongFlag(fbOptions, fbForceUpdate);
  1294.  
  1295. ExitPoint:
  1296.     {release read-lock, preserving IsamError}
  1297.     I := IsamError;
  1298.     fbReadLock(False);
  1299.     IsamError := I;
  1300.   end;
  1301.  
  1302.   function FBrowser.fbLastValidItem : Byte;
  1303.     {-Return last item containing data}
  1304.   var
  1305.     I, DI : Word;
  1306.   begin
  1307.     fbLastValidItem := 1;
  1308.     DI := fbDisplayItems;
  1309.     for I := 2 to DI do
  1310.       if fbItemRecs^[I].irRef <> 0 then
  1311.         fbLastValidItem := I
  1312.       else
  1313.         Exit;
  1314.   end;
  1315.  
  1316.   procedure FBrowser.fbGotoItem(Item : Byte);
  1317.     {-Move highlight to the specified item}
  1318.   begin
  1319.     {don't move beyond last valid row}
  1320.     if Item > fbLastValidItem then
  1321.       Item := fbLastValidItem;
  1322.  
  1323.     {change highlight}
  1324.     if (fbCurItem <> Item) and IsCurrent then begin
  1325.       DrawItem(fbCurItem, False);
  1326.       DrawItem(Item, True);
  1327.       ScreenUpdate;
  1328.     end;
  1329.  
  1330.     {change current row/record}
  1331.     fbCurItem := Item;
  1332.     with fbItemRecs^[Item] do begin
  1333.       fbCurKey := irKey;
  1334.       fbCurRef := irRef;
  1335.     end;
  1336.   end;
  1337.  
  1338.   procedure FBrowser.fbFlushKeyboard;
  1339.     {-Flush the keyboard if desired}
  1340.   var
  1341.     K : Word;
  1342.   begin
  1343.     if LongFlagIsSet(fbOptions, fbFlushKbd) then
  1344.       with cwCmdPtr^ do
  1345.         while cpKeyPressed do begin
  1346.           K := cpGetKey;
  1347.           if LongFlagIsSet(fbOptions, fbBellOnFlush) then
  1348.             RingBell;
  1349.         end;
  1350.   end;
  1351.  
  1352.   procedure FBrowser.fbScrollVert(ScDelta, HiDelta : Integer);
  1353.     {-Scroll window up/down ScDelta items; move highlight by HiDelta items}
  1354.  
  1355.     procedure PlaceAtEnd(Ref : LongInt; Key : IsamKeyStr);
  1356.       {-Place the specified record at the bottom of the window}
  1357.     var
  1358.       I, DI : Integer;
  1359.     begin
  1360.       DI := fbDisplayItems;
  1361.       I := fbLastValidItem;
  1362.       if I < DI then
  1363.         with fbItemRecs^[I] do begin
  1364.           irKey := Key;
  1365.           irRef := Ref;
  1366.           BuildOneItem(I, False);
  1367.         end
  1368.       else begin
  1369.         fbScrollItemRecs(-1, fbDisplayItems);
  1370.         with fbItemRecs^[DI] do begin
  1371.           irKey := Key;
  1372.           irRef := Ref;
  1373.           BuildOneItem(DI, False);
  1374.         end;
  1375.       end;
  1376.     end;
  1377.  
  1378.     procedure PlaceAtTop(Ref : LongInt; Key : IsamKeyStr);
  1379.       {-Place the specified record at the top of the window}
  1380.     var
  1381.       I : Integer;
  1382.     begin
  1383.       fbScrollItemRecs(1, fbDisplayItems);
  1384.       with fbItemRecs^[1] do begin
  1385.         irKey := Key;
  1386.         irRef := Ref;
  1387.         BuildOneItem(1, False);
  1388.       end;
  1389.     end;
  1390.  
  1391.     procedure FileblockIsLocked;
  1392.       {-Can't scroll because the fileblock is locked}
  1393.     begin
  1394.       fbFlushKeyboard;
  1395.       GotError(epWarning+ecFileBlockLocked, emFileBlockLocked);
  1396.       ClearErrors;
  1397.     end;
  1398.  
  1399.     procedure BuildNextPage(Nr : Integer);
  1400.       {-Build next page}
  1401.     var
  1402.       I : Integer;
  1403.       Ref : LongInt;
  1404.       Key : IsamKeyStr;
  1405.     begin
  1406.       I := fbLastValidItem;
  1407.       if I = 0 then
  1408.         Exit;
  1409.       with fbItemRecs^[I] do begin
  1410.         Ref := irRef;
  1411.         Key := irKey;
  1412.       end;
  1413.  
  1414.       fbFindKey(Ref, Key, 0);
  1415.       case IsamErrorClass of
  1416.         0..1 : fbNextKey(Ref, Key);
  1417.       end;
  1418.  
  1419.       case IsamErrorClass of
  1420.         0 : ;
  1421.         1 : with fbItemRecs^[I] do begin
  1422.               fbCurRef := irRef;
  1423.               fbCurKey := irKey;
  1424.               fbBuildCurPage(I);
  1425.               fbFlushKeyboard;
  1426.               Exit;
  1427.             end;
  1428.         2 : begin
  1429.               FileblockIsLocked;
  1430.               Exit;
  1431.             end;
  1432.         else
  1433.           GotError(epFatal+ecIsamError, emIsamError);
  1434.           Exit;
  1435.       end;
  1436.       I := 1;
  1437.       while (I <= Nr) and fbKeyInBounds(Key) and (IsamErrorClass = 0) do begin
  1438.         PlaceAtEnd(Ref, Key);
  1439.         if ClassifyError(cwGetLastError) = etFatal then {!!.06}
  1440.           Exit;                                         {!!.06}
  1441.         Inc(I);
  1442.         if (I <= Nr) and (IsamErrorClass = 0) then begin
  1443.           fbNextKey(Ref, Key);
  1444.           if IsamErrorClass > 1 then begin
  1445.             GotError(epFatal+ecIsamError, emIsamError);
  1446.             Exit;
  1447.           end;
  1448.         end;
  1449.       end;
  1450.  
  1451.       if (I <= 1) or (HiDelta <> Nr) then
  1452.         fbCurItem := Integer(fbLastValidItem)-(Nr-HiDelta)-(Pred(I)-Nr);
  1453.     end;
  1454.  
  1455.     procedure BuildPrevPage(Nr : Integer);
  1456.       {-Build previous page}
  1457.     var
  1458.       I : Integer;
  1459.       Ref : LongInt;
  1460.       Key : IsamKeyStr;
  1461.     begin
  1462.       with fbItemRecs^[1] do begin
  1463.         if irRef = 0 then
  1464.           Exit;
  1465.         Ref := irRef;
  1466.         Key := irKey;
  1467.       end;
  1468.  
  1469.       fbFindKey(Ref, Key, 0);
  1470.       case IsamErrorClass of
  1471.         0 : fbPrevKey(Ref, Key);
  1472.         1 : fbFindKey(Ref, Key, -1);
  1473.       end;
  1474.  
  1475.       case IsamErrorClass of
  1476.         0 : ;
  1477.         1 : with fbItemRecs^[1] do begin
  1478.               fbCurKey := irKey;
  1479.               fbCurRef := irRef;
  1480.               fbBuildCurPage(1);
  1481.               fbFlushKeyboard;
  1482.               Exit;
  1483.             end;
  1484.         2 : begin
  1485.               FileblockIsLocked;
  1486.               Exit;
  1487.             end;
  1488.         else
  1489.           GotError(epFatal+ecIsamError, emIsamError);
  1490.           Exit;
  1491.       end;
  1492.       I := 1;
  1493.       while (I <= Nr) and fbKeyInBounds(Key) and (IsamErrorClass = 0) do begin
  1494.         PlaceAtTop(Ref, Key);
  1495.         if ClassifyError(cwGetLastError) = etFatal then {!!.06}
  1496.           Exit;                                         {!!.06}
  1497.         Inc(I);
  1498.         if (I <= Nr) and (IsamErrorClass = 0) then begin
  1499.           fbPrevKey(Ref, Key);
  1500.           if IsamErrorClass > 1 then begin
  1501.             GotError(epFatal+ecIsamError, emIsamError);
  1502.             Exit;
  1503.           end;
  1504.         end;
  1505.       end;
  1506.  
  1507.       if (I = 1) or (HiDelta <> Nr) then begin
  1508.         I := 1+(Nr-HiDelta)-(Nr-Pred(I));
  1509.         if I < 1 then
  1510.           fbCurItem := 1
  1511.         else
  1512.           fbCurItem := I;
  1513.       end;
  1514.     end;
  1515.  
  1516.   begin
  1517.     HiDelta := Abs(HiDelta);
  1518.     if ScDelta = 0 then
  1519.       Exit;
  1520.  
  1521.     {read-lock the file if desired}
  1522.     fbReadLock(True);
  1523.  
  1524.     {build a new page}
  1525.     if ScDelta > 0 then
  1526.       BuildNextPage(ScDelta)
  1527.     else
  1528.       BuildPrevPage(-ScDelta);
  1529.  
  1530.     {release read-lock}
  1531.     fbReadLock(False);
  1532.  
  1533.     if fbCurItem < 1 then
  1534.       fbCurItem := 1
  1535.     else if fbCurItem > fbLastValidItem then
  1536.       fbCurItem := fbLastValidItem;
  1537.     with fbItemRecs^[fbCurItem] do begin
  1538.       fbCurKey := irKey;
  1539.       fbCurRef := irRef;
  1540.     end;
  1541.  
  1542.     {set redraw flag}
  1543.     SetLongFlag(fbOptions, fbForceRedraw);
  1544.   end;
  1545.  
  1546.   function FBrowser.fbOnePage(LessOne : Boolean) : Integer;
  1547.     {-Number of items to scroll on PgUp/PgDn}
  1548.   var
  1549.     DI : Word;
  1550.   begin
  1551.     DI := fbDisplayItems;
  1552.     if DI = 1 then
  1553.       fbOnePage := 1
  1554.     else
  1555.       fbOnePage := DI-Ord(LessOne);
  1556.   end;
  1557.  
  1558.   procedure FBrowser.fbLineUp;
  1559.     {-Cursor up one line}
  1560.   begin
  1561.     {just move highlight if possible}
  1562.     if fbCurItem > 1 then
  1563.       fbGotoItem(fbCurItem-1)
  1564.     else if LongFlagIsSet(fbOptions, fbScrollByPage) then
  1565.       fbScrollVert(-fbOnePage(False), -1)
  1566.     else
  1567.       fbScrollVert(-MinWord(fbVDelta, fbDisplayItems), -1);
  1568.   end;
  1569.  
  1570.   procedure FBrowser.fbLineDown;
  1571.     {-Cursor down one line}
  1572.   begin
  1573.     if fbCurItem < fbLastValidItem then
  1574.       fbGotoItem(fbCurItem+1)
  1575.     else if LongFlagIsSet(fbOptions, fbScrollByPage) then
  1576.       fbScrollVert(fbOnePage(False), 1)
  1577.     else
  1578.       fbScrollVert(MinWord(fbVDelta, fbDisplayItems), 1);
  1579.   end;
  1580.  
  1581.   procedure FBrowser.fbPageUp;
  1582.     {-Cursor up one page}
  1583.   var
  1584.     I : Integer;
  1585.   begin
  1586.     I := -fbOnePage(True);
  1587.     fbScrollVert(I, I);
  1588.   end;
  1589.  
  1590.   procedure FBrowser.fbPageDown;
  1591.     {-Cursor down one page}
  1592.   var
  1593.     I : Integer;
  1594.   begin
  1595.     I := fbOnePage(True);
  1596.     fbScrollVert(I, I);
  1597.   end;
  1598.  
  1599.   procedure FBrowser.fbScrollHoriz(Delta : Integer);
  1600.     {-Scroll horizontally delta columns}
  1601.   var
  1602.     NewCO, MaxCO : Integer;
  1603.   begin
  1604.     MaxCO := fbMaxCols-Width;
  1605.     NewCO := fbColOfs+Delta;
  1606.  
  1607.     if (NewCO < 0) or (MaxCO <= 0) then
  1608.       NewCO := 0
  1609.     else if NewCO > MaxCO then
  1610.       NewCO := MaxCO;
  1611.  
  1612.     if (NewCO <> fbColOfs) then begin
  1613.       fbColOfs := NewCO;
  1614.       UpdateContents;
  1615.     end;
  1616.   end;
  1617.  
  1618.   procedure FBrowser.fbFirstRec;
  1619.     {-Scroll to the first record in the file}
  1620.   begin
  1621.     SetCurrentRecord(fbLowKey, 1);
  1622.   end;
  1623.  
  1624.   procedure FBrowser.fbLastRec;
  1625.     {-Scroll to the last record in the file}
  1626.   begin
  1627.     SetCurrentRecord(fbHighKey, MaxLongInt);
  1628.   end;
  1629.  
  1630.   function FBrowser.fbCurRecExists : Boolean;
  1631.     {-Return True if currently highlighted record still exists and is
  1632.       unlocked}
  1633.   var
  1634.     Len : Word;
  1635.   begin
  1636.     fbCurRecExists := True;
  1637.     {if LongFlagIsSet(fbOptions, fbIsNet) then begin}  {!!.06}
  1638.       GetCurrentRecord(fbDatPtr^, Len);
  1639.       if not IsamOK then begin
  1640.         {generate warning message and redraw screen}
  1641.         if IsamErrorClass = 2 then
  1642.           GotError(epWarning+ecRecordLocked, emRecordLocked)
  1643.         else
  1644.           GotError(epWarning+ecRecordGone, emRecordGone);
  1645.         ClearErrors;
  1646.         SetLongFlag(fbOptions, fbForceUpdate);
  1647.         fbCurRecExists := False;
  1648.       end;
  1649.     {end;}                                             {!!.06}
  1650.   end;
  1651.  
  1652.   procedure FBrowser.ProcessSelf;
  1653.     {-Process browse commands}
  1654.   label
  1655.     ErrorExit;
  1656.   var
  1657.     Finished, HaveNextCmd : Boolean;
  1658.     SFS : Boolean;
  1659.     {$IFDEF UseScrollBars}
  1660.     SaveColOfs : Byte;
  1661.     SaveRef : LongInt;
  1662.     HasBars : Boolean;
  1663.     {$ENDIF}
  1664.   begin
  1665.     {check for pending error}
  1666.     cwCmd := ccError;
  1667.     if cwGetLastError <> 0 then
  1668.       Exit;
  1669.  
  1670.     {Clear any other errors as well}
  1671.     ClearErrors;
  1672.  
  1673.     {Draw initial screen if not already done}
  1674.     SetLongFlag(fbOptions, fbInProcess);
  1675.     Draw;
  1676.     if (RawError <> 0) or (cwGetLastError <> 0) then begin
  1677.       ClearLongFlag(fbOptions, fbInProcess);
  1678.       Exit;
  1679.     end;
  1680.  
  1681.     {save SearchForSequential state and enable it}
  1682.     TestSearchForSequential(fbIFB, fbKeyNum, SFS);
  1683.     if not SFS then
  1684.       EnableSearchForSequential(fbIFB, fbKeyNum);
  1685.  
  1686.     {initialize}
  1687.     Finished := False;
  1688.     HaveNextCmd := False;
  1689.  
  1690.     {$IFDEF UseScrollBars}
  1691.     HasBars := HasScrollBars;
  1692.     if HasBars then begin
  1693.       SaveColOfs := fbColOfs;
  1694.       SaveRef := fbCurRef;
  1695.     end;
  1696.     {$ENDIF}
  1697.  
  1698.     repeat
  1699.       {position the cursor at the start of the current item}
  1700.       fbPositionCursor;
  1701.  
  1702.       if not HaveNextCmd then begin
  1703.         {$IFDEF UseScrollBars}
  1704.         if HasBars then
  1705.           {update scroll bars if necessary}
  1706.           if (SaveColOfs <> fbColOfs) or (SaveRef <> fbCurRef) then begin
  1707.             fbUpdateScrollBars(SaveRef <> fbCurRef);
  1708.             SaveColOfs := fbColOfs;
  1709.             SaveRef := fbCurRef;
  1710.           end;
  1711.         {$ENDIF}
  1712.  
  1713.         {redraw screen if necessary}
  1714.         if LongFlagIsSet(fbOptions, fbForceUpdate+fbForceRedraw) then begin
  1715.           UpdateContents;
  1716.           if cwGetLastError <> 0 then
  1717.             goto ErrorExit;
  1718.         end;
  1719.  
  1720.         {Call user-defined routine prior to each user-generated command}
  1721.         PreMove;
  1722.         if cwGetLastError <> 0 then
  1723.           goto ErrorExit;
  1724.  
  1725.         {do we need to refresh the display?}
  1726.         if NeedRefresh then
  1727.           cwCmd := ccPlus
  1728.         else begin
  1729.           {get the next command}
  1730.           GetNextCommand;
  1731.  
  1732.           {is a fileblock lock pending?}
  1733.           if LongFlagIsSet(fbOptions, fbLockPending) then begin
  1734.             UpdateContents;
  1735.             if cwGetLastError <> 0 then
  1736.               cwCmd := ccError
  1737.             else if LongFlagIsSet(fbOptions, fbLockPending) then
  1738.               case cwCmd of
  1739.                 {$IFDEF UseMouse}
  1740.                 ccMouseSel,
  1741.                   {$IFDEF UseDrag}    {!!.06}
  1742.                   ccMouseDown,        {!!.06}
  1743.                   {$ENDIF}            {!!.06}
  1744.                 {$ENDIF}
  1745.                 ccLeft, ccRight, ccHome, ccEnd, ccQuit, ccHelp,
  1746.                 ccTask0..ccTask19, ccUser0..ccUser65335 :
  1747.                   {ok} ;
  1748.                 else
  1749.                   {cancel the command}
  1750.                   cwCmd := ccNone;
  1751.               end;
  1752.           end;
  1753.         end;
  1754.       end;
  1755.       HaveNextCmd := False;
  1756.  
  1757.       {Execute command}
  1758.       case cwCmd of
  1759.         ccChar :
  1760.           CharHook;
  1761.         ccUp :
  1762.           fbLineUp;
  1763.         ccDown :
  1764.           fbLineDown;
  1765.         ccPageUp :
  1766.           fbPageUp;
  1767.         ccPageDn :
  1768.           fbPageDown;
  1769.         ccLeft :
  1770.           CursorLeft;
  1771.         ccRight :
  1772.           CursorRight;
  1773.         ccHome :
  1774.           fbScrollHoriz(-fbColOfs);
  1775.         ccEnd :
  1776.           fbScrollHoriz(fbMaxCols);
  1777.         ccFirstRec :
  1778.           fbFirstRec;
  1779.         ccLastRec :
  1780.           fbLastRec;
  1781.         ccPlus :
  1782.           SetLongFlag(fbOptions, fbForceUpdate);
  1783.         ccTask0..ccTask19 :
  1784.           begin
  1785.             SpecialTask;
  1786.             HaveNextCmd := (cwCmd <> ccNone);
  1787.           end;
  1788.         ccSelect :
  1789.           Finished := fbCurRecExists;
  1790.         ccQuit,
  1791.         ccUser0..ccUser65335 :
  1792.           Finished := True;
  1793.       {$IFDEF UseMouse}
  1794.         {$IFDEF UseDrag}    {!!.06}
  1795.         ccMouseDown,        {!!.06}
  1796.         {$ENDIF}            {!!.06}
  1797.         ccMouseSel :
  1798.           if fbProcessMouseCommand then
  1799.             if cwCmd = ccSelect then
  1800.               Finished := fbCurRecExists
  1801.             else
  1802.               Finished := True;
  1803.       {$ENDIF}
  1804.         ccHelp :
  1805.           RequestHelp(wHelpIndex);
  1806.         else if (cwCmd <= 255) and (GetExitCommandPtr <> nil) then
  1807.           {Possibly a special exit command defined by a derived object}
  1808.           Finished := (cwCmd in GetExitCommandPtr^);
  1809.       end;
  1810.  
  1811. ErrorExit:
  1812.       if cwGetLastError <> 0 then
  1813.         cwCmd := ccError;
  1814.  
  1815.     until Finished or (cwCmd = ccError);
  1816.  
  1817.     {clear flag indicating that Process is active}
  1818.     ClearLongFlag(fbOptions, fbInProcess);
  1819.  
  1820.     {redraw screen if necessary}
  1821.     if LongFlagIsSet(fbOptions, fbForceUpdate+fbForceRedraw) then
  1822.       UpdateContents
  1823.     {redraw the current row unhighlighted if appropriate}
  1824.     else if not LongFlagIsSet(fbOptions, fbDrawActive) then
  1825.       DrawItem(fbCurItem, False);
  1826.  
  1827.     {restore state of SearchForSequential}
  1828.     if not SFS then
  1829.       DisableSearchForSequential(fbIFB, fbKeyNum);
  1830.  
  1831.     {save window state}
  1832.     rwSaveWindowState;
  1833.   end;
  1834.  
  1835.   procedure FBrowser.fbNextKeyPrim(var Ref : LongInt; var Key : IsamKeyStr);
  1836.     {-Primitive routine to get next key}
  1837.   var
  1838.     RT : Integer;
  1839.   begin
  1840.     RT := 0;
  1841.     repeat
  1842.       NextNetKey(fbIFB, fbKeyNum, Ref, Key);
  1843.       Inc(RT);
  1844.     until (RT >= fbRetries) or (IsamErrorClass <> 2);
  1845.   end;
  1846.  
  1847.   procedure FBrowser.fbSearchKeyPrim(var Ref : LongInt; var Key : IsamKeyStr);
  1848.     {-Primitive routine to search for a key}
  1849.   var
  1850.     RT : Integer;
  1851.   begin
  1852.     RT := 0;
  1853.     repeat
  1854.       SearchNetKey(fbIFB, fbKeyNum, Ref, Key);
  1855.       Inc(RT);
  1856.     until (RT >= fbRetries) or (IsamErrorClass <> 2);
  1857.   end;
  1858.  
  1859.   procedure FBrowser.fbPrevKeyPrim(var Ref : LongInt; var Key : IsamKeyStr);
  1860.     {-Primitive routine to get previous key}
  1861.   var
  1862.     RT : Integer;
  1863.   begin
  1864.     RT := 0;
  1865.     repeat
  1866.       PrevNetKey(fbIFB, fbKeyNum, Ref, Key);
  1867.       Inc(RT);
  1868.     until (RT >= fbRetries) or (IsamErrorClass <> 2);
  1869.   end;
  1870.  
  1871.   procedure FBrowser.fbFindKeyPrim(var Ref : LongInt; var Key : IsamKeyStr;
  1872.                                    NFSD : Integer);
  1873.     {-Primitive routine to find a key}
  1874.   var
  1875.     RT : Integer;
  1876.   begin
  1877.     RT := 0;
  1878.     repeat
  1879.       FindNetKeyAndRef(fbIFB, fbKeyNum, Ref, Key, NFSD);
  1880.       Inc(RT);
  1881.     until (RT >= fbRetries) or (IsamErrorClass <> 2);
  1882.   end;
  1883.  
  1884.   procedure FBrowser.fbNextKey(var Ref : LongInt; var Key : IsamKeyStr);
  1885.     {-Get next key, accounting for filtering}
  1886.   begin
  1887.     repeat
  1888.       fbNextKeyPrim(Ref, Key);
  1889.     until (not IsamOK) or RecordFilter(Ref, Key);
  1890.   end;
  1891.  
  1892.   procedure FBrowser.fbSearchKey(var Ref : LongInt; var Key : IsamKeyStr);
  1893.     {-Search for a key, accounting for filtering}
  1894.   var
  1895.     Finished : Boolean;
  1896.   begin
  1897.     fbSearchKeyPrim(Ref, Key);
  1898.     if IsamOK and not RecordFilter(Ref, Key) then begin
  1899.       IsamOK := False;
  1900.       IsamError := 10210;
  1901.     end;
  1902.   end;
  1903.  
  1904.   procedure FBrowser.fbPrevKey(var Ref : LongInt; var Key : IsamKeyStr);
  1905.     {-Get previous key, accounting for filtering}
  1906.   begin
  1907.     repeat
  1908.       fbPrevKeyPrim(Ref, Key);
  1909.     until (not IsamOK) or RecordFilter(Ref, Key);
  1910.   end;
  1911.  
  1912.   procedure FBrowser.fbFindKey(var Ref : LongInt; var Key : IsamKeyStr;
  1913.                                NFSD : Integer);
  1914.     {-Find a key, accounting for filtering}
  1915.   begin
  1916.     fbFindKeyPrim(Ref, Key, NFSD);
  1917.     while IsamOK and not RecordFilter(Ref, Key) do
  1918.       case NFSD of
  1919.         0 : begin {no direction}
  1920.               IsamOK := False;
  1921.               IsamError := 10270;
  1922.             end;
  1923.         1 : fbNextKeyPrim(Ref, Key);
  1924.         else fbPrevKeyPrim(Ref, Key);
  1925.       end;
  1926.   end;
  1927.  
  1928.   procedure FBrowser.GetRecord(Ref : LongInt; var DatS; var Len : Word);
  1929.     {-Low-level routine to read a record}
  1930.   begin
  1931.     Len := DatRecordSize(fbIFB);
  1932.     GetNetRec(fbIFB, Ref, DatS);
  1933.   end;
  1934.  
  1935.   procedure VBrowser.GetRecord(Ref : LongInt; var DatS; var Len : Word);
  1936.     {-Low-level routine to read a specific record}
  1937.   begin
  1938.     GetVariableRec(fbIFB, Ref, DatS, Len, Normal);
  1939.   end;
  1940.  
  1941. begin
  1942.   {initialize command processor}
  1943.   FBrowserCommands.Init(@FBrowserKeySet, FBrowserKeyMax);
  1944. end.
  1945.