sysstr.inc 49 KB

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