home *** CD-ROM | disk | FTP | other *** search
/ Datatid 1999 #6 / Datatid_1999-06.iso / internet / Tango352Promo / P.SQL / PTKPKG.1 / BTRAPID.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1997-06-12  |  58.5 KB  |  1,773 lines

  1. {*************************************************************************
  2. **
  3. **  Copyright 1982-1997 Pervasive Software Inc. All Rights Reserved
  4. **
  5. *************************************************************************}
  6. {***********************************************************************
  7.    BTRAPID.PAS
  8.       This is the PASCAL unit for DOS Btrieve to be called by Borland Turbo
  9.       PASCAL v5.x-6.0 and Borland PASCAL 7.0.
  10.  
  11.  
  12.       You must define one of the following to your compiler in order to
  13.       compile for a particular platform:
  14.  
  15.         BTI_DOS     - DOS Real Mode      ( 16-bit Applications )
  16.         BTI_DOS_16P - DOS Protected Mode ( 16-bit Applications )
  17.  
  18.       Before your application can use this program, it must be compiled to
  19.       a '.tpu' file for Real Mode or a '.tpp' file for Protected Mode.
  20.       See the Borland documentation for how to create a
  21.       '.tpu' or ',tpp' file.  Also, see 'btrsampd.pas' for a sample
  22.       application which references 'btrapid.tpu'.
  23.  
  24.       This routine sets up the parameter block expected by Btrieve, and
  25.       issues interrupt 7B.
  26.  
  27.       Calling procedure:
  28.  
  29.       STAT := BTRV( operation, positionBlock, dataBuffer, dataLen,
  30.                     keyBuffer, keyNumber );
  31.  
  32.         where
  33.           operation      - Btrieve Operation
  34.           positionBlock  - pointer to 128-byte position block
  35.           dataBuffer     - pointer to data buffer
  36.           dataLen        - pointer to length in bytes of data buffer
  37.           keyBuffer      - pointer to keyBuffer ( 255 bytes in size )
  38.           KeyNumber      - key Number
  39.  
  40.       There should never be any string variables declared in the
  41.       data or key records, because strings store an extra byte for
  42.       the length, which affects the total size of the record.
  43.  
  44.       IMPORTANT
  45.       ---------
  46.       Pervasive Software Inc., invites you to modify this file
  47.       if you find it necessary for your particular situation.  However,
  48.       we cannot provide technical support for this module if you
  49.       do modify it.
  50.  
  51. *****************************************************************************}
  52. UNIT BTRAPID;
  53.  
  54. {*****************************************************************************
  55.  
  56.    Interface Section
  57.  
  58. *****************************************************************************}
  59. INTERFACE
  60.  
  61. {$IFDEF BTI_DOS}
  62. USES DOS,
  63.      BTRCONST;
  64. {$ENDIF}
  65.  
  66. {$IFDEF BTI_DOS_16P}
  67. USES DOS,
  68.      WINAPI,
  69.      BTRCONST,                                       {Btrieve Constants Unit }
  70.      BLOBHDR;                       {Btrieve Chunk Operations Constants Unit }
  71. {$ENDIF}
  72.  
  73. FUNCTION BTRV(
  74.                 operation      : WORD;
  75.             VAR positionBlock;
  76.             VAR dataBuffer;
  77.             VAR dataLength     : WORD;
  78.             VAR keyBuffer;
  79.                 keyNumber      : INTEGER ) : INTEGER;
  80.  
  81.  
  82. FUNCTION BTRVID(   operation      : WORD;
  83.                VAR positionBlock;
  84.                VAR dataBuffer;
  85.                VAR dataLength     : WORD;
  86.                VAR keyBuffer;
  87.                    keyNumber      : INTEGER;
  88.                VAR clientID    ): INTEGER;
  89.  
  90. {=============================================================================
  91.  Constants defined for the BTRV() and BTRVID() functions.
  92. =============================================================================}
  93. CONST
  94.   BTR_INTRPT            = $7B;                    { Btrieve interrupt vector }
  95.   BTR_OFFSET            = $33;               { Btrieve offset within segment }
  96.   VARIABLE_ID           = $6176;     { id for variable length records - 'va' }
  97.   VERSION_OFFSET        = 0;
  98.   REVISION_OFFSET       = 2;
  99.   TYPE_OFFSET           = 4;
  100.   VERSION_BUF_SIZE      = 5;
  101.   BTRV_CODE             = 7;
  102.   CLIENT_ID_SIZE        = 16;
  103.  
  104.  
  105. {$IFDEF BTI_DOS_16P}
  106. {============================================================================
  107.  Data structure definitions for use with the protected mode BTRV and
  108.  BTRVID functions.
  109. ============================================================================}
  110. TYPE
  111.                                 { Definition for the Btrieve parameter block }
  112.    BTR_PARMS = RECORD
  113.       USER_BUF_ADDR:   LongInt;       { data buffer address                  }
  114.       USER_BUF_LEN:    Word;          { data buffer length                   }
  115.       USER_CUR_ADDR:   LongInt;       { currency block address               }
  116.       USER_FCB_ADDR:   LongInt;       { file control block address           }
  117.       USER_FUNCTION:   Word;          { Btrieve operation                    }
  118.       USER_KEY_ADDR:   LongInt;       { key buffer address                   }
  119.       USER_KEY_LENGTH: Byte;          { key buffer length                    }
  120.       USER_KEY_NUMBER: ShortInt;      { key number                           }
  121.       USER_STAT_ADDR:  LongInt;       { return status address                }
  122.       XFACE_ID:        Word;          { language interface id                }
  123.    end;
  124.  
  125.    {==========================================================================
  126.    This structure defines the real mode data buffer that is sent to Btrieve.
  127.    The DATA_BUF parameter is set up as one byte for reference.  Memory needs
  128.    to be declared large enough for data buffers that will be returned.
  129.    ==========================================================================}
  130.    RMBUFF = RECORD
  131.       XDATA:          BTR_PARMS;               { The Btrieve parameter block }
  132.       STATUS:         Integer;                 { Btrieve Status              }
  133.       POS_BLOCK:      Array [1..128] of Char;  { Position Block              }
  134.       KEY_BUFFER:     Array [1..255] of Char;  { Key Buffer                  }
  135.       DATA_BUF:       Byte;                    { Data Buffer                 }
  136.    end;
  137.  
  138.                                    { Define pointer types that will be used. }
  139.    RMBUFFPTR  = ^RMBUFF;
  140.    BytePtr    = ^BYTE;
  141.    LongIntPtr = ^LongInt;
  142.    XTRACTRPTR = ^XTRACTR;
  143. {$ENDIF}
  144.  
  145. {*****************************************************************************
  146.  
  147.    Implementation Section
  148.  
  149. *****************************************************************************}
  150. IMPLEMENTATION
  151.  
  152.  
  153. {$R-}    {Range checking off}
  154. {$B+}    {Boolean complete evaluation on}
  155. {$S+}    {Stack checking on}
  156. {$I+}    {I/O checking on}
  157. {$V-}    {Strict var-string off}
  158.  
  159.  
  160. {$IFDEF BTI_DOS}
  161. {=============================================================================
  162.    This section contains the Btrieve interface code for real mode
  163.    applications.
  164. =============================================================================}
  165. FUNCTION BTRV(   operation      : WORD;
  166.              VAR positionBlock;
  167.              VAR dataBuffer;
  168.              VAR dataLength     : WORD;
  169.              VAR keyBuffer;
  170.                  keyNumber      : INTEGER ): INTEGER;
  171.  
  172.  
  173. TYPE
  174.      ADDR32 = RECORD                                      { 32 bit address   }
  175.         OFFSET:  Word;                                    { &&&old->integer  }
  176.         SEGMENT: Word;                                    { &&&used->integer }
  177.      END;
  178.  
  179.      BTR_PARMS = RECORD
  180.         USER_BUF_ADDR:   ADDR32;                { data buffer address        }
  181.         USER_BUF_LEN:    Word;                  { data buffer length         }
  182.         USER_CUR_ADDR:   ADDR32;                { currency block address     }
  183.         USER_FCB_ADDR:   ADDR32;                { file control block address }
  184.         USER_FUNCTION:   Word;                  { Btrieve operation          }
  185.         USER_KEY_ADDR:   ADDR32;                { key buffer address         }
  186.         USER_KEY_LENGTH: Byte;                  { key buffer length          }
  187.         USER_KEY_NUMBER: ShortInt;              { key number&&&old->BYTE     }
  188.         USER_STAT_ADDR:  ADDR32;                { return status address      }
  189.         XFACE_ID:        Integer;               { language interface id      }
  190.      end;
  191.  
  192. VAR
  193.      STAT:  Integer;                                     {Btrieve status code}
  194.      XDATA: BTR_PARMS;                               {Btrieve parameter block}
  195.      REGS:  DOS.REGISTERS;        {register structure used on interrrupt call}
  196.      DONE:  Boolean;
  197.  
  198. BEGIN
  199.      REGS.AX := $3500 + BTR_INTRPT;
  200.      INTR ($21, REGS);
  201.      IF (REGS.BX <> BTR_OFFSET) THEN          {make sure Btrieve is installed}
  202.         STAT := 20
  203.      ELSE
  204.                                    { If Btrieve is installed, make the call. }
  205.         BEGIN
  206.            WITH XDATA DO
  207.               BEGIN
  208.                  USER_BUF_ADDR.SEGMENT  := SEG (dataBuffer);
  209.                  USER_BUF_ADDR.OFFSET   := OFS (dataBuffer);
  210.                  USER_BUF_LEN           := dataLength;
  211.                  USER_FCB_ADDR.SEGMENT  := SEG (positionBlock);
  212.                  USER_FCB_ADDR.OFFSET   := OFS (positionBlock);
  213.                  USER_CUR_ADDR.SEGMENT  := USER_FCB_ADDR.SEGMENT;
  214.                  USER_CUR_ADDR.OFFSET   := USER_FCB_ADDR.OFFSET+38;
  215.                  USER_FUNCTION          := operation;
  216.                  USER_KEY_ADDR.SEGMENT  := SEG (keyBuffer);
  217.                  USER_KEY_ADDR.OFFSET   := OFS (keyBuffer);
  218.                  USER_KEY_LENGTH        := 255;{keyBuffer must hold 255 bytes}
  219.                  USER_KEY_NUMBER        := keyNumber;
  220.                  USER_STAT_ADDR.SEGMENT := SEG (STAT);
  221.                  USER_STAT_ADDR.OFFSET  := OFS (STAT);  { set status address }
  222.                  XFACE_ID               := VARIABLE_ID;    { set language id }
  223.               END;
  224.  
  225.            REGS.DX := OFS (XDATA);
  226.            REGS.DS := SEG (XDATA);
  227.  
  228.            INTR (BTR_INTRPT, REGS);
  229.            dataLength := XDATA.USER_BUF_LEN;
  230.         END;
  231.      BTRV := STAT;
  232. END;
  233.  
  234. {*****************************************************************************
  235. BTRVID
  236. *****************************************************************************}
  237. FUNCTION BTRVID( operation      : WORD;
  238.              VAR positionBlock;
  239.              VAR dataBuffer;
  240.              VAR dataLength     : WORD;
  241.              VAR keyBuffer;
  242.                  keyNumber      : INTEGER;
  243.              VAR clientID ): INTEGER;
  244.  
  245.  
  246. TYPE
  247.      ADDR32 = RECORD                                      { 32 bit address   }
  248.         OFFSET:  Word;                                    { &&&old->integer  }
  249.         SEGMENT: Word;                                    { &&&used->integer }
  250.      END;
  251.  
  252.      PMPARMBLOCK = RECORD
  253.         sign:           array[1..4] of char;
  254.         flags:          LongInt;
  255.         functionCode:   LongInt;
  256.         pmSwitchStatus: LongInt;
  257.         dataLength:     LongInt;
  258.         dataPtr:        ADDR32;
  259.      end;
  260.  
  261.      BTR_PARMS = RECORD
  262.         USER_BUF_ADDR:   ADDR32;                { data buffer address        }
  263.         USER_BUF_LEN:    Word;                  { data buffer length         }
  264.         USER_CUR_ADDR:   ADDR32;                { currency block address     }
  265.         USER_FCB_ADDR:   ADDR32;                { file control block address }
  266.         USER_FUNCTION:   Word;                  { Btrieve operation          }
  267.         USER_KEY_ADDR:   ADDR32;                { key buffer address         }
  268.         USER_KEY_LENGTH: Byte;                  { key buffer length          }
  269.         USER_KEY_NUMBER: ShortInt;              { key number&&&old->BYTE     }
  270.         USER_STAT_ADDR:  ADDR32;                { return status address      }
  271.         XFACE_ID:        Integer;               { language interface id      }
  272.      end;
  273.  
  274.      TWO_POINTERS = RECORD
  275.         xDataPtr:    ADDR32;
  276.         clientIdPtr: ADDR32;
  277.      end;
  278.  
  279. VAR
  280.  
  281.      btrieveVersionOkay: Boolean;                     { Btrieve Version Flag }
  282.      versionOffset:      Byte;
  283.      revisionOffset:     Byte;
  284.      typeOffset:         Byte;
  285.      done:               Boolean;
  286.      typeP:              ^Byte;
  287.      versionP:           ^Word;
  288.      revisionP:          ^Byte;
  289.      stat:               Integer;                      { Btrieve status code }
  290.      XDATA:              BTR_PARMS;                { Btrieve parameter block }
  291.      REGS:               DOS.REGISTERS;  {register struct for interrupt call }
  292.      newParms:           PMPARMBLOCK;
  293.      twoPointers:        TWO_POINTERS;
  294.  
  295.                                           { Btrieve Parameters for stat call }
  296.      posBlockx: array[1..128] of char;
  297.      dataBufx:  array[1..255] of char;
  298.      keyBufx:   array[1..255] of char;
  299.      dataLenx:  Word;
  300.      keyNumx:   Word;
  301.  
  302. BEGIN
  303.      stat := B_NO_ERROR;
  304.      keyNumx := 0;
  305.      btrieveVersionOKay := FALSE;
  306.  
  307.      REGS.AX := $3500 + BTR_INTRPT;
  308.      INTR ($21, REGS);
  309.      if (REGS.BX <> BTR_OFFSET) then        { make sure Btrieve is installed }
  310.         stat := B_RECORD_MANAGER_INACTIVE
  311.      else                          { If Btrieve is installed, make the call. }
  312.        begin
  313.           {==================================================================
  314.            Check for correct versions of requester and engine.  This check is
  315.            done only once per applicaton
  316.           ==================================================================}
  317.           if (btrieveVersionOkay = FALSE) then
  318.             begin
  319.               versionOffset  := VERSION_OFFSET;
  320.               revisionOffset := REVISION_OFFSET;
  321.               typeOffset     := TYPE_OFFSET;
  322.               done           := FALSE;
  323.               dataLenx       := SizeOf( dataBufx );
  324.  
  325.               stat := BTRV(
  326.                         B_VERSION,
  327.                         posBlockx,
  328.                         dataBufx,
  329.                         dataLenx,
  330.                         keyBufx,
  331.                         keyNumx );
  332.               if ( stat = B_NO_ERROR ) then
  333.                 begin
  334.                   while ( done = FALSE ) do
  335.                     begin
  336.                       revisionP := Ptr(
  337.                                      Seg( dataBufx ),
  338.                                      Ofs( dataBufx ) + REVISION_OFFSET );
  339.  
  340.                       versionP := Ptr(
  341.                                     Seg(dataBufx),
  342.                                     Ofs(dataBufx) + VERSION_OFFSET );
  343.                       typeP := Ptr(
  344.                                  Seg(dataBufx),
  345.                                  Ofs(dataBufx) + typeOffset );
  346.  
  347.                       case ( typeP^ ) of
  348.  
  349.                           $78:  { 'N' }
  350.  
  351.                              begin { Must have requester ver. 6.16 or higher }
  352.                                 if ( versionP^ < 6 ) or
  353.                                    ( ( versionP^ = 6 ) and ( revisionP^ < 16 ) ) then
  354.                                   begin
  355.                                     stat := B_RECORD_MANAGER_INACTIVE;
  356.                                     done := TRUE;
  357.                                   end;
  358.                              end;
  359.  
  360.  
  361.                            $68:  {'D'}
  362.                               begin   { Must have engine version 6 or higher }
  363.                                 if versionP^ < 6 then
  364.                                   begin
  365.                                     stat := B_INVALID_INTERFACE;
  366.                                     done := TRUE;
  367.                                   end;
  368.                               end;
  369.  
  370.                            0:
  371.                               begin
  372.                                 done := TRUE;
  373.                               end;
  374.  
  375.                       end;  { end case }
  376.  
  377.                       if ( done = FALSE ) then
  378.                         begin
  379.                           versionOffset := versionOffset + VERSION_BUF_SIZE;
  380.                           revisionOffset := revisionOffset + VERSION_BUF_SIZE;
  381.                           typeOffset := typeOffset + VERSION_BUF_SIZE;
  382.                         end;
  383.  
  384.                     end; { end while }
  385.  
  386.                 end
  387.                 else
  388.                   stat := B_INVALID_INTERFACE;
  389.             end;
  390.  
  391.        end;
  392.  
  393.      if ( stat = B_NO_ERROR ) then
  394.        begin
  395.          btrieveVersionOkay := TRUE;
  396.          twoPointers.xdataPtr.SEGMENT := Seg( XDATA );
  397.          twoPointers.xdataPtr.OFFSET  := Ofs( XDATA );
  398.          twoPointers.clientIdPtr.SEGMENT := SEG( clientID );
  399.          twoPointers.clientIdPtr.OFFSET  := OFS( clientID );
  400.          newParms.sign := 'PMSW';
  401.          newParms.flags := 0;
  402.          newParms.functionCode := BTRV_CODE;
  403.          newParms.dataLength := SizeOf( PMPARMBLOCK );
  404.          newParms.dataPtr.SEGMENT := SEG( twoPointers );
  405.          newParms.dataPtr.OFFSET  := OFS( twoPointers );
  406.  
  407.          {===================================================================
  408.          Move user parameters to XDATA, the block where Btrieve expects them.
  409.          ===================================================================}
  410.          with XDATA do
  411.            begin
  412.              USER_BUF_ADDR.SEGMENT  := SEG( dataBuffer );
  413.              USER_BUF_ADDR.OFFSET   := OFS( dataBuffer );
  414.              USER_BUF_LEN           := dataLength;
  415.              USER_FCB_ADDR.SEGMENT  := SEG( positionBlock );
  416.              USER_FCB_ADDR.OFFSET   := OFS( positionBlock );
  417.              USER_CUR_ADDR.SEGMENT  := USER_FCB_ADDR.SEGMENT;
  418.              USER_CUR_ADDR.OFFSET   := USER_FCB_ADDR.OFFSET+38;
  419.              USER_FUNCTION          := operation;
  420.              USER_KEY_ADDR.SEGMENT  := SEG( keyBuffer );
  421.              USER_KEY_ADDR.OFFSET   := OFS( keyBuffer );
  422.              USER_KEY_LENGTH        := 255;    {keyBuffer must hold 255 bytes}
  423.              USER_KEY_NUMBER        := keyNumber;
  424.              USER_STAT_ADDR.SEGMENT := SEG( STAT );
  425.              USER_STAT_ADDR.OFFSET  := OFS( STAT );       {set status address}
  426.              XFACE_ID               := VARIABLE_ID;          {set language id}
  427.            end;
  428.  
  429.          REGS.DX := OFS( newParms );
  430.          REGS.DS := SEG( newParms );
  431.  
  432.          INTR( BTR_INTRPT, REGS );
  433.          dataLength := XDATA.USER_BUF_LEN
  434.        end;
  435.      BTRVID := stat;
  436. END;
  437. {$ENDIF}
  438.  
  439.  
  440.  
  441. {$IFDEF BTI_DOS_16P}
  442. {=============================================================================
  443.    This section contains the Btrieve interface code for 16-bit protected mode
  444.    applications.
  445. =============================================================================}
  446.  
  447. {*
  448. *****************************************************************************
  449. **
  450. **  Prototype:
  451. **
  452. **      FUNCTION GetRealModeBuffer(
  453. **                      VAR protectedP:    Pointer;
  454. **                      VAR realAddr:      LONGINT;
  455. **                          requestedSize: LONGINT ): INTEGER;
  456. **
  457. **  Description:
  458. **
  459. **      This function returns a protected mode pointer and a real mode
  460. **      pointer to a block of memory allocated in DOS real memory.
  461. **      This memory is used for the Btrieve parameter block information.
  462. **      When BTI_DOS_32B is defined, this function allocates DOS real
  463. **      memory.  When BTI_DOS_32P is defined, this function uses a
  464. **      DOS buffer that is preallocated by PharLap.
  465. **
  466. **  Preconditions:
  467. **
  468. **      None.
  469. **
  470. **  Parameters:
  471. **
  472. **      protectedP:         On output, protectedP is the protected mode
  473. **        <output>          pointer to the real memory Btrieve parameter
  474. **                          block.
  475. **
  476. **      realAddr:           On output, realAddr contains the real mode
  477. **        <output>          pointer the Btrieve parameter block in DOS
  478. **                          real memory.
  479. **
  480. **      requestedSize:      Contains the size of memory to allocate.
  481. **        <input>
  482. **
  483. **
  484. **  Return value:
  485. **
  486. **      B_NO_ERROR          GetRealModeBuffer is successful.
  487. **
  488. **      B_DATALENGTH_ERROR  If BTI_DOS_32B is defined, this status code is
  489. **                          returned if the int386 call fails to allocate
  490. **                          the DOS real memory block.
  491. **
  492. **                          If BTI_DOS_32P is defined, this status is
  493. **                          returned when the requestedSize + dataLength
  494. **                          is smaller than the size of the DOS buffer.
  495. **                          As an enhancement to the interface, a call to
  496. **                          _dx_dosbuf_set could be made to set the
  497. **                          size of the PharLap DOS buffer before the call
  498. **                          to _dx_dosbuf_get instead of relying on the
  499. **                          default buffer size.
  500. **
  501. **  Globals:
  502. **
  503. **      None.
  504. **
  505. **  Called Functions:
  506. **
  507. **      GlobalDOSAlloc()
  508. **
  509. **  Comments:
  510. **
  511. **      None.
  512. **
  513. *****************************************************************************
  514. *}
  515. FUNCTION GetRealModeBuffer(
  516.             VAR protectedP: Pointer;     { protected mode ptr to real memory }
  517.             VAR realAddr: LONGINT;        { real mode pointer to real memory }
  518.                 requestedSize: LONGINT ): INTEGER;        { size to allocate }
  519. var
  520.  
  521.    allocStatus: INTEGER;
  522.    memBlock:    LONGINT;
  523.    protSel:     WORD;
  524.    realSeg:     WORD;
  525.  
  526. begin
  527.  
  528.    memBlock := GlobalDOSAlloc( requestedSize );
  529.  
  530.    if memBlock = 0 then
  531.       allocStatus := B_DATALENGTH_ERROR
  532.    else
  533.       begin
  534.          protSel := LoWord( memBlock );
  535.          realSeg := HiWord( memBlock );
  536.  
  537.            { Make protected mode pointer using protected mode selector and }
  538.            { offset zero                                                   }
  539.          protectedP := Ptr( protSel, 0 );
  540.  
  541.            { Make real mode pointer with real mode segment and offset zero }
  542.          realAddr := MakeLong( 0, realSeg );
  543.  
  544.          allocStatus := B_NO_ERROR;
  545.       end;
  546.  
  547.    GetRealModeBuffer := allocStatus;
  548.  
  549. end;
  550.  
  551.  
  552. {*
  553. *****************************************************************************
  554. **
  555. **  Prototype:
  556. **
  557. **      PROCEDURE FreeRealModeBuffer( sel: WORD );
  558. **
  559. **
  560. **  Description:
  561. **
  562. **      FreeRealModeBuffer frees the memory allocated by GetRealModeBuffer
  563. **      when BTI_DOS_32B is defined.  For BTI_DOS_32P there is nothing to do.
  564. **
  565. **  Preconditions:
  566. **
  567. **      None.
  568. **
  569. **  Parameters:
  570. **
  571. **      sel:            Protected mode selector of the Real Mode buffer to
  572. **        <input>       free.
  573. **
  574. **
  575. **  Return value:
  576. **
  577. **      None.
  578. **
  579. **  Globals:
  580. **
  581. **      None.
  582. **
  583. **  Called Functions:
  584. **
  585. **      GlobalDOSFree()
  586. **
  587. **  Comments:
  588. **
  589. **      None.
  590. **
  591. *****************************************************************************
  592. *}
  593. PROCEDURE FreeRealModeBuffer( sel: WORD );
  594.  
  595. BEGIN
  596.                        { Free real mode memory using protected mode selector }
  597.     GlobalDOSFree( sel );
  598.  
  599. END;
  600.  
  601. {*
  602. *****************************************************************************
  603. **
  604. **  Prototype:
  605. **
  606. **      FUNCTION BlobInputDBlen( xtractP: XTRACTRPTR )
  607. **
  608. **  Description:
  609. **
  610. **      Returns the size of the Chunk Extractors based on the signature
  611. **      field.
  612. **
  613. **  Preconditions:
  614. **
  615. **      None.
  616. **
  617. **  Parameters:
  618. **
  619. **      XTRACTRPTR:             Pointer to the chunk extractor.
  620. **        <input>
  621. **
  622. **
  623. **  Return value:
  624. **
  625. **      Returns the number of bytes in the extractor descriptor.
  626. **
  627. **  Globals:
  628. **
  629. **      None.
  630. **
  631. **  Called Functions:
  632. **
  633. **      None.
  634. **
  635. **  Comments:
  636. **
  637. **      None.
  638. **
  639. *****************************************************************************
  640. *}
  641. FUNCTION BlobInputDBlen( xtractP: XTRACTRPTR ): Word;
  642. VAR
  643.    chunkSize:   Word;
  644.  
  645. BEGIN
  646.  
  647.    {*
  648.    ** The size returned is based on the Signature field.
  649.    *}
  650.  
  651.    if ( xtractP^.Signature and RECTANGLE_BIT ) > 0 then
  652.       chunkSize := SizeOf (PUT_RECTANGLE)
  653.    else
  654.       chunkSize := (xtractP^.NumChunks * SizeOf( CHUNK_REC ))
  655.                       + (2 * SizeOf(LongInt));
  656.    BlobInputDBLen := chunkSize;
  657.  
  658. END;
  659.  
  660. {*
  661. *****************************************************************************
  662. **
  663. **  Prototype:
  664. **
  665. **      FUNCTION VerifyChunk(
  666. **                   userDB:            Pointer;
  667. **                   bytesToProtect:    Word;
  668. **                   ChunkP:            Pointer;
  669. **                   ChunkLen:          Word;
  670. **                   bytesDone:         Word;
  671. **                   maxlen:            Word ): Word;
  672. **
  673. **  Description:
  674. **
  675. **      VerifyChunk makes sure the data will not overwrite the end of the
  676. **      output buffer.  It also catches attempts to overwrite the
  677. **      descriptors with the returned data.
  678. **
  679. **
  680. **  Preconditions:
  681. **
  682. **      None.
  683. **
  684. **  Parameters:
  685. **
  686. **      userDB:                 pointer to the user's data buffer.
  687. **        <input>
  688. **
  689. **      bytesToProtect:         Size of request buffer that must not be
  690. **        <input>               overwritten with returned data.
  691. **
  692. **      ChunkP:                 Pointer to the chunk data.
  693. **        <input>
  694. **
  695. **      ChunkLen:
  696. **        <input>               Length of the chunk data.
  697. **
  698. **      bytesDone:              Number of bytes copied so far to user's
  699. **        <input>               data buffer.
  700. **
  701. **      maxlen:                 Maximum length of the user's data buffer.
  702. **        <input>
  703. **
  704. **
  705. **  Return value:
  706. **
  707. **      B_NO_ERROR               Success
  708. **
  709. **      B_DATA_MESSAGE_TOO_SMALL Chunk cannot fit in the user's data buffer
  710. **
  711. **      B_INVALID_GET_EXPRESSION Chunk data overwrites chunk descriptors
  712. **
  713. **
  714. **  Globals:
  715. **
  716. **      None.
  717. **
  718. **  Called Functions:
  719. **
  720. **      None.
  721. **
  722. **  Comments:
  723. **
  724. **      None.
  725. **
  726. *****************************************************************************
  727. *}
  728. FUNCTION VerifyChunk(
  729.            userDB:              Pointer;
  730.            bytesToProtect:      Word;
  731.            ChunkP:              Pointer;
  732.            ChunkLen:            Word;
  733.            bytesDone:           Word;
  734.            maxlen:              Word ):      Word;
  735. VAR
  736.   uNorm: LongInt;
  737.   cNorm: LongInt;
  738.   stat:  Word;
  739.  
  740. BEGIN
  741.    {*
  742.    **   Check for buffer overrun
  743.    *}
  744.    if ( bytesDone + ChunkLen > maxlen )  then
  745.       stat := B_DATA_MESSAGE_TOO_SMALL
  746.    else
  747.      begin
  748.        uNorm := MakeLong( Ofs( userDB^ ), Seg( userDB^ ) );
  749.        cNorm := MakeLong( Ofs( ChunkP^ ), Seg( ChunkP^ ) );
  750.        {*
  751.        **   Check if chunk about to be written overlaps with the extractors
  752.        *}
  753.        if ( (cNorm + ChunkLen < uNorm) or (cNorm >= uNorm + bytesToProtect) ) then
  754.          stat := 0
  755.        else
  756.          stat := B_INVALID_GET_EXPRESSION;
  757.      end;
  758.  
  759.    VerifyChunk := stat;
  760. END;
  761.  
  762. {*
  763. *****************************************************************************
  764. **
  765. **  Prototype:
  766. **
  767. **      FUNCTIONn ProcessIndirect(
  768. **                      reqB:           Pointer;
  769. **                      usersDataBuf:   Pointer;
  770. **                      maxlen:         Word;
  771. **                      Action:         Integer;
  772. **                  VAR bytesDone:      Word ): Word;
  773. **
  774. **  Description:
  775. **
  776. **      ProcessIndirect() copies data to/from the address of the
  777. **      application's chunk data.
  778. **
  779. **  Preconditions:
  780. **
  781. **      None.
  782. **
  783. **  Parameters:
  784. **
  785. **      reqB:                   Protected-mode pointer to the data buffer
  786. **        <input/output>        in the Btrieve parameter block in DOS real
  787. **                              memory.
  788. **
  789. **      usersDataBuf:           Pointer to application's data buffer.
  790. **        <input/output>
  791. **
  792. **      maxlen:                 Maximum length of application's data buffer.
  793. **        <input>
  794. **
  795. **      Action:                 Type of action to take (See below)
  796. **        <input>
  797. **
  798. **      bytesDone:              Number of bytes copied.
  799. **        <input/output>
  800. **
  801. **
  802. **  Action can be one of the following:
  803. **
  804. **  PREPROCESS_BLOBGET
  805. **      Chunk extractor information is copied from the user's data buffer
  806. **      to the data buffer in the Btrieve parameter block.  The request
  807. **      type is changed to a direct data request so that we do not
  808. **      have to mess with pointer conversions between real and protected
  809. **      mode.  It also makes it easier for us to copy data to/from
  810. **      real-mode request buffer and user's buffer when request is
  811. **      pre/post processed.
  812. **
  813. **
  814. **  POSTPROCESS_BLOBGET
  815. **      Chunk data is copied from the Btrieve parameter block to the
  816. **      application's address given in the chunk extractor information
  817. **      (still in the application's data buffer)
  818. **
  819. **
  820. **  PREPROCESS_BLOBPUT
  821. **
  822. **      Chunk extractor information is copied from the user's data buffer
  823. **      to the data buffer in the Btrieve parameter block.  The request
  824. **      type is changed from indirect to direct so that the application's
  825. **      data can be copied into the Btrieve parameter block.
  826. **
  827. **  Return value:
  828. **
  829. **      B_NO_ERROR               Success
  830. **
  831. **      B_DATA_MESSAGE_TOO_SMALL Chunk cannot fit in the user's data buffer
  832. **
  833. **      B_INVALID_GET_EXPRESSION Chunk data overwrites chunk descriptors
  834. **
  835. **
  836. **  Globals:
  837. **
  838. **      None.
  839. **
  840. **  Called Functions:
  841. **
  842. **      BlobInputDBlen()
  843. **      VerifyChunk()
  844. **
  845. **  Comments:
  846. **
  847. **      None.
  848. **
  849. *****************************************************************************
  850. *}
  851. FUNCTION ProcessIndirect(
  852.                 reqB:           Pointer;
  853.                 usersDataBuf:   Pointer;
  854.                 maxlen:         Word;
  855.                 Action:         Integer;
  856.             VAR bytesDone:      Word ): Word;
  857.  
  858.    { Used 'goto' label because Turbo Pascal 6.0 does not have 'break'. }
  859.    LABEL         100;
  860.  
  861. VAR
  862.    xtr:          ^PUT_XTRACTR;
  863.    dataPtr:      Pointer;
  864.    rectP:        ^PUT_RECTANGLE;
  865.    iP:           ^CHUNK_REC;
  866.    protected:    Word;    { size of req. buffer that must not be overwritten }
  867.    len:          Word;                                { Len of current chunk }
  868.    tmpLen:       Word;
  869.    i, limit:     Word;                                             { Helpers }
  870.    stat:         Word;
  871.    pSeg, pOff:   Word;
  872.    verifyLength: Word;
  873.    chunkP:       PChar;
  874.    src:          PChar;
  875.    dest:         PChar;
  876.    tmpP:         LongIntPtr;
  877.    flags:        LongInt;
  878.    rectangle:    Integer;
  879.  
  880. BEGIN
  881.   len := 0;
  882.   stat := B_NO_ERROR;
  883.  
  884.   if (Action = PREPROCESS_BLOBGET) or (Action = POSTPROCESS_BLOBGET) then
  885.     dataPtr := Ptr( Seg( usersDataBuf^ ), Ofs( usersDataBuf^ ) + 4 )
  886.   else
  887.     dataPtr := usersDataBuf;
  888.  
  889.   xtr := dataPtr;
  890.   bytesDone := BlobInputDBlen( XTRACTRPTR(xtr) );
  891.   protected := bytesDone;
  892.  
  893.   rectangle := xtr^.Signature and RECTANGLE_BIT;
  894.   if ( rectangle > 0 ) then
  895.     begin
  896.       rectP := dataPtr;
  897.       limit := rectP^.NumRows
  898.     end
  899.   else
  900.     limit := xtr^.NumChunks;
  901.  
  902.   case Action of
  903.  
  904.       PREPROCESS_BLOBGET:
  905.         begin
  906.           bytesDone := bytesDone + 4;
  907.           tmpP  := usersDataBuf;
  908.           Move( tmpP^, reqB^, SizeOf( LongInt ) );
  909.           reqB := Ptr( Seg( reqB^ ), Ofs( reqB^ ) + 4 );
  910.  
  911.           Move( xtr^, reqB^, protected );                  { copy extractors }
  912.  
  913.           {*
  914.           ** Change the request to a direct data request so that we do not
  915.           ** have to mess with pointer conversions between real and protected
  916.           ** mode.  It also makes it easier for us to copy data to/from
  917.           ** real-mode request buffer and user's buffer when request is
  918.           ** pre/post processed.
  919.           *}
  920.  
  921.           Move( reqB^, flags, SizeOf( LongInt ) );
  922.           flags := flags and not(INDIRECT_BIT);
  923.           Move( flags, reqB^, SizeOf( LongInt ) );
  924.  
  925.                                         { bump pointer in server req. buffer }
  926.           reqB := Ptr( Seg( reqB^ ), Ofs( reqB^ ) + protected );
  927.  
  928.         end;
  929.  
  930.       PREPROCESS_BLOBPUT:
  931.         begin                                         { move over extractors }
  932.           Move( xtr^, reqB^, protected );
  933.  
  934.           {*
  935.           ** Change the request to a direct data request so that we do not
  936.           ** have to mess with pointer conversions between real and protected
  937.           ** mode.  It also makes it easier for us to copy data to/from
  938.           ** real-mode request buffer and user's buffer when request is
  939.           ** pre/post processed.
  940.           *}
  941.  
  942.           Move( reqB^, flags, SizeOf( LongInt ) );
  943.           flags := flags and not(INDIRECT_BIT);
  944.           Move( flags, reqB^, SizeOf( LongInt ) );
  945.                                         { bump pointer in server req. buffer }
  946.           reqB := Ptr( Seg( reqB^ ), Ofs( reqB^ ) + protected );
  947.         end;
  948.  
  949.       POSTPROCESS_BLOBGET:
  950.         bytesDone := 0;
  951.    end;
  952.  
  953.    if (Action = PREPROCESS_BLOBGET) then
  954.      {*
  955.      ** Zero bytesDone so that it can now accumulate the number of bytes
  956.      ** expected to be returned, looking for status 97.  This is done by
  957.      ** calling VerifyChunk who also catches attempts to overwrite the
  958.      ** descriptors with the returned data.
  959.      *}
  960.      bytesDone := 0;
  961.  
  962.    {=========================================================================
  963.    Tack the chunks together at the end of the request buffer.
  964.    =========================================================================}
  965.    {*
  966.    ** iP is always initialized and maintained, but not used if chunk type
  967.    ** is rectangle.
  968.    *}
  969.    iP := Addr(xtr^.Chunk);
  970.  
  971.    for i := 0 to limit - 1 do
  972.      begin
  973.        if ( rectangle > 0 ) then
  974.          begin
  975.                                                    { must be 16-bit number }
  976.            if (rectP^.BytesPerRow and $ffff0000) > 0 then
  977.              stat := B_INVALID_GET_EXPRESSION               { return error }
  978.            else
  979.              begin
  980.                len := rectP^.BytesPerRow;
  981.                chunkP := Ptr(
  982.                            Seg( rectP^.dataP^ ),
  983.                            Ofs( rectP^.dataP^ )
  984.                              + (i * rectP^.AppDistanceBetweenRows) );
  985.              end;
  986.          end
  987.  
  988.        else   { random chunk }
  989.          begin
  990.  
  991.            chunkP := iP^.dataP;
  992.  
  993.            if (iP^.ChunkLen and $ffff0000) > 0 then  { must be 16-bit number }
  994.              begin
  995.                stat := B_INVALID_GET_EXPRESSION;              { return error }
  996.                goto 100;
  997.              end
  998.            else
  999.              len := iP^.ChunkLen;
  1000.  
  1001.          end;
  1002.  
  1003.        case Action of
  1004.            POSTPROCESS_BLOBGET:
  1005.              begin
  1006.                src  := reqB;
  1007.                dest := chunkP;
  1008.              end;
  1009.  
  1010.            PREPROCESS_BLOBPUT:
  1011.              begin
  1012.                src  := chunkP;
  1013.                dest := reqB;
  1014.              end;
  1015.        end;
  1016.  
  1017.        {======================================================================
  1018.        Does the chunk about to be written overlap with the extractors?
  1019.        ======================================================================}
  1020.        if ( Action = POSTPROCESS_BLOBGET ) then
  1021.           verifyLength := $FFFF
  1022.        else
  1023.           verifyLength := maxlen;
  1024.  
  1025.        stat := VerifyChunk(
  1026.                  xtr,
  1027.                  protected,
  1028.                  chunkP,
  1029.                  len,
  1030.                  bytesDone,
  1031.                  verifyLength );
  1032.        if  stat = 0 then
  1033.          if (bytesDone >= maxlen) then           { Already consumed buffer ? }
  1034.             stat := B_DATA_MESSAGE_TOO_SMALL;
  1035.  
  1036.        if stat = 0 then
  1037.          begin
  1038.            if (Action <> PREPROCESS_BLOBGET) then
  1039.              {*
  1040.              ** Nothing to do yet for PREPROCESS BLOB_GET.  We're just here
  1041.              ** looking for trouble in the chunkLens, and counting up
  1042.              ** bytesDone.
  1043.              *}
  1044.              begin
  1045.                if len < (maxlen - bytesDone ) then
  1046.                  tmpLen := len
  1047.                else
  1048.                  tmpLen := maxlen - bytesDone;
  1049.  
  1050.                Move( src^, dest^, tmpLen );
  1051.              end;
  1052.  
  1053.            reqB := Ptr( Seg( reqB^ ), Ofs( reqB^ ) + len );
  1054.            bytesDone := bytesDone + len;
  1055.  
  1056.            iP := Ptr( Seg( iP^ ), Ofs( iP^ ) + SizeOf( CHUNK_REC ) );
  1057.          end
  1058.        else
  1059.          goto 100;
  1060.  
  1061.      end;  { end for loop }
  1062.  
  1063. 100:
  1064.    ProcessIndirect := stat;
  1065. END;  {ProcessIndirect}
  1066.  
  1067. {*
  1068. *****************************************************************************
  1069. **
  1070. **  Prototype:
  1071. **
  1072. **      FUNCTION SetUpBTRVData(
  1073. **                     protectedP: RMBUFFPTR;
  1074. **                 VAR posBlock;
  1075. **                 VAR dataBuffer;
  1076. **                 VAR keyBuffer ): Integer ;
  1077. **
  1078. **  Description:
  1079. **
  1080. **      This function copies Btrieve parameter data from the users
  1081. **      application to the Btrieve parameter block in DOS real memory.
  1082. **      It checks the Btrieve function code and key number parameters
  1083. **      that are already in the parameter block to see if the operation
  1084. **      processes indirect chunk data.  If so, ProcessIndirect() is called
  1085. **      to process the indirect Btrieve chunk data.
  1086. **
  1087. **  Preconditions:
  1088. **
  1089. **      Real Mode Btrieve parameter block is already initialized with
  1090. **      Function code, Key Number, Data buffer length.
  1091. **
  1092. **  Parameters:
  1093. **
  1094. **      protectedP:    Protected mode pointer to the Btrieve parameter
  1095. **       <input/output> block (RMBUFF data structure).
  1096. **
  1097. **      posBlock:       Application's parameter block
  1098. **        <input>
  1099. **
  1100. **      dataBuffer:     Application's data buffer
  1101. **        <input>
  1102. **
  1103. **      keyBuffer:      Application's key buffer
  1104. **        <input>
  1105. **
  1106. **
  1107. **  Return value:
  1108. **
  1109. **      B_NO_ERROR      SetUpBTRVData() is successful.
  1110. **
  1111. **      B_DATA_MESSAGE_TOO_SMALL Chunk cannot fit in the user's data buffer.
  1112. **
  1113. **      B_INVALID_GET_EXPRESSION Chunk data overwrites chunk descriptors.
  1114. **
  1115. **
  1116. **  Globals:
  1117. **
  1118. **      None.
  1119. **
  1120. **  Called Functions:
  1121. **
  1122. **      BlobInputDBlen()
  1123. **      ProcessIndirect()
  1124. **
  1125. **  Comments:
  1126. **
  1127. **      None.
  1128. **
  1129. *****************************************************************************
  1130. *}
  1131. FUNCTION SetUpBTRVData(
  1132.                protectedP: RMBUFFPTR;
  1133.            VAR posBlock;
  1134.            VAR dataBuffer;
  1135.            VAR keyBuffer ): Integer ;
  1136. VAR
  1137.    functionCode: Integer;
  1138.    copyLen:      Word;
  1139.    stat:         Integer;
  1140.    xtr:          ^PUT_XTRACTR;
  1141.    pSeg, pOff:   Word;
  1142.    dataBufP:     Pointer;
  1143.  
  1144. BEGIN
  1145.    stat := B_NO_ERROR;
  1146.  
  1147.    dataBufP := ADDR( protectedP^.DATA_BUF );
  1148.  
  1149.    functionCode := protectedP^.XDATA.USER_FUNCTION mod S_WAIT_LOCK;
  1150.    copyLen  := protectedP^.XDATA.USER_BUF_LEN;
  1151.    if (functionCode = B_GET_DIRECT) and
  1152.       (protectedP^.XDATA.USER_KEY_NUMBER = GET_DRTC_XTRACTOR_KEY ) then
  1153.      begin
  1154.        xtr  := Ptr( Seg( dataBuffer ), Ofs( dataBuffer ) + 4 );
  1155.  
  1156.        if  (xtr^.Signature and INDIRECT_BIT) > 0 then
  1157.          begin
  1158.            stat := ProcessIndirect(
  1159.                      dataBufP,
  1160.                      Ptr(Seg(dataBuffer), Ofs(dataBuffer)),
  1161.                      protectedP^.XDATA.USER_BUF_LEN,
  1162.                      PREPROCESS_BLOBGET,
  1163.                      copyLen );
  1164.            if stat = B_NO_ERROR then
  1165.              { Data was already copied in ProcessIndirect, so set copyLen to 0 }
  1166.              copyLen := 0;
  1167.          end
  1168.  
  1169.        else                 { Only copy the extractors & the record address. }
  1170.          copyLen := BlobInputDBlen( XTRACTRPTR(xtr) ) + 4;
  1171.  
  1172.      end;
  1173.  
  1174.    if functionCode = B_CHUNK_UPDATE then
  1175.      begin
  1176.  
  1177.         xtr  := Ptr( Seg( dataBuffer ), Ofs( dataBuffer ) );
  1178.  
  1179.         if  (xtr^.Signature and INDIRECT_BIT) > 0 then
  1180.           begin
  1181.             stat := ProcessIndirect(
  1182.                       dataBufP,
  1183.                       Ptr( Seg(dataBuffer), Ofs(dataBuffer) ),
  1184.                       protectedP^.XDATA.USER_BUF_LEN,
  1185.                       PREPROCESS_BLOBPUT,
  1186.                       copyLen );
  1187.             if stat = 0 then
  1188.            { Data was already copied in ProcessIndirect, so set copyLen to 0 }
  1189.               copyLen := 0;
  1190.           end;
  1191.      end;
  1192.  
  1193.  
  1194.    if stat = B_NO_ERROR then
  1195.      begin
  1196.                         { copy application's data to Btrieve parameter block }
  1197.        Move( posBlock, protectedP^.POS_BLOCK, 128 );
  1198.        Move( dataBuffer, dataBufP^, copyLen );
  1199.        Move( keyBuffer, protectedP^.KEY_BUFFER, 255 );
  1200.  
  1201.      end;
  1202.  
  1203.    SetUpBTRVData := stat;
  1204.  
  1205. END; { SetUpBTRVData }
  1206.  
  1207.  
  1208. {*
  1209. *****************************************************************************
  1210. **
  1211. **  Prototype:
  1212. **
  1213. **      PROCEDURE RetrieveBTRVData(
  1214. **                      protectedP: RMBUFFPTR;
  1215. **                  VAR posBlock;
  1216. **                  VAR dataBuffer;
  1217. **                  VAR keyBuffer );
  1218. **
  1219. **  Description:
  1220. **
  1221. **      RetrieveBTRVData() copies data from the Btrieve parameter block
  1222. **      in DOS real memory to the application's data area.  When there
  1223. **      is indirection in the destination of the data, then
  1224. **      RetrieveBTRVData() calls ProcessIndirect() to pull the data out
  1225. **      of the parameter block and place it at the correct address.
  1226. **
  1227. **  Preconditions:
  1228. **
  1229. **      None.
  1230. **
  1231. **  Parameters:
  1232. **
  1233. **      protectedP:             Protected-mode pointer to the Btrieve
  1234. **        <input>               parameter block (RMBUFF data structure)
  1235. **                              which contains data from the last
  1236. **                              Btrieve call.
  1237. **
  1238. **      posBlock:               Application's position block.
  1239. **        <output>
  1240. **
  1241. **      dataBuffer:             Application's data buffer.
  1242. **        <output>
  1243. **
  1244. **      keyBuffer:              Application's data buffer.
  1245. **        <output>
  1246. **
  1247. **
  1248. **  Return value:
  1249. **
  1250. **      B_NO_ERROR               RetrieveBTRVData() is successful.
  1251. **
  1252. **      B_DATA_MESSAGE_TOO_SMALL Chunk cannot fit in the user's data buffer.
  1253. **
  1254. **      B_INVALID_GET_EXPRESSION Chunk data overwrites chunk descriptors.
  1255. **
  1256. **  Globals:
  1257. **
  1258. **      None.
  1259. **
  1260. **  Called Functions:
  1261. **
  1262. **      ProcessIndirect()
  1263. **
  1264. **  Comments:
  1265. **
  1266. **      None.
  1267. **
  1268. *****************************************************************************
  1269. *}
  1270. PROCEDURE RetrieveBTRVData(
  1271.                 protectedP: RMBUFFPTR;
  1272.             VAR posBlock;
  1273.             VAR dataBuffer;
  1274.             VAR keyBuffer );
  1275. VAR
  1276.    BtrvFunction:   Word;
  1277.    ignoredDataLen: Word;
  1278.    getP:           ^GET_XTRACTR;
  1279.    dataBufP:       Pointer;
  1280.  
  1281. BEGIN
  1282.  
  1283.    BtrvFunction := protectedP^.XDATA.USER_FUNCTION mod S_WAIT_LOCK;
  1284.  
  1285.    if  (BtrvFunction = B_GET_DIRECT) and
  1286.        (protectedP^.XDATA.USER_KEY_NUMBER = GET_DRTC_XTRACTOR_KEY ) then
  1287.      begin
  1288.  
  1289.         getP := ADDR( dataBuffer );
  1290.         if (getP^.Signature and INDIRECT_BIT) > 0 then
  1291.           begin
  1292.             ProcessIndirect(
  1293.               Ptr( Seg(protectedP^.DATA_BUF), Ofs(protectedP^.DATA_BUF)),
  1294.               PTR( Seg(dataBuffer), Ofs(dataBuffer)),
  1295.               protectedP^.XDATA.USER_BUF_LEN,
  1296.               POSTPROCESS_BLOBGET,
  1297.               ignoredDataLen );
  1298.           end
  1299.         else
  1300.           begin
  1301.             dataBufP := Addr( protectedP^.DATA_BUF );
  1302.             Move( dataBufP^, dataBuffer, protectedP^.XDATA.USER_BUF_LEN );
  1303.           end
  1304.      end
  1305.    else
  1306.      begin
  1307.        dataBufP := Addr( protectedP^.DATA_BUF );
  1308.        Move( dataBufP^, dataBuffer, protectedP^.XDATA.USER_BUF_LEN );
  1309.      end;
  1310.  
  1311.  
  1312.    Move( protectedP^.POS_BLOCK, posBlock, 128 );
  1313.    Move( protectedP^.KEY_BUFFER, keyBuffer, 255 );
  1314.  
  1315. END; { RetrieveBTRVData }
  1316.  
  1317. {*****************************************************************************
  1318.  
  1319. BTRV
  1320.  
  1321. *****************************************************************************}
  1322.  
  1323. FUNCTION BTRV(   operation      : WORD;
  1324.              VAR positionBlock;
  1325.              VAR dataBuffer;
  1326.              VAR dataLength     : WORD;
  1327.              VAR keyBuffer;
  1328.                  keyNumber      : INTEGER ): INTEGER;
  1329.  
  1330. TYPE
  1331.    {*
  1332.    **  Real mode register structure used for call to DPMI services to
  1333.    **  issue real mode INT 7B.
  1334.    *}
  1335.    REALREGS = RECORD
  1336.       DI:       LongInt;
  1337.       SI:       LongInt;
  1338.       BP:       LongInt;
  1339.       reserved: LongInt;
  1340.       BX:       LongInt;
  1341.       DX:       LongInt;
  1342.       CX:       LongInt;
  1343.       AX:       LongInt;
  1344.       CPUflag:  Word;
  1345.       ES:       Word;
  1346.       DS:       Word;
  1347.       fs:       Word;
  1348.       gs:       Word;
  1349.       ip:       Word;
  1350.       cs:       Word;
  1351.       sp:       Word;
  1352.       ss:       Word;
  1353.    end;
  1354.  
  1355.  
  1356. VAR
  1357.      stat:         Integer;                            { Btrieve status code }
  1358.      REGS:         DOS.REGISTERS;{ register structure used on interrupt call }
  1359.      bufferSize:   LongInt;                       { Size of real mode memory }
  1360.      realPtr:      LongInt;          { Real mode pointer to real mode memory }
  1361.      protectedP:   RMBUFFPTR;   { protected mode pointer to real mode memory }
  1362.      realmodeRegs: REALREGS;
  1363.  
  1364. BEGIN
  1365.  
  1366.      {*
  1367.      ** Use DPMI services to get the real mode interrupt vector 7B to
  1368.      ** determine whether or not Btrieve is loaded.
  1369.      *}
  1370.      REGS.AX := $200;
  1371.      REGS.BX := BTR_INTRPT;
  1372.      INTR( $31, REGS );
  1373.      if ( REGS.DX <> BTR_OFFSET ) then      { make sure Btrieve is installed }
  1374.        stat := B_RECORD_MANAGER_INACTIVE     { Return error status to caller }
  1375.      else
  1376.        begin
  1377.  
  1378.          bufferSize := SizeOf( RMBUFF ) + dataLength;
  1379.          {*
  1380.          ** Call function GetRealModeBuffer to allocate DOS real memory for
  1381.          ** the Btrieve parameter block.
  1382.          *}
  1383.          stat := GetRealModeBuffer(
  1384.                    Pointer(protectedP),
  1385.                    realPtr,
  1386.                    bufferSize );
  1387.  
  1388.          if stat = B_NO_ERROR then
  1389.            begin
  1390.  
  1391.              {*
  1392.              ** Establish pointer links inside real mode buffer.
  1393.              *}
  1394.  
  1395.              protectedP^.XDATA.USER_CUR_ADDR  := realPtr +
  1396.                 Ofs( protectedP^.POS_BLOCK ) - Ofs( protectedP^ ) + 38;
  1397.  
  1398.              protectedP^.XDATA.USER_FCB_ADDR  := realPtr +
  1399.                 Ofs( protectedP^.POS_BLOCK ) - Ofs( protectedP^ );
  1400.  
  1401.              protectedP^.XDATA.USER_STAT_ADDR := realPtr +
  1402.                 Ofs( protectedP^.STATUS ) - Ofs( protectedP^ );
  1403.  
  1404.              protectedP^.XDATA.USER_KEY_ADDR  := realPtr +
  1405.                 Ofs( protectedP^.KEY_BUFFER ) - Ofs( protectedP^ );
  1406.  
  1407.              protectedP^.XDATA.USER_BUF_ADDR  := realPtr +
  1408.                 Ofs( protectedP^.DATA_BUF ) - Ofs( protectedP^ );
  1409.  
  1410.              protectedP^.XDATA.XFACE_ID       := VARIABLE_ID;
  1411.  
  1412.              protectedP^.XDATA.USER_FUNCTION  := operation;
  1413.              protectedP^.XDATA.USER_BUF_LEN   := dataLength;
  1414.  
  1415.                                 { use maximum key length since we don't know }
  1416.              protectedP^.XDATA.USER_KEY_LENGTH := 255;
  1417.              protectedP^.XDATA.USER_KEY_NUMBER := keyNumber;
  1418.  
  1419.              stat := SetUpBTRVData(
  1420.                        protectedP,         { pointer to real mode parm block }
  1421.                        positionBlock,      { application's position block    }
  1422.                        dataBuffer,         { application's data buffer       }
  1423.                        keyBuffer );        { application's key buffer        }
  1424.  
  1425.              if stat = B_NO_ERROR then
  1426.                begin
  1427.  
  1428.                  {============================================================
  1429.                  Make call to Btrieve using DPMI.
  1430.                  ============================================================}
  1431.  
  1432.                  REGS.AX := $300;
  1433.                  REGS.BX := BTR_INTRPT ;
  1434.                  {*
  1435.                  **   CX = Number of words to copy from protected-mode to
  1436.                  **   real-mode stack
  1437.                  *}
  1438.                  REGS.CX := 0;
  1439.  
  1440.                  {*
  1441.                  ** Initialize real mode segment registers for call to Btrieve
  1442.                  *}
  1443.  
  1444.                  FillChar( realmodeRegs, SizeOf( REALREGS ), 0 );
  1445.  
  1446.                  realmodeRegs.DS := HiWord( realPtr );
  1447.                  realmodeRegs.DX := LoWord( realPtr );
  1448.                  REGS.ES := Seg( realmodeRegs );
  1449.                  REGS.DI := Ofs( realmodeRegs );
  1450.  
  1451.                  INTR( $31, REGS );
  1452.  
  1453.                  dataLength := protectedP^.XDATA.USER_BUF_LEN;
  1454.                  stat := protectedP^.STATUS;
  1455.  
  1456.                  {============================================================
  1457.                  Copy data from protected mode back to user's data
  1458.                  ============================================================}
  1459.                  RetrieveBTRVData(
  1460.                    protectedP,
  1461.                    positionBlock,
  1462.                    dataBuffer,
  1463.                    keyBuffer );
  1464.                end;
  1465.  
  1466.              FreeRealModeBuffer( Seg( protectedP^ ) );
  1467.  
  1468.            end;
  1469.         end;
  1470.      BTRV := stat;
  1471. END; { BTRV }
  1472.  
  1473. {*****************************************************************************
  1474.  
  1475. BTRVID
  1476.  
  1477. *****************************************************************************}
  1478.  
  1479. FUNCTION BTRVID(   operation      : WORD;
  1480.                VAR positionBlock;
  1481.                VAR dataBuffer;
  1482.                VAR dataLength     : WORD;
  1483.                VAR keyBuffer;
  1484.                    keyNumber      : INTEGER;
  1485.                VAR clientID    ): INTEGER;
  1486.  
  1487.  
  1488. TYPE
  1489.      PMPARMBLOCK = RECORD
  1490.         sign:           array[1..4] of char;
  1491.         flags:          LongInt;
  1492.         functionCode:   LongInt;
  1493.         pmSwitchStatus: LongInt;
  1494.         dataLength:     LongInt;
  1495.         dataPtr:        LongInt;
  1496.      end;
  1497.  
  1498.      TWO_POINTERS = RECORD
  1499.         xDataPtr:    LongInt;
  1500.         clientIdPtr: LongInt;
  1501.      end;
  1502.  
  1503.      IDSTRUCT = RECORD
  1504.        newParms:      PMPARMBLOCK;
  1505.        twoPointers:   TWO_POINTERS;
  1506.        clientID:      array[1..CLIENT_ID_SIZE] of char;
  1507.        btrv:          RMBUFF;
  1508.      end;
  1509.  
  1510.    {*
  1511.    **  Real mode register structure used for call to DPMI services to
  1512.    **  issue real mode INT 7B.
  1513.    *}
  1514.    REALREGS = RECORD
  1515.       DI:       LongInt;
  1516.       SI:       LongInt;
  1517.       BP:       LongInt;
  1518.       reserved: LongInt;
  1519.       BX:       LongInt;
  1520.       DX:       LongInt;
  1521.       CX:       LongInt;
  1522.       AX:       LongInt;
  1523.       CPUflag:  Word;
  1524.       ES:       Word;
  1525.       DS:       Word;
  1526.       fs:       Word;
  1527.       gs:       Word;
  1528.       ip:       Word;
  1529.       cs:       Word;
  1530.       sp:       Word;
  1531.       ss:       Word;
  1532.    end;
  1533.  
  1534.  
  1535. VAR
  1536.      btrieveVersionOkay: Boolean;
  1537.      versionOffset:      Byte;
  1538.      revisionOffset:     Byte;
  1539.      typeOffset:         Byte;
  1540.      done:               Boolean;
  1541.      typeP:              ^Byte;
  1542.      versionP:           ^Word;
  1543.      revisionP:          ^Byte;
  1544.      stat:               Integer;                      { Btrieve status code }
  1545.      REGS:               DOS.REGISTERS; { register struct for interrupt call }
  1546.      bufferSize:         LongInt;                 { Size of real mode memory }
  1547.      realPtr:            LongInt;    { Real mode pointer to real mode memory }
  1548.      protectedP:         ^IDSTRUCT;  { protected-mode pointer to real memory }
  1549.      realmodeRegs:       REALREGS;            { real-mode register structure }
  1550.      newParms:           PMPARMBLOCK;
  1551.      twoPointers:        TWO_POINTERS;
  1552.      RMBTRVID:           IDSTRUCT;
  1553.                                           { Btrieve Parameters for stat call }
  1554.      posBlockx:          array[1..128] of char;
  1555.      dataBufx:           array[1..255] of char;
  1556.      keyBufx:            array[1..255] of char;
  1557.      dataLenx:           Word;
  1558.      keyNumx:            Word;
  1559.  
  1560. BEGIN
  1561.      stat := B_NO_ERROR;
  1562.      keyNumx := 0;
  1563.      btrieveVersionOkay := FALSE;
  1564.      {*
  1565.      ** Use DPMI services to get the real mode interrupt vector 7B to
  1566.      ** determine whether or not Btrieve is loaded.
  1567.      *}
  1568.      REGS.AX := $200;
  1569.      REGS.BX := BTR_INTRPT;
  1570.      INTR( $31, REGS );
  1571.      if ( REGS.DX <> BTR_OFFSET ) then      { make sure Btrieve is installed }
  1572.        stat := B_RECORD_MANAGER_INACTIVE     { Return error status to caller }
  1573.      else
  1574.        begin
  1575.  
  1576.          {==================================================================
  1577.          Set up the new parmeter block if version is 6.x or later.  Request
  1578.          the Btrieve version only once per program invocation.
  1579.          ==================================================================}
  1580.          if ( btrieveVersionOkay = FALSE ) then
  1581.            begin
  1582.               versionOffset  := VERSION_OFFSET;
  1583.               revisionOffset := REVISION_OFFSET;
  1584.               typeOffset     := TYPE_OFFSET;
  1585.               done           := FALSE;
  1586.               dataLenx       := SizeOf( dataBufx );
  1587.  
  1588.               stat := BTRV(
  1589.                         B_VERSION,
  1590.                         posBlockx,
  1591.                         dataBufx,
  1592.                         dataLenx,
  1593.                         keyBufx,
  1594.                         keyNumx );
  1595.               if ( stat = B_NO_ERROR ) then
  1596.                 begin
  1597.                   while ( done = FALSE ) do
  1598.                     begin
  1599.                       revisionP := Ptr(
  1600.                                      Seg( dataBufx ),
  1601.                                      Ofs( dataBufx ) + REVISION_OFFSET );
  1602.  
  1603.                       versionP := Ptr(
  1604.                                     Seg(dataBufx),
  1605.                                     Ofs(dataBufx) + VERSION_OFFSET );
  1606.                       typeP := Ptr(
  1607.                                  Seg(dataBufx),
  1608.                                  Ofs(dataBufx) + typeOffset );
  1609.  
  1610.                       case ( typeP^ ) of
  1611.  
  1612.  
  1613.                           $78:  { 'N' }
  1614.                              begin { Must have requester ver. 6.16 or higher }
  1615.                                 if ( versionP^ < 6 ) or
  1616.                                    ( ( versionP^ = 6 ) and ( revisionP^ < 16 ) ) then
  1617.                                   begin
  1618.                                     stat := B_RECORD_MANAGER_INACTIVE;
  1619.                                     done := TRUE;
  1620.                                   end;
  1621.                              end;
  1622.  
  1623.  
  1624.                            $68:  {'D'}
  1625.                               begin   { Must have engine version 6 or higher }
  1626.                                 if versionP^ < 6 then
  1627.                                   begin
  1628.                                     stat := B_INVALID_INTERFACE;
  1629.                                     done := TRUE;
  1630.                                   end;
  1631.                               end;
  1632.  
  1633.                            0:
  1634.                               begin
  1635.                                 done := TRUE;
  1636.                               end;
  1637.  
  1638.                       end;  { end case }
  1639.  
  1640.                       if ( done = FALSE ) then
  1641.                         begin
  1642.                           versionOffset := versionOffset + VERSION_BUF_SIZE;
  1643.                           revisionOffset := revisionOffset + VERSION_BUF_SIZE;
  1644.                           typeOffset := typeOffset + VERSION_BUF_SIZE;
  1645.                         end;
  1646.  
  1647.                     end; { end while }
  1648.  
  1649.                 end
  1650.                 else
  1651.                   stat := B_INVALID_INTERFACE;
  1652.            end;
  1653.        end;
  1654.  
  1655.      if ( stat = B_NO_ERROR ) then
  1656.        begin
  1657.          btrieveVersionOkay := TRUE;
  1658.  
  1659.          bufferSize := SizeOf( IDSTRUCT ) + dataLength;
  1660.          {*
  1661.          ** Call function GetRealModeBuffer to allocate DOS real memory for
  1662.          ** the Btrieve parameter block.
  1663.          *}
  1664.          stat := GetRealModeBuffer(
  1665.                    Pointer(protectedP),
  1666.                    realPtr,
  1667.                    bufferSize );
  1668.  
  1669.          if stat = B_NO_ERROR then
  1670.            begin
  1671.  
  1672.              {*
  1673.              ** Establish pointer links inside real mode buffer.
  1674.              *}
  1675.  
  1676.              protectedP^.twoPointers.xdataPtr := realPtr +
  1677.                            Ofs(protectedP^.btrv.XDATA) - Ofs( protectedP^ );
  1678.  
  1679.              protectedP^.twoPointers.clientIdPtr := realPtr +
  1680.                            Ofs( protectedP^.clientID ) - Ofs( protectedP^ );
  1681.  
  1682.              Move( clientID, protectedP^.clientID, CLIENT_ID_SIZE );
  1683.              protectedP^.newParms.sign  := 'PMSW';
  1684.              protectedP^.newParms.flags := 0;
  1685.              protectedP^.newParms.functionCode := BTRV_CODE;
  1686.              protectedP^.newParms.dataLength   := SizeOf( PMPARMBLOCK );
  1687.              protectedP^.newParms.dataPtr := realPtr +
  1688.                            Ofs( protectedP^.twoPointers) - Ofs( protectedP^ );
  1689.  
  1690.              protectedP^.btrv.XDATA.USER_CUR_ADDR  := realPtr +
  1691.                  Ofs( protectedP^.btrv.POS_BLOCK ) - Ofs( protectedP^ ) + 38;
  1692.  
  1693.              protectedP^.btrv.XDATA.USER_FCB_ADDR  := realPtr +
  1694.                  Ofs( protectedP^.btrv.POS_BLOCK ) - Ofs( protectedP^ );
  1695.  
  1696.              protectedP^.btrv.XDATA.USER_STAT_ADDR := realPtr +
  1697.                  Ofs( protectedP^.btrv.STATUS ) - Ofs( protectedP^ );
  1698.  
  1699.              protectedP^.btrv.XDATA.USER_KEY_ADDR  := realPtr +
  1700.                  Ofs( protectedP^.btrv.KEY_BUFFER ) - Ofs( protectedP^ );
  1701.  
  1702.              protectedP^.btrv.XDATA.USER_BUF_ADDR  := realPtr +
  1703.                  Ofs( protectedP^.btrv.DATA_BUF ) - Ofs( protectedP^ );
  1704.  
  1705.              protectedP^.btrv.XDATA.XFACE_ID       := VARIABLE_ID;
  1706.  
  1707.              protectedP^.btrv.XDATA.USER_FUNCTION  := operation;
  1708.              protectedP^.btrv.XDATA.USER_BUF_LEN   := dataLength;
  1709.  
  1710.                                 { use maximum key length since we don't know }
  1711.              protectedP^.btrv.XDATA.USER_KEY_LENGTH := 255;
  1712.              protectedP^.btrv.XDATA.USER_KEY_NUMBER := keyNumber;
  1713.  
  1714.              stat := SetUpBTRVData(
  1715.                        PTR(Seg(protectedP^.btrv),Ofs(protectedP^.btrv)),
  1716.                        positionBlock,      { application's position block    }
  1717.                        dataBuffer,         { application's data buffer       }
  1718.                        keyBuffer );        { application's key buffer        }
  1719.  
  1720.              if stat = B_NO_ERROR then
  1721.                begin
  1722.  
  1723.                  {============================================================
  1724.                  Make call to Btrieve using DPMI.
  1725.                  ============================================================}
  1726.  
  1727.                  REGS.AX := $300;
  1728.                  REGS.BX := BTR_INTRPT ;
  1729.                  {*
  1730.                  **   CX = Number of words to copy from protected-mode to
  1731.                  **   real-mode stack
  1732.                  *}
  1733.                  REGS.CX := 0;
  1734.  
  1735.                  {*
  1736.                  ** Initialize real mode segment registers for call to Btrieve
  1737.                  *}
  1738.  
  1739.                  FillChar( realmodeRegs, SizeOf( REALREGS ), 0 );
  1740.  
  1741.                  realmodeRegs.DS := HiWord( realPtr );
  1742.                  realmodeRegs.DX := LoWord( realPtr );
  1743.                  REGS.ES := Seg( realmodeRegs );
  1744.                  REGS.DI := Ofs( realmodeRegs );
  1745.  
  1746.                  INTR( $31, REGS );
  1747.  
  1748.                  dataLength := protectedP^.btrv.XDATA.USER_BUF_LEN;
  1749.                  stat := protectedP^.btrv.STATUS;
  1750.  
  1751.                  {============================================================
  1752.                  Copy data from protected mode back to user's data
  1753.                  ============================================================}
  1754.                  RetrieveBTRVData(
  1755.                    PTR(Seg(protectedP^.btrv),Ofs(protectedP^.btrv)),
  1756.                    positionBlock,
  1757.                    dataBuffer,
  1758.                    keyBuffer );
  1759.                end;
  1760.  
  1761.              FreeRealModeBuffer( Seg( protectedP^ ) );
  1762.  
  1763.            end;
  1764.        end;
  1765.      BTRVID := stat;
  1766.  
  1767. END; { BTRVID }
  1768. {$ENDIF}    { protected mode BTRV and BTRVID }
  1769.  
  1770. {$B-}
  1771.  
  1772. END.
  1773.