dbf_common.pas 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  1. unit dbf_common;
  2. interface
  3. {$I dbf_common.inc}
  4. uses
  5. SysUtils, Classes, DB
  6. {$ifndef WIN32}
  7. , Types, dbf_wtil
  8. {$ifdef KYLIX}
  9. , Libc
  10. {$endif}
  11. {$endif}
  12. ;
  13. const
  14. TDBF_MAJOR_VERSION = 6;
  15. TDBF_MINOR_VERSION = 49;
  16. TDBF_SUB_MINOR_VERSION = 0;
  17. TDBF_TABLELEVEL_FOXPRO = 25;
  18. JulianDateDelta = 1721425; { number of days between 1.1.4714 BC and "0" }
  19. type
  20. EDbfError = class (EDatabaseError);
  21. EDbfWriteError = class (EDbfError);
  22. TDbfFieldType = char;
  23. TXBaseVersion = (xUnknown, xClipper, xBaseIII, xBaseIV, xBaseV, xFoxPro, xBaseVII);
  24. TSearchKeyType = (stEqual, stGreaterEqual, stGreater);
  25. TDateTimeHandling = (dtDateTime, dtBDETimeStamp);
  26. //-------------------------------------
  27. PDateTime = ^TDateTime;
  28. {$ifdef FPC_VERSION}
  29. TDateTimeAlias = type TDateTime;
  30. TDateTimeRec = record
  31. case TFieldType of
  32. ftDate: (Date: Longint);
  33. ftTime: (Time: Longint);
  34. ftDateTime: (DateTime: TDateTimeAlias);
  35. end;
  36. {$else}
  37. PtrInt = Longint;
  38. {$endif}
  39. PSmallInt = ^SmallInt;
  40. PCardinal = ^Cardinal;
  41. PDouble = ^Double;
  42. PString = ^String;
  43. PDateTimeRec = ^TDateTimeRec;
  44. {$ifdef SUPPORT_INT64}
  45. PLargeInt = ^Int64;
  46. {$endif}
  47. {$ifdef DELPHI_3}
  48. dword = cardinal;
  49. {$endif}
  50. //-------------------------------------
  51. {$ifndef SUPPORT_FREEANDNIL}
  52. // some procedures for the less lucky who don't have newer versions yet :-)
  53. procedure FreeAndNil(var v);
  54. {$endif}
  55. procedure FreeMemAndNil(var P: Pointer);
  56. //-------------------------------------
  57. {$ifndef SUPPORT_PATHDELIM}
  58. const
  59. {$ifdef WIN32}
  60. PathDelim = '\';
  61. {$else}
  62. PathDelim = '/';
  63. {$endif}
  64. {$endif}
  65. {$ifndef SUPPORT_INCLTRAILPATHDELIM}
  66. function IncludeTrailingPathDelimiter(const Path: string): string;
  67. {$endif}
  68. //-------------------------------------
  69. function GetCompletePath(const Base, Path: string): string;
  70. function GetCompleteFileName(const Base, FileName: string): string;
  71. function IsFullFilePath(const Path: string): Boolean; // full means not relative
  72. function DateTimeToBDETimeStamp(aDT: TDateTime): double;
  73. function BDETimeStampToDateTime(aBT: double): TDateTime;
  74. function GetStrFromInt(Val: Integer; const Dst: PChar): Integer;
  75. procedure GetStrFromInt_Width(Val: Integer; const Width: Integer; const Dst: PChar; const PadChar: Char);
  76. {$ifdef SUPPORT_INT64}
  77. function GetStrFromInt64(Val: Int64; const Dst: PChar): Integer;
  78. procedure GetStrFromInt64_Width(Val: Int64; const Width: Integer; const Dst: PChar; const PadChar: Char);
  79. {$endif}
  80. procedure FindNextName(BaseName: string; var OutName: string; var Modifier: Integer);
  81. {$ifdef USE_CACHE}
  82. function GetFreeMemory: Integer;
  83. {$endif}
  84. // OH 2000-11-15 dBase7 support. Swap Byte order for 4 and 8 Byte Integer
  85. function SwapWord(const Value: word): word;
  86. function SwapInt(const Value: dword): dword;
  87. { SwapInt64 NOTE: do not call with same value for Value and Result ! }
  88. procedure SwapInt64(Value, Result: Pointer); register;
  89. function TranslateString(FromCP, ToCP: Cardinal; Src, Dest: PChar; Length: Integer): Integer;
  90. // Returns a pointer to the first occurence of Chr in Str within the first Length characters
  91. // Does not stop at null (#0) terminator!
  92. function MemScan(const Buffer: Pointer; Chr: Byte; Length: Integer): Pointer;
  93. // Delphi 3 does not have a Min function
  94. {$ifdef DELPHI_3}
  95. {$ifndef DELPHI_4}
  96. function Min(x, y: integer): integer;
  97. function Max(x, y: integer): integer;
  98. {$endif}
  99. {$endif}
  100. implementation
  101. {$ifdef WIN32}
  102. uses
  103. Windows;
  104. {$endif}
  105. //====================================================================
  106. function GetCompletePath(const Base, Path: string): string;
  107. begin
  108. if IsFullFilePath(Path)
  109. then begin
  110. Result := Path;
  111. end else begin
  112. if Length(Base) > 0 then
  113. Result := ExpandFileName(IncludeTrailingPathDelimiter(Base) + Path)
  114. else
  115. Result := ExpandFileName(Path);
  116. end;
  117. // add last backslash if not present
  118. if Length(Result) > 0 then
  119. Result := IncludeTrailingPathDelimiter(Result);
  120. end;
  121. function IsFullFilePath(const Path: string): Boolean; // full means not relative
  122. begin
  123. {$ifdef WIN32}
  124. Result := Length(Path) > 1;
  125. if Result then
  126. // check for 'x:' or '\\' at start of path
  127. Result := ((Path[2]=':') and (upcase(Path[1]) in ['A'..'Z']))
  128. or ((Path[1]='\') and (Path[2]='\'));
  129. {$else} // Linux
  130. Result := Length(Path) > 0;
  131. if Result then
  132. Result := Path[1]='/';
  133. {$endif}
  134. end;
  135. //====================================================================
  136. function GetCompleteFileName(const Base, FileName: string): string;
  137. var
  138. lpath: string;
  139. lfile: string;
  140. begin
  141. lpath := GetCompletePath(Base, ExtractFilePath(FileName));
  142. lfile := ExtractFileName(FileName);
  143. lpath := lpath + lfile;
  144. result := lpath;
  145. end;
  146. // it seems there is no pascal function to convert an integer into a PChar???
  147. procedure GetStrFromInt_Width(Val: Integer; const Width: Integer; const Dst: PChar; const PadChar: Char);
  148. var
  149. Temp: array[0..10] of Char;
  150. I, J: Integer;
  151. NegSign: boolean;
  152. begin
  153. {$I getstrfromint.inc}
  154. end;
  155. {$ifdef SUPPORT_INT64}
  156. procedure GetStrFromInt64_Width(Val: Int64; const Width: Integer; const Dst: PChar; const PadChar: Char);
  157. var
  158. Temp: array[0..19] of Char;
  159. I, J: Integer;
  160. NegSign: boolean;
  161. begin
  162. {$I getstrfromint.inc}
  163. end;
  164. {$endif}
  165. // it seems there is no pascal function to convert an integer into a PChar???
  166. // NOTE: in dbf_dbffile.pas there is also a convert routine, but is slightly different
  167. function GetStrFromInt(Val: Integer; const Dst: PChar): Integer;
  168. var
  169. Temp: array[0..10] of Char;
  170. I, J: Integer;
  171. begin
  172. Val := Abs(Val);
  173. // we'll have to store characters backwards first
  174. I := 0;
  175. J := 0;
  176. repeat
  177. Temp[I] := Chr((Val mod 10) + Ord('0'));
  178. Val := Val div 10;
  179. Inc(I);
  180. until Val = 0;
  181. // remember number of digits
  182. Result := I;
  183. // copy value, remember: stored backwards
  184. repeat
  185. Dst[J] := Temp[I-1];
  186. Inc(J);
  187. Dec(I);
  188. until I = 0;
  189. // done!
  190. end;
  191. {$ifdef SUPPORT_INT64}
  192. function GetStrFromInt64(Val: Int64; const Dst: PChar): Integer;
  193. var
  194. Temp: array[0..19] of Char;
  195. I, J: Integer;
  196. begin
  197. Val := Abs(Val);
  198. // we'll have to store characters backwards first
  199. I := 0;
  200. J := 0;
  201. repeat
  202. Temp[I] := Chr((Val mod 10) + Ord('0'));
  203. Val := Val div 10;
  204. Inc(I);
  205. until Val = 0;
  206. // remember number of digits
  207. Result := I;
  208. // copy value, remember: stored backwards
  209. repeat
  210. Dst[J] := Temp[I-1];
  211. inc(J);
  212. dec(I);
  213. until I = 0;
  214. // done!
  215. end;
  216. {$endif}
  217. function DateTimeToBDETimeStamp(aDT: TDateTime): double;
  218. var
  219. aTS: TTimeStamp;
  220. begin
  221. aTS := DateTimeToTimeStamp(aDT);
  222. Result := TimeStampToMSecs(aTS);
  223. end;
  224. function BDETimeStampToDateTime(aBT: double): TDateTime;
  225. var
  226. aTS: TTimeStamp;
  227. begin
  228. aTS := MSecsToTimeStamp(aBT);
  229. Result := TimeStampToDateTime(aTS);
  230. end;
  231. //====================================================================
  232. {$ifndef SUPPORT_FREEANDNIL}
  233. procedure FreeAndNil(var v);
  234. var
  235. Temp: TObject;
  236. begin
  237. Temp := TObject(v);
  238. TObject(v) := nil;
  239. Temp.Free;
  240. end;
  241. {$endif}
  242. procedure FreeMemAndNil(var P: Pointer);
  243. var
  244. Temp: Pointer;
  245. begin
  246. Temp := P;
  247. P := nil;
  248. FreeMem(Temp);
  249. end;
  250. //====================================================================
  251. {$ifndef SUPPORT_INCLTRAILPATHDELIM}
  252. {$ifndef SUPPORT_INCLTRAILBACKSLASH}
  253. function IncludeTrailingPathDelimiter(const Path: string): string;
  254. var
  255. len: Integer;
  256. begin
  257. Result := Path;
  258. len := Length(Result);
  259. if len = 0 then
  260. Result := PathDelim
  261. else
  262. if Result[len] <> PathDelim then
  263. Result := Result + PathDelim;
  264. end;
  265. {$else}
  266. function IncludeTrailingPathDelimiter(const Path: string): string;
  267. begin
  268. {$ifdef WIN32}
  269. Result := IncludeTrailingBackslash(Path);
  270. {$else}
  271. Result := IncludeTrailingSlash(Path);
  272. {$endif}
  273. end;
  274. {$endif}
  275. {$endif}
  276. {$ifdef USE_CACHE}
  277. function GetFreeMemory: Integer;
  278. var
  279. MemStatus: TMemoryStatus;
  280. begin
  281. GlobalMemoryStatus(MemStatus);
  282. Result := MemStatus.dwAvailPhys;
  283. end;
  284. {$endif}
  285. //====================================================================
  286. // Utility routines
  287. //====================================================================
  288. function SwapWord(const Value: word): word;
  289. begin
  290. Result := ((Value and $FF) shl 8) or ((Value shr 8) and $FF);
  291. end;
  292. {$ifdef USE_ASSEMBLER_486_UP}
  293. function SwapInt(const Value: dword): dword; register; assembler;
  294. asm
  295. BSWAP EAX;
  296. end;
  297. procedure SwapInt64(Value {EAX}, Result {EDX}: Pointer); register; assembler;
  298. asm
  299. MOV ECX, dword ptr [EAX]
  300. MOV EAX, dword ptr [EAX + 4]
  301. BSWAP ECX
  302. BSWAP EAX
  303. MOV dword ptr [EDX+4], ECX
  304. MOV dword ptr [EDX], EAX
  305. end;
  306. {$else}
  307. function SwapInt(const Value: Cardinal): Cardinal;
  308. begin
  309. PByteArray(@Result)[0] := PByteArray(@Value)[3];
  310. PByteArray(@Result)[1] := PByteArray(@Value)[2];
  311. PByteArray(@Result)[2] := PByteArray(@Value)[1];
  312. PByteArray(@Result)[3] := PByteArray(@Value)[0];
  313. end;
  314. procedure SwapInt64(Value, Result: Pointer); register;
  315. var
  316. PtrResult: PByteArray;
  317. PtrSource: PByteArray;
  318. begin
  319. // temporary storage is actually not needed, but otherwise compiler crashes (?)
  320. PtrResult := PByteArray(Result);
  321. PtrSource := PByteArray(Value);
  322. PtrResult[0] := PtrSource[7];
  323. PtrResult[1] := PtrSource[6];
  324. PtrResult[2] := PtrSource[5];
  325. PtrResult[3] := PtrSource[4];
  326. PtrResult[4] := PtrSource[3];
  327. PtrResult[5] := PtrSource[2];
  328. PtrResult[6] := PtrSource[1];
  329. PtrResult[7] := PtrSource[0];
  330. end;
  331. {$endif}
  332. function TranslateString(FromCP, ToCP: Cardinal; Src, Dest: PChar; Length: Integer): Integer;
  333. var
  334. WideCharStr: array[0..1023] of WideChar;
  335. wideBytes: Cardinal;
  336. begin
  337. if Length = -1 then
  338. Length := StrLen(Src);
  339. Result := Length;
  340. if (FromCP = GetOEMCP) and (ToCP = GetACP) then
  341. OemToCharBuff(Src, Dest, Length)
  342. else
  343. if (FromCP = GetACP) and (ToCP = GetOEMCP) then
  344. CharToOemBuff(Src, Dest, Length)
  345. else
  346. if FromCP = ToCP then
  347. begin
  348. if Src <> Dest then
  349. Move(Src^, Dest^, Length);
  350. end else begin
  351. // does this work on Win95/98/ME?
  352. wideBytes := MultiByteToWideChar(FromCP, MB_PRECOMPOSED, Src, Length, LPWSTR(@WideCharStr[0]), 1024);
  353. WideCharToMultiByte(ToCP, 0, LPWSTR(@WideCharStr[0]), wideBytes, Dest, Length, nil, nil);
  354. end;
  355. end;
  356. procedure FindNextName(BaseName: string; var OutName: string; var Modifier: Integer);
  357. var
  358. Extension: string;
  359. begin
  360. Extension := ExtractFileExt(BaseName);
  361. BaseName := Copy(BaseName, 1, Length(BaseName)-Length(Extension));
  362. repeat
  363. Inc(Modifier);
  364. OutName := ChangeFileExt(BaseName+'_'+IntToStr(Modifier), Extension);
  365. until not FileExists(OutName);
  366. end;
  367. {$ifdef FPC}
  368. function MemScan(const Buffer: Pointer; Chr: Byte; Length: Integer): Pointer;
  369. var
  370. I: Integer;
  371. begin
  372. I := System.IndexByte(Buffer, Length, Chr);
  373. if I = -1 then
  374. Result := nil
  375. else
  376. Result := Buffer+I;
  377. end;
  378. {$else}
  379. function MemScan(const Buffer: Pointer; Chr: Byte; Length: Integer): Pointer;
  380. asm
  381. PUSH EDI
  382. MOV EDI,Buffer
  383. MOV AL, Chr
  384. MOV ECX,Length
  385. REPNE SCASB
  386. MOV EAX,0
  387. JNE @@1
  388. MOV EAX,EDI
  389. DEC EAX
  390. @@1: POP EDI
  391. end;
  392. {$endif}
  393. {$ifdef DELPHI_3}
  394. {$ifndef DELPHI_4}
  395. function Min(x, y: integer): integer;
  396. begin
  397. if x < y then
  398. result := x
  399. else
  400. result := y;
  401. end;
  402. function Max(x, y: integer): integer;
  403. begin
  404. if x < y then
  405. result := y
  406. else
  407. result := x;
  408. end;
  409. {$endif}
  410. {$endif}
  411. end.