sysstr.inc 50 KB

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