sysstr.inc 51 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027
  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 StrToFloatDef(const S: string; const Default: Extended): Extended;
  866. begin
  867. if not TextToFloat(PChar(S),Result,fvExtended) then
  868. Result:=Default;
  869. end;
  870. Function TextToFloat(Buffer: PChar; Var Value: Extended): Boolean;
  871. Var
  872. E,P : Integer;
  873. S : String;
  874. Begin
  875. S:=StrPas(Buffer);
  876. P:=Pos(DecimalSeparator,S);
  877. If (P<>0) Then
  878. S[P] := '.';
  879. Val(S,Value,E);
  880. Result:=(E=0);
  881. End;
  882. Function TextToFloat(Buffer: PChar; Var Value; ValueType: TFloatValue): Boolean;
  883. Var
  884. E,P : Integer;
  885. S : String;
  886. C : Currency;
  887. Ext : Extended;
  888. Begin
  889. S:=StrPas(Buffer);
  890. P:=Pos(DecimalSeparator,S);
  891. If (P<>0) Then
  892. S[P] := '.';
  893. case ValueType of
  894. fvCurrency:
  895. Val(S,Currency(Value),E);
  896. fvExtended:
  897. Val(S,Extended(Value),E);
  898. fvDouble:
  899. Val(S,Double(Value),E);
  900. fvSingle:
  901. Val(S,Single(Value),E);
  902. fvComp:
  903. Val(S,Comp(Value),E);
  904. fvReal:
  905. Val(S,Real(Value),E);
  906. end;
  907. Result:=(E=0);
  908. End;
  909. Function FloatToStr(Value: Extended): String;
  910. Begin
  911. Result := FloatToStrF(Value, ffGeneral, 15, 0);
  912. End;
  913. Function FloatToText(Buffer: PChar; Value: Extended; format: TFloatFormat; Precision, Digits: Integer): Longint;
  914. Var
  915. Tmp: String[40];
  916. Begin
  917. Tmp := FloatToStrF(Value, format, Precision, Digits);
  918. Result := Length(Tmp);
  919. Move(Tmp[1], Buffer[0], Result);
  920. End;
  921. Function FloatToStrF(Value: Extended; format: TFloatFormat; Precision, Digits: Integer): String;
  922. Var
  923. P: Integer;
  924. Negative, TooSmall, TooLarge: Boolean;
  925. Begin
  926. Case format Of
  927. ffGeneral:
  928. Begin
  929. If (Precision = -1) Or (Precision > 15) Then Precision := 15;
  930. TooSmall := (Abs(Value) < 0.00001) and (Value>0.0);
  931. If Not TooSmall Then
  932. Begin
  933. Str(Value:0:999, Result);
  934. P := Pos('.', Result);
  935. Result[P] := DecimalSeparator;
  936. TooLarge := P > Precision + 1;
  937. End;
  938. If TooSmall Or TooLarge Then
  939. begin
  940. Result := FloatToStrF(Value, ffExponent, Precision, Digits);
  941. // Strip unneeded zeroes.
  942. P:=Pos('E',result)-1;
  943. If P<>-1 then
  944. While (P>1) and (Result[P]='0') do
  945. begin
  946. system.Delete(Result,P,1);
  947. Dec(P);
  948. end;
  949. end
  950. else
  951. begin
  952. P := Length(Result);
  953. While Result[P] = '0' Do Dec(P);
  954. If Result[P] = DecimalSeparator Then Dec(P);
  955. SetLength(Result, P);
  956. end;
  957. End;
  958. ffExponent:
  959. Begin
  960. If (Precision = -1) Or (Precision > 15) Then Precision := 15;
  961. Str(Value:Precision + 8, Result);
  962. Result[3] := DecimalSeparator;
  963. P:=4;
  964. While (P>0) and (Digits < P) And (Result[Precision + 5] = '0') do
  965. Begin
  966. If P<>1 then
  967. system.Delete(Result, Precision + 5, 1)
  968. else
  969. system.Delete(Result, Precision + 3, 3);
  970. Dec(P);
  971. end;
  972. If Result[1] = ' ' Then
  973. System.Delete(Result, 1, 1);
  974. End;
  975. ffFixed:
  976. Begin
  977. If Digits = -1 Then Digits := 2
  978. Else If Digits > 15 Then Digits := 15;
  979. Str(Value:0:Digits, Result);
  980. If Result[1] = ' ' Then
  981. System.Delete(Result, 1, 1);
  982. P := Pos('.', Result);
  983. If P <> 0 Then Result[P] := DecimalSeparator;
  984. End;
  985. ffNumber:
  986. Begin
  987. If Digits = -1 Then Digits := 2
  988. Else If Digits > 15 Then Digits := 15;
  989. Str(Value:0:Digits, Result);
  990. If Result[1] = ' ' Then System.Delete(Result, 1, 1);
  991. P := Pos('.', Result);
  992. If P <> 0 Then
  993. Result[P] := DecimalSeparator
  994. else
  995. P := Length(Result)+1;
  996. Dec(P, 3);
  997. While (P > 1) Do
  998. Begin
  999. If Result[P - 1] <> '-' Then Insert(ThousandSeparator, Result, P);
  1000. Dec(P, 3);
  1001. End;
  1002. End;
  1003. ffCurrency:
  1004. Begin
  1005. If Value < 0 Then
  1006. Begin
  1007. Negative := True;
  1008. Value := -Value;
  1009. End
  1010. Else Negative := False;
  1011. If Digits = -1 Then Digits := CurrencyDecimals
  1012. Else If Digits > 18 Then Digits := 18;
  1013. Str(Value:0:Digits, Result);
  1014. If Result[1] = ' ' Then System.Delete(Result, 1, 1);
  1015. P := Pos('.', Result);
  1016. If P <> 0 Then Result[P] := DecimalSeparator;
  1017. Dec(P, 3);
  1018. While (P > 1) Do
  1019. Begin
  1020. Insert(ThousandSeparator, Result, P);
  1021. Dec(P, 3);
  1022. End;
  1023. If Not Negative Then
  1024. Begin
  1025. Case CurrencyFormat Of
  1026. 0: Result := CurrencyString + Result;
  1027. 1: Result := Result + CurrencyString;
  1028. 2: Result := CurrencyString + ' ' + Result;
  1029. 3: Result := Result + ' ' + CurrencyString;
  1030. End
  1031. End
  1032. Else
  1033. Begin
  1034. Case NegCurrFormat Of
  1035. 0: Result := '(' + CurrencyString + Result + ')';
  1036. 1: Result := '-' + CurrencyString + Result;
  1037. 2: Result := CurrencyString + '-' + Result;
  1038. 3: Result := CurrencyString + Result + '-';
  1039. 4: Result := '(' + Result + CurrencyString + ')';
  1040. 5: Result := '-' + Result + CurrencyString;
  1041. 6: Result := Result + '-' + CurrencyString;
  1042. 7: Result := Result + CurrencyString + '-';
  1043. 8: Result := '-' + Result + ' ' + CurrencyString;
  1044. 9: Result := '-' + CurrencyString + ' ' + Result;
  1045. 10: Result := CurrencyString + ' ' + Result + '-';
  1046. End;
  1047. End;
  1048. End;
  1049. End;
  1050. End;
  1051. Function FloatToDateTime (Const Value : Extended) : TDateTime;
  1052. begin
  1053. If (Value<MinDateTime) or (Value>MaxDateTime) then
  1054. Raise EConvertError.CreateFmt (SInvalidDateTime,[Value]);
  1055. Result:=Value;
  1056. end;
  1057. Function FloatToCurr (Const Value : Extended) : Currency;
  1058. begin
  1059. end;
  1060. Function CurrToStr(Value: Currency): string;
  1061. begin
  1062. end;
  1063. function StrToCurr(const S: string): Currency;
  1064. begin
  1065. end;
  1066. function StrToBool(const S: string): Boolean;
  1067. Var
  1068. Temp : String;
  1069. D : Double;
  1070. Code : word;
  1071. begin
  1072. Temp:=upcase(S);
  1073. Val(temp,D,code);
  1074. If Code=0 then
  1075. Result:=(D<>0.0)
  1076. else If Temp='TRUE' then
  1077. result:=true
  1078. else if Temp='FALSE' then
  1079. result:=false
  1080. else
  1081. Raise EConvertError.CreateFmt(SInvalidBoolean,[S]);
  1082. end;
  1083. function BoolToStr(B: Boolean): string;
  1084. begin
  1085. If B then
  1086. Result:='TRUE'
  1087. else
  1088. Result:='FALSE';
  1089. end;
  1090. Function FloatToTextFmt(Buffer: PChar; Value: Extended; format: PChar): Integer;
  1091. Var
  1092. Digits: String[40]; { String Of Digits }
  1093. Exponent: String[8]; { Exponent strin }
  1094. FmtStart, FmtStop: PChar; { Start And End Of relevant part }
  1095. { Of format String }
  1096. ExpFmt, ExpSize: Integer; { Type And Length Of }
  1097. { exponential format chosen }
  1098. Placehold: Array[1..4] Of Integer; { Number Of placeholders In All }
  1099. { four Sections }
  1100. thousand: Boolean; { thousand separators? }
  1101. UnexpectedDigits: Integer; { Number Of unexpected Digits that }
  1102. { have To be inserted before the }
  1103. { First placeholder. }
  1104. DigitExponent: Integer; { Exponent Of First digit In }
  1105. { Digits Array. }
  1106. { Find end of format section starting at P. False, if empty }
  1107. Function GetSectionEnd(Var P: PChar): Boolean;
  1108. Var
  1109. C: Char;
  1110. SQ, DQ: Boolean;
  1111. Begin
  1112. Result := False;
  1113. SQ := False;
  1114. DQ := False;
  1115. C := P[0];
  1116. While (C<>#0) And ((C<>';') Or SQ Or DQ) Do
  1117. Begin
  1118. Result := True;
  1119. Case C Of
  1120. #34: If Not SQ Then DQ := Not DQ;
  1121. #39: If Not DQ Then SQ := Not SQ;
  1122. End;
  1123. Inc(P);
  1124. C := P[0];
  1125. End;
  1126. End;
  1127. { Find start and end of format section to apply. If section doesn't exist,
  1128. use section 1. If section 2 is used, the sign of value is ignored. }
  1129. Procedure GetSectionRange(section: Integer);
  1130. Var
  1131. Sec: Array[1..3] Of PChar;
  1132. SecOk: Array[1..3] Of Boolean;
  1133. Begin
  1134. Sec[1] := format;
  1135. SecOk[1] := GetSectionEnd(Sec[1]);
  1136. If section > 1 Then
  1137. Begin
  1138. Sec[2] := Sec[1];
  1139. If Sec[2][0] <> #0 Then
  1140. Inc(Sec[2]);
  1141. SecOk[2] := GetSectionEnd(Sec[2]);
  1142. If section > 2 Then
  1143. Begin
  1144. Sec[3] := Sec[2];
  1145. If Sec[3][0] <> #0 Then
  1146. Inc(Sec[3]);
  1147. SecOk[3] := GetSectionEnd(Sec[3]);
  1148. End;
  1149. End;
  1150. If Not SecOk[1] Then
  1151. FmtStart := Nil
  1152. Else
  1153. Begin
  1154. If Not SecOk[section] Then
  1155. section := 1
  1156. Else If section = 2 Then
  1157. Value := -Value; { Remove sign }
  1158. If section = 1 Then FmtStart := format Else
  1159. Begin
  1160. FmtStart := Sec[section - 1];
  1161. Inc(FmtStart);
  1162. End;
  1163. FmtStop := Sec[section];
  1164. End;
  1165. End;
  1166. { Find format section ranging from FmtStart to FmtStop. }
  1167. Procedure GetFormatOptions;
  1168. Var
  1169. Fmt: PChar;
  1170. SQ, DQ: Boolean;
  1171. area: Integer;
  1172. Begin
  1173. SQ := False;
  1174. DQ := False;
  1175. Fmt := FmtStart;
  1176. ExpFmt := 0;
  1177. area := 1;
  1178. thousand := False;
  1179. Placehold[1] := 0;
  1180. Placehold[2] := 0;
  1181. Placehold[3] := 0;
  1182. Placehold[4] := 0;
  1183. While Fmt < FmtStop Do
  1184. Begin
  1185. Case Fmt[0] Of
  1186. #34:
  1187. Begin
  1188. If Not SQ Then
  1189. DQ := Not DQ;
  1190. Inc(Fmt);
  1191. End;
  1192. #39:
  1193. Begin
  1194. If Not DQ Then
  1195. SQ := Not SQ;
  1196. Inc(Fmt);
  1197. End;
  1198. Else
  1199. { This was 'if not SQ or DQ'. Looked wrong... }
  1200. If Not SQ Or DQ Then
  1201. Begin
  1202. Case Fmt[0] Of
  1203. '0':
  1204. Begin
  1205. Case area Of
  1206. 1:
  1207. area := 2;
  1208. 4:
  1209. Begin
  1210. area := 3;
  1211. Inc(Placehold[3], Placehold[4]);
  1212. Placehold[4] := 0;
  1213. End;
  1214. End;
  1215. Inc(Placehold[area]);
  1216. Inc(Fmt);
  1217. End;
  1218. '#':
  1219. Begin
  1220. If area=3 Then
  1221. area:=4;
  1222. Inc(Placehold[area]);
  1223. Inc(Fmt);
  1224. End;
  1225. '.':
  1226. Begin
  1227. If area<3 Then
  1228. area:=3;
  1229. Inc(Fmt);
  1230. End;
  1231. ',':
  1232. Begin
  1233. thousand := True;
  1234. Inc(Fmt);
  1235. End;
  1236. 'e', 'E':
  1237. If ExpFmt = 0 Then
  1238. Begin
  1239. If (Fmt[0]='E') Then
  1240. ExpFmt:=1
  1241. Else
  1242. ExpFmt := 3;
  1243. Inc(Fmt);
  1244. If (Fmt<FmtStop) Then
  1245. Begin
  1246. Case Fmt[0] Of
  1247. '+':
  1248. Begin
  1249. End;
  1250. '-':
  1251. Inc(ExpFmt);
  1252. Else
  1253. ExpFmt := 0;
  1254. End;
  1255. If ExpFmt <> 0 Then
  1256. Begin
  1257. Inc(Fmt);
  1258. ExpSize := 0;
  1259. While (Fmt<FmtStop) And
  1260. (ExpSize<4) And
  1261. (Fmt[0] In ['0'..'9']) Do
  1262. Begin
  1263. Inc(ExpSize);
  1264. Inc(Fmt);
  1265. End;
  1266. End;
  1267. End;
  1268. End
  1269. Else
  1270. Inc(Fmt);
  1271. Else { Case }
  1272. Inc(Fmt);
  1273. End; { Case }
  1274. End; { Begin }
  1275. End; { Case }
  1276. End; { While .. Begin }
  1277. End;
  1278. Procedure FloatToStr;
  1279. Var
  1280. I, J, Exp, Width, Decimals, DecimalPoint, len: Integer;
  1281. Begin
  1282. If ExpFmt = 0 Then
  1283. Begin
  1284. { Fixpoint }
  1285. Decimals:=Placehold[3]+Placehold[4];
  1286. Width:=Placehold[1]+Placehold[2]+Decimals;
  1287. If (Decimals=0) Then
  1288. Str(Value:Width:0,Digits)
  1289. Else
  1290. Str(Value:Width+1:Decimals,Digits);
  1291. len:=Length(Digits);
  1292. { Find the decimal point }
  1293. If (Decimals=0) Then
  1294. DecimalPoint:=len+1
  1295. Else
  1296. DecimalPoint:=len-Decimals;
  1297. { If value is very small, and no decimal places
  1298. are desired, remove the leading 0. }
  1299. If (Abs(Value) < 1) And (Placehold[2] = 0) Then
  1300. Begin
  1301. If (Placehold[1]=0) Then
  1302. Delete(Digits,DecimalPoint-1,1)
  1303. Else
  1304. Digits[DecimalPoint-1]:=' ';
  1305. End;
  1306. { Convert optional zeroes to spaces. }
  1307. I:=len;
  1308. J:=DecimalPoint+Placehold[3];
  1309. While (I>J) And (Digits[I]='0') Do
  1310. Begin
  1311. Digits[I] := ' ';
  1312. Dec(I);
  1313. End;
  1314. { If integer value and no obligatory decimal
  1315. places, remove decimal point. }
  1316. If (DecimalPoint < len) And (Digits[DecimalPoint + 1] = ' ') Then
  1317. Digits[DecimalPoint] := ' ';
  1318. { Convert spaces left from obligatory decimal point to zeroes. }
  1319. I:=DecimalPoint-Placehold[2];
  1320. While (I<DecimalPoint) And (Digits[I]=' ') Do
  1321. Begin
  1322. Digits[I] := '0';
  1323. Inc(I);
  1324. End;
  1325. Exp := 0;
  1326. End
  1327. Else
  1328. Begin
  1329. { Scientific: exactly <Width> Digits With <Precision> Decimals
  1330. And adjusted Exponent. }
  1331. If Placehold[1]+Placehold[2]=0 Then
  1332. Placehold[1]:=1;
  1333. Decimals := Placehold[3] + Placehold[4];
  1334. Width:=Placehold[1]+Placehold[2]+Decimals;
  1335. Str(Value:Width+8,Digits);
  1336. { Find and cut out exponent. Always the
  1337. last 6 characters in the string.
  1338. -> 0000E+0000 }
  1339. I:=Length(Digits)-5;
  1340. Val(Copy(Digits,I+1,5),Exp,J);
  1341. Exp:=Exp+1-(Placehold[1]+Placehold[2]);
  1342. Delete(Digits, I, 6);
  1343. { Str() always returns at least one digit after the decimal point.
  1344. If we don't want it, we have to remove it. }
  1345. If (Decimals=0) And (Placehold[1]+Placehold[2]<= 1) Then
  1346. Begin
  1347. If (Digits[4]>='5') Then
  1348. Begin
  1349. Inc(Digits[2]);
  1350. If (Digits[2]>'9') Then
  1351. Begin
  1352. Digits[2] := '1';
  1353. Inc(Exp);
  1354. End;
  1355. End;
  1356. Delete(Digits, 3, 2);
  1357. DecimalPoint := Length(Digits) + 1;
  1358. End
  1359. Else
  1360. Begin
  1361. { Move decimal point at the desired position }
  1362. Delete(Digits, 3, 1);
  1363. DecimalPoint:=2+Placehold[1]+Placehold[2];
  1364. If (Decimals<>0) Then
  1365. Insert('.',Digits,DecimalPoint);
  1366. End;
  1367. { Convert optional zeroes to spaces. }
  1368. I := Length(Digits);
  1369. J := DecimalPoint + Placehold[3];
  1370. While (I > J) And (Digits[I] = '0') Do
  1371. Begin
  1372. Digits[I] := ' ';
  1373. Dec(I);
  1374. End;
  1375. { If integer number and no obligatory decimal paces, remove decimal point }
  1376. If (DecimalPoint<Length(Digits)) And
  1377. (Digits[DecimalPoint+1]=' ') Then
  1378. Digits[DecimalPoint]:=' ';
  1379. If (Digits[1]=' ') Then
  1380. Begin
  1381. Delete(Digits, 1, 1);
  1382. Dec(DecimalPoint);
  1383. End;
  1384. { Calculate exponent string }
  1385. Str(Abs(Exp), Exponent);
  1386. While Length(Exponent)<ExpSize Do
  1387. Insert('0',Exponent,1);
  1388. If Exp >= 0 Then
  1389. Begin
  1390. If (ExpFmt In [1,3]) Then
  1391. Insert('+', Exponent, 1);
  1392. End
  1393. Else
  1394. Insert('-',Exponent,1);
  1395. If (ExpFmt<3) Then
  1396. Insert('E',Exponent,1)
  1397. Else
  1398. Insert('e',Exponent,1);
  1399. End;
  1400. DigitExponent:=DecimalPoint-2;
  1401. If (Digits[1]='-') Then
  1402. Dec(DigitExponent);
  1403. UnexpectedDigits:=DecimalPoint-1-(Placehold[1]+Placehold[2]);
  1404. End;
  1405. Function PutResult: LongInt;
  1406. Var
  1407. SQ, DQ: Boolean;
  1408. Fmt, Buf: PChar;
  1409. Dig, N: Integer;
  1410. Begin
  1411. SQ := False;
  1412. DQ := False;
  1413. Fmt := FmtStart;
  1414. Buf := Buffer;
  1415. Dig := 1;
  1416. While (Fmt<FmtStop) Do
  1417. Begin
  1418. //Write(Fmt[0]);
  1419. Case Fmt[0] Of
  1420. #34:
  1421. Begin
  1422. If Not SQ Then
  1423. DQ := Not DQ;
  1424. Inc(Fmt);
  1425. End;
  1426. #39:
  1427. Begin
  1428. If Not DQ Then
  1429. SQ := Not SQ;
  1430. Inc(Fmt);
  1431. End;
  1432. Else
  1433. If Not (SQ Or DQ) Then
  1434. Begin
  1435. Case Fmt[0] Of
  1436. '0', '#', '.':
  1437. Begin
  1438. If (Dig=1) And (UnexpectedDigits>0) Then
  1439. Begin
  1440. { Everything unexpected is written before the first digit }
  1441. For N := 1 To UnexpectedDigits Do
  1442. Begin
  1443. Buf[0] := Digits[N];
  1444. Inc(Buf);
  1445. If thousand And (Digits[N]<>'-') Then
  1446. Begin
  1447. If (DigitExponent Mod 3 = 0) And (DigitExponent>0) Then
  1448. Begin
  1449. Buf[0] := ThousandSeparator;
  1450. Inc(Buf);
  1451. End;
  1452. Dec(DigitExponent);
  1453. End;
  1454. End;
  1455. Inc(Dig, UnexpectedDigits);
  1456. End;
  1457. If (Digits[Dig]<>' ') Then
  1458. Begin
  1459. If (Digits[Dig]='.') Then
  1460. Buf[0] := DecimalSeparator
  1461. Else
  1462. Buf[0] := Digits[Dig];
  1463. Inc(Buf);
  1464. If thousand And (DigitExponent Mod 3 = 0) And (DigitExponent > 0) Then
  1465. Begin
  1466. Buf[0] := ThousandSeparator;
  1467. Inc(Buf);
  1468. End;
  1469. End;
  1470. Inc(Dig);
  1471. Dec(DigitExponent);
  1472. Inc(Fmt);
  1473. End;
  1474. 'e', 'E':
  1475. Begin
  1476. If ExpFmt <> 0 Then
  1477. Begin
  1478. Inc(Fmt);
  1479. If Fmt < FmtStop Then
  1480. Begin
  1481. If Fmt[0] In ['+', '-'] Then
  1482. Begin
  1483. Inc(Fmt, ExpSize);
  1484. For N:=1 To Length(Exponent) Do
  1485. Buf[N-1] := Exponent[N];
  1486. Inc(Buf,Length(Exponent));
  1487. ExpFmt:=0;
  1488. End;
  1489. Inc(Fmt);
  1490. End;
  1491. End
  1492. Else
  1493. Begin
  1494. { No legal exponential format.
  1495. Simply write the 'E' to the result. }
  1496. Buf[0] := Fmt[0];
  1497. Inc(Buf);
  1498. Inc(Fmt);
  1499. End;
  1500. End;
  1501. Else { Case }
  1502. { Usual character }
  1503. If (Fmt[0]<>',') Then
  1504. Begin
  1505. Buf[0] := Fmt[0];
  1506. Inc(Buf);
  1507. End;
  1508. Inc(Fmt);
  1509. End; { Case }
  1510. End
  1511. Else { IF }
  1512. Begin
  1513. { Character inside single or double quotes }
  1514. Buf[0] := Fmt[0];
  1515. Inc(Buf);
  1516. Inc(Fmt);
  1517. End;
  1518. End; { Case }
  1519. End; { While .. Begin }
  1520. Result:=LongInt(Buf)-LongInt(Buffer);
  1521. End;
  1522. Begin
  1523. If (Value>0) Then
  1524. GetSectionRange(1)
  1525. Else If (Value<0) Then
  1526. GetSectionRange(2)
  1527. Else
  1528. GetSectionRange(3);
  1529. If FmtStart = Nil Then
  1530. Begin
  1531. Result := FloatToText(Buffer, Value, ffGeneral, 15, 4);
  1532. End
  1533. Else
  1534. Begin
  1535. GetFormatOptions;
  1536. If (ExpFmt = 0) And (Abs(Value) >= 1E18) Then
  1537. Result := FloatToText(Buffer, Value, ffGeneral, 15, 4)
  1538. Else
  1539. Begin
  1540. FloatToStr;
  1541. Result := PutResult;
  1542. End;
  1543. End;
  1544. End;
  1545. Procedure FloatToDecimal(Var Result: TFloatRec; Value: Extended; Precision, Decimals : integer);
  1546. Var
  1547. Buffer: String[24];
  1548. Error, N: Integer;
  1549. Begin
  1550. Str(Value:23, Buffer);
  1551. Result.Negative := (Buffer[1] = '-');
  1552. Val(Copy(Buffer, 19, 5), Result.Exponent, Error);
  1553. Inc(Result. Exponent);
  1554. Result.Digits[0] := Buffer[2];
  1555. Move(Buffer[4], Result.Digits[1], 14);
  1556. If Decimals + Result.Exponent < Precision Then
  1557. N := Decimals + Result.Exponent
  1558. Else
  1559. N := Precision;
  1560. If N > 15 Then
  1561. N := 15;
  1562. If N = 0 Then
  1563. Begin
  1564. If Result.Digits[0] >= '5' Then
  1565. Begin
  1566. Result.Digits[0] := '1';
  1567. Result.Digits[1] := #0;
  1568. Inc(Result.Exponent);
  1569. End
  1570. Else
  1571. Result.Digits[0] := #0;
  1572. End
  1573. Else If N > 0 Then
  1574. Begin
  1575. If Result.Digits[N] >= '5' Then
  1576. Begin
  1577. Repeat
  1578. Result.Digits[N] := #0;
  1579. Dec(N);
  1580. Inc(Result.Digits[N]);
  1581. Until (N = 0) Or (Result.Digits[N] < ':');
  1582. If Result.Digits[0] = ':' Then
  1583. Begin
  1584. Result.Digits[0] := '1';
  1585. Inc(Result.Exponent);
  1586. End;
  1587. End
  1588. Else
  1589. Begin
  1590. Result.Digits[N] := '0';
  1591. While (Result.Digits[N] = '0') And (N > -1) Do
  1592. Begin
  1593. Result.Digits[N] := #0;
  1594. Dec(N);
  1595. End;
  1596. End;
  1597. End
  1598. Else
  1599. Result.Digits[0] := #0;
  1600. If Result.Digits[0] = #0 Then
  1601. Begin
  1602. Result.Exponent := 0;
  1603. Result.Negative := False;
  1604. End;
  1605. End;
  1606. Function FormatFloat(Const format: String; Value: Extended): String;
  1607. Var
  1608. Temp: ShortString;
  1609. buf : Array[0..1024] of char;
  1610. Begin
  1611. Buf[FloatToTextFmt(@Buf[0],Value,Pchar(Format))]:=#0;
  1612. Result:=StrPas(@Buf);
  1613. End;
  1614. {==============================================================================}
  1615. { extra functions }
  1616. {==============================================================================}
  1617. { LeftStr returns Count left-most characters from S }
  1618. function LeftStr(const S: string; Count: integer): string;
  1619. begin
  1620. result := Copy(S, 1, Count);
  1621. end ;
  1622. { RightStr returns Count right-most characters from S }
  1623. function RightStr(const S: string; Count: integer): string;
  1624. begin
  1625. If Count>Length(S) then
  1626. Count:=Length(S);
  1627. result := Copy(S, 1 + Length(S) - Count, Count);
  1628. end;
  1629. { BCDToInt converts the BCD value Value to an integer }
  1630. function BCDToInt(Value: integer): integer;
  1631. var i, j: integer;
  1632. begin
  1633. result := 0;
  1634. j := 1;
  1635. for i := 0 to SizeOf(Value) shr 1 - 1 do begin
  1636. result := result + j * (Value and 15);
  1637. j := j * 10;
  1638. Value := Value shr 4;
  1639. end ;
  1640. end ;
  1641. Function IsDelimiter(const Delimiters, S: string; Index: Integer): Boolean;
  1642. begin
  1643. Result:=False;
  1644. If Index<=Length(S) then
  1645. Result:=Pos(S[Index],Delimiters)<>0; // Note we don't do MBCS yet
  1646. end;
  1647. Function LastDelimiter(const Delimiters, S: string): Integer;
  1648. begin
  1649. Result:=Length(S);
  1650. While (Result>0) and (Pos(S[Result],Delimiters)=0) do
  1651. Dec(Result);
  1652. end;
  1653. function StringReplace(const S, OldPattern, NewPattern: string; Flags: TReplaceFlags): string;
  1654. var
  1655. Srch,OldP,RemS: string; // Srch and Oldp can contain uppercase versions of S,OldPattern
  1656. P : Integer;
  1657. begin
  1658. Srch:=S;
  1659. OldP:=OldPattern;
  1660. if rfIgnoreCase in Flags then
  1661. begin
  1662. Srch:=UpperCase(Srch);
  1663. OldP:=UpperCase(OldP);
  1664. end;
  1665. RemS:=S;
  1666. Result:='';
  1667. while (Length(Srch)<>0) do
  1668. begin
  1669. P:=Pos(OldP, Srch);
  1670. if P=0 then
  1671. begin
  1672. Result:=Result+RemS;
  1673. Srch:='';
  1674. end
  1675. else
  1676. begin
  1677. Result:=Result+Copy(RemS,1,P-1)+NewPattern;
  1678. P:=P+Length(OldP);
  1679. RemS:=Copy(RemS,P,Length(RemS)-P+1);
  1680. if not (rfReplaceAll in Flags) then
  1681. begin
  1682. Result:=Result+RemS;
  1683. Srch:='';
  1684. end
  1685. else
  1686. Srch:=Copy(Srch,P,Length(Srch)-P+1);
  1687. end;
  1688. end;
  1689. end;
  1690. {
  1691. Case Translation Tables
  1692. Can be used in internationalization support.
  1693. Although these tables can be obtained through system calls
  1694. it is better to not use those, since most implementation are not 100%
  1695. WARNING:
  1696. before modifying a translation table make sure that the current codepage
  1697. of the OS corresponds to the one you make changes to
  1698. }
  1699. const
  1700. { upper case translation table for character set 850 }
  1701. CP850UCT: array[128..255] of char =
  1702. ('€', 'š', '�', '¶', 'Ž', '¶', '�', '€', 'Ò', 'Ó', 'Ô', 'Ø', '×', 'Þ', 'Ž', '�',
  1703. '�', '’', '’', 'â', '™', 'ã', 'ê', 'ë', 'Y', '™', 'š', '�', 'œ', '�', 'ž', 'Ÿ',
  1704. 'µ', 'Ö', 'à', 'é', '¥', '¥', '¦', '§', '¨', '©', 'ª', '«', '¬', '­', '®', '¯',
  1705. '°', '±', '²', '³', '´', 'µ', '¶', '·', '¸', '¹', 'º', '»', '¼', '½', '¾', '¿',
  1706. 'À', 'Á', 'Â', 'Ã', 'Ä', 'Å', 'Ç', 'Ç', 'È', 'É', 'Ê', 'Ë', 'Ì', 'Í', 'Î', 'Ï',
  1707. 'Ð', 'Ñ', 'Ò', 'Ó', 'Ô', 'Õ', 'Ö', '×', 'Ø', 'Ù', 'Ú', 'Û', 'Ü', 'Ý', 'Þ', 'ß',
  1708. 'à', 'á', 'â', 'ã', 'å', 'å', 'æ', 'í', 'è', 'é', 'ê', 'ë', 'í', 'í', 'î', 'ï',
  1709. 'ð', 'ñ', 'ò', 'ó', 'ô', 'õ', 'ö', '÷', 'ø', 'ù', 'ú', 'û', 'ü', 'ý', 'þ', 'ÿ');
  1710. { lower case translation table for character set 850 }
  1711. CP850LCT: array[128..255] of char =
  1712. ('‡', '�', '‚', 'ƒ', '„', '…', '†', '‡', 'ˆ', '‰', 'Š', '‹', 'Œ', '�', '„', '†',
  1713. '‚', '‘', '‘', '“', '”', '•', '–', '—', '˜', '”', '�', '›', 'œ', '›', 'ž', 'Ÿ',
  1714. ' ', '¡', '¢', '£', '¤', '¤', '¦', '§', '¨', '©', 'ª', '«', '¬', '­', '®', '¯',
  1715. '°', '±', '²', '³', '´', ' ', 'ƒ', '…', '¸', '¹', 'º', '»', '¼', '½', '¾', '¿',
  1716. 'À', 'Á', 'Â', 'Ã', 'Ä', 'Å', 'Æ', 'Æ', 'È', 'É', 'Ê', 'Ë', 'Ì', 'Í', 'Î', 'Ï',
  1717. 'Ð', 'Ñ', 'ˆ', '‰', 'Š', 'Õ', '¡', 'Œ', '‹', 'Ù', 'Ú', 'Û', 'Ü', 'Ý', '�', 'ß',
  1718. '¢', 'á', '“', '•', 'ä', 'ä', 'æ', 'í', 'è', '£', '–', '—', 'ì', 'ì', 'î', 'ï',
  1719. 'ð', 'ñ', 'ò', 'ó', 'ô', 'õ', 'ö', '÷', 'ø', 'ù', 'ú', 'û', 'ü', 'ý', 'þ', 'ÿ');
  1720. { upper case translation table for character set ISO 8859/1 Latin 1 }
  1721. CPISO88591UCT: array[192..255] of char =
  1722. ( #192, #193, #194, #195, #196, #197, #198, #199,
  1723. #200, #201, #202, #203, #204, #205, #206, #207,
  1724. #208, #209, #210, #211, #212, #213, #214, #215,
  1725. #216, #217, #218, #219, #220, #221, #222, #223,
  1726. #192, #193, #194, #195, #196, #197, #198, #199,
  1727. #200, #201, #202, #203, #204, #205, #206, #207,
  1728. #208, #209, #210, #211, #212, #213, #214, #247,
  1729. #216, #217, #218, #219, #220, #221, #222, #89 );
  1730. { lower case translation table for character set ISO 8859/1 Latin 1 }
  1731. CPISO88591LCT: array[192..255] of char =
  1732. ( #224, #225, #226, #227, #228, #229, #230, #231,
  1733. #232, #233, #234, #235, #236, #237, #238, #239,
  1734. #240, #241, #242, #243, #244, #245, #246, #215,
  1735. #248, #249, #250, #251, #252, #253, #254, #223,
  1736. #224, #225, #226, #227, #228, #229, #230, #231,
  1737. #232, #233, #234, #235, #236, #237, #238, #239,
  1738. #240, #241, #242, #243, #244, #245, #246, #247,
  1739. #248, #249, #250, #251, #252, #253, #254, #255 );
  1740. {
  1741. $Log$
  1742. Revision 1.25 2002-12-23 23:26:08 florian
  1743. + addition to previous commit, forgot to save in the editor
  1744. Revision 1.23 2002/11/28 22:26:30 michael
  1745. + Fixed float<>string conversion routines
  1746. Revision 1.22 2002/11/28 20:29:26 michael
  1747. + made it compile again
  1748. Revision 1.21 2002/11/28 20:15:37 michael
  1749. + Fixed comparestr (merge from fix)
  1750. Revision 1.20 2002/09/15 17:50:35 peter
  1751. * Fixed AnsiStrComp crashes
  1752. Revision 1.1.2.16 2002/11/28 22:25:01 michael
  1753. + Fixed float<>string conversion routines
  1754. Revision 1.1.2.15 2002/11/28 20:24:11 michael
  1755. + merged some fixes from mainbranch
  1756. Revision 1.19 2002/09/07 16:01:22 peter
  1757. * old logs removed and tabs fixed
  1758. Revision 1.1.2.14 2002/11/28 20:13:10 michael
  1759. + Fixed comparestr
  1760. Revision 1.1.2.13 2002/10/29 23:41:06 michael
  1761. + Added lots of D4 functions
  1762. Revision 1.18 2002/09/02 06:07:16 michael
  1763. + Fix for formatbuf not applied correct
  1764. Revision 1.17 2002/08/29 10:04:48 michael
  1765. + Fix for bug report 2097 in formatbuf
  1766. Revision 1.16 2002/08/29 10:04:25 michael
  1767. + Fix for bug report 2097 in formatbuf
  1768. Revision 1.15 2002/07/06 12:14:03 daniel
  1769. - Changes from Strasbourg
  1770. Revision 1.14 2002/01/24 12:33:53 jonas
  1771. * adapted ranges of native types to int64 (e.g. high cardinal is no
  1772. longer longint($ffffffff), but just $fffffff in psystem)
  1773. * small additional fix in 64bit rangecheck code generation for 32 bit
  1774. processors
  1775. * adaption of ranges required the matching talgorithm used for selecting
  1776. which overloaded procedure to call to be adapted. It should now always
  1777. select the closest match for ordinal parameters.
  1778. + inttostr(qword) in sysstr.inc/sysstrh.inc
  1779. + abs(int64), sqr(int64), sqr(qword) in systemh.inc/generic.inc (previous
  1780. fixes were required to be able to add them)
  1781. * is_in_limit() moved from ncal to types unit, should always be used
  1782. instead of direct comparisons of low/high values of orddefs because
  1783. qword is a special case
  1784. }