home *** CD-ROM | disk | FTP | other *** search
/ Turbo Toolbox / Turbo_Toolbox.iso / dtx9101 / tools / dbtopas / dbutil.pas
Encoding:
Pascal/Delphi Source File  |  1991-03-07  |  22.9 KB  |  775 lines

  1. (* ------------------------------------------------------ *)
  2. (*                     DBUTIL.PAS                         *)
  3. (*                dBase III Schnittstelle                 *)
  4. (*             (c) 1991 F.Vogler & DMV-Verlag             *)
  5. (* ------------------------------------------------------ *)
  6. UNIT DBUTIL;
  7.  
  8. {.$DEFINE Debug }       (* zum Testen den '.' löschen ... *)
  9.  
  10. INTERFACE
  11.  
  12. USES Dos, Crt;
  13.  
  14. {$IFDEF Debug}
  15. VAR
  16.   OutF    : Text;
  17.   OutTyp  : CHAR;
  18.   Ch      : CHAR;
  19.   OutName : PathStr;
  20. {$ENDIF}
  21.  
  22. CONST
  23.   MAX_OPENED = 3;    { maximale Anzahl offener DBF-Dateien }
  24.  
  25. TYPE
  26.   pBuffer = ^tBuffer;
  27.   tBuffer = RECORD
  28.     Buf : ARRAY [1..4096] OF BYTE;
  29.   END;
  30.  
  31.   pField = ^tField;          { Zeiger auf Feldbeschreibung }
  32.   tField = RECORD            { Beschreibung eines Felds    }
  33.     F_Name   : STRING [10];
  34.     F_Type   : CHAR;
  35.     F_Length : BYTE;
  36.     F_Dec    : BYTE;
  37.     F_Offset : WORD;         { erstes Byte des Felds       }
  38.   END;
  39.  
  40.   pDatabase = ^tDatabase;    { Zeiger auf eine DBF-Datei   }
  41.   tDatabase = RECORD         { Daten für jede DBF-Datei    }
  42.     DOS_FName    : PathStr;
  43.     DBT_FName    : PathStr;
  44.     Fields       : ARRAY [1..128] OF pField;
  45.     MaxFields    : BYTE;
  46.     RecLength    : WORD;
  47.     RecNumber    : LONGINT;
  48.     StartByte    : WORD;
  49.     LastRecord   : LONGINT;
  50.     FieldCont    : tBuffer;
  51.     ContainsMemo : BOOLEAN;
  52.     MemoOpened   : BOOLEAN;
  53.     MemoRead     : BOOLEAN;
  54.     MemoBuffer   : pBuffer;
  55.   END;
  56.  
  57. VAR
  58.   DBF_Selected : BYTE;     { aktuell selektierte DBF-Datei }
  59.   DBF_File     : FILE;     { DBF- und DBT-Dateien sind     }
  60.   DBT_File     : FILE;     { nicht typisiert.              }
  61.   a_DBF_File   : ARRAY [1..MAX_OPENED] OF pDatabase;
  62.                            { Zeiger auf eine DBF-Datei     }
  63.   aBuffer      : tBuffer;
  64.  
  65.  
  66.   FUNCTION DBF_Open(Select : WORD;
  67.                     FName  : PathStr) : BOOLEAN;
  68.     (* öffnet eine DBF-Datei.                             *)
  69.     (*                                                    *)
  70.     (* Argumente: Select = Arbeitsbereich                 *)
  71.     (*            FName  = DOS-Name der DBF-Datei         *)
  72.  
  73.   FUNCTION DBF_Read(Select : WORD;
  74.                     RecNo  : LONGINT) : BOOLEAN;
  75.     (* Versucht, eine DBF-Datei zu öffnen und             *)
  76.     (* initialisiert die verwendeten Variablen.           *)
  77.     (*                                                    *)
  78.     (* Argumente: Select = Arbeitsbereich                 *)
  79.     (*            RecNo  = zu lesender Datensatz          *)
  80.     (* Rückgabe : TRUE, wenn der Satz gelesen wurde       *)
  81.     (*                                                    *)
  82.     (* Struktur einer DBF-Datei:                          *)
  83.     (*                                                    *)
  84.     (*                   Bytes     Inhalt                 *)
  85.     (*   Bytes 1..32 :  5- 8   (LONGINT) = Anzahl Records *)
  86.     (*                  9-10   (WORD)    = Offset 1.Satz  *)
  87.     (*                 11-12   (WORD)    = Bytes/Record   *)
  88.     (*                                                    *)
  89.     (*   Bytes 32..1.Satz (in Einheiten zu je 32 Bytes)   *)
  90.     (*                                                    *)
  91.     (*                  1-10   (ASCIIZ)  = F_Name         *)
  92.     (*                    12   (CHAR)    = F_Type         *)
  93.     (*                    17   (BYTE)    = F_Length       *)
  94.     (*                    18   (BYTE)    = F_Dec          *)
  95.     (*                                                    *)
  96.     (*   Jeder Datensatz beginnt mit einem Markierungs-   *)
  97.     (*   feld: ' ' = Datensatz aktiv, '*' gelöscht.       *)
  98.     (* -------------------------------------------------- *)
  99.  
  100.   PROCEDURE DBF_Close;
  101.     (* Schließt DBF-Datei                                 *)
  102.  
  103.   FUNCTION Get_By_Nr(Select, i : WORD) : STRING;
  104.     (* Gibt den Inhalt eines Feldes zurück                *)
  105.     (*                                                    *)
  106.     (* Argumente: Select = Arbeitsbereich                 *)
  107.     (*            i      = Nummer des Felds               *)
  108.  
  109.   FUNCTION Get_Fields_Nr(Select : WORD;
  110.                          FName  : STRING) : WORD;
  111.     (* Gibt die Feldnummer zurück                         *)
  112.     (*                                                    *)
  113.     (* Argumente: Select = Arbeitsbereich                 *)
  114.     (*            FName  = Feldname                       *)
  115.  
  116.   FUNCTION Get_Fields_Cont(Select : WORD;
  117.                            FName : STRING) : STRING;
  118.     (* Selektiert ein Feld, wenn der Datensatz gelesen    *)
  119.     (* und gibt dessen Inhalt als String zurück. Ein      *)
  120.     (* leerer String bedeutet, daß das Feld nicht         *)
  121.     (* gefunden wurde.                                    *)
  122.     (*                                                    *)
  123.     (* Argumente: Select = Arbeitsbereich                 *)
  124.     (*            FName  = Feldname                       *)
  125.  
  126. CONST
  127.   MAXKEYS = 600;          { maximale Anzahl an NDX-Zeigern }
  128.  
  129. TYPE
  130.   pIndex = ^tIndex;
  131.   tIndex = RECORD
  132.     Satz       : LONGINT;
  133.     Last, Next : pIndex;
  134.   END;
  135.  
  136. VAR
  137.   Header    : pIndex;     { Zeiger auf ersten Datensatz    }
  138.   FoundKeys : LONGINT;    { Anzahl der indizierten Records }
  139.  
  140.  
  141.   FUNCTION NTX_Get(FName  : STRING;
  142.                    IdxKey : STRING;
  143.                    IsNtx  : BOOLEAN) : BOOLEAN;
  144.     (* Durchsucht NTX- oder NDX-Datei und zählt gefundene *)
  145.     (* Indizes in die Variable "FoundKeys". Entsprechende *)
  146.     (* Datensätze werden während der Prozedur "NewKey"    *)
  147.     (* gespeichert.                                       *)
  148.     (*                                                    *)
  149.     (* Argumente: FName  = kompl. Name der NTX-Datei      *)
  150.     (*            IdxKey = gesuchter Schlüssel            *)
  151.     (*            IsNtx  = TRUE  für NTX-Datei            *)
  152.     (*                     FALSE für NDX-Datei            *)
  153.     (* Rückgabe : TRUE, wenn Schlüssel gefunden wurde     *)
  154.  
  155.   FUNCTION IndexKey(FName : STRING;
  156.                      IsNtx : BOOLEAN) : STRING;
  157.     (* Gibt den Indexschlüssel zurück, der unter dBase    *)
  158.     (* mit INDEX ON ...  angelegt wurde. Er beginnt in    *)
  159.     (* NDX-Dateien mit Byte 22, in NTX-Dateien mit        *)
  160.     (* Byte 24 und endet mit #0.                          *)
  161.     (*                                                    *)
  162.     (* Argumente: FName = Dateiname                       *)
  163.     (*            IsNtx = TRUE für Clipper NTX-Dateien    *)
  164.  
  165.   FUNCTION FExists(FName : PathStr) : BOOLEAN;
  166.     (* gibt TRUE zurück, wenn die angegebene Datei        *)
  167.     (* existiert                                          *)
  168.  
  169.   FUNCTION Trim(S : STRING) : STRING;
  170.     (* entführt führende und folgende Leerzeichen einer   *)
  171.     (* Zeichenkette                                       *)
  172.  
  173.   FUNCTION StUpCase(S : STRING) : STRING;
  174.     (* Wandelt eine Zeichenkette in Großbuchstaben um     *)
  175.  
  176.  
  177. IMPLEMENTATION
  178.  
  179. VAR
  180.   MaxnPtr  : pIndex;         { Letzter Zeiger auf tIndex   }
  181.   NTX      : FILE;           { Handle der Indexdatei       }
  182.   IndexLen : BYTE;           { Länge des Schlüssels in der }
  183.                              { Indexdatei                  }
  184.   KeyLen   : WORD;           { Minimum von IndexLen und    }
  185.                              { Length(INDXKEY)             }
  186.   MaxPages : LONGINT;        { Seiten in der NDX-Datei     }
  187.  
  188.  
  189.   FUNCTION StUpCase(S : STRING) : STRING;
  190.   VAR
  191.     i : WORD;
  192.   BEGIN
  193.     FOR i := 1 TO Length(S) DO S[i] := UpCase(S[i]);
  194.     StUpCase := S;
  195.   END;
  196.  
  197.   FUNCTION Trim(S : STRING) : STRING;
  198.   VAR
  199.     i    : WORD;
  200.     SLen : BYTE ABSOLUTE S;
  201.   BEGIN
  202.     WHILE (SLen > 0) AND (S[SLen] <= ' ') DO DEC(SLen);
  203.     i := 1;
  204.     WHILE (i <= SLen) AND (S[i] <= ' ') DO INC(i);
  205.     DEC(i);
  206.     IF i > 0 THEN Delete(S, 1, i);
  207.     Trim := S;
  208.   END;
  209.  
  210.   FUNCTION FExists(FName : PathStr) : BOOLEAN;
  211.   VAR
  212.     f : FILE;
  213.   BEGIN
  214.     Assign(f, FName);
  215.     {$I-}
  216.     Reset(f)
  217.     {$I+} ;
  218.     IF IOResult = 0 THEN BEGIN
  219.       Close(f);
  220.       FExists := TRUE;
  221.     END ELSE FExists := FALSE;
  222.   END;
  223.  
  224.   FUNCTION DBT_Read(Select : WORD;
  225.                     RecNo  : LONGINT) : BOOLEAN;
  226.   VAR
  227.     r  : LONGINT;
  228.     LL : LONGINT;
  229.   BEGIN
  230.     WITH a_DBF_File[Select]^ DO BEGIN
  231.       IF MemoOpened THEN BEGIN
  232.         r := RecNo * 512;
  233.         Seek(DBT_File, r);
  234.         LL := 512;
  235.         {
  236.         BlockRead(DBT_File, aBuffer, 4);
  237.         Move(aBuffer.buf[1], LL, 4);
  238.         Seek(DBT_File, r);
  239.         LL := LL + 4;
  240.         }
  241.         BlockRead(DBT_File, MemoBuffer^, LL);
  242.         DBT_Read := TRUE;
  243.       END ELSE
  244.         DBT_Read := FALSE;
  245.     END;
  246.   END;
  247.  
  248.   FUNCTION Get_Fields_Nr(Select : WORD;
  249.                          FName  : STRING) : WORD;
  250.   VAR
  251.     i : WORD;
  252.     s : STRING;
  253.   BEGIN
  254.     s := StUpCase(Trim(FName));
  255.     i := 1;
  256.     WITH a_DBF_File[Select]^ DO BEGIN
  257.       WHILE (i <= MaxFields) AND
  258.             (Trim(Fields[i]^.F_Name) <> s) DO INC(i);
  259.       IF (i <= MaxFields) THEN
  260.         Get_Fields_Nr := i
  261.       ELSE
  262.         Get_Fields_Nr := 0;
  263.     END;
  264.   END;
  265.  
  266.   FUNCTION Get_By_Nr(Select, i : WORD) : STRING;
  267.   VAR
  268.     s : STRING;
  269.     r : LONGINT;
  270.     e : INTEGER;
  271.   BEGIN
  272.     s[0] := Chr(0);
  273.     WITH a_DBF_File[Select]^ DO BEGIN
  274.       MemoRead := FALSE;
  275.       IF (i > 0) AND (i <= MaxFields) THEN BEGIN
  276.         Move(FieldCont.Buf[Fields[i]^.F_Offset],
  277.              s[1], Fields[i]^.F_Length);
  278.         s[0] := Chr(Fields[i]^.F_Length);
  279.         IF Fields[i]^.F_Type = 'M' THEN BEGIN
  280.           Val(Trim(s), r, e);
  281.           IF (r > 0) AND (e = 0) THEN
  282.             MemoRead := DBT_Read(Select, r);
  283.         END;
  284.       END;
  285.     END;
  286.     Get_By_Nr := s;
  287.   END;
  288.  
  289.   FUNCTION Get_Fields_Cont(Select : WORD;
  290.                            FName  : STRING) : STRING;
  291.   BEGIN
  292.     Get_Fields_Cont := Get_By_Nr(Select,
  293.                        Get_Fields_Nr(Select, FName));
  294.   END;
  295.  
  296.   PROCEDURE DBF_Close;
  297.   BEGIN
  298.     {$I-}
  299.     Close(DBF_File);
  300.     {$I+}
  301.     IF IOResult <> 0 THEN ;
  302.     {$I-}
  303.     Close(DBT_File);
  304.     {$I+}
  305.     IF IOResult <> 0 THEN ;
  306.     DBF_Selected := 0;
  307.   END;
  308.  
  309.   PROCEDURE Blocks(    Start          : LONGINT;
  310.                        Select, Number : WORD;
  311.                    VAR Buffer         : tBuffer);
  312.     (*  füllt den Puffer "Buffer"                         *)
  313.     (* Argumente : Start  = Anfangsadresse zum Lesen      *)
  314.     (*             Select = Arbeitsbereich                *)
  315.     (*             Number = Anzahl zu lesender Bytes      *)
  316.   BEGIN
  317.     WITH a_DBF_File[Select]^ DO BEGIN
  318.       IF DBF_Selected <> Select THEN BEGIN
  319.         DBF_Close;
  320.         Assign(DBF_File, DOS_FName);
  321.         Reset(DBF_File, 1);
  322.         IF ContainsMemo THEN BEGIN
  323.           Assign(DBT_File, DBT_FName);
  324.           Reset(DBT_File, 1);
  325.           MemoOpened := TRUE;
  326.         END;
  327.       END;
  328.       DBF_Selected := Select;
  329.       Seek(DBF_File, Start);
  330.       BlockRead(DBF_File, Buffer, Number);
  331.     END;
  332.   END;
  333.  
  334.   FUNCTION DBF_Open(Select : WORD;
  335.                     FName  : PathStr) : BOOLEAN;
  336.   VAR
  337.     s         : STRING;
  338.     i, Offset : WORD;
  339.     r         : LONGINT;
  340.   BEGIN
  341.     DBF_Open := FALSE;
  342.     IF NOT (Select IN [1..MAX_OPENED]) THEN Exit;
  343.     s := StUpCase(FName);
  344.  
  345.     IF NOT FExists(s) THEN Exit;
  346.  
  347.     IF a_DBF_File[Select] = NIL THEN
  348.       New(a_DBF_File[Select]);
  349.     WITH a_DBF_File[Select]^ DO BEGIN
  350.       Assign(DBF_File, s);
  351.       DOS_FName    := s;
  352.       ContainsMemo := FALSE;
  353.       MemoOpened   := FALSE;
  354.       MemoBuffer   := NIL;
  355.       MemoRead     := FALSE;
  356.       Reset(DBF_File);
  357.       Blocks(0, Select, 128, aBuffer);
  358.       Move(aBuffer.Buf[5], RecNumber, 4);
  359.  
  360.       Move(aBuffer.Buf[9], StartByte, 2);
  361.  
  362.       Move(aBuffer.Buf[11], RecLength, 2);
  363.  
  364.       r         := 32;
  365.       MaxFields := 0;
  366.       Offset    := 2;
  367.       WHILE (r+4) < (StartByte) DO BEGIN
  368.         INC(MaxFields);
  369.         New(Fields[MaxFields]);
  370.         WITH Fields[MaxFields]^ DO BEGIN
  371.           Blocks(r, Select, 32, aBuffer);
  372.           i      := 1;
  373.           F_Name := '';
  374.           WHILE aBuffer.Buf[i] > 0 DO BEGIN
  375.             F_Name := F_Name + CHAR(aBuffer.Buf[i]);
  376.             i := i+1;
  377.           END;
  378.           F_Type := CHAR(aBuffer.Buf[12]);
  379.           IF (F_Type = 'M') AND
  380.               NOT ContainsMemo THEN BEGIN
  381.             s := Copy(DOS_FName, 1,
  382.                       Pos('.', DOS_FName)) + 'DBT';
  383.             IF FExists(s) THEN BEGIN
  384.               New(MemoBuffer);
  385.               DBT_FName    := s;
  386.               ContainsMemo := TRUE;
  387.             END;
  388.           END;
  389.           F_Length := aBuffer.Buf[17];
  390.           F_Dec    := aBuffer.Buf[18];
  391.           F_Offset := Offset;
  392.           Offset   := Offset + F_Length;
  393.         END;
  394.         r := r + 32;
  395.       END;
  396.       DBF_Open := TRUE;
  397. {$IFDEF Debug}
  398.       IF OutTyp = 'S' THEN ClrScr;
  399.       IF OutTyp = 'F' THEN Append(OutF);
  400.       WriteLn(OutF, 'File Name: ', FName,
  401.                     ' is Nr: ', Select);
  402.       WriteLn(OutF, 'Contains ', RecNumber:10,
  403.                     ' Recs; Record Length is ', RecLength);
  404.       WriteLn(OutF, 'Nr Name      Type  Len  Dec');
  405.  
  406.       FOR i := 1 TO MaxFields DO
  407.         WITH Fields[i]^ DO BEGIN
  408.           Write(OutF, i:3, F_Name:10, '  ',
  409.                       F_Type:1, '   ');
  410.           Write(OutF, F_Length:3);
  411.           IF F_Type = 'N' THEN Write(OutF, F_Dec:4);
  412.           WriteLn(OutF);
  413.           IF (OutTyp = 'S') AND ((i MOD 20) = 0) THEN BEGIN
  414.             Write('Hit any key to continue...');
  415.             Ch := ReadKey;
  416.           END;
  417.         END;
  418.  
  419.       IF OutTyp = 'F' THEN Close(OutF);
  420. {$ENDIF}
  421.     END;
  422.   END;
  423.  
  424.   FUNCTION DBF_Read(Select : WORD;
  425.                     RecNo  : LONGINT) : BOOLEAN;
  426.   VAR
  427.     r : LONGINT;
  428.   BEGIN
  429.     DBF_Read := FALSE;
  430.     IF NOT (Select IN [1..MAX_OPENED]) THEN Exit;
  431.                                            { illegal nr    }
  432.     WITH a_DBF_File[Select]^ DO BEGIN
  433.       IF (RecNo < 1) OR(RecNo > RecNumber) THEN Exit;
  434.                                            { illegal RecNo }
  435.       LastRecord := RecNo;
  436.       r := (RecNo-1) * RecLength + StartByte;
  437.       Blocks(r, Select, RecLength, FieldCont);
  438.     END;
  439.     DBF_Read := TRUE;
  440.   END;
  441.  
  442.   FUNCTION IndexKey(FName : STRING;
  443.                      IsNtx : BOOLEAN) : STRING;
  444.   VAR
  445.     Bufs : ARRAY [0..511] OF BYTE;
  446.     s    : STRING;
  447.     i    : WORD;
  448.   BEGIN
  449.     Assign(NTX, FName);
  450.     Reset(NTX, 512);
  451.     BlockRead(NTX, Bufs, 1);
  452.     Close(NTX);
  453.     IF IsNtx THEN
  454.       i := 22
  455.     ELSE
  456.       i := 24;  { Start des Indexschlüssels (INDEX ON ...) }
  457.     s := '';
  458.     WHILE (i < 512) AND (Bufs[i] >= 32) DO BEGIN
  459.       s := s + Chr(Bufs[i]); INC(i);
  460.     END;
  461.     IndexKey := s;
  462.   END;
  463.  
  464.  
  465.   FUNCTION Equals(s1, s2 : STRING) : BYTE;
  466.     (* Byteweiser Stringvergleich                         *)
  467.     (* Argumente: s1 = Index aus der Datei                *)
  468.     (*            s2 = gesuchter Schlüssel                *)
  469.     (*            Length(s1) = Length(s2) !!!             *)
  470.     (* Rückgabe : 0, wenn s1 < s2                         *)
  471.     (*            1, wenn s1 = s2                         *)
  472.     (*            2, wenn s1 > s2                         *)
  473.   VAR
  474.     i : WORD;
  475.     b : BYTE;
  476.   BEGIN
  477.     b := 1;
  478.     i := 0;
  479.     WHILE (i < Length(s1)) AND (b = 1) DO BEGIN
  480.       INC(i);
  481.       IF s1[i] < s2[i] THEN
  482.         b := 0
  483.       ELSE IF s1[i] > s2[i] THEN
  484.         b := 2;
  485.     END;
  486.     Equals := b;
  487.   END;
  488.  
  489.   FUNCTION NewRec(RecNo : LONGINT;
  490.                   IsNtx : BOOLEAN) : BOOLEAN;
  491.   BEGIN
  492.     NewRec := FALSE;
  493.     IF FoundKeys = MAXKEYS THEN Exit;
  494.     NewRec := TRUE;
  495.     INC(FoundKeys);
  496.     IF Header = NIL THEN BEGIN
  497.       New(Header);
  498.       MaxnPtr      := Header;
  499.       Header^.Last := NIL;
  500.     END ELSE BEGIN
  501.       New(MaxnPtr^.Next);
  502.       MaxnPtr^.Next^.Last := MaxnPtr;
  503.       MaxnPtr             := MaxnPtr^.Next;
  504.     END;
  505.     MaxnPtr^.Next := NIL;
  506.     MaxnPtr^.Satz := RecNo;
  507.  
  508. {$IFDEF Debug}
  509.     Write(OutF, ' add found ', FoundKeys, ' ', RecNo);
  510.     IF OutTyp = 'S' THEN BEGIN
  511.       Write(' [enter]->'); ReadLn;
  512.     END ELSE
  513.       WriteLn(OutF);
  514. {$ENDIF}
  515.  
  516.   END;
  517.  
  518.  
  519.   PROCEDURE NTX_Read(Ofs0   : LONGINT;
  520.                      KeyLen : WORD;
  521.                      IdxKey : STRING);
  522.   VAR
  523.     Ofs1, PG, Satz : LONGINT;
  524.     j, Max, Offset : WORD;
  525.     i              : INTEGER;
  526.     BB             : BYTE;
  527.     Buffer         : ARRAY [0..1023] OF BYTE;
  528.     OneStr         : STRING;
  529.     ok             : BOOLEAN;
  530.   BEGIN
  531.     Ofs1 := Ofs0;
  532.     IF FoundKeys = MAXKEYS THEN Exit;
  533.     WHILE (Ofs1 > 0) DO BEGIN
  534.       Seek(NTX, Ofs1);
  535.       BlockRead(NTX, Buffer, 1);
  536.       Move(Buffer[0], Max, 2);
  537.       Move(Buffer[2], Offset, 2);
  538.       ok := TRUE;
  539.       i  := -1;
  540.       WHILE (i < Pred(Max)) AND ok DO BEGIN
  541.         INC(i);
  542.         Move(Buffer[i*2+2], j, 2);
  543.         Move(Buffer[j+8], OneStr[1], IndexLen);
  544.         OneStr[0] := Chr(IndexLen);
  545.         BB := Equals(Copy(OneStr, 1, KeyLen),
  546.                      Copy(IdxKey, 1, KeyLen));
  547.         IF BB IN [1..2] THEN BEGIN
  548.           Move(Buffer[j], PG, 4);
  549.           PG := PG DIV 1024;
  550.           Move(Buffer[j+4], Satz, 4);
  551.           IF (BB = 1) AND (PG = 0) THEN
  552.             IF NOT (NewRec(Satz, TRUE)) THEN Exit;
  553.           IF PG > 0 THEN BEGIN
  554.             NTX_Read(PG, KeyLen, IdxKey);
  555.             IF BB = 1 THEN
  556.               IF NOT (NewRec(Satz, TRUE)) THEN Exit;
  557.           END;
  558.           IF BB = 2 THEN ok := FALSE;
  559.         END;
  560.       END;
  561.       Ofs1 := 0;
  562.       IF ok THEN BEGIN
  563.         Move(Buffer[Max*2+2], j, 2);
  564.         Move(Buffer[j], Ofs1, 4);
  565.         Ofs1 := Ofs1 DIV 1024;
  566.       END;
  567.     END;
  568.   END;
  569.  
  570.  
  571.   FUNCTION NTX_Get(FName  : STRING;
  572.                    IdxKey : STRING;
  573.                    IsNtx  : BOOLEAN) : BOOLEAN;
  574.   TYPE
  575.     EinRecPtr = ^EinRec;
  576.     EinRec    = RECORD
  577.       PG   : LONGINT;
  578.       Satz : LONGINT;
  579.       Key  : STRING [30];
  580.       Next : EinRecPtr;
  581.     END;
  582.   VAR
  583.     Buffer     : ARRAY [0..1023] OF BYTE;      { ein Block }
  584.     Root       : LONGINT;                      { Start PG  }
  585.     KeyOffset  : BYTE;
  586.     BB         : BYTE;
  587.     Pass       : LONGINT;
  588.  
  589.  
  590.     PROCEDURE NDX_Start;
  591.     BEGIN
  592.       Assign(NTX, FName);
  593.       Reset(NTX, 512);
  594.       BlockRead(NTX, Buffer, 1);
  595.       Move(Buffer[12], IndexLen, 1);
  596.       Move(Buffer[0], Root, 4);
  597.       Move(Buffer[18], KeyOffset, 1);
  598.       Move(Buffer[4], MaxPages, 4);
  599.     END;
  600.  
  601.     PROCEDURE NTX_Start;
  602.     BEGIN
  603.       Assign(NTX, FName);
  604.       Reset(NTX, 1024);
  605.       BlockRead(NTX, Buffer, 1);
  606.       Move(Buffer[4], Root, 4);
  607.       Root := Root DIV 1024;
  608.       Move(Buffer[14], IndexLen, 2);
  609.     END;
  610.  
  611.     PROCEDURE NDX_Read(Ofs0 : LONGINT);
  612.     VAR
  613.       Buffer         : ARRAY [0..511] OF BYTE;
  614.       Rec, PGG, Satz : LONGINT;
  615.       Key            : STRING;
  616.       Offset         : WORD;
  617.       ok             : BOOLEAN;
  618.     BEGIN
  619.       IF FoundKeys = MAXKEYS THEN Exit;
  620.       Rec := Ofs0;
  621.       Seek(NTX, Rec);
  622.       BlockRead(NTX, Buffer, 1);
  623.       ok     := TRUE;
  624.       Offset := 4;
  625.       WHILE ok AND ((Offset + KeyOffset) <= 512) DO BEGIN
  626.         Move(Buffer[Offset], PGG, 4);
  627.         Move(Buffer[Offset+4], Satz, 4);
  628.         Move(Buffer[Offset+8], Key[1], IndexLen);
  629.         Key[0] := Chr(IndexLen);
  630.         Offset := Offset + KeyOffset;
  631.         IF (Satz + PGG) = 0 THEN
  632.           ok := FALSE
  633.         ELSE BEGIN
  634.           IF (KeyLen > 0) THEN
  635.             BB := Equals(Copy(Key, 1, KeyLen),
  636.                          Copy(IdxKey, 1, KeyLen))
  637.           ELSE
  638.             BB := 1;
  639.  
  640. {$IFDEF Debug}
  641.           Write(OutF, 'Internalkey: ', Key,
  642.                       ' Searchkey: ', IdxKey, ' ', BB);
  643.           IF (BB = 0) THEN             { Internal < Search }
  644.             IF OutTyp = 'S' THEN BEGIN
  645.               Write(' [enter]->'); ReadLn;
  646.             END ELSE
  647.               WriteLn(OutF);
  648. {$ENDIF}
  649.           IF (BB = 1) AND (PGG = 0) THEN
  650.             IF NOT (NewRec(Satz, IsNtx)) THEN Exit;
  651.           IF BB IN [1..2] THEN BEGIN
  652.             IF PGG > 0 THEN BEGIN
  653. {$IFDEF Debug}
  654.               Write(' add pointer ', PGG, ' ', Key);
  655.               IF OutTyp = 'S' THEN BEGIN
  656.                 Write(' [enter]->'); ReadLn;
  657.               END ELSE
  658.                 WriteLn(OutF);
  659. {$ENDIF}
  660.               IF (FoundKeys >= 600) OR (BB = 2) THEN
  661.                 ok := FALSE;
  662.             END;
  663.           END;
  664.           IF PGG > 0 THEN NDX_Read(PGG);
  665.         END;
  666.       END;
  667.       IF ok THEN BEGIN
  668.         INC(Rec);
  669.         IF Rec > MaxPages THEN ok := FALSE;
  670.       END;
  671.       IF NOT ok THEN Rec := 0;
  672.     END;
  673.  
  674.   BEGIN
  675.     NTX_Get   := FALSE;
  676.     Header    := NIL;
  677.     FoundKeys := 0;
  678. {$IFDEF Debug}
  679.     IF OutTyp = 'F' THEN Append(OutF);
  680.     ClrScr;
  681.     WriteLn(OutF, 'Index: ', FName, ' ',
  682.                   FExists(FName), ' ', Length(IdxKey), ' ',
  683.                   IdxKey);
  684.     Write(OutF, IndexKey(FName, IsNtx));
  685.     IF OutTyp = 'S' THEN BEGIN
  686.       Write(' [enter]->'); ReadLn;
  687.     END ELSE
  688.       WriteLn(OutF);
  689. {$ENDIF}
  690.     IF Length(Trim(FName)) = 0 THEN Exit;
  691.     IF NOT FExists(FName) THEN Exit;
  692.     IF IsNtx THEN
  693.       NTX_Start
  694.     ELSE
  695.       NDX_Start;
  696. {$IFDEF Debug}
  697.     Write(OutF, 'Is_NTX: ', IsNtx, ' Root ', Root);
  698.     IF OutTyp = 'S' THEN BEGIN
  699.       Write(' [enter]->'); ReadLn;
  700.     END ELSE
  701.       WriteLn(OutF);
  702. {$ENDIF}
  703.     KeyLen := Length(IdxKey);
  704.     IF IndexLen < KeyLen THEN KeyLen := IndexLen;
  705.     IF Root > 0 THEN
  706.       IF IsNtx THEN
  707.         NTX_Read(Root, KeyLen, IdxKey)
  708.       ELSE
  709.         NDX_Read(Root);
  710.     NTX_Get := Header <> NIL;
  711.     Close(NTX);
  712. {$IFDEF Debug}
  713.     Write(OutF, 'Recs Found ', FoundKeys);
  714.     IF OutTyp = 'S' THEN BEGIN
  715.       Write(' [enter]->'); ReadLn;
  716.     END ELSE
  717.       WriteLn(OutF);
  718.     IF OutTyp = 'F' THEN Close(OutF);
  719. {$ENDIF}
  720.   END;
  721.  
  722.   PROCEDURE Init;
  723. {$IFDEF Debug}
  724.   VAR
  725.     x, y : BYTE;
  726. {$ENDIF}
  727.   VAR
  728.     i : WORD;
  729.   BEGIN
  730.     FOR i := 1 TO MAX_OPENED DO
  731.       a_DBF_File[i] := NIL;
  732.     DBF_Selected := 0;
  733.        { keine dBase III Datei ist geöffnet }
  734. {$IFDEF Debug}
  735.     ClrScr;
  736.     Write('Output to S(creen), P(rinter), F(ile) S/P/F ');
  737.     x := WhereX;
  738.     y := WhereY;
  739.     REPEAT
  740.       GotoXY(x,y);
  741.       OutTyp := ReadKey;
  742.       OutTyp := UpCase(OutTyp);
  743.     UNTIL OutTyp IN ['F', 'P', 'S'];
  744.     CASE OutTyp OF
  745.       'F' : BEGIN
  746.               REPEAT
  747.                 Write('Output Text File Name? ');
  748.                 ReadLn(OutName);
  749.               UNTIL Length(OutName) > 0;
  750.               Assign(OutF, OutName);
  751.               IF NOT FExists(OutName) THEN BEGIN
  752.                 Rewrite(OutF);
  753.                 Close(OutF);
  754.               END;
  755.             END;
  756.       'P' : BEGIN
  757.               Assign(OutF, 'PRN');
  758.               Rewrite(OutF);
  759.             END;
  760.       'S' : BEGIN
  761.               Assign(OutF, 'CON');
  762.               Rewrite(OutF);
  763.             END;
  764.     END;
  765. {$ENDIF}
  766.  
  767.   END;
  768.  
  769.  
  770. BEGIN
  771.   Init;
  772. END.
  773. (* ------------------------------------------------------ *)
  774. (*               Ende von DBUTIL.PAS                      *)
  775.