sysstr.inc 50 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987
  1. {
  2. *********************************************************************
  3. $Id$
  4. Copyright (C) 1997, 1998 Gertjan Schouten
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. *********************************************************************
  17. System Utilities For Free Pascal
  18. }
  19. { NewStr creates a new PString and assigns S to it
  20. if length(s) = 0 NewStr returns Nil }
  21. function NewStr(const S: string): PString;
  22. begin
  23. if (S='') then
  24. Result:=nil
  25. else
  26. begin
  27. getmem(Result,length(s)+1);
  28. if (Result<>nil) then
  29. Result^:=s;
  30. end;
  31. end;
  32. { DisposeStr frees the memory occupied by S }
  33. procedure DisposeStr(S: PString);
  34. begin
  35. if S <> Nil then
  36. begin
  37. Freemem(S,Length(S^)+1);
  38. S:=nil;
  39. end;
  40. end;
  41. { AssignStr assigns S to P^ }
  42. procedure AssignStr(var P: PString; const S: string);
  43. begin
  44. P^ := s;
  45. end ;
  46. { AppendStr appends S to Dest }
  47. procedure AppendStr(var Dest: String; const S: string);
  48. begin
  49. Dest := Dest + S;
  50. end ;
  51. { UpperCase returns a copy of S where all lowercase characters ( from a to z )
  52. have been converted to uppercase }
  53. function UpperCase(const S: string): string;
  54. var i: integer;
  55. begin
  56. result := S;
  57. i := Length(S);
  58. while i <> 0 do begin
  59. if (result[i] in ['a'..'z']) then result[i] := char(byte(result[i]) - 32);
  60. Dec(i);
  61. end;
  62. end;
  63. { LowerCase returns a copy of S where all uppercase characters ( from A to Z )
  64. have been converted to lowercase }
  65. function LowerCase(const S: string): string;
  66. var i: integer;
  67. begin
  68. result := S;
  69. i := Length(result);
  70. while i <> 0 do begin
  71. if (result[i] in ['A'..'Z']) then result[i] := char(byte(result[i]) + 32);
  72. dec(i);
  73. end;
  74. end;
  75. { CompareStr compares S1 and S2, the result is the based on
  76. substraction of the ascii values of the characters in S1 and S2
  77. case result
  78. S1 < S2 < 0
  79. S1 > S2 > 0
  80. S1 = S2 = 0 }
  81. function CompareStr(const S1, S2: string): Integer;
  82. var count, count1, count2: integer;
  83. begin
  84. result := 0;
  85. Count1 := Length(S1);
  86. Count2 := Length(S2);
  87. if Count1>Count2 then
  88. Count:=Count2
  89. else
  90. Count:=Count1;
  91. result := CompareMemRange(Pointer(S1),Pointer(S2), Count);
  92. if (result=0) and (Count1<>Count2) then
  93. begin
  94. if Count1>Count2 then
  95. result:=ord(s1[Count+1])
  96. else
  97. result:=-ord(s2[Count+1]);
  98. end;
  99. end;
  100. { CompareMemRange returns the result of comparison of Length bytes at P1 and P2
  101. case result
  102. P1 < P2 < 0
  103. P1 > P2 > 0
  104. P1 = P2 = 0 }
  105. function CompareMemRange(P1, P2: Pointer; Length: cardinal): integer;
  106. var
  107. i: cardinal;
  108. begin
  109. i := 0;
  110. result := 0;
  111. while (result=0) and (I<length) do
  112. begin
  113. result:=byte(P1^)-byte(P2^);
  114. P1:=P1+1;
  115. P2:=P2+1;
  116. i := i + 1;
  117. end ;
  118. end ;
  119. function CompareMem(P1, P2: Pointer; Length: cardinal): Boolean;
  120. var
  121. i: cardinal;
  122. begin
  123. for i := 0 to Length - 1 do
  124. begin
  125. if Byte(P1^) <> Byte(P2^) then
  126. begin
  127. Result := False;
  128. exit;
  129. end;
  130. Inc(P1);
  131. Inc(P2);
  132. end;
  133. Result := True;
  134. end;
  135. { CompareText compares S1 and S2, the result is the based on
  136. substraction of the ascii values of characters in S1 and S2
  137. comparison is case-insensitive
  138. case result
  139. S1 < S2 < 0
  140. S1 > S2 > 0
  141. S1 = S2 = 0 }
  142. function CompareText(const S1, S2: string): integer;
  143. var
  144. i, count, count1, count2: integer; Chr1, Chr2: byte;
  145. begin
  146. result := 0;
  147. Count1 := Length(S1);
  148. Count2 := Length(S2);
  149. if (Count1>Count2) then
  150. Count := Count2
  151. else
  152. Count := Count1;
  153. i := 0;
  154. while (result=0) and (i<count) do
  155. begin
  156. inc (i);
  157. Chr1 := byte(s1[i]);
  158. Chr2 := byte(s2[i]);
  159. if Chr1 in [97..122] then
  160. dec(Chr1,32);
  161. if Chr2 in [97..122] then
  162. dec(Chr2,32);
  163. result := Chr1 - Chr2;
  164. end ;
  165. if (result = 0) then
  166. result:=(count1-count2);
  167. end;
  168. {==============================================================================}
  169. { Ansi string functions }
  170. { these functions rely on the character set loaded by the OS }
  171. {==============================================================================}
  172. function AnsiUpperCase(const s: string): string;
  173. var len, i: integer;
  174. begin
  175. len := length(s);
  176. SetLength(result, len);
  177. for i := 1 to len do
  178. result[i] := UpperCaseTable[ord(s[i])];
  179. end ;
  180. function AnsiLowerCase(const s: string): string;
  181. var len, i: integer;
  182. begin
  183. len := length(s);
  184. SetLength(result, len);
  185. for i := 1 to len do
  186. result[i] := LowerCaseTable[ord(s[i])];
  187. end ;
  188. function AnsiCompareStr(const S1, S2: string): integer;
  189. Var I,L1,L2 : Longint;
  190. begin
  191. Result:=0;
  192. L1:=Length(S1);
  193. L2:=Length(S2);
  194. I:=1;
  195. While (Result=0) and ((I<=L1) and (I<=L2)) do
  196. begin
  197. Result:=Ord(S1[I])-Ord(S2[I]); //!! Must be replaced by ansi characters !!
  198. Inc(I);
  199. end;
  200. If Result=0 Then
  201. Result:=L1-L2;
  202. end;
  203. function AnsiCompareText(const S1, S2: string): integer;
  204. Var I,L1,L2 : Longint;
  205. begin
  206. Result:=0;
  207. L1:=Length(S1);
  208. L2:=Length(S2);
  209. I:=1;
  210. While (Result=0) and ((I<=L1) and (I<=L2)) do
  211. begin
  212. Result:=Ord(LowerCaseTable[Ord(S1[I])])-Ord(LowerCaseTable[Ord(S2[I])]); //!! Must be replaced by ansi characters !!
  213. Inc(I);
  214. end;
  215. If Result=0 Then
  216. Result:=L1-L2;
  217. end;
  218. function AnsiStrComp(S1, S2: PChar): integer;
  219. begin
  220. Result:=0;
  221. If S1=Nil then
  222. begin
  223. If S2=Nil Then Exit;
  224. result:=-1;
  225. exit;
  226. end;
  227. If S2=Nil then
  228. begin
  229. Result:=1;
  230. exit;
  231. end;
  232. Repeat
  233. Result:=Ord(S1[0])-Ord(S2[0]); //!! Must be replaced by ansi characters !!
  234. Inc(S1);
  235. Inc(S2);
  236. Until (Result<>0) or ((S1[0]=#0) or (S2[0]=#0))
  237. end;
  238. function AnsiStrIComp(S1, S2: PChar): integer;
  239. begin
  240. Result:=0;
  241. If S1=Nil then
  242. begin
  243. If S2=Nil Then Exit;
  244. result:=-1;
  245. exit;
  246. end;
  247. If S2=Nil then
  248. begin
  249. Result:=1;
  250. exit;
  251. end;
  252. Repeat
  253. Result:=Ord(LowerCaseTable[Ord(S1[0])])-Ord(LowerCaseTable[Ord(S2[0])]); //!! Must be replaced by ansi characters !!
  254. Inc(S1);
  255. Inc(S2);
  256. Until (Result<>0) or ((S1[0]=#0) or (S2[0]=#0))
  257. end;
  258. function AnsiStrLComp(S1, S2: PChar; MaxLen: cardinal): integer;
  259. Var I : cardinal;
  260. begin
  261. Result:=0;
  262. If MaxLen=0 then exit;
  263. If S1=Nil then
  264. begin
  265. If S2=Nil Then Exit;
  266. result:=-1;
  267. exit;
  268. end;
  269. If S2=Nil then
  270. begin
  271. Result:=1;
  272. exit;
  273. end;
  274. I:=0;
  275. Repeat
  276. Result:=Ord(S1[0])-Ord(S2[0]); //!! Must be replaced by ansi characters !!
  277. Inc(S1);
  278. Inc(S2);
  279. Inc(I);
  280. Until (Result<>0) or ((S1[0]=#0) or (S2[0]=#0)) or (I=MaxLen)
  281. end ;
  282. function AnsiStrLIComp(S1, S2: PChar; MaxLen: cardinal): integer;
  283. Var I : cardinal;
  284. begin
  285. Result:=0;
  286. If MaxLen=0 then exit;
  287. If S1=Nil then
  288. begin
  289. If S2=Nil Then Exit;
  290. result:=-1;
  291. exit;
  292. end;
  293. If S2=Nil then
  294. begin
  295. Result:=1;
  296. exit;
  297. end;
  298. I:=0;
  299. Repeat
  300. Result:=Ord(LowerCaseTable[Ord(S1[0])])-Ord(LowerCaseTable[Ord(S2[0])]); //!! Must be replaced by ansi characters !!
  301. Inc(S1);
  302. Inc(S2);
  303. Inc(I);
  304. Until (Result<>0) or ((S1[0]=#0) or (S2[0]=#0)) or (I=MaxLen)
  305. end ;
  306. function AnsiStrLower(Str: PChar): PChar;
  307. begin
  308. result := Str;
  309. if Str <> Nil then begin
  310. while Str^ <> #0 do begin
  311. Str^ := LowerCaseTable[byte(Str^)];
  312. Str := Str + 1;
  313. end ;
  314. end ;
  315. end ;
  316. function AnsiStrUpper(Str: PChar): PChar;
  317. begin
  318. result := Str;
  319. if Str <> Nil then begin
  320. while Str^ <> #0 do begin
  321. Str^ := UpperCaseTable[byte(Str^)];
  322. Str := Str + 1;
  323. end ;
  324. end ;
  325. end ;
  326. function AnsiLastChar(const S: string): PChar;
  327. begin
  328. //!! No multibyte yet, so we return the last one.
  329. result:=StrEnd(Pchar(S));
  330. Dec(Result);
  331. end ;
  332. function AnsiStrLastChar(Str: PChar): PChar;
  333. begin
  334. //!! No multibyte yet, so we return the last one.
  335. result:=StrEnd(Str);
  336. Dec(Result);
  337. end ;
  338. {==============================================================================}
  339. { End of Ansi functions }
  340. {==============================================================================}
  341. { Trim returns a copy of S with blanks characters on the left and right stripped off }
  342. Const WhiteSpace = [' ',#10,#13,#9];
  343. function Trim(const S: string): string;
  344. var Ofs, Len: integer;
  345. begin
  346. len := Length(S);
  347. while (Len>0) and (S[Len] in WhiteSpace) do
  348. dec(Len);
  349. Ofs := 1;
  350. while (Ofs<=Len) and (S[Ofs] in WhiteSpace) do
  351. Inc(Ofs);
  352. result := Copy(S, Ofs, 1 + Len - Ofs);
  353. end ;
  354. { TrimLeft returns a copy of S with all blank characters on the left stripped off }
  355. function TrimLeft(const S: string): string;
  356. var i,l:integer;
  357. begin
  358. l := length(s);
  359. i := 1;
  360. while (i<=l) and (s[i] in whitespace) do
  361. inc(i);
  362. Result := copy(s, i, l);
  363. end ;
  364. { TrimRight returns a copy of S with all blank characters on the right stripped off }
  365. function TrimRight(const S: string): string;
  366. var l:integer;
  367. begin
  368. l := length(s);
  369. while (l>0) and (s[l] in whitespace) do
  370. dec(l);
  371. result := copy(s,1,l);
  372. end ;
  373. { QuotedStr returns S quoted left and right and every single quote in S
  374. replaced by two quotes }
  375. function QuotedStr(const S: string): string;
  376. begin
  377. result := AnsiQuotedStr(s, '''');
  378. end ;
  379. { AnsiQuotedStr returns S quoted left and right by Quote,
  380. and every single occurance of Quote replaced by two }
  381. function AnsiQuotedStr(const S: string; Quote: char): string;
  382. var i, j, count: integer;
  383. begin
  384. result := '' + Quote;
  385. count := length(s);
  386. i := 0;
  387. j := 0;
  388. while i < count do begin
  389. i := i + 1;
  390. if S[i] = Quote then begin
  391. result := result + copy(S, 1 + j, i - j) + Quote;
  392. j := i;
  393. end ;
  394. end ;
  395. if i <> j then
  396. result := result + copy(S, 1 + j, i - j);
  397. result := result + Quote;
  398. end ;
  399. { AnsiExtractQuotedStr returns a copy of Src with quote characters
  400. deleted to the left and right and double occurances
  401. of Quote replaced by a single Quote }
  402. function AnsiExtractQuotedStr(Const Src: PChar; Quote: Char): string;
  403. var i: integer; P, Q: PChar;
  404. begin
  405. P := Src;
  406. if Src^ = Quote then P := P + 1;
  407. Q := StrEnd(P);
  408. if PChar(Q - 1)^ = Quote then Q := Q - 1;
  409. SetLength(result, Q - P);
  410. i := 0;
  411. while P <> Q do begin
  412. i := i + 1;
  413. result[i] := P^;
  414. if (P^ = Quote) and (PChar(P + 1)^ = Quote) then
  415. P := P + 1;
  416. P := P + 1;
  417. end ;
  418. SetLength(result, i);
  419. end ;
  420. { AdjustLineBreaks returns S with all CR characters not followed by LF
  421. replaced with CR/LF }
  422. // under Linux all CR characters or CR/LF combinations should be replaced with LF
  423. function AdjustLineBreaks(const S: string): string;
  424. var i, j, count: integer;
  425. begin
  426. result := '';
  427. i := 0;
  428. j := 0;
  429. count := Length(S);
  430. while i < count do begin
  431. i := i + 1;
  432. {$ifndef Unix}
  433. if (S[i] = #13) and ((i = count) or (S[i + 1] <> #10)) then
  434. begin
  435. result := result + Copy(S, 1 + j, i - j) + #10;
  436. j := i;
  437. end;
  438. {$else}
  439. If S[i]=#13 then
  440. begin
  441. Result:= Result+Copy(S,J+1,i-j-1)+#10;
  442. If I<>Count Then
  443. If S[I+1]=#10 then inc(i);
  444. J :=I;
  445. end;
  446. {$endif}
  447. end ;
  448. if j <> i then
  449. result := result + copy(S, 1 + j, i - j);
  450. end ;
  451. { IsValidIdent returns true if the first character of Ident is in:
  452. 'A' to 'Z', 'a' to 'z' or '_' and the following characters are
  453. on of: 'A' to 'Z', 'a' to 'z', '0'..'9' or '_' }
  454. function IsValidIdent(const Ident: string): boolean;
  455. var i, len: integer;
  456. begin
  457. result := false;
  458. len := length(Ident);
  459. if len <> 0 then begin
  460. result := Ident[1] in ['A'..'Z', 'a'..'z', '_'];
  461. i := 1;
  462. while (result) and (i < len) do begin
  463. i := i + 1;
  464. result := result and (Ident[i] in ['A'..'Z', 'a'..'z', '0'..'9', '_']);
  465. end ;
  466. end ;
  467. end ;
  468. { IntToStr returns a string representing the value of Value }
  469. function IntToStr(Value: integer): string;
  470. begin
  471. System.Str(Value, result);
  472. end ;
  473. function IntToStr(Value: int64): string;
  474. begin
  475. System.Str(Value, result);
  476. end ;
  477. function IntToStr(Value: QWord): string;
  478. begin
  479. System.Str(Value, result);
  480. end ;
  481. { IntToHex returns a string representing the hexadecimal value of Value }
  482. const
  483. HexDigits: array[0..15] of char = '0123456789ABCDEF';
  484. function IntToHex(Value: integer; Digits: integer): string;
  485. var i: integer;
  486. begin
  487. SetLength(result, digits);
  488. for i := 0 to digits - 1 do
  489. begin
  490. result[digits - i] := HexDigits[value and 15];
  491. value := value shr 4;
  492. end ;
  493. end ;
  494. function IntToHex(Value: int64; Digits: integer): string;
  495. var i: integer;
  496. begin
  497. SetLength(result, digits);
  498. for i := 0 to digits - 1 do
  499. begin
  500. result[digits - i] := HexDigits[value and 15];
  501. value := value shr 4;
  502. end ;
  503. end ;
  504. { StrToInt converts the string S to an integer value,
  505. if S does not represent a valid integer value EConvertError is raised }
  506. function StrToInt(const S: string): integer;
  507. var Error: word;
  508. begin
  509. Val(S, result, Error);
  510. if Error <> 0 then raise EConvertError.createfmt(SInValidInteger,[S]);
  511. end ;
  512. function StrToInt64(const S: string): int64;
  513. var Error: word;
  514. begin
  515. Val(S, result, Error);
  516. if Error <> 0 then raise EConvertError.createfmt(SInValidInteger,[S]);
  517. end ;
  518. { StrToIntDef converts the string S to an integer value,
  519. Default is returned in case S does not represent a valid integer value }
  520. function StrToIntDef(const S: string; Default: integer): integer;
  521. var Error: word;
  522. begin
  523. Val(S, result, Error);
  524. if Error <> 0 then result := Default;
  525. end ;
  526. { StrToIntDef converts the string S to an integer value,
  527. Default is returned in case S does not represent a valid integer value }
  528. function StrToInt64Def(const S: string; Default: int64): int64;
  529. var Error: word;
  530. begin
  531. Val(S, result, Error);
  532. if Error <> 0 then result := Default;
  533. end ;
  534. { LoadStr returns the string resource Ident. }
  535. function LoadStr(Ident: integer): string;
  536. begin
  537. result:='';
  538. end ;
  539. { FmtLoadStr returns the string resource Ident and formats it accordingly }
  540. function FmtLoadStr(Ident: integer; const Args: array of const): string;
  541. begin
  542. result:='';
  543. end;
  544. Const
  545. feInvalidFormat = 1;
  546. feMissingArgument = 2;
  547. feInvalidArgIndex = 3;
  548. {$ifdef fmtdebug}
  549. Procedure Log (Const S: String);
  550. begin
  551. Writeln (S);
  552. end;
  553. {$endif}
  554. Procedure DoFormatError (ErrCode : Longint);
  555. Var
  556. S : String;
  557. begin
  558. //!! must be changed to contain format string...
  559. S:='';
  560. Case ErrCode of
  561. feInvalidFormat : raise EConvertError.Createfmt(SInvalidFormat,[s]);
  562. feMissingArgument : raise EConvertError.Createfmt(SArgumentMissing,[s]);
  563. feInvalidArgIndex : raise EConvertError.Createfmt(SInvalidArgIndex,[s]);
  564. end;
  565. end;
  566. Function Format (Const Fmt : String; const Args : Array of const) : String;
  567. Var ChPos,OldPos,ArgPos,DoArg,Len : Longint;
  568. Hs,ToAdd : String;
  569. Index,Width,Prec : Longint;
  570. Left : Boolean;
  571. Fchar : char;
  572. {
  573. ReadFormat reads the format string. It returns the type character in
  574. uppercase, and sets index, Width, Prec to their correct values,
  575. or -1 if not set. It sets Left to true if left alignment was requested.
  576. In case of an error, DoFormatError is called.
  577. }
  578. Function ReadFormat : Char;
  579. Var Value : longint;
  580. Procedure ReadInteger;
  581. Var Code : Word;
  582. begin
  583. If Value<>-1 then exit; // Was already read.
  584. OldPos:=chPos;
  585. While (Chpos<=Len) and
  586. (Pos(Fmt[chpos],'1234567890')<>0) do inc(chpos);
  587. If Chpos>len then
  588. DoFormatError(feInvalidFormat);
  589. If Fmt[Chpos]='*' then
  590. begin
  591. If (Chpos>OldPos) or (ArgPos>High(Args))
  592. or (Args[ArgPos].Vtype<>vtInteger) then
  593. DoFormatError(feInvalidFormat);
  594. Value:=Args[ArgPos].VInteger;
  595. Inc(ArgPos);
  596. Inc(chPos);
  597. end
  598. else
  599. begin
  600. If (OldPos<chPos) Then
  601. begin
  602. Val (Copy(Fmt,OldPos,ChPos-OldPos),value,code);
  603. // This should never happen !!
  604. If Code>0 then DoFormatError (feInvalidFormat);
  605. end
  606. else
  607. Value:=-1;
  608. end;
  609. end;
  610. Procedure ReadIndex;
  611. begin
  612. ReadInteger;
  613. If Fmt[ChPos]=':' then
  614. begin
  615. If Value=-1 then DoFormatError(feMissingArgument);
  616. Index:=Value;
  617. Value:=-1;
  618. Inc(Chpos);
  619. end;
  620. {$ifdef fmtdebug}
  621. Log ('Read index');
  622. {$endif}
  623. end;
  624. Procedure ReadLeft;
  625. begin
  626. If Fmt[chpos]='-' then
  627. begin
  628. left:=True;
  629. Inc(chpos);
  630. end
  631. else
  632. Left:=False;
  633. {$ifdef fmtdebug}
  634. Log ('Read Left');
  635. {$endif}
  636. end;
  637. Procedure ReadWidth;
  638. begin
  639. ReadInteger;
  640. If Value<>-1 then
  641. begin
  642. Width:=Value;
  643. Value:=-1;
  644. end;
  645. {$ifdef fmtdebug}
  646. Log ('Read width');
  647. {$endif}
  648. end;
  649. Procedure ReadPrec;
  650. begin
  651. If Fmt[chpos]='.' then
  652. begin
  653. inc(chpos);
  654. ReadInteger;
  655. If Value=-1 then
  656. Value:=0;
  657. prec:=Value;
  658. end;
  659. {$ifdef fmtdebug}
  660. Log ('Read precision');
  661. {$endif}
  662. end;
  663. begin
  664. {$ifdef fmtdebug}
  665. Log ('Start format');
  666. {$endif}
  667. Index:=-1;
  668. Width:=-1;
  669. Prec:=-1;
  670. Value:=-1;
  671. inc(chpos);
  672. If Fmt[Chpos]='%' then exit('%');
  673. ReadIndex;
  674. ReadLeft;
  675. ReadWidth;
  676. ReadPrec;
  677. ReadFormat:=Upcase(Fmt[ChPos]);
  678. {$ifdef fmtdebug}
  679. Log ('End format');
  680. {$endif}
  681. end;
  682. {$ifdef fmtdebug}
  683. Procedure DumpFormat (C : char);
  684. begin
  685. Write ('Fmt : ',fmt:10);
  686. Write (' Index : ',Index:3);
  687. Write (' Left : ',left:5);
  688. Write (' Width : ',Width:3);
  689. Write (' Prec : ',prec:3);
  690. Writeln (' Type : ',C);
  691. end;
  692. {$endif}
  693. function Checkarg (AT : Longint;err:boolean):boolean;
  694. {
  695. Check if argument INDEX is of correct type (AT)
  696. If Index=-1, ArgPos is used, and argpos is augmented with 1
  697. DoArg is set to the argument that must be used.
  698. }
  699. begin
  700. result:=false;
  701. if Index=-1 then
  702. begin
  703. DoArg:=Argpos;
  704. inc(ArgPos);
  705. end
  706. else
  707. DoArg:=Index;
  708. If (Doarg>High(Args)) or (Args[Doarg].Vtype<>AT) then
  709. begin
  710. if err then
  711. DoFormatError(feInvalidArgindex);
  712. dec(ArgPos);
  713. exit;
  714. end;
  715. result:=true;
  716. end;
  717. Const Zero = '000000000000000000000000000000000000000000000000000000000000000';
  718. begin
  719. Result:='';
  720. Len:=Length(Fmt);
  721. Chpos:=1;
  722. OldPos:=1;
  723. ArgPos:=0;
  724. While chpos<=len do
  725. begin
  726. While (ChPos<=Len) and (Fmt[chpos]<>'%') do
  727. inc(chpos);
  728. If ChPos>OldPos Then
  729. Result:=Result+Copy(Fmt,OldPos,Chpos-Oldpos);
  730. If ChPos<Len then
  731. begin
  732. FChar:=ReadFormat;
  733. {$ifdef fmtdebug}
  734. DumpFormat(FCHar);
  735. {$endif}
  736. Case FChar of
  737. 'D' : begin
  738. if Checkarg(vtinteger,false) then
  739. Str(Args[Doarg].VInteger,ToAdd)
  740. else if CheckArg(vtInt64,true) then
  741. Str(Args[DoArg].VInt64^,toadd);
  742. Width:=Abs(width);
  743. Index:=Prec-Length(ToAdd);
  744. If ToAdd[1]<>'-' then
  745. ToAdd:=StringOfChar('0',Index)+ToAdd
  746. else
  747. // + 1 to accomodate for - sign in length !!
  748. Insert(StringOfChar('0',Index+1),toadd,2);
  749. end;
  750. 'E' : begin
  751. CheckArg(vtExtended,true);
  752. ToAdd:=FloatToStrF(Args[doarg].VExtended^,ffexponent,Prec,3);
  753. end;
  754. 'F' : begin
  755. CheckArg(vtExtended,true);
  756. ToAdd:=FloatToStrF(Args[doarg].VExtended^,ffFixed,9999,Prec);
  757. end;
  758. 'G' : begin
  759. CheckArg(vtExtended,true);
  760. ToAdd:=FloatToStrF(Args[doarg].VExtended^,ffGeneral,Prec,3);
  761. end;
  762. 'N' : begin
  763. CheckArg(vtExtended,true);
  764. ToAdd:=FloatToStrF(Args[doarg].VExtended^,ffNumber,9999,Prec);
  765. end;
  766. 'M' : begin
  767. CheckArg(vtExtended,true);
  768. ToAdd:=FloatToStrF(Args[doarg].VExtended^,ffCurrency,9999,Prec);
  769. end;
  770. 'S' : begin
  771. if CheckArg(vtString,false) then
  772. hs:=Args[doarg].VString^
  773. else
  774. if CheckArg(vtChar,false) then
  775. hs:=Args[doarg].VChar
  776. else
  777. if CheckArg(vtPChar,false) then
  778. hs:=Args[doarg].VPChar
  779. else
  780. if CheckArg(vtPWideChar,false) then
  781. hs:=char(Args[doarg].VPWideChar^)
  782. else
  783. if CheckArg(vtWideChar,false) then
  784. hs:=char(Args[doarg].VWideChar)
  785. else
  786. if CheckArg(vtWidestring,false) then
  787. hs:=ansistring(Args[doarg].VWideString)
  788. else
  789. if CheckArg(vtAnsiString,true) then
  790. hs:=ansistring(Args[doarg].VAnsiString);
  791. Index:=Length(hs);
  792. If (Prec<>-1) and (Index>Prec) then
  793. Index:=Prec;
  794. ToAdd:=Copy(hs,1,Index);
  795. end;
  796. 'P' : Begin
  797. CheckArg(vtpointer,true);
  798. ToAdd:=HexStr(Longint(Args[DoArg].VPointer),8);
  799. // Insert ':'. Is this needed in 32 bit ? No it isn't.
  800. // Insert(':',ToAdd,5);
  801. end;
  802. 'X' : begin
  803. Checkarg(vtinteger,true);
  804. If Prec>15 then
  805. ToAdd:=HexStr(Args[Doarg].VInteger,15)
  806. else
  807. begin
  808. // determine minimum needed number of hex digits.
  809. Index:=1;
  810. While (DWord(1 shl (Index*4))<=DWord(Args[DoArg].VInteger)) and (index<8) do
  811. inc(Index);
  812. If Index>Prec then
  813. Prec:=Index;
  814. ToAdd:=HexStr(Args[DoArg].VInteger,Prec);
  815. end;
  816. end;
  817. '%': ToAdd:='%';
  818. end;
  819. If Width<>-1 then
  820. If Length(ToAdd)<Width then
  821. If not Left then
  822. ToAdd:=Space(Width-Length(ToAdd))+ToAdd
  823. else
  824. ToAdd:=ToAdd+space(Width-Length(ToAdd));
  825. Result:=Result+ToAdd;
  826. end;
  827. inc(chpos);
  828. Oldpos:=chpos;
  829. end;
  830. end;
  831. Function FormatBuf (Var Buffer; BufLen : Cardinal;
  832. Const Fmt; fmtLen : Cardinal;
  833. Const Args : Array of const) : Cardinal;
  834. Var S,F : String;
  835. begin
  836. Setlength(F,fmtlen);
  837. if fmtlen > 0 then
  838. Move(fmt,F[1],fmtlen);
  839. S:=Format (F,Args);
  840. If Length(S)<Buflen then
  841. Result:=Length(S)
  842. else
  843. Result:=Buflen;
  844. Move(S[1],Buffer,Result);
  845. end;
  846. Procedure FmtStr(Var Res: String; Const Fmt : String; Const args: Array of const);
  847. begin
  848. Res:=Format(fmt,Args);
  849. end;
  850. Function StrFmt(Buffer,Fmt : PChar; Const args: Array of const) : Pchar;
  851. begin
  852. Buffer[FormatBuf(Buffer^,Maxint,Fmt^,strlen(fmt),args)]:=#0;
  853. Result:=Buffer;
  854. end;
  855. Function StrLFmt(Buffer : PCHar; Maxlen : Cardinal;Fmt : PChar; Const args: Array of const) : Pchar;
  856. begin
  857. Buffer[FormatBuf(Buffer^,MaxLen,Fmt^,strlen(fmt),args)]:=#0;
  858. Result:=Buffer;
  859. end;
  860. Function StrToFloat(Const S: String): Extended;
  861. Begin
  862. If Not TextToFloat(Pchar(S),Result) then
  863. Raise EConvertError.createfmt(SInValidFLoat,[S]);
  864. End;
  865. Function TextToFloat(Buffer: PChar; Var Value: Extended): Boolean;
  866. Var
  867. E,P : Integer;
  868. S : String;
  869. Begin
  870. S:=StrPas(Buffer);
  871. P:=Pos(DecimalSeparator,S);
  872. If (P<>0) Then
  873. S[P] := '.';
  874. Val(S,Value,E);
  875. Result:=(E=0);
  876. End;
  877. Function FloatToStr(Value: Extended): String;
  878. Begin
  879. Result := FloatToStrF(Value, ffGeneral, 15, 0);
  880. End;
  881. Function FloatToText(Buffer: PChar; Value: Extended; format: TFloatFormat; Precision, Digits: Integer): Longint;
  882. Var
  883. Tmp: String[40];
  884. Begin
  885. Tmp := FloatToStrF(Value, format, Precision, Digits);
  886. Result := Length(Tmp);
  887. Move(Tmp[1], Buffer[0], Result);
  888. End;
  889. Function FloatToStrF(Value: Extended; format: TFloatFormat; Precision, Digits: Integer): String;
  890. Var
  891. P: Integer;
  892. Negative, TooSmall, TooLarge: Boolean;
  893. Begin
  894. Case format Of
  895. ffGeneral:
  896. Begin
  897. If (Precision = -1) Or (Precision > 15) Then Precision := 15;
  898. TooSmall := (Abs(Value) < 0.00001) and (Value>0.0);
  899. If Not TooSmall Then
  900. Begin
  901. Str(Value:0:999, Result);
  902. P := Pos('.', Result);
  903. Result[P] := DecimalSeparator;
  904. TooLarge := P > Precision + 1;
  905. End;
  906. If TooSmall Or TooLarge Then
  907. begin
  908. Result := FloatToStrF(Value, ffExponent, Precision, Digits);
  909. // Strip unneeded zeroes.
  910. P:=Pos('E',result)-1;
  911. If P<>-1 then
  912. While (P>1) and (Result[P]='0') do
  913. begin
  914. system.Delete(Result,P,1);
  915. Dec(P);
  916. end;
  917. end
  918. else
  919. begin
  920. P := Length(Result);
  921. While Result[P] = '0' Do Dec(P);
  922. If Result[P] = DecimalSeparator Then Dec(P);
  923. SetLength(Result, P);
  924. end;
  925. End;
  926. ffExponent:
  927. Begin
  928. If (Precision = -1) Or (Precision > 15) Then Precision := 15;
  929. Str(Value:Precision + 8, Result);
  930. Result[3] := DecimalSeparator;
  931. P:=4;
  932. While (P>0) and (Digits < P) And (Result[Precision + 5] = '0') do
  933. Begin
  934. If P<>1 then
  935. system.Delete(Result, Precision + 5, 1)
  936. else
  937. system.Delete(Result, Precision + 3, 3);
  938. Dec(P);
  939. end;
  940. If Result[1] = ' ' Then
  941. System.Delete(Result, 1, 1);
  942. End;
  943. ffFixed:
  944. Begin
  945. If Digits = -1 Then Digits := 2
  946. Else If Digits > 15 Then Digits := 15;
  947. Str(Value:0:Digits, Result);
  948. If Result[1] = ' ' Then
  949. System.Delete(Result, 1, 1);
  950. P := Pos('.', Result);
  951. If P <> 0 Then Result[P] := DecimalSeparator;
  952. End;
  953. ffNumber:
  954. Begin
  955. If Digits = -1 Then Digits := 2
  956. Else If Digits > 15 Then Digits := 15;
  957. Str(Value:0:Digits, Result);
  958. If Result[1] = ' ' Then System.Delete(Result, 1, 1);
  959. P := Pos('.', Result);
  960. If P <> 0 Then
  961. Result[P] := DecimalSeparator
  962. else
  963. P := Length(Result)+1;
  964. Dec(P, 3);
  965. While (P > 1) Do
  966. Begin
  967. If Result[P - 1] <> '-' Then Insert(ThousandSeparator, Result, P);
  968. Dec(P, 3);
  969. End;
  970. End;
  971. ffCurrency:
  972. Begin
  973. If Value < 0 Then
  974. Begin
  975. Negative := True;
  976. Value := -Value;
  977. End
  978. Else Negative := False;
  979. If Digits = -1 Then Digits := CurrencyDecimals
  980. Else If Digits > 18 Then Digits := 18;
  981. Str(Value:0:Digits, Result);
  982. If Result[1] = ' ' Then System.Delete(Result, 1, 1);
  983. P := Pos('.', Result);
  984. If P <> 0 Then Result[P] := DecimalSeparator;
  985. Dec(P, 3);
  986. While (P > 1) Do
  987. Begin
  988. Insert(ThousandSeparator, Result, P);
  989. Dec(P, 3);
  990. End;
  991. If Not Negative Then
  992. Begin
  993. Case CurrencyFormat Of
  994. 0: Result := CurrencyString + Result;
  995. 1: Result := Result + CurrencyString;
  996. 2: Result := CurrencyString + ' ' + Result;
  997. 3: Result := Result + ' ' + CurrencyString;
  998. End
  999. End
  1000. Else
  1001. Begin
  1002. Case NegCurrFormat Of
  1003. 0: Result := '(' + CurrencyString + Result + ')';
  1004. 1: Result := '-' + CurrencyString + Result;
  1005. 2: Result := CurrencyString + '-' + Result;
  1006. 3: Result := CurrencyString + Result + '-';
  1007. 4: Result := '(' + Result + CurrencyString + ')';
  1008. 5: Result := '-' + Result + CurrencyString;
  1009. 6: Result := Result + '-' + CurrencyString;
  1010. 7: Result := Result + CurrencyString + '-';
  1011. 8: Result := '-' + Result + ' ' + CurrencyString;
  1012. 9: Result := '-' + CurrencyString + ' ' + Result;
  1013. 10: Result := CurrencyString + ' ' + Result + '-';
  1014. End;
  1015. End;
  1016. End;
  1017. End;
  1018. End;
  1019. Function FloatToDateTime (Const Value : Extended) : TDateTime;
  1020. begin
  1021. If (Value<MinDateTime) or (Value>MaxDateTime) then
  1022. Raise EConvertError.CreateFmt (SInvalidDateTime,[Value]);
  1023. Result:=Value;
  1024. end;
  1025. Function FloatToCurr (Const Value : Extended) : Currency;
  1026. begin
  1027. end;
  1028. Function CurrToStr(Value: Currency): string;
  1029. begin
  1030. end;
  1031. function StrToCurr(const S: string): Currency;
  1032. begin
  1033. end;
  1034. function StrToBool(const S: string): Boolean;
  1035. Var
  1036. Temp : String;
  1037. D : Double;
  1038. Code : word;
  1039. begin
  1040. Temp:=upcase(S);
  1041. Val(temp,D,code);
  1042. If Code=0 then
  1043. Result:=(D<>0.0)
  1044. else If Temp='TRUE' then
  1045. result:=true
  1046. else if Temp='FALSE' then
  1047. result:=false
  1048. else
  1049. Raise EConvertError.CreateFmt(SInvalidBoolean,[S]);
  1050. end;
  1051. function BoolToStr(B: Boolean): string;
  1052. begin
  1053. If B then
  1054. Result:='TRUE'
  1055. else
  1056. Result:='FALSE';
  1057. end;
  1058. Function FloatToTextFmt(Buffer: PChar; Value: Extended; format: PChar): Integer;
  1059. Var
  1060. Digits: String[40]; { String Of Digits }
  1061. Exponent: String[8]; { Exponent strin }
  1062. FmtStart, FmtStop: PChar; { Start And End Of relevant part }
  1063. { Of format String }
  1064. ExpFmt, ExpSize: Integer; { Type And Length Of }
  1065. { exponential format chosen }
  1066. Placehold: Array[1..4] Of Integer; { Number Of placeholders In All }
  1067. { four Sections }
  1068. thousand: Boolean; { thousand separators? }
  1069. UnexpectedDigits: Integer; { Number Of unexpected Digits that }
  1070. { have To be inserted before the }
  1071. { First placeholder. }
  1072. DigitExponent: Integer; { Exponent Of First digit In }
  1073. { Digits Array. }
  1074. { Find end of format section starting at P. False, if empty }
  1075. Function GetSectionEnd(Var P: PChar): Boolean;
  1076. Var
  1077. C: Char;
  1078. SQ, DQ: Boolean;
  1079. Begin
  1080. Result := False;
  1081. SQ := False;
  1082. DQ := False;
  1083. C := P[0];
  1084. While (C<>#0) And ((C<>';') Or SQ Or DQ) Do
  1085. Begin
  1086. Result := True;
  1087. Case C Of
  1088. #34: If Not SQ Then DQ := Not DQ;
  1089. #39: If Not DQ Then SQ := Not SQ;
  1090. End;
  1091. Inc(P);
  1092. C := P[0];
  1093. End;
  1094. End;
  1095. { Find start and end of format section to apply. If section doesn't exist,
  1096. use section 1. If section 2 is used, the sign of value is ignored. }
  1097. Procedure GetSectionRange(section: Integer);
  1098. Var
  1099. Sec: Array[1..3] Of PChar;
  1100. SecOk: Array[1..3] Of Boolean;
  1101. Begin
  1102. Sec[1] := format;
  1103. SecOk[1] := GetSectionEnd(Sec[1]);
  1104. If section > 1 Then
  1105. Begin
  1106. Sec[2] := Sec[1];
  1107. If Sec[2][0] <> #0 Then
  1108. Inc(Sec[2]);
  1109. SecOk[2] := GetSectionEnd(Sec[2]);
  1110. If section > 2 Then
  1111. Begin
  1112. Sec[3] := Sec[2];
  1113. If Sec[3][0] <> #0 Then
  1114. Inc(Sec[3]);
  1115. SecOk[3] := GetSectionEnd(Sec[3]);
  1116. End;
  1117. End;
  1118. If Not SecOk[1] Then
  1119. FmtStart := Nil
  1120. Else
  1121. Begin
  1122. If Not SecOk[section] Then
  1123. section := 1
  1124. Else If section = 2 Then
  1125. Value := -Value; { Remove sign }
  1126. If section = 1 Then FmtStart := format Else
  1127. Begin
  1128. FmtStart := Sec[section - 1];
  1129. Inc(FmtStart);
  1130. End;
  1131. FmtStop := Sec[section];
  1132. End;
  1133. End;
  1134. { Find format section ranging from FmtStart to FmtStop. }
  1135. Procedure GetFormatOptions;
  1136. Var
  1137. Fmt: PChar;
  1138. SQ, DQ: Boolean;
  1139. area: Integer;
  1140. Begin
  1141. SQ := False;
  1142. DQ := False;
  1143. Fmt := FmtStart;
  1144. ExpFmt := 0;
  1145. area := 1;
  1146. thousand := False;
  1147. Placehold[1] := 0;
  1148. Placehold[2] := 0;
  1149. Placehold[3] := 0;
  1150. Placehold[4] := 0;
  1151. While Fmt < FmtStop Do
  1152. Begin
  1153. Case Fmt[0] Of
  1154. #34:
  1155. Begin
  1156. If Not SQ Then
  1157. DQ := Not DQ;
  1158. Inc(Fmt);
  1159. End;
  1160. #39:
  1161. Begin
  1162. If Not DQ Then
  1163. SQ := Not SQ;
  1164. Inc(Fmt);
  1165. End;
  1166. Else
  1167. { This was 'if not SQ or DQ'. Looked wrong... }
  1168. If Not SQ Or DQ Then
  1169. Begin
  1170. Case Fmt[0] Of
  1171. '0':
  1172. Begin
  1173. Case area Of
  1174. 1:
  1175. area := 2;
  1176. 4:
  1177. Begin
  1178. area := 3;
  1179. Inc(Placehold[3], Placehold[4]);
  1180. Placehold[4] := 0;
  1181. End;
  1182. End;
  1183. Inc(Placehold[area]);
  1184. Inc(Fmt);
  1185. End;
  1186. '#':
  1187. Begin
  1188. If area=3 Then
  1189. area:=4;
  1190. Inc(Placehold[area]);
  1191. Inc(Fmt);
  1192. End;
  1193. '.':
  1194. Begin
  1195. If area<3 Then
  1196. area:=3;
  1197. Inc(Fmt);
  1198. End;
  1199. ',':
  1200. Begin
  1201. thousand := True;
  1202. Inc(Fmt);
  1203. End;
  1204. 'e', 'E':
  1205. If ExpFmt = 0 Then
  1206. Begin
  1207. If (Fmt[0]='E') Then
  1208. ExpFmt:=1
  1209. Else
  1210. ExpFmt := 3;
  1211. Inc(Fmt);
  1212. If (Fmt<FmtStop) Then
  1213. Begin
  1214. Case Fmt[0] Of
  1215. '+':
  1216. Begin
  1217. End;
  1218. '-':
  1219. Inc(ExpFmt);
  1220. Else
  1221. ExpFmt := 0;
  1222. End;
  1223. If ExpFmt <> 0 Then
  1224. Begin
  1225. Inc(Fmt);
  1226. ExpSize := 0;
  1227. While (Fmt<FmtStop) And
  1228. (ExpSize<4) And
  1229. (Fmt[0] In ['0'..'9']) Do
  1230. Begin
  1231. Inc(ExpSize);
  1232. Inc(Fmt);
  1233. End;
  1234. End;
  1235. End;
  1236. End
  1237. Else
  1238. Inc(Fmt);
  1239. Else { Case }
  1240. Inc(Fmt);
  1241. End; { Case }
  1242. End; { Begin }
  1243. End; { Case }
  1244. End; { While .. Begin }
  1245. End;
  1246. Procedure FloatToStr;
  1247. Var
  1248. I, J, Exp, Width, Decimals, DecimalPoint, len: Integer;
  1249. Begin
  1250. If ExpFmt = 0 Then
  1251. Begin
  1252. { Fixpoint }
  1253. Decimals:=Placehold[3]+Placehold[4];
  1254. Width:=Placehold[1]+Placehold[2]+Decimals;
  1255. If (Decimals=0) Then
  1256. Str(Value:Width:0,Digits)
  1257. Else
  1258. Str(Value:Width+1:Decimals,Digits);
  1259. len:=Length(Digits);
  1260. { Find the decimal point }
  1261. If (Decimals=0) Then
  1262. DecimalPoint:=len+1
  1263. Else
  1264. DecimalPoint:=len-Decimals;
  1265. { If value is very small, and no decimal places
  1266. are desired, remove the leading 0. }
  1267. If (Abs(Value) < 1) And (Placehold[2] = 0) Then
  1268. Begin
  1269. If (Placehold[1]=0) Then
  1270. Delete(Digits,DecimalPoint-1,1)
  1271. Else
  1272. Digits[DecimalPoint-1]:=' ';
  1273. End;
  1274. { Convert optional zeroes to spaces. }
  1275. I:=len;
  1276. J:=DecimalPoint+Placehold[3];
  1277. While (I>J) And (Digits[I]='0') Do
  1278. Begin
  1279. Digits[I] := ' ';
  1280. Dec(I);
  1281. End;
  1282. { If integer value and no obligatory decimal
  1283. places, remove decimal point. }
  1284. If (DecimalPoint < len) And (Digits[DecimalPoint + 1] = ' ') Then
  1285. Digits[DecimalPoint] := ' ';
  1286. { Convert spaces left from obligatory decimal point to zeroes. }
  1287. I:=DecimalPoint-Placehold[2];
  1288. While (I<DecimalPoint) And (Digits[I]=' ') Do
  1289. Begin
  1290. Digits[I] := '0';
  1291. Inc(I);
  1292. End;
  1293. Exp := 0;
  1294. End
  1295. Else
  1296. Begin
  1297. { Scientific: exactly <Width> Digits With <Precision> Decimals
  1298. And adjusted Exponent. }
  1299. If Placehold[1]+Placehold[2]=0 Then
  1300. Placehold[1]:=1;
  1301. Decimals := Placehold[3] + Placehold[4];
  1302. Width:=Placehold[1]+Placehold[2]+Decimals;
  1303. Str(Value:Width+8,Digits);
  1304. { Find and cut out exponent. Always the
  1305. last 6 characters in the string.
  1306. -> 0000E+0000 }
  1307. I:=Length(Digits)-5;
  1308. Val(Copy(Digits,I+1,5),Exp,J);
  1309. Exp:=Exp+1-(Placehold[1]+Placehold[2]);
  1310. Delete(Digits, I, 6);
  1311. { Str() always returns at least one digit after the decimal point.
  1312. If we don't want it, we have to remove it. }
  1313. If (Decimals=0) And (Placehold[1]+Placehold[2]<= 1) Then
  1314. Begin
  1315. If (Digits[4]>='5') Then
  1316. Begin
  1317. Inc(Digits[2]);
  1318. If (Digits[2]>'9') Then
  1319. Begin
  1320. Digits[2] := '1';
  1321. Inc(Exp);
  1322. End;
  1323. End;
  1324. Delete(Digits, 3, 2);
  1325. DecimalPoint := Length(Digits) + 1;
  1326. End
  1327. Else
  1328. Begin
  1329. { Move decimal point at the desired position }
  1330. Delete(Digits, 3, 1);
  1331. DecimalPoint:=2+Placehold[1]+Placehold[2];
  1332. If (Decimals<>0) Then
  1333. Insert('.',Digits,DecimalPoint);
  1334. End;
  1335. { Convert optional zeroes to spaces. }
  1336. I := Length(Digits);
  1337. J := DecimalPoint + Placehold[3];
  1338. While (I > J) And (Digits[I] = '0') Do
  1339. Begin
  1340. Digits[I] := ' ';
  1341. Dec(I);
  1342. End;
  1343. { If integer number and no obligatory decimal paces, remove decimal point }
  1344. If (DecimalPoint<Length(Digits)) And
  1345. (Digits[DecimalPoint+1]=' ') Then
  1346. Digits[DecimalPoint]:=' ';
  1347. If (Digits[1]=' ') Then
  1348. Begin
  1349. Delete(Digits, 1, 1);
  1350. Dec(DecimalPoint);
  1351. End;
  1352. { Calculate exponent string }
  1353. Str(Abs(Exp), Exponent);
  1354. While Length(Exponent)<ExpSize Do
  1355. Insert('0',Exponent,1);
  1356. If Exp >= 0 Then
  1357. Begin
  1358. If (ExpFmt In [1,3]) Then
  1359. Insert('+', Exponent, 1);
  1360. End
  1361. Else
  1362. Insert('-',Exponent,1);
  1363. If (ExpFmt<3) Then
  1364. Insert('E',Exponent,1)
  1365. Else
  1366. Insert('e',Exponent,1);
  1367. End;
  1368. DigitExponent:=DecimalPoint-2;
  1369. If (Digits[1]='-') Then
  1370. Dec(DigitExponent);
  1371. UnexpectedDigits:=DecimalPoint-1-(Placehold[1]+Placehold[2]);
  1372. End;
  1373. Function PutResult: LongInt;
  1374. Var
  1375. SQ, DQ: Boolean;
  1376. Fmt, Buf: PChar;
  1377. Dig, N: Integer;
  1378. Begin
  1379. SQ := False;
  1380. DQ := False;
  1381. Fmt := FmtStart;
  1382. Buf := Buffer;
  1383. Dig := 1;
  1384. While (Fmt<FmtStop) Do
  1385. Begin
  1386. //Write(Fmt[0]);
  1387. Case Fmt[0] Of
  1388. #34:
  1389. Begin
  1390. If Not SQ Then
  1391. DQ := Not DQ;
  1392. Inc(Fmt);
  1393. End;
  1394. #39:
  1395. Begin
  1396. If Not DQ Then
  1397. SQ := Not SQ;
  1398. Inc(Fmt);
  1399. End;
  1400. Else
  1401. If Not (SQ Or DQ) Then
  1402. Begin
  1403. Case Fmt[0] Of
  1404. '0', '#', '.':
  1405. Begin
  1406. If (Dig=1) And (UnexpectedDigits>0) Then
  1407. Begin
  1408. { Everything unexpected is written before the first digit }
  1409. For N := 1 To UnexpectedDigits Do
  1410. Begin
  1411. Buf[0] := Digits[N];
  1412. Inc(Buf);
  1413. If thousand And (Digits[N]<>'-') Then
  1414. Begin
  1415. If (DigitExponent Mod 3 = 0) And (DigitExponent>0) Then
  1416. Begin
  1417. Buf[0] := ThousandSeparator;
  1418. Inc(Buf);
  1419. End;
  1420. Dec(DigitExponent);
  1421. End;
  1422. End;
  1423. Inc(Dig, UnexpectedDigits);
  1424. End;
  1425. If (Digits[Dig]<>' ') Then
  1426. Begin
  1427. If (Digits[Dig]='.') Then
  1428. Buf[0] := DecimalSeparator
  1429. Else
  1430. Buf[0] := Digits[Dig];
  1431. Inc(Buf);
  1432. If thousand And (DigitExponent Mod 3 = 0) And (DigitExponent > 0) Then
  1433. Begin
  1434. Buf[0] := ThousandSeparator;
  1435. Inc(Buf);
  1436. End;
  1437. End;
  1438. Inc(Dig);
  1439. Dec(DigitExponent);
  1440. Inc(Fmt);
  1441. End;
  1442. 'e', 'E':
  1443. Begin
  1444. If ExpFmt <> 0 Then
  1445. Begin
  1446. Inc(Fmt);
  1447. If Fmt < FmtStop Then
  1448. Begin
  1449. If Fmt[0] In ['+', '-'] Then
  1450. Begin
  1451. Inc(Fmt, ExpSize);
  1452. For N:=1 To Length(Exponent) Do
  1453. Buf[N-1] := Exponent[N];
  1454. Inc(Buf,Length(Exponent));
  1455. ExpFmt:=0;
  1456. End;
  1457. Inc(Fmt);
  1458. End;
  1459. End
  1460. Else
  1461. Begin
  1462. { No legal exponential format.
  1463. Simply write the 'E' to the result. }
  1464. Buf[0] := Fmt[0];
  1465. Inc(Buf);
  1466. Inc(Fmt);
  1467. End;
  1468. End;
  1469. Else { Case }
  1470. { Usual character }
  1471. If (Fmt[0]<>',') Then
  1472. Begin
  1473. Buf[0] := Fmt[0];
  1474. Inc(Buf);
  1475. End;
  1476. Inc(Fmt);
  1477. End; { Case }
  1478. End
  1479. Else { IF }
  1480. Begin
  1481. { Character inside single or double quotes }
  1482. Buf[0] := Fmt[0];
  1483. Inc(Buf);
  1484. Inc(Fmt);
  1485. End;
  1486. End; { Case }
  1487. End; { While .. Begin }
  1488. Result:=LongInt(Buf)-LongInt(Buffer);
  1489. End;
  1490. Begin
  1491. If (Value>0) Then
  1492. GetSectionRange(1)
  1493. Else If (Value<0) Then
  1494. GetSectionRange(2)
  1495. Else
  1496. GetSectionRange(3);
  1497. If FmtStart = Nil Then
  1498. Begin
  1499. Result := FloatToText(Buffer, Value, ffGeneral, 15, 4);
  1500. End
  1501. Else
  1502. Begin
  1503. GetFormatOptions;
  1504. If (ExpFmt = 0) And (Abs(Value) >= 1E18) Then
  1505. Result := FloatToText(Buffer, Value, ffGeneral, 15, 4)
  1506. Else
  1507. Begin
  1508. FloatToStr;
  1509. Result := PutResult;
  1510. End;
  1511. End;
  1512. End;
  1513. Procedure FloatToDecimal(Var Result: TFloatRec; Value: Extended; Precision, Decimals : integer);
  1514. Var
  1515. Buffer: String[24];
  1516. Error, N: Integer;
  1517. Begin
  1518. Str(Value:23, Buffer);
  1519. Result.Negative := (Buffer[1] = '-');
  1520. Val(Copy(Buffer, 19, 5), Result.Exponent, Error);
  1521. Inc(Result. Exponent);
  1522. Result.Digits[0] := Buffer[2];
  1523. Move(Buffer[4], Result.Digits[1], 14);
  1524. If Decimals + Result.Exponent < Precision Then
  1525. N := Decimals + Result.Exponent
  1526. Else
  1527. N := Precision;
  1528. If N > 15 Then
  1529. N := 15;
  1530. If N = 0 Then
  1531. Begin
  1532. If Result.Digits[0] >= '5' Then
  1533. Begin
  1534. Result.Digits[0] := '1';
  1535. Result.Digits[1] := #0;
  1536. Inc(Result.Exponent);
  1537. End
  1538. Else
  1539. Result.Digits[0] := #0;
  1540. End
  1541. Else If N > 0 Then
  1542. Begin
  1543. If Result.Digits[N] >= '5' Then
  1544. Begin
  1545. Repeat
  1546. Result.Digits[N] := #0;
  1547. Dec(N);
  1548. Inc(Result.Digits[N]);
  1549. Until (N = 0) Or (Result.Digits[N] < ':');
  1550. If Result.Digits[0] = ':' Then
  1551. Begin
  1552. Result.Digits[0] := '1';
  1553. Inc(Result.Exponent);
  1554. End;
  1555. End
  1556. Else
  1557. Begin
  1558. Result.Digits[N] := '0';
  1559. While (Result.Digits[N] = '0') And (N > -1) Do
  1560. Begin
  1561. Result.Digits[N] := #0;
  1562. Dec(N);
  1563. End;
  1564. End;
  1565. End
  1566. Else
  1567. Result.Digits[0] := #0;
  1568. If Result.Digits[0] = #0 Then
  1569. Begin
  1570. Result.Exponent := 0;
  1571. Result.Negative := False;
  1572. End;
  1573. End;
  1574. Function FormatFloat(Const format: String; Value: Extended): String;
  1575. Var
  1576. Temp: ShortString;
  1577. buf : Array[0..1024] of char;
  1578. Begin
  1579. Buf[FloatToTextFmt(@Buf[0],Value,Pchar(Format))]:=#0;
  1580. Result:=StrPas(@Buf);
  1581. End;
  1582. {==============================================================================}
  1583. { extra functions }
  1584. {==============================================================================}
  1585. { LeftStr returns Count left-most characters from S }
  1586. function LeftStr(const S: string; Count: integer): string;
  1587. begin
  1588. result := Copy(S, 1, Count);
  1589. end ;
  1590. { RightStr returns Count right-most characters from S }
  1591. function RightStr(const S: string; Count: integer): string;
  1592. begin
  1593. If Count>Length(S) then
  1594. Count:=Length(S);
  1595. result := Copy(S, 1 + Length(S) - Count, Count);
  1596. end;
  1597. { BCDToInt converts the BCD value Value to an integer }
  1598. function BCDToInt(Value: integer): integer;
  1599. var i, j: integer;
  1600. begin
  1601. result := 0;
  1602. j := 1;
  1603. for i := 0 to SizeOf(Value) shr 1 - 1 do begin
  1604. result := result + j * (Value and 15);
  1605. j := j * 10;
  1606. Value := Value shr 4;
  1607. end ;
  1608. end ;
  1609. Function IsDelimiter(const Delimiters, S: string; Index: Integer): Boolean;
  1610. begin
  1611. Result:=False;
  1612. If Index<=Length(S) then
  1613. Result:=Pos(S[Index],Delimiters)<>0; // Note we don't do MBCS yet
  1614. end;
  1615. Function LastDelimiter(const Delimiters, S: string): Integer;
  1616. begin
  1617. Result:=Length(S);
  1618. While (Result>0) and (Pos(S[Result],Delimiters)=0) do
  1619. Dec(Result);
  1620. end;
  1621. function StringReplace(const S, OldPattern, NewPattern: string; Flags: TReplaceFlags): string;
  1622. var
  1623. Srch,OldP,RemS: string; // Srch and Oldp can contain uppercase versions of S,OldPattern
  1624. P : Integer;
  1625. begin
  1626. Srch:=S;
  1627. OldP:=OldPattern;
  1628. if rfIgnoreCase in Flags then
  1629. begin
  1630. Srch:=UpperCase(Srch);
  1631. OldP:=UpperCase(OldP);
  1632. end;
  1633. RemS:=S;
  1634. Result:='';
  1635. while (Length(Srch)<>0) do
  1636. begin
  1637. P:=Pos(OldP, Srch);
  1638. if P=0 then
  1639. begin
  1640. Result:=Result+RemS;
  1641. Srch:='';
  1642. end
  1643. else
  1644. begin
  1645. Result:=Result+Copy(RemS,1,P-1)+NewPattern;
  1646. P:=P+Length(OldP);
  1647. RemS:=Copy(RemS,P,Length(RemS)-P+1);
  1648. if not (rfReplaceAll in Flags) then
  1649. begin
  1650. Result:=Result+RemS;
  1651. Srch:='';
  1652. end
  1653. else
  1654. Srch:=Copy(Srch,P,Length(Srch)-P+1);
  1655. end;
  1656. end;
  1657. end;
  1658. {
  1659. Case Translation Tables
  1660. Can be used in internationalization support.
  1661. Although these tables can be obtained through system calls
  1662. it is better to not use those, since most implementation are not 100%
  1663. WARNING:
  1664. before modifying a translation table make sure that the current codepage
  1665. of the OS corresponds to the one you make changes to
  1666. }
  1667. const
  1668. { upper case translation table for character set 850 }
  1669. CP850UCT: array[128..255] of char =
  1670. ('€', 'š', '�', '¶', 'Ž', '¶', '�', '€', 'Ò', 'Ó', 'Ô', 'Ø', '×', 'Þ', 'Ž', '�',
  1671. '�', '’', '’', 'â', '™', 'ã', 'ê', 'ë', 'Y', '™', 'š', '�', 'œ', '�', 'ž', 'Ÿ',
  1672. 'µ', 'Ö', 'à', 'é', '¥', '¥', '¦', '§', '¨', '©', 'ª', '«', '¬', '­', '®', '¯',
  1673. '°', '±', '²', '³', '´', 'µ', '¶', '·', '¸', '¹', 'º', '»', '¼', '½', '¾', '¿',
  1674. 'À', 'Á', 'Â', 'Ã', 'Ä', 'Å', 'Ç', 'Ç', 'È', 'É', 'Ê', 'Ë', 'Ì', 'Í', 'Î', 'Ï',
  1675. 'Ð', 'Ñ', 'Ò', 'Ó', 'Ô', 'Õ', 'Ö', '×', 'Ø', 'Ù', 'Ú', 'Û', 'Ü', 'Ý', 'Þ', 'ß',
  1676. 'à', 'á', 'â', 'ã', 'å', 'å', 'æ', 'í', 'è', 'é', 'ê', 'ë', 'í', 'í', 'î', 'ï',
  1677. 'ð', 'ñ', 'ò', 'ó', 'ô', 'õ', 'ö', '÷', 'ø', 'ù', 'ú', 'û', 'ü', 'ý', 'þ', 'ÿ');
  1678. { lower case translation table for character set 850 }
  1679. CP850LCT: array[128..255] of char =
  1680. ('‡', '�', '‚', 'ƒ', '„', '…', '†', '‡', 'ˆ', '‰', 'Š', '‹', 'Œ', '�', '„', '†',
  1681. '‚', '‘', '‘', '“', '”', '•', '–', '—', '˜', '”', '�', '›', 'œ', '›', 'ž', 'Ÿ',
  1682. ' ', '¡', '¢', '£', '¤', '¤', '¦', '§', '¨', '©', 'ª', '«', '¬', '­', '®', '¯',
  1683. '°', '±', '²', '³', '´', ' ', 'ƒ', '…', '¸', '¹', 'º', '»', '¼', '½', '¾', '¿',
  1684. 'À', 'Á', 'Â', 'Ã', 'Ä', 'Å', 'Æ', 'Æ', 'È', 'É', 'Ê', 'Ë', 'Ì', 'Í', 'Î', 'Ï',
  1685. 'Ð', 'Ñ', 'ˆ', '‰', 'Š', 'Õ', '¡', 'Œ', '‹', 'Ù', 'Ú', 'Û', 'Ü', 'Ý', '�', 'ß',
  1686. '¢', 'á', '“', '•', 'ä', 'ä', 'æ', 'í', 'è', '£', '–', '—', 'ì', 'ì', 'î', 'ï',
  1687. 'ð', 'ñ', 'ò', 'ó', 'ô', 'õ', 'ö', '÷', 'ø', 'ù', 'ú', 'û', 'ü', 'ý', 'þ', 'ÿ');
  1688. { upper case translation table for character set ISO 8859/1 Latin 1 }
  1689. CPISO88591UCT: array[192..255] of char =
  1690. ( #192, #193, #194, #195, #196, #197, #198, #199,
  1691. #200, #201, #202, #203, #204, #205, #206, #207,
  1692. #208, #209, #210, #211, #212, #213, #214, #215,
  1693. #216, #217, #218, #219, #220, #221, #222, #223,
  1694. #192, #193, #194, #195, #196, #197, #198, #199,
  1695. #200, #201, #202, #203, #204, #205, #206, #207,
  1696. #208, #209, #210, #211, #212, #213, #214, #247,
  1697. #216, #217, #218, #219, #220, #221, #222, #89 );
  1698. { lower case translation table for character set ISO 8859/1 Latin 1 }
  1699. CPISO88591LCT: array[192..255] of char =
  1700. ( #224, #225, #226, #227, #228, #229, #230, #231,
  1701. #232, #233, #234, #235, #236, #237, #238, #239,
  1702. #240, #241, #242, #243, #244, #245, #246, #215,
  1703. #248, #249, #250, #251, #252, #253, #254, #223,
  1704. #224, #225, #226, #227, #228, #229, #230, #231,
  1705. #232, #233, #234, #235, #236, #237, #238, #239,
  1706. #240, #241, #242, #243, #244, #245, #246, #247,
  1707. #248, #249, #250, #251, #252, #253, #254, #255 );
  1708. {
  1709. $Log$
  1710. Revision 1.23 2002-11-28 22:26:30 michael
  1711. + Fixed float<>string conversion routines
  1712. Revision 1.22 2002/11/28 20:29:26 michael
  1713. + made it compile again
  1714. Revision 1.21 2002/11/28 20:15:37 michael
  1715. + Fixed comparestr (merge from fix)
  1716. Revision 1.20 2002/09/15 17:50:35 peter
  1717. * Fixed AnsiStrComp crashes
  1718. Revision 1.1.2.16 2002/11/28 22:25:01 michael
  1719. + Fixed float<>string conversion routines
  1720. Revision 1.1.2.15 2002/11/28 20:24:11 michael
  1721. + merged some fixes from mainbranch
  1722. Revision 1.19 2002/09/07 16:01:22 peter
  1723. * old logs removed and tabs fixed
  1724. Revision 1.1.2.14 2002/11/28 20:13:10 michael
  1725. + Fixed comparestr
  1726. Revision 1.1.2.13 2002/10/29 23:41:06 michael
  1727. + Added lots of D4 functions
  1728. Revision 1.18 2002/09/02 06:07:16 michael
  1729. + Fix for formatbuf not applied correct
  1730. Revision 1.17 2002/08/29 10:04:48 michael
  1731. + Fix for bug report 2097 in formatbuf
  1732. Revision 1.16 2002/08/29 10:04:25 michael
  1733. + Fix for bug report 2097 in formatbuf
  1734. Revision 1.15 2002/07/06 12:14:03 daniel
  1735. - Changes from Strasbourg
  1736. Revision 1.14 2002/01/24 12:33:53 jonas
  1737. * adapted ranges of native types to int64 (e.g. high cardinal is no
  1738. longer longint($ffffffff), but just $fffffff in psystem)
  1739. * small additional fix in 64bit rangecheck code generation for 32 bit
  1740. processors
  1741. * adaption of ranges required the matching talgorithm used for selecting
  1742. which overloaded procedure to call to be adapted. It should now always
  1743. select the closest match for ordinal parameters.
  1744. + inttostr(qword) in sysstr.inc/sysstrh.inc
  1745. + abs(int64), sqr(int64), sqr(qword) in systemh.inc/generic.inc (previous
  1746. fixes were required to be able to add them)
  1747. * is_in_limit() moved from ncal to types unit, should always be used
  1748. instead of direct comparisons of low/high values of orddefs because
  1749. qword is a special case
  1750. }