home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / TPDB21.ZIP / TPDB.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1989-02-22  |  37.5 KB  |  1,531 lines

  1. {$A+,B+,D-,E-,F-,I-,L-,N-,O-,R-,S-,V-}
  2. {$M 65520,0,655360}
  3. Unit TPDB;
  4.  
  5. {This version is Version 2.1 February ??, 1989}
  6.  
  7.                      (***********************************)
  8.                      (*     Turbo Pascal 5.0 Unit       *)
  9.                      (*    for Accessing dBASE III      *)
  10.                      (*             files.              *)
  11.                      (*        Copyright 1989           *)
  12.                      (*          Brian Corll            *)
  13.                      (*       All Rights Reserved       *)
  14.                      (*     dBASE is a registered       *)
  15.                      (* trademark of Ashton-Tate, Inc.  *)
  16.                      (* Version 2.1  February ??, 1989  *)
  17.                      (***********************************)
  18.                      (* Credits : Juan Vegarra          *)
  19.                      (***********************************)
  20.  
  21.  
  22. INTERFACE
  23.  
  24. Uses CRT,Dos,TPDBINDX,TPDBDate;
  25.  
  26.  
  27. (******************************)
  28. (*      Global Variables      *)
  29. (******************************)
  30.  
  31. Const
  32.  
  33.   AutoWrap    : Boolean = False;
  34.   CursorDown  = ^X;
  35.   CursorEnd   = ^F;
  36.   CursorHome  = ^A;
  37.   CursorLeft  = ^S;
  38.   CursorRight = ^D;
  39.   CursorUp    = ^E;
  40.   DelKey      = ^G;
  41.   Duplicates = 1;
  42.   Escape      = ^[;
  43.   ExtKey      : Boolean = False;
  44.   Filler      : Char =  #32;
  45.   MaxLong = 2147483647;
  46.   MaxReal = 3.4E37;
  47.   MinLong = -2147483647;
  48.   MinReal = 1.5E-45;
  49.   NoDuplicates = 0;
  50.   PageDown    = ^C;
  51.   PageUp      = ^R;
  52.   Return      = ^M;
  53.   TabKey      = #9;
  54.   UpperCase   : Boolean = False;
  55.  
  56.  
  57. {Color constants - defined to take advantage of Turbo Pascal's
  58.  constant folding capabilities.  See documentation.}
  59.  
  60.  
  61.   Black        = $00;       DarkGray     = $08;
  62.   Blue         = $01;       LightBlue    = $09;
  63.   Green        = $02;       LightGreen   = $0A;
  64.   Cyan         = $03;       LighBCyan    = $0B;
  65.   Red          = $04;       LightRed     = $0C;
  66.   Magenta      = $05;       LightMagenta = $0D;
  67.   Brown        = $06;       Yellow       = $0E;
  68.   LightGray    = $07;       White        = $0F;
  69.   Blink        = $80;
  70.  
  71.   BlackBG      = $00;
  72.   BlueBG       = $10;
  73.   GreenBG      = $20;
  74.   CyanBG       = $30;
  75.   RedBG        = $40;
  76.   MagentaBG    = $50;
  77.   BrownBG      = $60;
  78.   LightGrayBG  = $70;
  79.  
  80.  
  81. Type
  82.  
  83.   Str2 = String[2];
  84.   Str4 = String[4];
  85.   Str5 = String[5];
  86.   Str6 = String[6];
  87.   Str8 = String[8];
  88.   Str10 = String[10];
  89.   Str15 = String[15];
  90.   Str20 = String[20];
  91.   Str30 = String[30];
  92.   Str60 = String[60];
  93.   Str80 = String[80];
  94.   Str132 = String[132];
  95.   CharSet = Set of Char;
  96.   ByteSet = Set of Byte;
  97.  
  98.   FileName = String[66];
  99.   DBRecPtr = ^DBType;
  100.   DBType   = Array[1..4000] of Char;
  101.   DBKey    = String[254];
  102.   DisplayType = (Monochrome, CGA, EGA, MCGA, VGA);
  103.  
  104.   DBHeader = Record
  105.        DBType    : Byte;
  106.        Year      : Byte;
  107.        Month     : Byte;
  108.        Day       : Byte;
  109.        RecCount  : LongInt;
  110.        Location  : Integer;
  111.        RecordLen : Integer;
  112.        Reserved  : Array[1..20] of Byte;
  113.        Terminator : Char;
  114.          end;
  115.  
  116.     DBField = Record
  117.        FieldName    : Array[1..11] of Char;
  118.        FieldType    : Byte;
  119.        FieldAddress : LongInt;
  120.        FieldLen     : Byte;
  121.        FieldDec     : Byte;
  122.        Reserved     : Array[1..14] of Char;
  123.          end;
  124.  
  125. HeadPtr = ^DBHeader;
  126. PosPtr = ^DBEditArray;
  127. FieldPtr = ^FieldArray;
  128. DBEditArray = Array[1..2,1..128] of Integer;
  129. FieldArray  = Array[1..128] of DBField;
  130.  
  131.  
  132. Const
  133.  
  134.   Up   : CharSet = [CursorUp];
  135.   Down : CharSet = [CursorDown,Return];
  136.   Next : CharSet = [Escape];
  137.  
  138.  
  139.  
  140. Var
  141.     Normal             : Byte;
  142.     Reverse            : Byte;
  143.     UCKey,IndOpen,
  144.         DBFOpen    : Boolean;
  145.     DBFileName         : FileName;
  146.     DBFile,TempFile    : File;
  147.     Header             : HeadPtr;
  148.     Fields             : FieldPtr;
  149.     Allocated,MAlloc   : Boolean;
  150.     Message          : String[80];
  151.     Positions          : PosPtr;
  152.     DBRecord           : DBRecPtr;
  153.     NumFields,ErrCode  : Integer;
  154.     BC,Ch              : Char;
  155.     TotalRecs,DBRecNum,
  156.         R          : LongInt;
  157.     Y,M,D,DW           : Word;
  158.     NumLen,Decimals,
  159.         LL,K       : Byte;
  160.     DBIndex            : IndexFile;
  161.     DBIndexName        : FileName;
  162.     Found              : Boolean;
  163.     Start,Stop         : Integer;
  164.     CTxt           : Byte;
  165.     VideoBase        : Word;
  166.     VideoWait          : Boolean;
  167.  
  168.  
  169. (**********************************)
  170. (*   Procedures and Functions     *)
  171. (**********************************)
  172.  
  173. Procedure AddDBKey(KeyStr : DBKey);
  174. {Add a new key to an index.}
  175.  
  176. Procedure AddDBRec;
  177. {Add a new record to a .DBF, after the record has been created with
  178.  a call to NewDBRec.}
  179.  
  180. Procedure BailOut;
  181. {TPDB error handling routine.}
  182.  
  183. Procedure Beep;
  184. {Sound a couple of tones.}
  185.  
  186. Procedure BlockCursor;
  187. {Turn on a block cursor.}
  188.  
  189. Function  BOF : Boolean;
  190. {Test for beginning of .DBF file.}
  191.  
  192. Function BoolToStr(Param : Byte;IfTrue,IfFalse : Char): String;
  193.  
  194. Procedure CheckScreen(Var CurrPos:Byte;BC:Char;Up,Down:CharSet;Low,High:Byte);
  195. {Used in full screen editing.}
  196.  
  197. Procedure CloseDBFile;
  198. {Close dBASE file.}
  199.  
  200. Procedure CloseDBIndex;
  201. {Close an index.}
  202.  
  203. Procedure CursorOff;
  204.  
  205. Procedure CursorOn;
  206.  
  207. Procedure DBOpenFile(DBName : FileName);
  208. {Open dBASE file.}
  209.  
  210. Procedure DBReset;
  211. {Reset dBASE file.}
  212.  
  213. Procedure DelDBKey(KeyStr : DBKey);
  214. {Delete a key expression from an index}
  215.  
  216. Function  Deleted : Boolean;
  217. {Test whether or not a record is deleted.}
  218.  
  219. Procedure Display;
  220. {Display a record.}
  221.  
  222. Function  EOF : Boolean;
  223. {Test for end of .DBF file.}
  224.  
  225. Function  FieldToStr(FNo : Byte) : string;
  226. {Convert a field to a single string.}
  227.  
  228. Procedure FillRecs(NumRecs : LongInt);
  229. {Append a specified number of records to a .DBF file.}
  230.  
  231. Procedure Find(SearchStr : String);
  232. {Find a key string in an index.}
  233.  
  234. Procedure Flash(Row,Col, Attr:byte; Str : String);
  235. {Display a string at a specific row and column on the screen, using
  236.  direct screen writing methods.}
  237.  
  238. Procedure FlashC(Row,Attr:Byte;Str : String);
  239. {Same as above, except string is centered.}
  240.  
  241. Procedure FlashFill(Row,Col,Rows,Cols,Attr : Byte;Ch : Char);
  242. {Fill a region of the screen with a specified color and character.}
  243.  
  244. Procedure FlushDB;
  245. {Flush record in memory to disk.}
  246.  
  247. Procedure Get(FNo,X,Y : Byte);
  248. {Edit a field.}
  249.  
  250. Function GetBoolean(Var Param:Byte;IfTrue,IfFalse:Char;X,Y:Byte):Char;
  251.  
  252. Function GetByte(Var Param:Byte;LowLim,UpLim,Len,X,Y:Byte):Char;
  253.  
  254. Procedure GetDBRec(RecordNumber : LongInt);
  255. {Read a specific record.}
  256.  
  257. Function GetInteger(Var Param:Integer;LowLim,UpLim:Integer;Len,X,Y:Byte):Char;
  258. {Input an integer.}
  259.  
  260. Function GetLongInt(Var Param:LongInt;LowLim,UpLim:LongInt;Len,X,Y:Byte):Char;
  261. {Input a long integer.}
  262.  
  263. Function GetReal(Var Param : Real; LowLim, UpLim : Real; Len, X, Y : Word) : Char;
  264. {Input a real number.}
  265.  
  266. Function GetString(Var Param : String; Len, X, Y : Byte) : Char;
  267. {Input a string.}
  268.  
  269. Procedure GoBottom;
  270. {Go to bottom of file.}
  271.  
  272. Procedure GoTop;
  273. {Go to top of file.}
  274.  
  275. Function  IIF(BoolVar : Boolean;IfTrue,IfFalse : String) : String;
  276. {Test a boolean variable and return one of two strings.}
  277.  
  278. Function Input(Var S:String;Term:CharSet;L,X,Y:Byte;Var BC:Char):String;
  279.  
  280. Function IntToStr(Number : LongInt): String;
  281.  
  282. Function  JustL(InpStr: String; FieldLen: Integer): String;
  283. {Left justify a string.}
  284.  
  285. Procedure LookUp(SearchStr : string);
  286. {Find a key string in the open index.}
  287.  
  288. Function Lower(InpStr : string) : string;
  289.  
  290. Function  LTrim(InpStr: String): String;
  291. {Trim leading blanks from a string.}
  292.  
  293. Procedure MakeDBIndex(DBIndexName : FileName;KeyLen,Status : Integer);
  294. {Create a new index structure.}
  295.  
  296. Procedure Mark;
  297. {Mark record for deletion.}
  298.  
  299. Procedure NewDBRec;
  300. {Create new blank record.}
  301.  
  302. Procedure NextDBKey(KeyStr : DBKey);
  303. {Move to next key in an index.}
  304.  
  305. Procedure NextRec;
  306. {Skip to next record in .DBF}
  307.  
  308. Procedure OpenDBIndex(DBIndexName : FileName;KeyLen,Status : Integer);
  309. {Open an index file.}
  310.  
  311. Procedure Pack;
  312. {Pack a file.}
  313.  
  314. Function  PadL(InpStr: String; FieldLen: Integer): String;
  315. {Pad a string with blanks on the left.}
  316.  
  317. Function  PadR(InpStr: String; FieldLen: Integer): String;
  318. {Pad a string with blanks on the right.}
  319.  
  320. Procedure PrevDBKey(KeyStr : DBKey);
  321. {Skip backward to previous key in an index.}
  322.  
  323. Procedure PrevRec;
  324. {Skip backward to previous key in a .DBF file.}
  325.  
  326. Procedure Prompt(Row,Col : Byte;PromptStr : Str80);
  327. {Display a prompt at a specified row and column.}
  328.  
  329. Procedure PutDBRec(RecordNumber : LongInt);
  330. {Write a specified record.}
  331.  
  332. Function ReadChar : Char;
  333.  
  334. Procedure ReadDBHeader;
  335. {Read .DBF header.}
  336.  
  337. Procedure ReadKB (Var ExtKey: Boolean; Var Ch: Char);
  338.  
  339. Function RealToStr(Number : Real): String;
  340.  
  341. Procedure Recall;
  342. {Undelete a deleted record.}
  343.  
  344. Procedure Repl(FNo : Byte;InStr : string);
  345. {Replace a particular field with a specified string.}
  346.  
  347. Procedure ReplEach(FNo : Byte;InStr : String);
  348. {Replace a particular field in all records in a .DBF file with a
  349.  specified string.}
  350.  
  351. Function  Replicate(Ch : Char;Count : word) : String;
  352. {Create a string of a specified number of a character.}
  353.  
  354. Function  RTrim(InpStr: String): String;
  355. {Trim trailing blanks from a string.}
  356.  
  357. Procedure Say(FNo,Row,Col : Byte);
  358. {Display a field.}
  359.  
  360. Procedure SetColor(FG,BG : Byte);
  361. {Set initial foreground and background colors.}
  362.  
  363. Procedure ShowStatus;
  364. {Display .DBF status.}
  365.  
  366. Function  Sum(FNo : Byte) : Real;
  367. {Sum the value of numeric fields in records.}
  368.  
  369. Function  Upper(InpStr: String): String;
  370. {Convert a string to upper case.}
  371.  
  372. Procedure Wait;
  373. {Wait for a key press and display a message.}
  374.  
  375. Procedure WriteDBHeader;
  376. {Update .DBF header and write to disk.}
  377.  
  378. Procedure Zap;
  379. {Delete all records.}
  380.  
  381.  
  382. IMPLEMENTATION
  383.  
  384. Procedure AddDBKey(KeyStr : DBKey);
  385. begin
  386.      If UCKey then KeyStr := Upper(KeyStr);
  387.      AddKey(DBIndex,DBRecNum,KeyStr);
  388. end;
  389.  
  390. Procedure AddDBRec; {Add new record, no index open.}
  391. Var
  392.    RecordNumber : LongInt;
  393. begin
  394.      TotalRecs := TotalRecs + 1;
  395.      RecordNumber := TotalRecs;
  396.      DBRecNum := RecordNumber;
  397.      RecordNumber := (RecordNumber - 1) * Header^.RecordLen + Header^.Location;
  398.      Seek(DBFile,RecordNumber);
  399.      BlockWrite(DBFile,DBRecord^,Header^.RecordLen,ErrCode);
  400.      Dispose(DBRecord);
  401.      Allocated := False;
  402. end;
  403.  
  404. Procedure BailOut;
  405. Var
  406.    Message : String[80];
  407.    Blooper : Word;
  408.  
  409. begin
  410.      GotOne := True;
  411.      If DBFOpen then CloseDBFile;
  412.      If IndOpen then CloseDBIndex;
  413.      SetColor(White,Blue);
  414.      ClrScr;
  415.      Case TPDBErr of
  416.           1    : Message := 'Invalid DOS function code !';
  417.              2    : Message := 'File not found ! '+
  418.                     IIF(Length(RTrim(LTrim(TErrorName)))<>0,' -- > '+Upper(TErrorName),'');
  419.           3    : Message := 'Path not found !';
  420.           4    : Message := 'Too many open files !';
  421.           5    : Message := 'File access denied !';
  422.           6    : Message := 'Invalid file handle !';
  423.           8    : Message := 'Not enough memory !';
  424.           12   : Message := 'Invalid file access code !';
  425.           15   : Message := 'Invalid drive number !';
  426.           16   : Message := 'Cannot remove current directory !';
  427.           17   : Message := 'Cannot rename across drives !';
  428.           100  : Message := 'Disk read error !';
  429.           101  : Message := 'Disk write error !';
  430.           102  : Message := 'File not assigned !';
  431.           103  : Message := 'File not open !';
  432.           104  : Message := 'File not open for input !';
  433.           105  : Message := 'File not open for output !';
  434.           106  : Message := 'Invalid numeric format !';
  435.           200  : Message := 'Division by zero !';
  436.           201  : Message := 'Range check error !';
  437.           202  : Message := 'Stack overflow error !';
  438.           203  : Message := 'Heap overflow error !';
  439.           204  : Message := 'Invalid pointer operation !';
  440.           1000 : Message := 'Record size is greater than 4000 chars !';
  441.           1002 : Message := 'Specified Index Key Length is greater than 254 chars !';
  442.           1003 : Message := 'Invalid DBF File structure !';
  443.           1004 : Message := 'Index File created with different key size !';
  444.           1005 : Message := 'Not enough memory for index page stack !';
  445.           end;
  446.              Beep;Beep;
  447.              FlashC(8,White+BlueBG,'TPDB Version 2.1');
  448.              FlashC(10,Yellow+BlueBG,'ERROR !');
  449.              FlashC(12,White+BlueBG,Message);
  450.           CursorOff;
  451.              FlashC(14,LightGreen+BlueBG,'Press any key to halt program....');
  452.              FlashC(16,LightCyan+BlueBG,'Copyright 1989 Brian Corll');
  453.           Repeat Until KeyPressed;
  454.           TErrorName := '';
  455.           TPDBErr := 0;
  456.           ClrScr;
  457.           Halt(1);
  458. end;
  459.  
  460. Procedure Beep;
  461.  
  462. Begin
  463.   Sound(1500); Delay(50);
  464.   Sound(1000); Delay(50);
  465.   NoSound;
  466. End;
  467.  
  468.  
  469. Function BOF : Boolean;
  470. begin
  471.      If DBRecNum = 1 then
  472.         BOF := True
  473.      else BOF := False;
  474. end;
  475.  
  476. Function BoolToStr(Param : Byte;IfTrue,IfFalse : Char): String;
  477. Var
  478.   Temp : String;
  479. BEGIN
  480.   Case Param of
  481.     0: Temp := Filler;
  482.     1: Temp := IfTrue;
  483.     2: Temp := IfFalse;
  484.   End;
  485.   BoolToStr:=Temp;
  486. END;
  487.  
  488. Procedure CheckScreen(Var CurrPos:Byte;BC:Char;Up,Down:CharSet;Low,High:Byte);
  489.  
  490. Begin
  491.   If (BC In Down) Then
  492.      If CurrPos = High Then CurrPos := Low
  493.      Else Inc(CurrPos)
  494.   Else
  495.      If (BC In Up) Then
  496.         If CurrPos = Low Then CurrPos := High
  497.         Else Dec(CurrPos)
  498. End;
  499.  
  500. Procedure CloseDBFile;
  501. Var
  502.    EOFMarker : Byte;
  503. begin
  504.      WriteDBHeader;
  505.      EOFMarker := $1A;
  506.      Seek(DBFile,Header^.Location+(Header^.RecCount*Header^.RecordLen));
  507.      BlockWrite(DBFile,EOFMarker,1);
  508.      Close(DBFile);
  509.      If not MAlloc then
  510.      begin
  511.     Dispose(Header);
  512.     Dispose(Fields);
  513.     Dispose(Positions);
  514.      end;
  515.      DBFOpen := False;
  516. end;
  517.  
  518. Procedure CloseDBIndex;
  519. begin
  520.      CloseIndex(DBIndex);
  521.      IndOpen := False;
  522. end;
  523.  
  524. Procedure DBOpenFile(DBName : FileName); {Open dBASE file.}
  525. begin
  526.      New(Header);
  527.      New(Fields);
  528.      New(Positions);
  529.      DBFileName := RTrim(LTrim(DBName));
  530.      Assign(DBFile,DBFileName);
  531.      {$I-} Reset(DBFile,1); {$I+}
  532.      TPDBErr := IOResult;
  533.      If (TPDBErr<>0) and (not GotOne) then
  534.      begin
  535.      TErrorName := DBName;
  536.      BailOut;
  537.      end;
  538.      DBFOpen := True;
  539.      DBRecNum := 1;
  540.      ReadDBHeader;
  541. end;
  542.  
  543. Procedure DBReset; {Reset dBASE file.}
  544. begin
  545.      {$I-} Reset(DBFile,1); {$I+}
  546.      If TPDBErr=0 then TPDBErr := IOResult;
  547.       If (TPDBErr<>0) and (not GotOne) then
  548.       begin
  549.       TErrorName := DBFileName;
  550.       BailOut;
  551.       end;
  552. end;
  553.  
  554. Procedure DelDBKey(KeyStr : DBKey);
  555. begin
  556.      If UCKey then KeyStr := Upper(KeyStr);
  557.      DeleteKey(DBIndex,DBRecNum,KeyStr);
  558. end;
  559.  
  560. Function Deleted : Boolean;
  561. begin
  562.      If DBRecord^[1] = Chr(Ord($2A)) then
  563.         Deleted := True
  564.      else
  565.          Deleted := False;
  566. end;
  567.  
  568. Procedure Display;
  569. Var
  570.     FNo : Byte;
  571.     K   : Integer;
  572.  
  573. begin
  574.      ClrScr;
  575.      For FNo := 1 to NumFields do
  576.      begin
  577.           For K := 1 to 11 do
  578.              Write(Fields^[FNo].FieldName[K]);
  579.           Write(': ');
  580.           If Chr(Ord(Fields^[FNo].FieldType)) = 'D' then
  581.           Write(FormDate(FieldToStr(FNo)))
  582.           else Write(FieldToStr(FNo));
  583.           Writeln;
  584.       If FNo mod 23 = 0 then
  585.       begin
  586.       Wait;
  587.       ClrScr;
  588.       end;
  589.      end;
  590.      Wait;
  591. end;
  592.  
  593. Function EOF : Boolean;
  594. begin
  595.      If DBRecNum = TotalRecs then
  596.         EOF := True
  597.      else EOF := False;
  598. end;
  599.  
  600. Function FieldToStr(FNo : Byte) : string;
  601. Var
  602.    FF : Integer;
  603.    Temp : String;
  604. begin
  605.      Temp := '';
  606.      For FF := Positions^[1,FNo] to Positions^[2,FNo] do
  607.          Temp := Temp + DBRecord^[FF];
  608.      FieldToStr := Temp;
  609. end;
  610.  
  611. Procedure FillRecs(NumRecs : LongInt);
  612. Var
  613.    J : LongInt;
  614. begin
  615.      If TotalRecs>0 then GoBottom;
  616.      For J := 1 to NumRecs do
  617.      begin
  618.           NewDBRec;
  619.           AddDBRec;
  620.      end;
  621. end;
  622.  
  623. Procedure Find(SearchStr : string); {Find a key string in the open index.}
  624. begin
  625.      FindKey(DBIndex,DBRecNum,SearchStr);
  626.      If OK then
  627.      begin
  628.           GetDBRec(DBRecNum);
  629.           Found := True;
  630.      end
  631.      else
  632.      Found := False;
  633. end;
  634.  
  635. {$L Flash.obj}
  636.  
  637. {$F+}
  638.  
  639. Procedure Flash(Row,Col, Attr:byte; Str : String);external;
  640.  
  641.    Function CurrVidDisplay: DisplayType; external;
  642.  
  643.     Function CurrentVideoMode: Byte; external;
  644.  
  645.     Procedure CursorOn;external;
  646.  
  647.     Procedure CursorOff;external;
  648.  
  649.     Procedure BlockCursor;external;
  650.  
  651. {$F-}
  652.  
  653. Procedure FlashC(Row,Attr:Byte;Str : String);
  654. begin
  655.      Flash(Row,40 - Length(Str) div 2,Attr,Str);
  656. end;
  657.  
  658. Procedure FlashFill(Row,Col,Rows,Cols,Attr : Byte;Ch : Char);
  659. Var
  660.    Z : Byte;
  661.    Temp : String;
  662. begin
  663.      Temp := Replicate(Ch,Cols);
  664.      For Z := Row to Row + Rows-1 do
  665.          Flash(Z,Col,Attr,Temp);
  666. end;
  667.  
  668. Procedure FlushDB;
  669. begin
  670.      MAlloc := True;
  671.      CloseDBFile;
  672.      MAlloc := False;
  673.      DBReset;
  674. end;
  675.  
  676. Procedure Get(FNo,X,Y : Byte);
  677. Var
  678.    TempStr1 : string;
  679.    TempLen,DC : Byte;
  680.  
  681.          Procedure Character;
  682.          Var
  683.             GG : Integer;
  684.          begin
  685.      TempStr1 := '';
  686.      TempLen := Fields^[FNo].FieldLen;
  687.      For GG := Positions^[1,FNo] to Positions^[2,FNo] do
  688.      begin
  689.          TempStr1 := TempStr1 + DBRecord^[GG];
  690.      end;
  691.          BC := GetString(TempStr1,TempLen,Y,X); {from DER12.arc}
  692.      For GG := Positions^[1,FNo] to Positions^[2,FNo] do
  693.          DBRecord^[GG] := Chr(Ord(#32));
  694.      TempStr1 := PadR(TempStr1,Fields^[FNo].FieldLen);
  695.      DC := 1;
  696.      For GG := Positions^[1,FNo] to Positions^[2,FNo] do
  697.          begin
  698.           DBRecord^[GG] := TempStr1[DC];
  699.           DC := DC + 1;
  700.          end;
  701.          Flash(X,Y,Normal,Tempstr1);
  702.          end; {Procedure Character}
  703.  
  704.  
  705.          Procedure Numeric;
  706.          Var
  707.             NumLen,DC : Byte;
  708.             GG : Integer;
  709.             TempInt : LongInt;
  710.             TempReal : Real;
  711.             RealStr : String;
  712.             IntStr : String;
  713.  
  714.  
  715.          begin
  716.               NumLen := Fields^[FNo].FieldLen;
  717.           Decimals := Fields^[FNo].FieldDec;
  718.               If Decimals>0 then
  719.               begin
  720.           RealStr := '';
  721.               TempReal := 0;
  722.           For GG := Positions^[1,FNo] to Positions^[2,FNo] do
  723.               RealStr := RealStr +DBRecord^[GG];
  724.           Val(RealStr,TempReal,ErrCode);
  725.               BC := GetReal(TempReal,MinReal,MaxReal,NumLen,Y,X);
  726.               Str(TempReal : NumLen : Decimals,RealStr);
  727.               DC := 1;
  728.           For GG := Positions^[1,FNo] to Positions^[2,FNo] do
  729.               begin
  730.                DBRecord^[GG] := RealStr[DC];
  731.                DC := DC + 1;
  732.               end;
  733.               Flash(X,Y,Normal,RealStr);
  734.               end
  735.               else
  736.               begin
  737.               IntStr := '';
  738.               TempInt := 0;
  739.           For GG := Positions^[1,FNo] to Positions^[2,FNo] do
  740.               IntStr := IntStr+DBRecord^[GG];
  741.           Val(IntStr,TempInt,ErrCode);
  742.               BC := GetLongInt(TempInt,MinLong,MaxLong,NumLen,Y,X);
  743.               Str(TempInt : NumLen,IntStr);
  744.               DC := 1;
  745.           For GG := Positions^[1,FNo] to Positions^[2,FNo] do
  746.               begin
  747.                DBRecord^[GG] := IntStr[DC];
  748.                DC := DC + 1;
  749.               end;
  750.               Flash(X,Y,Normal,IntStr);
  751.               end;
  752.          end; {Procedure Numeric}
  753.  
  754.          Procedure Dates;
  755.          Var
  756.             TempDate,TmpDat2 : String[8];
  757.             MM,DD,DC : Byte;
  758.             YY,GG : Integer;
  759.             TM,TD,TY,Month,Day : String[2];
  760.             Year : String[4];
  761.          begin
  762.               TempDate := '';
  763.               For GG := Positions^[1,FNo] to Positions^[2,FNo] do
  764.                   TempDate := TempDate+DBRecord^[GG];
  765.               Repeat
  766.               Year := Copy(TempDate,1,4);
  767.               Month := Copy(TempDate,5,2);
  768.               Day := Copy(TempDate,7,2);
  769.               Val(Year,YY,ErrCode);
  770.               Val(Month,MM,ErrCode);
  771.               Val(Day,DD,ErrCode);
  772.               If YY>=1900 then YY := YY-1900;
  773.               BC := GetByte(MM,0,12,2,Y,X);
  774.               BC := GetByte(DD,0,31,2,Y+3,X);
  775.               BC := GetInteger(YY,0,99,2,Y+6,X);
  776.               Str(MM,Month);
  777.               Str(DD,Day);
  778.               YY := YY + 1900;
  779.               Str(YY:4,Year);
  780.               If DD<10 then Day := '0'+Day;
  781.               If MM<10 then Month := '0'+Month;
  782.               TempDate :=Year+Month+Day;
  783.               If not ValidDate(TempDate) then Beep;
  784.               TmpDat2 := Copy(TempDate,5,2)+'/'+Copy(TempDate,7,2)+'/'+
  785.                       Copy(TempDate,3,2);
  786.               Flash(X,Y,Normal,TmpDat2);
  787.               Until ValidDate(TempDate);
  788.               DC := 1;
  789.           For GG := Positions^[1,FNo] to Positions^[2,FNo] do
  790.               begin
  791.                DBRecord^[GG] := TempDate[DC];
  792.                DC := DC + 1;
  793.               end;
  794.  
  795.          end; {Procedure Dates}
  796.  
  797.          Procedure Logical;
  798.          Var
  799.             BoolVar : Byte;
  800.         TF : String[1];
  801.      begin
  802.             Case DBRecord^[Positions^[1,FNo]] of
  803.                  'Y' : BoolVar := 1;
  804.                  'N' : BoolVar := 2
  805.                  else BoolVar := 0;
  806.                  end;
  807.         BC := GetBoolean(BoolVar,'Y','N',Y,X);
  808.         TF := BoolToStr(BoolVar,'Y','N');
  809.         DBRecord^[Positions^[1,FNo]] := TF[1];
  810.             Flash(X,Y,Normal,TF);
  811.          end;
  812.  
  813.      begin {Procedure Get}
  814.            Case Chr(Ord(Fields^[FNo].FieldType)) of
  815.           'C'     : Character;
  816.           'L'     : Logical;
  817.           'N'     : Numeric;
  818.           'D'     : Dates;
  819.           end;
  820.      end;{Procedure Get}
  821.  
  822.  
  823. Function GetBoolean(Var Param:Byte;IfTrue,IfFalse:Char;X,Y:Byte):Char;
  824. Var
  825.   BC    : Char;
  826.   Temp  : String;
  827.   Value : Byte;
  828. Begin
  829.   Value := Param;
  830.   Temp := BoolToStr(Value,IfTrue,IfFalse);
  831.   UpperCase := True;
  832.   Temp := Input(Temp,[IfTrue,IfFalse],1,X,Y,BC);
  833.   If Length(Temp) =  0 Then
  834.   Begin
  835.     Param := 0;
  836.     Flash(Y,X,Normal,BoolToStr(Param,IfTrue,Iffalse));
  837.   End
  838.   Else
  839.   Begin
  840.     If Temp = Filler  Then Param := 0;
  841.     If Temp = IfTrue  Then Param := 1;
  842.     If Temp = IfFalse Then Param := 2;
  843.   End;
  844.   UpperCase := False;
  845.   GetBoolean := BC;
  846. End;
  847.  
  848. Function GetByte(Var Param:Byte;LowLim,UpLim,Len,X,Y:Byte):Char;
  849. Var
  850.   BC : Char;
  851.   WW,WL,WH : LongInt;
  852. Begin
  853.   WW := LongInt(Param);
  854.   WL := LongInt(LowLim);
  855.   WH := LongInt(UpLim);
  856.   BC := GetLongInt(WW,WL,WH,Len,X,Y);
  857.   Param := Byte(WW);
  858.   GetByte := BC;
  859. End;                                                         { GetByte }
  860.  
  861. Procedure GetDBRec(RecordNumber : LongInt); {Read a specific record.}
  862. begin
  863.      If not Allocated then
  864.      begin
  865.           New(DBRecord);
  866.           Allocated := True;
  867.      end
  868.      else
  869.      begin
  870.           Dispose(DBRecord);
  871.           New(DBRecord);
  872.           Allocated := True;
  873.      end;
  874.      DBRecNum := RecordNumber;
  875.      RecordNumber := (RecordNumber - 1) * Header^.RecordLen + Header^.Location;
  876.      Seek(DBFile,RecordNumber);
  877.      BlockRead(DBFile,DBRecord^,Header^.RecordLen,ErrCode);
  878. end;
  879.  
  880. Function GetInteger(Var Param:Integer;LowLim,UpLim:Integer;Len,X,Y:Byte):Char;
  881. Var
  882.   BC : Char;
  883.   WW,WL,WH : LongInt;
  884. Begin
  885.   WW := LongInt(Param);
  886.   WL := LongInt(LowLim);
  887.   WH := LongInt(UpLim);
  888.   BC := GetLongInt(WW,WL,WH,Len,X,Y);
  889.   Param := Integer(WW);
  890.   GetInteger := BC;
  891. End;
  892.  
  893. Function GetLongInt(Var Param:LongInt;LowLim,UpLim:LongInt;Len,X,Y:Byte):Char;
  894. Var
  895.   Temp     : String;
  896.   P, Value : LongInt;
  897.   I        : Integer;
  898.   Err      : Boolean;
  899.   BC       : Char;
  900. Begin
  901.   Repeat
  902.     Err := False;
  903.      Str(Param, Temp);
  904.     Temp := Input(Temp, ['0'..'9'], Len, X, Y, BC);
  905.     Val(Temp, P, I);
  906.     If length(Temp) = 0 Then Value := 0
  907.     Else If I = 0 Then Value := P
  908.          Else
  909.          Begin
  910.            Value := Param;
  911.            Beep;
  912.            Err := True;
  913.          End;
  914.     If (Not((Value >= LowLim) And (Value <= UpLim))) Then Beep;
  915.   Until (Value >= LowLim) And (Value <= UpLim) And (Not(Err));
  916.   Param := Value;
  917.   GetLongInt := BC;
  918. End;
  919.  
  920.  
  921. Function GetReal(Var Param : Real; LowLim, UpLim : Real; Len, X, Y : Word) : Char;
  922. Var
  923.    Temp : String;
  924.    P, Value : Real;
  925.    I : Word;
  926.    Err : Boolean;
  927.    BC : Char;
  928. Begin
  929.    Repeat
  930.          Err := False;
  931.          Temp := RealToStr(Param);
  932.          Temp := Input(Temp, ['0'..'9', '.','-'], Len, X, Y, BC);
  933.          Val(Temp, P, I);
  934.          If Length(Temp) = 0 Then Value := 0.0
  935.             Else If I = 0 Then Value := P
  936.             Else
  937.             Begin
  938.                  Value := Param;
  939.                  Beep;
  940.                  Err := True;
  941.             End;
  942.          If (Not((Value >= LowLim) And (Value <= UpLim))) Then Beep;
  943.    Until (Value >= LowLim) And (Value <= UpLim) And (Not(Err));
  944.    Param := Value;
  945.    GetReal := BC;
  946. End;
  947.  
  948. Function GetString(Var Param : String; Len, X, Y : Byte) : Char;
  949. Var
  950.    Temp : String;
  951.    BC : Char;
  952. Begin
  953.    Temp := Param;
  954.    Temp := Input(Temp, [#32..#126], Len, X, Y, BC);
  955.    Param := Temp;
  956.    GetString := BC;
  957. End;
  958.  
  959. Function GetWord(Var Param:Word;LowLim,UpLim:Word;Len,X,Y:Byte):Char;
  960. Var
  961.    BC : Char;
  962.    WW,WL,WH : LongInt;
  963. Begin
  964.    WW := LongInt(Param);
  965.    WL := LongInt(LowLim);
  966.    WH := LongInt(UpLim);
  967.    BC := GetLongInt(WW,WL,WH,Len,X,Y);
  968.    Param := Word(WW);
  969.    GetWord := BC;
  970. End;
  971.  
  972. Procedure GoBottom;
  973. begin
  974.      GetDBRec(Header^.RecCount);
  975. end;
  976.  
  977. Procedure GoTop;
  978. begin
  979.      GetDBRec(1);
  980. end;
  981.  
  982. Function IIF(BoolVar : Boolean;IfTrue,IfFalse : String) : String;
  983. begin
  984.      If BoolVar then IIF := IfTrue
  985.      else IIF := IfFalse;
  986. end;
  987.  
  988.  
  989. Function Input(Var S:String;Term:CharSet;L,X,Y:Byte;Var BC:Char):String;
  990. Const
  991.   Next : CharSet = [Return,CursorUp,CursorDown,PageUp,PageDown,Escape];
  992. Var
  993.   P    : Byte;
  994.   Ch   : Char;
  995.   Temp : String;
  996. Begin
  997.   CursorOn;
  998.   If S = '0' Then S[0] := #0;
  999.   Temp:= Replicate(Filler,L-Length(S));
  1000.   Temp := Concat(S,Temp);
  1001.   Flash(Y,X,Reverse,Temp);
  1002.   P := 0;
  1003.   Repeat
  1004.     GoToXY(X+P,Y);
  1005.     Ch := ReadChar;
  1006.     If UpperCase Then CH := UpCase(CH);
  1007.     If (CH In Term) Then
  1008.     Begin
  1009.       If P < L Then
  1010.       Begin
  1011.         If Length(S) = L Then Delete(S, L, 1);
  1012.         Inc(P);
  1013.         Insert(CH, S, P);
  1014.         Write(Copy(S, P, L));
  1015.         If AutoWrap AND (P = L) Then Ch := Return;
  1016.       End
  1017.       Else If Not(AutoWrap) Then Beep;
  1018.     End
  1019.     Else
  1020.     Case CH Of
  1021.           ^H, #127 : If P > 0 Then
  1022.                    Begin
  1023.                      Delete(S, P, 1);
  1024.                      Write(^H, Copy(S, P, L), Filler);
  1025.                      Dec(P);
  1026.                    End
  1027.                    Else Beep;
  1028.           DelKey : If P < Length(S) Then
  1029.                    Begin
  1030.                      Delete(S, Succ(P), 1);
  1031.                      Write(Copy(S, Succ(P), L), Filler);
  1032.                    End;
  1033.         CursorLeft : If P > 0 Then Dec(P)
  1034.                    Else Beep;
  1035.         CursorRight: If P < Length(S) Then Inc(P)
  1036.                    Else Beep;
  1037.       CursorHome : P := 0;
  1038.        CursorEnd : P := Length(S);
  1039.                   ^Y : Begin
  1040.                             Write(Replicate(Filler, Length(S)-P));
  1041.                      Delete(S, Succ(P), L);
  1042.                          End;
  1043.     End;
  1044.   Until CH In Next;
  1045.   P := Length(S);
  1046.   Input := S;
  1047.   BC := CH;
  1048.   CursorOff;
  1049. End;
  1050.  
  1051.  
  1052. Function IntToStr(Number : LongInt): String;
  1053. Var
  1054.   Temp : String;
  1055. begin
  1056.   Str(Number,Temp);
  1057.   IntToStr := RTrim(LTrim(Temp));
  1058. end;
  1059.  
  1060. Function JustL(InpStr: String; FieldLen: Integer): String;
  1061. Begin
  1062.      JustL := PadR(LTrim(InpStr),FieldLen)
  1063. End;
  1064.  
  1065. Procedure LookUp(SearchStr : string); {Find a key string in the open index.}
  1066. begin
  1067.      SearchKey(DBIndex,DBRecNum,SearchStr);
  1068.      If OK then
  1069.      begin
  1070.           GetDBRec(DBRecNum);
  1071.           Found := True;
  1072.      end
  1073.      else
  1074.      Found := False;
  1075. end;
  1076.  
  1077. Function LTrim(InpStr: String): String;
  1078. Var i,len : Integer;
  1079. Begin
  1080.      len := length(InpStr);
  1081.      i := 1;
  1082.      While (i <= len) and (InpStr[i] = ' ') do
  1083.            i := i + 1;
  1084.      LTrim := Copy(InpStr,i,len-i+1)
  1085. End;
  1086.  
  1087. Procedure MakeDBIndex(DBIndexName : FileName;KeyLen,Status : Integer);
  1088. begin
  1089.      MakeIndex(DBIndex,DBIndexName,KeyLen,Status);
  1090.      CloseIndex(DBIndex);
  1091. end;
  1092.  
  1093. Procedure Mark;
  1094. begin
  1095.      DBRecord^[1] := Chr(Ord($2A));
  1096. end;
  1097.  
  1098. Procedure NewDBRec;
  1099. begin
  1100.      If not Allocated then
  1101.      begin
  1102.           New(DBRecord);
  1103.           Allocated := True;
  1104.      end
  1105.      else
  1106.      begin
  1107.           Dispose(DBRecord);
  1108.           New(DBRecord);
  1109.           Allocated := True;
  1110.      end;
  1111.      FillChar(DBRecord^,SizeOf(DBRecord^),#32);
  1112.      DBRecNum := TotalRecs + 1;
  1113. end;
  1114.  
  1115. Procedure NextDBKey(KeyStr : DBKey);
  1116. begin
  1117.      If UCKey then KeyStr := Upper(KeyStr);
  1118.      NextKey(DBIndex,DBRecNum,KeyStr);
  1119.      GetDBRec(DBRecNum);
  1120. end;
  1121.  
  1122. Procedure NextRec;
  1123. begin
  1124.      GetDBRec(DBRecNum+1);
  1125. end;
  1126.  
  1127.  
  1128. Procedure OpenDBIndex(DBIndexName : FileName;KeyLen,Status : Integer);
  1129. begin
  1130.      OpenIndex(DBIndex,DBIndexName,KeyLen,Status);
  1131.      IndOpen := True;
  1132. end;
  1133.  
  1134. Procedure Pack;
  1135. Var
  1136.    FNo : Byte;
  1137.    J,TRec   : LongInt;
  1138.  
  1139.    Procedure PutTempRec(RecordNumber : LongInt); {Add new record, no index open.}
  1140.    begin
  1141.         DBRecNum := RecordNumber;
  1142.         RecordNumber := (RecordNumber - 1) * Header^.RecordLen + Header^.Location;
  1143.         Seek(TempFile,RecordNumber);
  1144.         BlockWrite(TempFile,DBRecord^,Header^.RecordLen,ErrCode);
  1145.    end;
  1146.  
  1147.    begin
  1148.         MAlloc := True;
  1149.         CloseDBFile;
  1150.         Malloc := False;
  1151.         DBReset;
  1152.         ReadDBHeader;
  1153.         Assign(TempFile,'temp.$$$');
  1154.         ReWrite(TempFile,1);
  1155.         BlockWrite(TempFile,Header^,32,ErrCode);
  1156.         For FNo := 1 to NumFields do
  1157.         Begin
  1158.            BlockWrite(TempFile,Fields^[FNo],32,ErrCode);
  1159.         end;
  1160.         Header^.Terminator := Chr(Ord($0D));
  1161.         BlockWrite(TempFile,Header^.Terminator,1,ErrCode);
  1162.         TRec := 1;
  1163.         For J := 1 to TotalRecs do
  1164.         begin
  1165.              GetDBRec(J);
  1166.              If not Deleted then
  1167.                 begin
  1168.                 PutTempRec(TRec);
  1169.                 TRec := TRec + 1;
  1170.                 end;
  1171.         end;
  1172.         CloseDBFile;
  1173.         Close(TempFile);
  1174.         Erase(DBFile);
  1175.         Rename(TempFile,DBFileName);
  1176.         DBOpenFile(DBFileName);
  1177.         TotalRecs := TRec-1;
  1178.         WriteDBHeader;
  1179. end;{Procedure Pack}
  1180.  
  1181. Function PadL(InpStr: String; FieldLen: Integer): String;
  1182. Var
  1183.    STemp : String;
  1184.    i : Integer;
  1185. Begin
  1186.    If FieldLen >= SizeOF(InpStr) then
  1187.       FieldLen := SizeOf(InpStr)-1;
  1188.    If length(InpStr) > FieldLen then
  1189.       PadL := Copy(InpStr,1,FieldLen)
  1190.    Else
  1191.       Begin
  1192.         STemp := InpStr;
  1193.         For i := Length(STemp)+1 to FieldLen do
  1194.            Insert(' ',STemp,1);
  1195.         PadL := STemp
  1196.       End
  1197. End;{PadL}
  1198.  
  1199. Function PadR(InpStr: String; FieldLen: Integer): String;
  1200. Var
  1201.    STemp : String;
  1202.    i : Integer;
  1203. Begin
  1204.    If FieldLen >= SizeOF(InpStr) then
  1205.       FieldLen := SizeOf(InpStr)-1;
  1206.    If length(InpStr) > FieldLen then
  1207.       PadR := Copy(InpStr,1,FieldLen)
  1208.    Else
  1209.       Begin
  1210.         STemp := InpStr;
  1211.         For i := Length(STemp)+1 to FieldLen do
  1212.            STemp := STemp + ' ';
  1213.         PadR := STemp
  1214.       End
  1215. End;{PadR}
  1216.  
  1217. Procedure PrevDBKey(KeyStr : DBKey);
  1218. begin
  1219.      If UCKey then KeyStr := Upper(KeyStr);
  1220.      PrevKey(DBIndex,DBRecNum,KeyStr);
  1221.      GetDBRec(DBRecNum);
  1222. end;
  1223.  
  1224. Procedure PrevRec;
  1225. begin
  1226.      GetDBRec(DBRecNum-1);
  1227. end;
  1228.  
  1229. Procedure Prompt(Row,Col : Byte;PromptStr : Str80);
  1230. begin
  1231.      Flash(Row,Col,Normal,PromptStr);
  1232. end;
  1233.  
  1234. Procedure PutDBRec(RecordNumber : LongInt); {Add new record, no index open.}
  1235. begin
  1236.      DBRecNum := RecordNumber;
  1237.      RecordNumber := (RecordNumber - 1) * Header^.RecordLen + Header^.Location;
  1238.      Seek(DBFile,RecordNumber);
  1239.      BlockWrite(DBFile,DBRecord^,Header^.RecordLen,ErrCode);
  1240.      Dispose(DBRecord);
  1241.      Allocated := False;
  1242. end;{PutDBRec}
  1243.  
  1244. Function ReadChar : Char;
  1245. Var
  1246.    CH : Char;
  1247. Begin
  1248.     ReadKb(ExtKey, CH);
  1249.     If ExtKey Then
  1250.    Begin
  1251.    Case CH Of
  1252.         #75 : CH := CursorLeft;
  1253.         #77 : CH := CursorRight;
  1254.         #72 : CH := CursorUp;
  1255.         #80 : CH := CursorDown;
  1256.         #73 : CH := PageUp;
  1257.         #81 : CH := PageDown;
  1258.         #71 : CH := CursorHome;
  1259.         #79 : CH := CursorEnd;
  1260.         #83 : CH := DelKey;
  1261.         Else  CH := #0;
  1262.      End;
  1263.     If CH = #9  Then CH := TabKey;
  1264.   End;
  1265.   ReadChar := CH;
  1266. End;
  1267.  
  1268. Procedure ReadDBHeader;
  1269. {Read .DBF header.}
  1270. Var
  1271.    FNo : Byte;
  1272.    begin
  1273.         BlockRead(DBFile,Header^,32,ErrCode);
  1274.         TotalRecs := Header^.RecCount;
  1275.         NumFields := (Header^.Location - 33) div 32;
  1276.         For FNo := 1 to NumFields do
  1277.         Begin
  1278.            BlockRead(DBFile,Fields^[FNo],32,ErrCode);
  1279.         end;
  1280.         For K := 1 to NumFields do
  1281.     begin
  1282.          Positions^[1,K] := 0;
  1283.          Positions^[2,K] := 0;
  1284.         end;
  1285.         Start := 2;
  1286.     For FNo := 1 to NumFields do
  1287.     begin
  1288.          Stop := Start+Fields^[FNo].FieldLen-1;
  1289.          Positions^[1,FNo] := Start;
  1290.          Positions^[2,FNo] := Stop;
  1291.          Start := Stop+1;
  1292.     end;
  1293. end;
  1294.  
  1295. Procedure ReadKB (Var ExtKey: Boolean; Var Ch: Char);
  1296. begin
  1297.   ExtKey := False;
  1298.   Ch := ReadKey;
  1299.   If Ch = #0 Then
  1300.   Begin
  1301.     ExtKey := True;
  1302.     Ch := ReadKey;
  1303.   End;
  1304. end;
  1305.  
  1306. Function RealToStr(Number : Real): String;
  1307. Var
  1308.   Temp : String;
  1309.   I    : Word;
  1310. Begin
  1311.   Str(Number:NumLen:Decimals, Temp);
  1312.   Temp := LTrim(Temp);
  1313.   I := Length(Temp);
  1314.   While Temp[I] = '0' Do Dec(I);
  1315.   If Temp[I] = '.' Then Dec(I);
  1316.   RealToStr := Copy(Temp, 1, I);
  1317. End;
  1318.  
  1319.  
  1320. Procedure Recall;
  1321. begin
  1322.      DBRecord^[1] := Chr(Ord($20));
  1323. end;
  1324.  
  1325. Procedure Repl(FNo : Byte;InStr : string);
  1326. Var
  1327.    KK : Byte;
  1328.    FF : Integer;
  1329.    Temp : String;
  1330. begin
  1331.      Temp := RTrim(Ltrim(InStr));
  1332.      For FF := Positions^[1,FNo] to Positions^[2,FNo] do
  1333.      begin
  1334.     DBRecord^[FF] := #32;
  1335.      end;
  1336.      KK := 1;
  1337.      For FF := Positions^[1,FNo] to Positions^[2,FNo] do
  1338.      begin
  1339.     DBRecord^[FF] := Temp[KK];
  1340.     KK := KK + 1;
  1341.     If KK>Length(Temp) then Exit;
  1342.      end;
  1343. end;
  1344.  
  1345. Procedure ReplEach(FNo : Byte;InStr : String);
  1346. Var
  1347.    J : LongInt;
  1348.  
  1349. begin
  1350.      DBReset;
  1351.      For J := 1 to TotalRecs do
  1352.      begin
  1353.           GetDBrec(J);
  1354.       Repl(FNo,InStr);
  1355.       PutDBRec(J);
  1356.      end;
  1357. end;
  1358.  
  1359. {$L tpdb.obj}
  1360.  
  1361. {$F+}
  1362. Function Lower;external;
  1363.  
  1364. Function Replicate;external;
  1365.  
  1366. Function Upper;external;
  1367.  
  1368. {F-}
  1369.  
  1370. Function RTrim(InpStr: String): String;
  1371. Var
  1372.    i : Integer;
  1373. Begin
  1374.    i := length(InpStr);
  1375.    While (i >= 1) and (InpStr[i] = ' ') do
  1376.       i := i - 1;
  1377.    RTrim := Copy(InpStr,1,i)
  1378. End;
  1379.  
  1380. Procedure Say(FNo,Row,Col : Byte);
  1381. Var
  1382.    GG : Integer;
  1383.    TempStr : String;
  1384.    Bool : Char;
  1385.    TempDate : String[8];
  1386.    Month,Day,Year : String[2];
  1387.    YY : Integer;
  1388.    MM,DD : Byte;
  1389. begin
  1390.      Case Chr(Ord(Fields^[FNo].FieldType)) of
  1391.           'C','N' : begin
  1392.               TempStr :='';
  1393.           For GG := Positions^[1,FNo] to Positions^[2,FNo] do
  1394.           TempStr := TempStr+DBRecord^[GG];
  1395.           Flash(Row,Col,Normal,TempStr);
  1396.           end;
  1397.       'L' : begin
  1398.               Bool := DBRecord^[Positions^[1,FNo]];
  1399.               Flash(Row,Col,Normal,Bool);
  1400.       end;
  1401.       'D' : begin
  1402.                   TempDate := FormDate(FieldToStr(FNo));
  1403.                   Flash(Row,Col,Normal,TempDate);
  1404.               end;
  1405.       end;
  1406. end;
  1407.  
  1408. Procedure SetColor(FG,BG : Byte);
  1409. begin
  1410.      TextColor(FG);
  1411.      TextBackGround(BG);
  1412. end;
  1413.  
  1414. Procedure ShowStatus; {Display .DBF status.}
  1415. Var
  1416.    FNo,K : Byte;
  1417. begin
  1418.      ClrScr;
  1419.      WriteLn('File name is ',Upper(DBFileName),'.');
  1420.      WriteLn('Last update was on ',Header^.Month,'/',Header^.Day,'/',Header^.Year,'.');
  1421.      WriteLn('Number of records is ',Header^.RecCount,'.');
  1422.      WriteLn('Data starts at byte # ',Header^.Location,'.');
  1423.      WriteLn('Record length is ',Header^.RecordLen,' bytes.');
  1424.      WriteLn('There are ',NumFields,' fields.');
  1425.      Wait;
  1426.      For FNo := 1 to NumFields do
  1427.      begin
  1428.           Write('Field # ',FNo:2,': ');
  1429.           For K := 1 to 11 do
  1430.           Write(Fields^[FNo].FieldName[K]);
  1431.           Write(' Type: ',Chr(Fields^[FNo].FieldType));
  1432.           Write('     Length: ',Fields^[FNo].FieldLen:3);
  1433.           If Chr(Ord(Fields^[FNo].FieldType))='N' then
  1434.              Write('     Decimals: ',Fields^[FNo].FieldDec:2);
  1435.           WriteLn;
  1436.           If FNo mod 20 = 0 then Wait;
  1437.      end;
  1438.      Wait;
  1439.      DBReset;
  1440. end;
  1441.  
  1442. Function Sum(FNo : Byte) : Real;
  1443. {Sums a numeric field.  If specified field is not numeric returns 0.}
  1444. Var
  1445.    J : LongInt;
  1446.    TempStr : String;
  1447.    TempReal : Real;
  1448.    EC : Integer;
  1449.    TotalSum : Real;
  1450. begin
  1451.      If Chr(Ord(Fields^[FNo].FieldType))<>'N' then
  1452.      begin
  1453.           Sum := 0;
  1454.       Exit;
  1455.      end
  1456.      else
  1457.      begin
  1458.           DBReset;
  1459.       TotalSum := 0;
  1460.       For J := 1 to TotalRecs do
  1461.       begin
  1462.         GetDBRec(J);
  1463.         TempStr := RTrim(LTrim(FieldToStr(FNo)));
  1464.         Val(TempStr,TempReal,EC);
  1465.         TotalSum := TotalSum + TempReal;
  1466.       end;
  1467.       end;
  1468.     Sum := TotalSum;
  1469. end;
  1470.  
  1471.  
  1472.  
  1473. Procedure Wait;
  1474. begin
  1475.      Writeln('Press any key to continue...');
  1476.      Ch := ReadKey;
  1477. end;
  1478.  
  1479.  
  1480. Procedure WriteDBHeader; {Update .DBF header.}
  1481. begin
  1482.      DBReset;
  1483.      GetDate(Y,M,D,DW);
  1484.      Y := Y-1900;
  1485.      Header^.Year := Y;
  1486.      Header^.Month := M;
  1487.      Header^.Day := D;
  1488.      Header^.RecCount := TotalRecs;
  1489.      BlockWrite(DBFile,Header^,32,ErrCode);
  1490. end;
  1491.  
  1492. Procedure Zap;
  1493. Var
  1494.    FNo : Byte;
  1495. begin
  1496.      ReWrite(DBFile,1);
  1497.      TotalRecs := 0;
  1498.      Header^.RecCount := 0;
  1499.      BlockWrite(DBFile,Header^,32,ErrCode);
  1500.      For FNo := 1 to NumFields do
  1501.      Begin
  1502.      BlockWrite(DBFile,Fields^[FNo],32,ErrCode);
  1503.      end;
  1504.      Header^.Terminator := Chr(Ord($0D));
  1505.      BlockWrite(DBFile,Header^.Terminator,1,ErrCode);
  1506.      DBReset;
  1507. end;
  1508.  
  1509. begin {TPDB}
  1510.      TAErrorProc := @BailOut;
  1511.      DBFOpen := False;
  1512.      IndOpen := False;
  1513.      Allocated := False;
  1514.      MAlloc := False;
  1515.      if CurrentVideoMode = 7 then
  1516.         VideoBase := $B000
  1517.      else
  1518.         VideoBase := $B800;
  1519.      VideoWait := (CurrVidDisplay = CGA);
  1520.      TErrorName := '';
  1521.      TPDBErr := 0;
  1522. end. {TPDB}
  1523.  
  1524. {End of Source Code - TPDB.pas}
  1525.  
  1526. { Version 2.1
  1527.   - fixed bug in Display procedure which sometimes caused
  1528.     date field not to display properly.
  1529.  
  1530.   - fixed bug in FieldToStr procedure - changed FF from byte to integer.}
  1531.