sysstr.inc 78 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059
  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. See the file COPYING.FPC, included in this distribution,
  9. for details about the copyright.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  13. **********************************************************************
  14. System Utilities For Free Pascal
  15. }
  16. { NewStr creates a new PString and assigns S to it
  17. if length(s) = 0 NewStr returns Nil }
  18. function NewStr(const S: string): PString;
  19. begin
  20. if (S='') then
  21. Result:=nil
  22. else
  23. begin
  24. new(result);
  25. if (Result<>nil) then
  26. Result^:=s;
  27. end;
  28. end;
  29. {$ifdef dummy}
  30. { declaring this breaks delphi compatibility and e.g. tw3721.pp }
  31. FUNCTION NewStr (Const S: ShortString): PShortString;
  32. VAR P: PShortString;
  33. BEGIN
  34. If (S = '') Then
  35. P := Nil
  36. Else
  37. Begin { Return nil }
  38. GetMem(P, Length(S) + 1); { Allocate memory }
  39. If (P<>Nil) Then P^ := S; { Hold string }
  40. End;
  41. NewStr := P; { Return result }
  42. END;
  43. {$endif dummy}
  44. { DisposeStr frees the memory occupied by S }
  45. procedure DisposeStr(S: PString);
  46. begin
  47. if S <> Nil then
  48. begin
  49. dispose(s);
  50. S:=nil;
  51. end;
  52. end;
  53. PROCEDURE DisposeStr (S: PShortString);
  54. BEGIN
  55. If (S <> Nil) Then FreeMem(S, Length(S^) + 1); { Release memory }
  56. END;
  57. { AssignStr assigns S to P^ }
  58. procedure AssignStr(var P: PString; const S: string);
  59. begin
  60. P^ := s;
  61. end ;
  62. { AppendStr appends S to Dest }
  63. procedure AppendStr(var Dest: String; const S: string);
  64. begin
  65. Dest := Dest + S;
  66. end ;
  67. { UpperCase returns a copy of S where all lowercase characters ( from a to z )
  68. have been converted to uppercase }
  69. Function UpperCase(Const S : String) : String;
  70. Var
  71. i : Integer;
  72. P : PChar;
  73. begin
  74. Result := S;
  75. if not assigned(pointer(result)) then exit;
  76. UniqueString(Result);
  77. P:=Pchar(pointer(Result));
  78. for i := 1 to Length(Result) do
  79. begin
  80. if (P^ in ['a'..'z']) then P^ := char(byte(p^) - 32);
  81. Inc(P);
  82. end;
  83. end;
  84. { LowerCase returns a copy of S where all uppercase characters ( from A to Z )
  85. have been converted to lowercase }
  86. Function Lowercase(Const S : String) : String;
  87. Var
  88. i : Integer;
  89. P : PChar;
  90. begin
  91. Result := S;
  92. if not assigned(pointer(result)) then exit;
  93. UniqueString(Result);
  94. P:=Pchar(pointer(Result));
  95. for i := 1 to Length(Result) do
  96. begin
  97. if (P^ in ['A'..'Z']) then P^ := char(byte(p^) + 32);
  98. Inc(P);
  99. end;
  100. end;
  101. function LowerCase(const V: variant): string; overload;{$ifdef SYSUTILSINLINE}inline;{$endif}
  102. begin
  103. result:=LowerCase(ansistring(V));
  104. end;
  105. { CompareStr compares S1 and S2, the result is the based on
  106. substraction of the ascii values of the characters in S1 and S2
  107. case result
  108. S1 < S2 < 0
  109. S1 > S2 > 0
  110. S1 = S2 = 0 }
  111. function CompareStr(const S1, S2: string): Integer;
  112. var count, count1, count2: integer;
  113. begin
  114. result := 0;
  115. Count1 := Length(S1);
  116. Count2 := Length(S2);
  117. if Count1>Count2 then
  118. Count:=Count2
  119. else
  120. Count:=Count1;
  121. result := CompareMemRange(Pointer(S1),Pointer(S2), Count);
  122. if result=0 then
  123. result:=Count1-Count2;
  124. end;
  125. { CompareMemRange returns the result of comparison of Length bytes at P1 and P2
  126. case result
  127. P1 < P2 < 0
  128. P1 > P2 > 0
  129. P1 = P2 = 0 }
  130. function CompareMemRange(P1, P2: Pointer; Length: PtrUInt): integer;{$ifdef SYSUTILSINLINE}inline;{$endif}
  131. begin
  132. Result:=CompareByte(P1^,P2^,Length);
  133. end;
  134. function CompareMem(P1, P2: Pointer; Length: PtrUInt): Boolean;{$ifdef SYSUTILSINLINE}inline;{$endif}
  135. begin
  136. Result:=CompareByte(P1^,P2^,Length)=0;
  137. end;
  138. { CompareText compares S1 and S2, the result is the based on
  139. substraction of the ascii values of characters in S1 and S2
  140. comparison is case-insensitive
  141. case result
  142. S1 < S2 < 0
  143. S1 > S2 > 0
  144. S1 = S2 = 0 }
  145. function CompareText(const S1, S2: string): integer;
  146. var
  147. i, count, count1, count2: integer; Chr1, Chr2: byte;
  148. P1, P2: PChar;
  149. begin
  150. Count1 := Length(S1);
  151. Count2 := Length(S2);
  152. if (Count1>Count2) then
  153. Count := Count2
  154. else
  155. Count := Count1;
  156. i := 0;
  157. if count>0 then
  158. begin
  159. P1 := @S1[1];
  160. P2 := @S2[1];
  161. while i < Count do
  162. begin
  163. Chr1 := byte(p1^);
  164. Chr2 := byte(p2^);
  165. if Chr1 <> Chr2 then
  166. begin
  167. if Chr1 in [97..122] then
  168. dec(Chr1,32);
  169. if Chr2 in [97..122] then
  170. dec(Chr2,32);
  171. if Chr1 <> Chr2 then
  172. Break;
  173. end;
  174. Inc(P1); Inc(P2); Inc(I);
  175. end;
  176. end;
  177. if i < Count then
  178. result := Chr1-Chr2
  179. else
  180. result := count1-count2;
  181. end;
  182. function SameText(const s1,s2:String):Boolean;
  183. begin
  184. Result:=CompareText(S1,S2)=0;
  185. end;
  186. {$ifndef FPC_NOGENERICANSIROUTINES}
  187. {==============================================================================}
  188. { Ansi string functions }
  189. { these functions rely on the character set loaded by the OS }
  190. {==============================================================================}
  191. type
  192. TCaseTranslationTable = array[0..255] of char;
  193. var
  194. { Tables with upper and lowercase forms of character sets.
  195. MUST be initialized with the correct code-pages }
  196. UpperCaseTable: TCaseTranslationTable;
  197. LowerCaseTable: TCaseTranslationTable;
  198. function GenericAnsiUpperCase(const s: string): string;
  199. var
  200. len, i: integer;
  201. begin
  202. len := length(s);
  203. SetLength(result, len);
  204. for i := 1 to len do
  205. result[i] := UpperCaseTable[ord(s[i])];
  206. end;
  207. function GenericAnsiLowerCase(const s: string): string;
  208. var
  209. len, i: integer;
  210. begin
  211. len := length(s);
  212. SetLength(result, len);
  213. for i := 1 to len do
  214. result[i] := LowerCaseTable[ord(s[i])];
  215. end;
  216. function GenericAnsiCompareStr(const S1, S2: string): PtrInt;
  217. Var
  218. I,L1,L2 : SizeInt;
  219. begin
  220. Result:=0;
  221. L1:=Length(S1);
  222. L2:=Length(S2);
  223. I:=1;
  224. While (Result=0) and ((I<=L1) and (I<=L2)) do
  225. begin
  226. Result:=Ord(S1[I])-Ord(S2[I]); //!! Must be replaced by ansi characters !!
  227. Inc(I);
  228. end;
  229. If Result=0 Then
  230. Result:=L1-L2;
  231. end;
  232. function GenericAnsiCompareText(const S1, S2: string): PtrInt;
  233. Var
  234. I,L1,L2 : SizeInt;
  235. begin
  236. Result:=0;
  237. L1:=Length(S1);
  238. L2:=Length(S2);
  239. I:=1;
  240. While (Result=0) and ((I<=L1) and (I<=L2)) do
  241. begin
  242. Result:=Ord(LowerCaseTable[Ord(S1[I])])-Ord(LowerCaseTable[Ord(S2[I])]); //!! Must be replaced by ansi characters !!
  243. Inc(I);
  244. end;
  245. If Result=0 Then
  246. Result:=L1-L2;
  247. end;
  248. function GenericAnsiStrComp(S1, S2: PChar): PtrInt;
  249. begin
  250. Result:=0;
  251. If S1=Nil then
  252. begin
  253. If S2=Nil Then Exit;
  254. result:=-1;
  255. exit;
  256. end;
  257. If S2=Nil then
  258. begin
  259. Result:=1;
  260. exit;
  261. end;
  262. While (Result=0) and (S1^<>#0) and (S2^<>#0) do begin
  263. Result:=Ord(S1^)-Ord(S2^); //!! Must be replaced by ansi characters !!
  264. Inc(S1);
  265. Inc(S2);
  266. end;
  267. if (Result=0) and (S1^<>S2^) then // loop ended because exactly one has #0
  268. if S1^=#0 then // shorter string is smaller
  269. result:=-1
  270. else
  271. result:=1;
  272. end;
  273. function GenericAnsiStrIComp(S1, S2: PChar): PtrInt;
  274. begin
  275. Result:=0;
  276. If S1=Nil then
  277. begin
  278. If S2=Nil Then Exit;
  279. result:=-1;
  280. exit;
  281. end;
  282. If S2=Nil then
  283. begin
  284. Result:=1;
  285. exit;
  286. end;
  287. While (Result=0) and (S1^<>#0) and (S2^<>#0) do begin
  288. Result:=Ord(LowerCaseTable[Ord(S1[0])])-Ord(LowerCaseTable[Ord(S2[0])]); //!! Must be replaced by ansi characters !!
  289. Inc(S1);
  290. Inc(S2);
  291. end;
  292. if (Result=0) and (s1[0]<>s2[0]) then //length(s1)<>length(s2)
  293. if s1[0]=#0 then
  294. Result:=-1 //s1 shorter than s2
  295. else
  296. Result:=1; //s1 longer than s2
  297. end;
  298. function GenericAnsiStrLComp(S1, S2: PChar; MaxLen: PtrUInt): PtrInt;
  299. Var I : cardinal;
  300. begin
  301. Result:=0;
  302. If MaxLen=0 then exit;
  303. If S1=Nil then
  304. begin
  305. If S2=Nil Then Exit;
  306. result:=-1;
  307. exit;
  308. end;
  309. If S2=Nil then
  310. begin
  311. Result:=1;
  312. exit;
  313. end;
  314. I:=0;
  315. Repeat
  316. Result:=Ord(S1[0])-Ord(S2[0]); //!! Must be replaced by ansi characters !!
  317. Inc(S1);
  318. Inc(S2);
  319. Inc(I);
  320. Until (Result<>0) or (I=MaxLen)
  321. end;
  322. function GenericAnsiStrLIComp(S1, S2: PChar; MaxLen: PtrUInt): PtrInt;
  323. Var I : cardinal;
  324. begin
  325. Result:=0;
  326. If MaxLen=0 then exit;
  327. If S1=Nil then
  328. begin
  329. If S2=Nil Then Exit;
  330. result:=-1;
  331. exit;
  332. end;
  333. If S2=Nil then
  334. begin
  335. Result:=1;
  336. exit;
  337. end;
  338. I:=0;
  339. Repeat
  340. Result:=Ord(LowerCaseTable[Ord(S1[0])])-Ord(LowerCaseTable[Ord(S2[0])]); //!! Must be replaced by ansi characters !!
  341. Inc(S1);
  342. Inc(S2);
  343. Inc(I);
  344. Until (Result<>0) or (I=MaxLen)
  345. end;
  346. function GenericAnsiStrLower(Str: PChar): PChar;
  347. begin
  348. result := Str;
  349. if Str <> Nil then begin
  350. while Str^ <> #0 do begin
  351. Str^ := LowerCaseTable[byte(Str^)];
  352. Str := Str + 1;
  353. end;
  354. end;
  355. end;
  356. function GenericAnsiStrUpper(Str: PChar): PChar;
  357. begin
  358. result := Str;
  359. if Str <> Nil then begin
  360. while Str^ <> #0 do begin
  361. Str^ := UpperCaseTable[byte(Str^)];
  362. Str := Str + 1;
  363. end ;
  364. end ;
  365. end ;
  366. {$endif FPC_NOGENERICANSIROUTINES}
  367. function AnsiSameText(const s1,s2:String):Boolean;{$ifdef SYSUTILSINLINE}inline;{$endif}
  368. begin
  369. AnsiSameText:=AnsiCompareText(S1,S2)=0;
  370. end;
  371. function AnsiSameStr(const s1,s2:String):Boolean;{$ifdef SYSUTILSINLINE}inline;{$endif}
  372. begin
  373. AnsiSameStr:=AnsiCompareStr(S1,S2)=0;
  374. end;
  375. function AnsiLastChar(const S: string): PChar;
  376. begin
  377. //!! No multibyte yet, so we return the last one.
  378. result:=StrEnd(Pchar(pointer(S))); // strend checks for nil
  379. Dec(Result);
  380. end ;
  381. function AnsiStrLastChar(Str: PChar): PChar;
  382. begin
  383. //!! No multibyte yet, so we return the last one.
  384. result:=StrEnd(Str);
  385. Dec(Result);
  386. end ;
  387. function AnsiUpperCase(const s: string): string;{$ifdef SYSUTILSINLINE}inline;{$endif}
  388. begin
  389. result:=widestringmanager.UpperAnsiStringProc(s);
  390. end;
  391. function AnsiLowerCase(const s: string): string;{$ifdef SYSUTILSINLINE}inline;{$endif}
  392. begin
  393. result:=widestringmanager.LowerAnsiStringProc(s);
  394. end;
  395. function AnsiCompareStr(const S1, S2: string): integer;{$ifdef SYSUTILSINLINE}inline;{$endif}
  396. begin
  397. result:=widestringmanager.CompareStrAnsiStringProc(s1,s2);
  398. end;
  399. function AnsiCompareText(const S1, S2: string): integer;{$ifdef SYSUTILSINLINE}inline;{$endif}
  400. begin
  401. result:=widestringmanager.CompareTextAnsiStringProc(s1,s2);
  402. end;
  403. function AnsiStrComp(S1, S2: PChar): integer;{$ifdef SYSUTILSINLINE}inline;{$endif}
  404. begin
  405. result:=widestringmanager.StrCompAnsiStringProc(s1,s2);
  406. end;
  407. function AnsiStrIComp(S1, S2: PChar): integer;{$ifdef SYSUTILSINLINE}inline;{$endif}
  408. begin
  409. result:=widestringmanager.StrICompAnsiStringProc(s1,s2);
  410. end;
  411. function AnsiStrLComp(S1, S2: PChar; MaxLen: cardinal): integer;{$ifdef SYSUTILSINLINE}inline;{$endif}
  412. begin
  413. result:=widestringmanager.StrLCompAnsiStringProc(s1,s2,maxlen);
  414. end;
  415. function AnsiStrLIComp(S1, S2: PChar; MaxLen: cardinal): integer;{$ifdef SYSUTILSINLINE}inline;{$endif}
  416. begin
  417. result:=widestringmanager.StrLICompAnsiStringProc(s1,s2,maxlen);
  418. end;
  419. function AnsiStrLower(Str: PChar): PChar;{$ifdef SYSUTILSINLINE}inline;{$endif}
  420. begin
  421. result:=widestringmanager.StrLowerAnsiStringProc(Str);
  422. end;
  423. function AnsiStrUpper(Str: PChar): PChar;{$ifdef SYSUTILSINLINE}inline;{$endif}
  424. begin
  425. result:=widestringmanager.StrUpperAnsiStringProc(Str);
  426. end;
  427. {==============================================================================}
  428. { End of Ansi functions }
  429. {==============================================================================}
  430. { Trim returns a copy of S with blanks characters on the left and right stripped off }
  431. Const WhiteSpace = [#0..' '];
  432. function Trim(const S: string): string;
  433. var Ofs, Len: integer;
  434. begin
  435. len := Length(S);
  436. while (Len>0) and (S[Len] in WhiteSpace) do
  437. dec(Len);
  438. Ofs := 1;
  439. while (Ofs<=Len) and (S[Ofs] in WhiteSpace) do
  440. Inc(Ofs);
  441. result := Copy(S, Ofs, 1 + Len - Ofs);
  442. end ;
  443. { TrimLeft returns a copy of S with all blank characters on the left stripped off }
  444. function TrimLeft(const S: string): string;
  445. var i,l:integer;
  446. begin
  447. l := length(s);
  448. i := 1;
  449. while (i<=l) and (s[i] in whitespace) do
  450. inc(i);
  451. Result := copy(s, i, l);
  452. end ;
  453. { TrimRight returns a copy of S with all blank characters on the right stripped off }
  454. function TrimRight(const S: string): string;
  455. var l:integer;
  456. begin
  457. l := length(s);
  458. while (l>0) and (s[l] in whitespace) do
  459. dec(l);
  460. result := copy(s,1,l);
  461. end ;
  462. { QuotedStr returns S quoted left and right and every single quote in S
  463. replaced by two quotes }
  464. function QuotedStr(const S: string): string;
  465. begin
  466. result := AnsiQuotedStr(s, '''');
  467. end ;
  468. { AnsiQuotedStr returns S quoted left and right by Quote,
  469. and every single occurance of Quote replaced by two }
  470. function AnsiQuotedStr(const S: string; Quote: char): string;
  471. var i, j, count: integer;
  472. begin
  473. result := '' + Quote;
  474. count := length(s);
  475. i := 0;
  476. j := 0;
  477. while i < count do begin
  478. i := i + 1;
  479. if S[i] = Quote then begin
  480. result := result + copy(S, 1 + j, i - j) + Quote;
  481. j := i;
  482. end ;
  483. end ;
  484. if i <> j then
  485. result := result + copy(S, 1 + j, i - j);
  486. result := result + Quote;
  487. end ;
  488. { AnsiExtractQuotedStr returns a copy of Src with quote characters
  489. deleted to the left and right and double occurances
  490. of Quote replaced by a single Quote }
  491. function AnsiExtractQuotedStr(var Src: PChar; Quote: Char): string;
  492. var
  493. P,Q,R: PChar;
  494. begin
  495. P := Src;
  496. Q := StrEnd(P);
  497. result:='';
  498. if P=Q then exit;
  499. if P^<>quote then exit;
  500. inc(p);
  501. setlength(result,(Q-P)+1);
  502. R:=@Result[1];
  503. while P <> Q do
  504. begin
  505. R^:=P^;
  506. inc(R);
  507. if (P^ = Quote) then
  508. begin
  509. P := P + 1;
  510. if (p^ <> Quote) then
  511. begin
  512. dec(R);
  513. break;
  514. end;
  515. end;
  516. P := P + 1;
  517. end ;
  518. src:=p;
  519. SetLength(result, (R-pchar(@Result[1])));
  520. end ;
  521. { AdjustLineBreaks returns S with all CR characters not followed by LF
  522. replaced with CR/LF }
  523. // under Linux all CR characters or CR/LF combinations should be replaced with LF
  524. function AdjustLineBreaks(const S: string): string;
  525. begin
  526. Result:=AdjustLineBreaks(S,DefaultTextLineBreakStyle);
  527. end;
  528. function AdjustLineBreaks(const S: string; Style: TTextLineBreakStyle): string;
  529. var
  530. Source,Dest: PChar;
  531. DestLen: Integer;
  532. I,J,L: Longint;
  533. begin
  534. Source:=Pointer(S);
  535. L:=Length(S);
  536. DestLen:=L;
  537. I:=1;
  538. while (I<=L) do
  539. begin
  540. case S[i] of
  541. #10: if (Style=tlbsCRLF) then
  542. Inc(DestLen);
  543. #13: if (Style=tlbsCRLF) then
  544. if (I<L) and (S[i+1]=#10) then
  545. Inc(I)
  546. else
  547. Inc(DestLen)
  548. else if (I<L) and (S[I+1]=#10) then
  549. Dec(DestLen);
  550. end;
  551. Inc(I);
  552. end;
  553. if (DestLen=L) then
  554. Result:=S
  555. else
  556. begin
  557. SetLength(Result, DestLen);
  558. FillChar(Result[1],DestLen,0);
  559. Dest := Pointer(Result);
  560. J:=0;
  561. I:=0;
  562. While I<L do
  563. case Source[I] of
  564. #10: begin
  565. if Style=tlbsCRLF then
  566. begin
  567. Dest[j]:=#13;
  568. Inc(J);
  569. end;
  570. Dest[J] := #10;
  571. Inc(J);
  572. Inc(I);
  573. end;
  574. #13: begin
  575. if Style=tlbsCRLF then
  576. begin
  577. Dest[j] := #13;
  578. Inc(J);
  579. end;
  580. Dest[j]:=#10;
  581. Inc(J);
  582. Inc(I);
  583. if Source[I]=#10 then
  584. Inc(I);
  585. end;
  586. else
  587. Dest[j]:=Source[i];
  588. Inc(J);
  589. Inc(I);
  590. end;
  591. end;
  592. end;
  593. { IsValidIdent returns true if the first character of Ident is in:
  594. 'A' to 'Z', 'a' to 'z' or '_' and the following characters are
  595. on of: 'A' to 'Z', 'a' to 'z', '0'..'9' or '_' }
  596. function IsValidIdent(const Ident: string): boolean;
  597. var i, len: integer;
  598. begin
  599. result := false;
  600. len := length(Ident);
  601. if len <> 0 then begin
  602. result := Ident[1] in ['A'..'Z', 'a'..'z', '_'];
  603. i := 1;
  604. while (result) and (i < len) do begin
  605. i := i + 1;
  606. result := result and (Ident[i] in ['A'..'Z', 'a'..'z', '0'..'9', '_']);
  607. end ;
  608. end ;
  609. end ;
  610. { IntToStr returns a string representing the value of Value }
  611. function IntToStr(Value: integer): string;
  612. begin
  613. System.Str(Value, result);
  614. end ;
  615. function IntToStr(Value: int64): string;
  616. begin
  617. System.Str(Value, result);
  618. end ;
  619. function IntToStr(Value: QWord): string;
  620. begin
  621. System.Str(Value, result);
  622. end ;
  623. { IntToHex returns a string representing the hexadecimal value of Value }
  624. const
  625. HexDigits: array[0..15] of char = '0123456789ABCDEF';
  626. function IntToHex(Value: integer; Digits: integer): string;
  627. var i: integer;
  628. begin
  629. If Digits=0 then
  630. Digits:=1;
  631. SetLength(result, digits);
  632. for i := 0 to digits - 1 do
  633. begin
  634. result[digits - i] := HexDigits[value and 15];
  635. value := value shr 4;
  636. end ;
  637. while value <> 0 do begin
  638. result := HexDigits[value and 15] + result;
  639. value := value shr 4;
  640. end;
  641. end ;
  642. function IntToHex(Value: int64; Digits: integer): string;
  643. var i: integer;
  644. begin
  645. If Digits=0 then
  646. Digits:=1;
  647. SetLength(result, digits);
  648. for i := 0 to digits - 1 do
  649. begin
  650. result[digits - i] := HexDigits[value and 15];
  651. value := value shr 4;
  652. end ;
  653. while value <> 0 do begin
  654. result := HexDigits[value and 15] + result;
  655. value := value shr 4;
  656. end;
  657. end ;
  658. function IntToHex(Value: QWord; Digits: integer): string;
  659. begin
  660. result:=IntToHex(Int64(Value),Digits);
  661. end;
  662. function TryStrToInt(const s: string; out i : integer) : boolean;
  663. var Error : word;
  664. begin
  665. Val(s, i, Error);
  666. TryStrToInt:=Error=0
  667. end;
  668. { StrToInt converts the string S to an integer value,
  669. if S does not represent a valid integer value EConvertError is raised }
  670. function StrToInt(const S: string): integer;
  671. var Error: word;
  672. begin
  673. Val(S, result, Error);
  674. if Error <> 0 then raise EConvertError.createfmt(SInvalidInteger,[S]);
  675. end ;
  676. function StrToInt64(const S: string): int64;
  677. var Error: word;
  678. begin
  679. Val(S, result, Error);
  680. if Error <> 0 then raise EConvertError.createfmt(SInvalidInteger,[S]);
  681. end;
  682. function TryStrToInt64(const s: string; Out i : int64) : boolean;
  683. var Error : word;
  684. begin
  685. Val(s, i, Error);
  686. TryStrToInt64:=Error=0
  687. end;
  688. function StrToQWord(const s: string): QWord;
  689. var Error: word;
  690. begin
  691. Val(S, result, Error);
  692. if Error <> 0 then raise EConvertError.createfmt(SInvalidInteger,[S]);
  693. end;
  694. function TryStrToQWord(const s: string; Out Q: QWord): boolean;
  695. var Error : word;
  696. begin
  697. Val(s, Q, Error);
  698. TryStrToQWord:=Error=0
  699. end;
  700. { StrToIntDef converts the string S to an integer value,
  701. Default is returned in case S does not represent a valid integer value }
  702. function StrToIntDef(const S: string; Default: integer): integer;
  703. var Error: word;
  704. begin
  705. Val(S, result, Error);
  706. if Error <> 0 then result := Default;
  707. end ;
  708. { StrToInt64Def converts the string S to an int64 value,
  709. Default is returned in case S does not represent a valid int64 value }
  710. function StrToInt64Def(const S: string; Default: int64): int64;
  711. var Error: word;
  712. begin
  713. Val(S, result, Error);
  714. if Error <> 0 then result := Default;
  715. end ;
  716. { StrToQWordDef converts the string S to an QWord value,
  717. Default is returned in case S does not represent a valid QWord value }
  718. function StrToQWordDef(const S: string; Default: QWord): QWord;
  719. var Error: word;
  720. begin
  721. Val(S, result, Error);
  722. if Error <> 0 then result := Default;
  723. end;
  724. { LoadStr returns the string resource Ident. }
  725. function LoadStr(Ident: integer): string;
  726. begin
  727. result:='';
  728. end ;
  729. { FmtLoadStr returns the string resource Ident and formats it accordingly }
  730. function FmtLoadStr(Ident: integer; const Args: array of const): string;
  731. begin
  732. result:='';
  733. end;
  734. Const
  735. feInvalidFormat = 1;
  736. feMissingArgument = 2;
  737. feInvalidArgIndex = 3;
  738. {$ifdef fmtdebug}
  739. Procedure Log (Const S: String);
  740. begin
  741. Writeln (S);
  742. end;
  743. {$endif}
  744. Procedure DoFormatError (ErrCode : Longint;const fmt:ansistring);
  745. Var
  746. S : String;
  747. begin
  748. //!! must be changed to contain format string...
  749. S:=fmt;
  750. Case ErrCode of
  751. feInvalidFormat : raise EConvertError.Createfmt(SInvalidFormat,[s]);
  752. feMissingArgument : raise EConvertError.Createfmt(SArgumentMissing,[s]);
  753. feInvalidArgIndex : raise EConvertError.Createfmt(SInvalidArgIndex,[s]);
  754. end;
  755. end;
  756. { we've no templates, but with includes we can simulate this :) }
  757. {$macro on}
  758. {$define INFORMAT}
  759. {$define TFormatString:=ansistring}
  760. {$define TFormatChar:=char}
  761. Function Format (Const Fmt : AnsiString; const Args : Array of const; const FormatSettings: TFormatSettings) : AnsiString;
  762. {$i sysformt.inc}
  763. {$undef TFormatString}
  764. {$undef TFormatChar}
  765. {$undef INFORMAT}
  766. {$macro off}
  767. Function Format (Const Fmt : AnsiString; const Args : Array of const) : AnsiString;
  768. begin
  769. Result:=Format(Fmt,Args,DefaultFormatSettings);
  770. end;
  771. Function FormatBuf (Var Buffer; BufLen : Cardinal; Const Fmt; fmtLen : Cardinal; Const Args : Array of const; Const FormatSettings: TFormatSettings) : Cardinal;
  772. Var S,F : String;
  773. begin
  774. Setlength(F,fmtlen);
  775. if fmtlen > 0 then
  776. Move(fmt,F[1],fmtlen);
  777. S:=Format (F,Args,FormatSettings);
  778. If Cardinal(Length(S))<Buflen then
  779. Result:=Length(S)
  780. else
  781. Result:=Buflen;
  782. Move(S[1],Buffer,Result);
  783. end;
  784. Function FormatBuf (Var Buffer; BufLen : Cardinal;
  785. Const Fmt; fmtLen : Cardinal;
  786. Const Args : Array of const) : Cardinal;
  787. begin
  788. Result:=FormatBuf(Buffer,BufLen,Fmt,FmtLen,Args,DefaultFormatSettings);
  789. end;
  790. Procedure FmtStr(Var Res: string; const Fmt : string; Const args: Array of const; Const FormatSettings: TFormatSettings);
  791. begin
  792. Res:=Format(fmt,Args,FormatSettings);
  793. end;
  794. Procedure FmtStr(Var Res: String; Const Fmt : String; Const args: Array of const);
  795. begin
  796. FmtStr(Res,Fmt,Args,DefaultFormatSettings);
  797. end;
  798. Function StrFmt(Buffer,Fmt : PChar; Const args: Array of const) : Pchar;
  799. begin
  800. Result:=StrFmt(Buffer,Fmt,Args,DefaultFormatSettings);
  801. end;
  802. Function StrFmt(Buffer,Fmt : PChar; Const Args: Array of const; Const FormatSettings: TFormatSettings): PChar;
  803. begin
  804. Buffer[FormatBuf(Buffer^,Maxint,Fmt^,strlen(fmt),args,FormatSettings)]:=#0;
  805. Result:=Buffer;
  806. end;
  807. Function StrLFmt(Buffer : PCHar; Maxlen : Cardinal;Fmt : PChar; Const args: Array of const) : Pchar;
  808. begin
  809. Result:=StrLFmt(Buffer,MaxLen,Fmt,Args,DefaultFormatSettings);
  810. end;
  811. Function StrLFmt(Buffer : PCHar; Maxlen : Cardinal;Fmt : PChar; Const args: Array of const; Const FormatSettings: TFormatSettings) : Pchar;
  812. begin
  813. Buffer[FormatBuf(Buffer^,MaxLen,Fmt^,strlen(fmt),args,FormatSettings)]:=#0;
  814. Result:=Buffer;
  815. end;
  816. {$ifndef FPUNONE}
  817. Function StrToFloat(Const S: String): Extended;
  818. begin
  819. Result:=StrToFloat(S,DefaultFormatSettings);
  820. end;
  821. Function StrToFloat(Const S : String; Const FormatSettings: TFormatSettings) : Extended;
  822. Begin // texttofloat handles NIL properly
  823. If Not TextToFloat(Pchar(pointer(S)),Result,FormatSettings) then
  824. Raise EConvertError.createfmt(SInValidFLoat,[S]);
  825. End;
  826. function StrToFloatDef(const S: string; const Default: Extended): Extended;
  827. begin
  828. Result:=StrToFloatDef(S,Default,DefaultFormatSettings);
  829. end;
  830. Function StrToFloatDef(Const S: String; Const Default: Extended; Const FormatSettings: TFormatSettings): Extended;
  831. begin
  832. if not TextToFloat(PChar(pointer(S)),Result,fvExtended,FormatSettings) then
  833. Result:=Default;
  834. end;
  835. Function TextToFloat(Buffer: PChar; Out Value: Extended; Const FormatSettings: TFormatSettings): Boolean;
  836. Var
  837. E,P : Integer;
  838. S : String;
  839. Begin
  840. S:=StrPas(Buffer);
  841. //ThousandSeparator not allowed as by Delphi specs
  842. if (FormatSettings.ThousandSeparator <> FormatSettings.DecimalSeparator) and
  843. (Pos(FormatSettings.ThousandSeparator, S) <> 0) then
  844. begin
  845. Result := False;
  846. Exit;
  847. end;
  848. if (FormatSettings.DecimalSeparator <> '.') and
  849. (Pos('.', S) <>0) then
  850. begin
  851. Result := False;
  852. Exit;
  853. end;
  854. P:=Pos(FormatSettings.DecimalSeparator,S);
  855. If (P<>0) Then
  856. S[P] := '.';
  857. Val(trim(S),Value,E);
  858. Result:=(E=0);
  859. End;
  860. Function TextToFloat(Buffer: PChar; Out Value: Extended): Boolean;
  861. begin
  862. Result:=TextToFloat(Buffer,Value,DefaultFormatSettings);
  863. end;
  864. Function TextToFloat(Buffer: PChar; Out Value; ValueType: TFloatValue): Boolean;
  865. begin
  866. Result:=TextToFloat(Buffer,Value,ValueType,DefaultFormatSettings);
  867. end;
  868. Function TextToFloat(Buffer: PChar; Out Value; ValueType: TFloatValue; Const FormatSettings: TFormatSettings): Boolean;
  869. Var
  870. E,P : Integer;
  871. S : String;
  872. {$ifndef FPC_HAS_STR_CURRENCY}
  873. TempValue: extended;
  874. {$endif FPC_HAS_STR_CURRENCY}
  875. Begin
  876. S:=StrPas(Buffer);
  877. //ThousandSeparator not allowed as by Delphi specs
  878. if (FormatSettings.ThousandSeparator <> FormatSettings.DecimalSeparator) and
  879. (Pos(FormatSettings.ThousandSeparator, S) <> 0) then
  880. begin
  881. Result := False;
  882. Exit;
  883. end;
  884. if (FormatSettings.DecimalSeparator <> '.') and
  885. (Pos('.', S) <>0) then
  886. begin
  887. Result := False;
  888. Exit;
  889. end;
  890. P:=Pos(FormatSettings.DecimalSeparator,S);
  891. If (P<>0) Then
  892. S[P] := '.';
  893. case ValueType of
  894. fvCurrency:
  895. {$ifdef FPC_HAS_STR_CURRENCY}
  896. Val(S,Currency(Value),E);
  897. {$else FPC_HAS_STR_CURRENCY}
  898. begin
  899. // needed for platforms where Currency = Int64
  900. Val(S,TempValue,E);
  901. Currency(Value) := TempValue;
  902. end;
  903. {$endif FPC_HAS_STR_CURRENCY}
  904. fvExtended:
  905. Val(S,Extended(Value),E);
  906. fvDouble:
  907. Val(S,Double(Value),E);
  908. fvSingle:
  909. Val(S,Single(Value),E);
  910. fvComp:
  911. Val(S,Comp(Value),E);
  912. fvReal:
  913. Val(S,Real(Value),E);
  914. end;
  915. Result:=(E=0);
  916. End;
  917. Function TryStrToFloat(Const S : String; Out Value: Single): Boolean;
  918. begin
  919. Result:=TryStrToFloat(S,Value,DefaultFormatSettings);
  920. end;
  921. Function TryStrToFloat(Const S : String; Out Value: Single; Const FormatSettings: TFormatSettings): Boolean;
  922. Begin
  923. Result := TextToFloat(PChar(pointer(S)), Value, fvSingle,FormatSettings);
  924. End;
  925. Function TryStrToFloat(Const S : String; Out Value: Double): Boolean;
  926. begin
  927. Result:=TryStrToFloat(S,Value,DefaultFormatSettings);
  928. end;
  929. Function TryStrToFloat(Const S : String; Out Value: Double; Const FormatSettings: TFormatSettings): Boolean;
  930. Begin
  931. Result := TextToFloat(PChar(pointer(S)), Value, fvDouble,FormatSettings);
  932. End;
  933. {$ifdef FPC_HAS_TYPE_EXTENDED}
  934. Function TryStrToFloat(Const S : String; Out Value: Extended): Boolean;
  935. begin
  936. Result:=TryStrToFloat(S,Value,DefaultFormatSettings);
  937. end;
  938. Function TryStrToFloat(Const S : String; Out Value: Extended; Const FormatSettings: TFormatSettings): Boolean;
  939. Begin
  940. Result := TextToFloat(PChar(pointer(S)), Value,FormatSettings);
  941. End;
  942. {$endif FPC_HAS_TYPE_EXTENDED}
  943. const
  944. {$ifdef FPC_HAS_TYPE_EXTENDED}
  945. maxdigits = 17;
  946. {$else}
  947. maxdigits = 15;
  948. {$endif}
  949. Function FloatToStrFIntl(const Value; format: TFloatFormat; Precision, Digits: Integer; ValueType: TFloatValue; Const FormatSettings: TFormatSettings): String;
  950. Var
  951. P, PE, Q, Exponent: Integer;
  952. Negative: Boolean;
  953. DS: Char;
  954. function RemoveLeadingNegativeSign(var AValue: String): Boolean;
  955. // removes negative sign in case when result is zero eg. -0.00
  956. var
  957. i: PtrInt;
  958. TS: Char;
  959. StartPos: PtrInt;
  960. begin
  961. Result := False;
  962. if Format = ffCurrency then
  963. StartPos := 1
  964. else
  965. StartPos := 2;
  966. TS := FormatSettings.ThousandSeparator;
  967. for i := StartPos to length(AValue) do
  968. begin
  969. Result := (AValue[i] in ['0', DS, 'E', '+', TS]);
  970. if not Result then
  971. break;
  972. end;
  973. if (Result) and (Format <> ffCurrency) then
  974. Delete(AValue, 1, 1);
  975. end;
  976. Begin
  977. DS:=FormatSettings.DecimalSeparator;
  978. Case format Of
  979. ffGeneral:
  980. Begin
  981. case ValueType of
  982. fvCurrency:
  983. If (Precision = -1) Or (Precision > 19) Then Precision := 19;
  984. else
  985. If (Precision = -1) Or (Precision > maxdigits) Then Precision := maxdigits;
  986. end;
  987. { First convert to scientific format, with correct precision }
  988. case ValueType of
  989. fvDouble:
  990. Str(Double(Extended(Value)):precision+7, Result);
  991. fvSingle:
  992. Str(Single(Extended(Value)):precision+6, Result);
  993. fvCurrency:
  994. {$ifdef FPC_HAS_STR_CURRENCY}
  995. Str(Currency(Value):precision+6, Result);
  996. {$else}
  997. Str(Extended(Currency(Value)):precision+8, Result);
  998. {$endif FPC_HAS_STR_CURRENCY}
  999. else
  1000. Str(Extended(Value):precision+8, Result);
  1001. end;
  1002. { Delete leading spaces }
  1003. while Result[1] = ' ' do
  1004. System.Delete(Result, 1, 1);
  1005. P := Pos('.', Result);
  1006. if P<>0 then
  1007. Result[P] := DS
  1008. else
  1009. Exit; { NAN or other special case }
  1010. { Consider removing exponent }
  1011. PE:=Pos('E',Result);
  1012. if PE > 0 then begin
  1013. { Read exponent }
  1014. Q := PE+2;
  1015. Exponent := 0;
  1016. while (Q <= Length(Result)) do begin
  1017. Exponent := Exponent*10 + Ord(Result[Q])-Ord('0');
  1018. Inc(Q);
  1019. end;
  1020. if Result[PE+1] = '-' then
  1021. Exponent := -Exponent;
  1022. if (P+Exponent < PE) and (Exponent > -6) then begin
  1023. { OK to remove exponent }
  1024. SetLength(Result,PE-1); { Trim exponent }
  1025. if Exponent >= 0 then begin
  1026. { Shift point to right }
  1027. for Q := 0 to Exponent-1 do begin
  1028. Result[P] := Result[P+1];
  1029. Inc(P);
  1030. end;
  1031. Result[P] := DS;
  1032. P := 1;
  1033. if Result[P] = '-' then
  1034. Inc(P);
  1035. while (Result[P] = '0') and (P < Length(Result)) and (Result[P+1] <> DS) do
  1036. { Trim leading zeros; conversion above should not give any, but occasionally does
  1037. because of rounding }
  1038. System.Delete(Result,P,1);
  1039. end else begin
  1040. { Add zeros at start }
  1041. Insert(Copy('00000',1,-Exponent),Result,P-1);
  1042. Result[P-Exponent] := Result[P-Exponent-1]; { Copy leading digit }
  1043. Result[P] := DS;
  1044. if Exponent <> -1 then
  1045. Result[P-Exponent-1] := '0';
  1046. end;
  1047. { Remove trailing zeros }
  1048. Q := Length(Result);
  1049. while (Q > 0) and (Result[Q] = '0') do
  1050. Dec(Q);
  1051. if Result[Q] = DS then
  1052. Dec(Q); { Remove trailing decimal point }
  1053. if (Q = 0) or ((Q=1) and (Result[1] = '-')) then
  1054. Result := '0'
  1055. else
  1056. SetLength(Result,Q);
  1057. end else begin
  1058. { Need exponent, but remove superfluous characters }
  1059. { Delete trailing zeros }
  1060. while Result[PE-1] = '0' do begin
  1061. System.Delete(Result,PE-1,1);
  1062. Dec(PE);
  1063. end;
  1064. { If number ends in decimal point, remove it }
  1065. if Result[PE-1] = DS then begin
  1066. System.Delete(Result,PE-1,1);
  1067. Dec(PE);
  1068. end;
  1069. { delete superfluous + in exponent }
  1070. if Result[PE+1]='+' then
  1071. System.Delete(Result,PE+1,1)
  1072. else
  1073. Inc(PE);
  1074. while Result[PE+1] = '0' do
  1075. { Delete leading zeros in exponent }
  1076. System.Delete(Result,PE+1,1)
  1077. end;
  1078. end;
  1079. End;
  1080. ffExponent:
  1081. Begin
  1082. If (Precision = -1) Or (Precision > maxdigits) Then Precision := maxdigits;
  1083. case ValueType of
  1084. fvDouble:
  1085. Str(Double(Extended(Value)):Precision+7, Result);
  1086. fvSingle:
  1087. Str(Single(Extended(Value)):Precision+6, Result);
  1088. fvCurrency:
  1089. {$ifdef FPC_HAS_STR_CURRENCY}
  1090. Str(Currency(Value):Precision+6, Result);
  1091. {$else}
  1092. Str(Extended(Currency(Value)):Precision+8, Result);
  1093. {$endif FPC_HAS_STR_CURRENCY}
  1094. else
  1095. Str(Extended(Value):Precision+8, Result);
  1096. end;
  1097. { Delete leading spaces }
  1098. while Result[1] = ' ' do
  1099. System.Delete(Result, 1, 1);
  1100. if Result[1] = '-' then
  1101. Result[3] := DS
  1102. else
  1103. Result[2] := DS;
  1104. P:=Pos('E',Result);
  1105. if P <> 0 then
  1106. begin
  1107. Inc(P, 2);
  1108. if Digits > 4 then
  1109. Digits:=4;
  1110. Digits:=Length(Result) - P - Digits + 1;
  1111. if Digits < 0 then
  1112. insert(copy('0000',1,-Digits),Result,P)
  1113. else
  1114. while (Digits > 0) and (Result[P] = '0') do
  1115. begin
  1116. System.Delete(Result, P, 1);
  1117. if P > Length(Result) then
  1118. begin
  1119. System.Delete(Result, P - 2, 2);
  1120. break;
  1121. end;
  1122. Dec(Digits);
  1123. end;
  1124. end;
  1125. End;
  1126. ffFixed:
  1127. Begin
  1128. If Digits = -1 Then Digits := 2
  1129. Else If Digits > 18 Then Digits := 18;
  1130. case ValueType of
  1131. fvDouble:
  1132. Str(Double(Extended(Value)):0:Digits, Result);
  1133. fvSingle:
  1134. Str(Single(Extended(Value)):0:Digits, Result);
  1135. fvCurrency:
  1136. {$ifdef FPC_HAS_STR_CURRENCY}
  1137. Str(Currency(Value):0:Digits, Result);
  1138. {$else}
  1139. Str(Extended(Currency(Value)):0:Digits, Result);
  1140. {$endif FPC_HAS_STR_CURRENCY}
  1141. else
  1142. Str(Extended(Value):0:Digits, Result);
  1143. end;
  1144. If Result[1] = ' ' Then
  1145. System.Delete(Result, 1, 1);
  1146. P := Pos('.', Result);
  1147. If P <> 0 Then Result[P] := DS;
  1148. End;
  1149. ffNumber:
  1150. Begin
  1151. If Digits = -1 Then Digits := 2
  1152. Else If Digits > maxdigits Then Digits := maxdigits;
  1153. case ValueType of
  1154. fvDouble:
  1155. Str(Double(Extended(Value)):0:Digits, Result);
  1156. fvSingle:
  1157. Str(Single(Extended(Value)):0:Digits, Result);
  1158. fvCurrency:
  1159. {$ifdef FPC_HAS_STR_CURRENCY}
  1160. Str(Currency(Value):0:Digits, Result);
  1161. {$else}
  1162. Str(Extended(Currency(Value)):0:Digits, Result);
  1163. {$endif FPC_HAS_STR_CURRENCY}
  1164. else
  1165. Str(Extended(Value):0:Digits, Result);
  1166. end;
  1167. If Result[1] = ' ' Then System.Delete(Result, 1, 1);
  1168. P := Pos('.', Result);
  1169. If P <> 0 Then
  1170. Result[P] := DS
  1171. else
  1172. P := Length(Result)+1;
  1173. Dec(P, 3);
  1174. While (P > 1) Do
  1175. Begin
  1176. If (Result[P - 1] <> '-') And (FormatSettings.ThousandSeparator <> #0) Then
  1177. Insert(FormatSettings.ThousandSeparator, Result, P);
  1178. Dec(P, 3);
  1179. End;
  1180. End;
  1181. ffCurrency:
  1182. Begin
  1183. If Digits = -1 Then Digits := FormatSettings.CurrencyDecimals
  1184. Else If Digits > 18 Then Digits := 18;
  1185. case ValueType of
  1186. fvDouble:
  1187. Str(Double(Extended(Value)):0:Digits, Result);
  1188. fvSingle:
  1189. Str(Single(Extended(Value)):0:Digits, Result);
  1190. fvCurrency:
  1191. {$ifdef FPC_HAS_STR_CURRENCY}
  1192. Str(Currency(Value):0:Digits, Result);
  1193. {$else}
  1194. Str(Extended(Currency(Value)):0:Digits, Result);
  1195. {$endif FPC_HAS_STR_CURRENCY}
  1196. else
  1197. Str(Extended(Value):0:Digits, Result);
  1198. end;
  1199. Negative:=Result[1] = '-';
  1200. if Negative then
  1201. System.Delete(Result, 1, 1);
  1202. P := Pos('.', Result);
  1203. If P <> 0 Then Result[P] := DS;
  1204. Dec(P, 3);
  1205. While (P > 1) Do
  1206. Begin
  1207. If FormatSettings.ThousandSeparator<>#0 Then
  1208. Insert(FormatSettings.ThousandSeparator, Result, P);
  1209. Dec(P, 3);
  1210. End;
  1211. if (length(Result) > 1) and Negative then
  1212. Negative := not RemoveLeadingNegativeSign(Result);
  1213. If Not Negative Then
  1214. Begin
  1215. Case FormatSettings.CurrencyFormat Of
  1216. 0: Result := FormatSettings.CurrencyString + Result;
  1217. 1: Result := Result + FormatSettings.CurrencyString;
  1218. 2: Result := FormatSettings.CurrencyString + ' ' + Result;
  1219. 3: Result := Result + ' ' + FormatSettings.CurrencyString;
  1220. End
  1221. End
  1222. Else
  1223. Begin
  1224. Case FormatSettings.NegCurrFormat Of
  1225. 0: Result := '(' + FormatSettings.CurrencyString + Result + ')';
  1226. 1: Result := '-' + FormatSettings.CurrencyString + Result;
  1227. 2: Result := FormatSettings.CurrencyString + '-' + Result;
  1228. 3: Result := FormatSettings.CurrencyString + Result + '-';
  1229. 4: Result := '(' + Result + FormatSettings.CurrencyString + ')';
  1230. 5: Result := '-' + Result + FormatSettings.CurrencyString;
  1231. 6: Result := Result + '-' + FormatSettings.CurrencyString;
  1232. 7: Result := Result + FormatSettings.CurrencyString + '-';
  1233. 8: Result := '-' + Result + ' ' + FormatSettings.CurrencyString;
  1234. 9: Result := '-' + FormatSettings.CurrencyString + ' ' + Result;
  1235. 10: Result := Result + ' ' + FormatSettings.CurrencyString + '-';
  1236. 11: Result := FormatSettings.CurrencyString + ' ' + Result + '-';
  1237. 12: Result := FormatSettings.CurrencyString + ' ' + '-' + Result;
  1238. 13: Result := Result + '-' + ' ' + FormatSettings.CurrencyString;
  1239. 14: Result := '(' + FormatSettings.CurrencyString + ' ' + Result + ')';
  1240. 15: Result := '(' + Result + ' ' + FormatSettings.CurrencyString + ')';
  1241. End;
  1242. End;
  1243. End;
  1244. End;
  1245. if not (format in [ffCurrency]) and (length(Result) > 1) and (Result[1] = '-') then
  1246. RemoveLeadingNegativeSign(Result);
  1247. End;
  1248. {$ifdef FPC_HAS_TYPE_EXTENDED}
  1249. Function FloatToStr(Value: Extended; Const FormatSettings: TFormatSettings): String;
  1250. Begin
  1251. Result := FloatToStrFIntl(Value, ffGeneral, 15, 0, fvExtended,FormatSettings);
  1252. End;
  1253. Function FloatToStr(Value: Extended): String;
  1254. begin
  1255. Result:=FloatToStr(Value,DefaultFormatSettings);
  1256. end;
  1257. {$endif FPC_HAS_TYPE_EXTENDED}
  1258. Function FloatToStr(Value: Currency; Const FormatSettings: TFormatSettings): String;
  1259. Begin
  1260. Result := FloatToStrFIntl(Value, ffGeneral, 15, 0, fvCurrency,FormatSettings);
  1261. End;
  1262. Function FloatToStr(Value: Currency): String;
  1263. begin
  1264. Result:=FloatToStr(Value,DefaultFormatSettings);
  1265. end;
  1266. Function FloatToStr(Value: Double; Const FormatSettings: TFormatSettings): String;
  1267. var
  1268. e: Extended;
  1269. Begin
  1270. e := Value;
  1271. Result := FloatToStrFIntl(e, ffGeneral, 15, 0, fvDouble,FormatSettings);
  1272. End;
  1273. Function FloatToStr(Value: Double): String;
  1274. begin
  1275. Result:=FloatToStr(Value,DefaultFormatSettings);
  1276. end;
  1277. Function FloatToStr(Value: Single; Const FormatSettings: TFormatSettings): String;
  1278. var
  1279. e: Extended;
  1280. Begin
  1281. e := Value;
  1282. Result := FloatToStrFIntl(e, ffGeneral, 15, 0, fvSingle,FormatSettings);
  1283. End;
  1284. Function FloatToStr(Value: Single): String;
  1285. begin
  1286. Result:=FloatToStr(Value,DefaultFormatSettings);
  1287. end;
  1288. Function FloatToStr(Value: Comp; Const FormatSettings: TFormatSettings): String;
  1289. var
  1290. e: Extended;
  1291. Begin
  1292. e := Value;
  1293. Result := FloatToStrFIntl(e, ffGeneral, 15, 0, fvComp,FormatSettings);
  1294. End;
  1295. Function FloatToStr(Value: Comp): String;
  1296. begin
  1297. Result:=FloatToStr(Value,DefaultFormatSettings);
  1298. end;
  1299. {$ifndef FPC_COMP_IS_INT64}
  1300. Function FloatToStr(Value: Int64): String;
  1301. begin
  1302. Result:=FloatToStr(Value,DefaultFormatSettings);
  1303. end;
  1304. Function FloatToStr(Value: Int64; Const FormatSettings: TFormatSettings): String;
  1305. var
  1306. e: Extended;
  1307. Begin
  1308. e := Comp(Value);
  1309. Result := FloatToStrFIntl(e, ffGeneral, 15, 0, fvComp,FormatSettings);
  1310. End;
  1311. {$endif FPC_COMP_IS_INT64}
  1312. Function FloatToText(Buffer: PChar; Value: Extended; format: TFloatFormat; Precision, Digits: Integer; Const FormatSettings: TFormatSettings): Longint;
  1313. Var
  1314. Tmp: String[40];
  1315. Begin
  1316. Tmp := FloatToStrF(Value, format, Precision, Digits,FormatSettings);
  1317. Result := Length(Tmp);
  1318. Move(Tmp[1], Buffer[0], Result);
  1319. End;
  1320. Function FloatToText(Buffer: PChar; Value: Extended; format: TFloatFormat; Precision, Digits: Integer): Longint;
  1321. begin
  1322. Result:=FloatToText(Buffer,Value,Format,Precision,Digits,DefaultFormatSettings);
  1323. end;
  1324. {$ifdef FPC_HAS_TYPE_EXTENDED}
  1325. Function FloatToStrF(Value: Extended; format: TFloatFormat; Precision, Digits: Integer; Const FormatSettings: TFormatSettings): String;
  1326. begin
  1327. Result := FloatToStrFIntl(value,format,precision,digits,fvExtended,FormatSettings);
  1328. end;
  1329. Function FloatToStrF(Value: Extended; format: TFloatFormat; Precision, Digits: Integer): String;
  1330. begin
  1331. Result:=FloatToStrF(Value,Format,Precision,Digits,DefaultFormatSettings);
  1332. end;
  1333. {$endif}
  1334. Function FloatToStrF(Value: Currency; format: TFloatFormat; Precision, Digits: Integer; Const FormatSettings: TFormatSettings): String;
  1335. begin
  1336. Result := FloatToStrFIntl(value,format,precision,digits,fvCurrency,FormatSettings);
  1337. end;
  1338. Function FloatToStrF(Value: Currency; format: TFloatFormat; Precision, Digits: Integer): String;
  1339. begin
  1340. Result:=FloatToStrF(Value,format,Precision,Digits,DefaultFormatSettings);
  1341. end;
  1342. Function FloatToStrF(Value: Double; format: TFloatFormat; Precision, Digits: Integer; Const FormatSettings: TFormatSettings): String;
  1343. var
  1344. e: Extended;
  1345. begin
  1346. e := Value;
  1347. result := FloatToStrFIntl(e,format,precision,digits,fvDouble,FormatSettings);
  1348. end;
  1349. Function FloatToStrF(Value: Double; format: TFloatFormat; Precision, Digits: Integer): String;
  1350. begin
  1351. Result:= FloatToStrF(Value,Format,Precision,Digits,DefaultFormatSettings);
  1352. end;
  1353. Function FloatToStrF(Value: Single; format: TFloatFormat; Precision, Digits: Integer; Const FormatSettings: TFormatSettings): String;
  1354. var
  1355. e: Extended;
  1356. begin
  1357. e:=Value;
  1358. result := FloatToStrFIntl(e,format,precision,digits,fvSingle,FormatSettings);
  1359. end;
  1360. Function FloatToStrF(Value: Single; format: TFloatFormat; Precision, Digits: Integer): String;
  1361. begin
  1362. Result:= FloatToStrF(Value,Format,Precision,Digits,DefaultFormatSettings);
  1363. end;
  1364. Function FloatToStrF(Value: Comp; format: TFloatFormat; Precision, Digits: Integer; Const FormatSettings: TFormatSettings): String;
  1365. var
  1366. e: Extended;
  1367. begin
  1368. e := Value;
  1369. Result := FloatToStrFIntl(e,format,precision,digits,fvComp,FormatSettings);
  1370. end;
  1371. Function FloatToStrF(Value: Comp; format: TFloatFormat; Precision, Digits: Integer): String;
  1372. begin
  1373. Result:=FloatToStrF(Value,Format,Precision,Digits,DefaultFormatSettings);
  1374. end;
  1375. {$ifndef FPC_COMP_IS_INT64}
  1376. Function FloatToStrF(Value: Int64; format: TFloatFormat; Precision, Digits: Integer; Const FormatSettings: TFormatSettings): String;
  1377. var
  1378. e: Extended;
  1379. begin
  1380. e := Comp(Value);
  1381. result := FloatToStrFIntl(e,format,precision,digits,fvComp,FormatSettings);
  1382. end;
  1383. Function FloatToStrF(Value: Int64; format: TFloatFormat; Precision, Digits: Integer): String;
  1384. begin
  1385. Result:=FloatToStrF(Value,Format,Precision,Digits,DefaultFormatSettings);
  1386. end;
  1387. {$endif FPC_COMP_IS_INT64}
  1388. Function CurrToStrF(Value: Currency; Format: TFloatFormat; Digits: Integer; Const FormatSettings: TFormatSettings): string;
  1389. begin
  1390. result:=FloatToStrF(Value,Format,19,Digits,FormatSettings);
  1391. end;
  1392. Function CurrToStrF(Value: Currency; Format: TFloatFormat; Digits: Integer): string;
  1393. begin
  1394. Result:=CurrToStrF(Value,Format,Digits,DefaultFormatSettings);
  1395. end;
  1396. Function FloatToDateTime (Const Value : Extended) : TDateTime;
  1397. begin
  1398. If (Value<MinDateTime) or (Value>MaxDateTime) then
  1399. Raise EConvertError.CreateFmt (SInvalidDateTime,[Value]);
  1400. Result:=Value;
  1401. end;
  1402. function TryFloatToCurr(const Value: Extended; var AResult: Currency): Boolean;
  1403. begin
  1404. Result:=(Value>=MinCurrency) and (Value<=MaxCurrency);
  1405. if Result then
  1406. AResult := Value;
  1407. end;
  1408. function FloatToCurr(const Value: Extended): Currency;
  1409. begin
  1410. if not TryFloatToCurr(Value, Result) then
  1411. Raise EConvertError.CreateFmt(SInvalidCurrency, [FloatToStr(Value)]);
  1412. end;
  1413. Function CurrToStr(Value: Currency): string;
  1414. begin
  1415. Result:=FloatToStrF(Value,ffGeneral,-1,0);
  1416. end;
  1417. Function CurrToStr(Value: Currency; Const FormatSettings: TFormatSettings): string;
  1418. begin
  1419. Result:=FloatToStrF(Value,ffGeneral,-1,0,FormatSettings);
  1420. end;
  1421. function StrToCurr(const S: string): Currency;
  1422. begin
  1423. if not TextToFloat(PChar(pointer(S)), Result, fvCurrency) then
  1424. Raise EConvertError.createfmt(SInValidFLoat,[S]);
  1425. end;
  1426. function StrToCurr(const S: string; Const FormatSettings: TFormatSettings): Currency;
  1427. begin
  1428. if not TextToFloat(PChar(pointer(S)), Result, fvCurrency,FormatSettings) then
  1429. Raise EConvertError.createfmt(SInValidFLoat,[S]);
  1430. end;
  1431. Function TryStrToCurr(Const S : String; Out Value: Currency): Boolean;
  1432. Begin
  1433. Result := TextToFloat(PChar(pointer(S)), Value, fvCurrency);
  1434. End;
  1435. function TryStrToCurr(const S: string;Out Value : Currency; Const FormatSettings: TFormatSettings): Boolean;
  1436. Begin
  1437. Result := TextToFloat(PChar(pointer(S)), Value, fvCurrency,FormatSettings);
  1438. End;
  1439. function StrToCurrDef(const S: string; Default : Currency): Currency;
  1440. begin
  1441. if not TextToFloat(PChar(pointer(S)), Result, fvCurrency) then
  1442. Result:=Default;
  1443. end;
  1444. function StrToCurrDef(const S: string; Default : Currency; Const FormatSettings: TFormatSettings): Currency;
  1445. begin
  1446. if not TextToFloat(PChar(pointer(S)), Result, fvCurrency,FormatSettings) then
  1447. Result:=Default;
  1448. end;
  1449. {$endif FPUNONE}
  1450. function AnsiDequotedStr(const S: string; AQuote: Char): string;
  1451. var p : pchar;
  1452. begin
  1453. p:=pchar(pointer(s)); // work around CONST. Ansiextract is safe for nil
  1454. result:=AnsiExtractquotedStr(p,AQuote);
  1455. if result='' Then
  1456. result:=s;
  1457. end;
  1458. function StrToBool(const S: string): Boolean;
  1459. begin
  1460. if not(TryStrToBool(S,Result)) then
  1461. Raise EConvertError.CreateFmt(SInvalidBoolean,[S]);
  1462. end;
  1463. procedure CheckBoolStrs;
  1464. begin
  1465. If Length(TrueBoolStrs)=0 then
  1466. begin
  1467. SetLength(TrueBoolStrs,1);
  1468. TrueBoolStrs[0]:='True';
  1469. end;
  1470. If Length(FalseBoolStrs)=0 then
  1471. begin
  1472. SetLength(FalseBoolStrs,1);
  1473. FalseBoolStrs[0]:='False';
  1474. end;
  1475. end;
  1476. function BoolToStr(B: Boolean;UseBoolStrs:Boolean=False): string;
  1477. begin
  1478. if UseBoolStrs Then
  1479. begin
  1480. CheckBoolStrs;
  1481. if B then
  1482. Result:=TrueBoolStrs[0]
  1483. else
  1484. Result:=FalseBoolStrs[0];
  1485. end
  1486. else
  1487. If B then
  1488. Result:='-1'
  1489. else
  1490. Result:='0';
  1491. end;
  1492. // from textmode IDE util funcs.
  1493. function BoolToStr(B: boolean; const TrueS, FalseS: string): string;
  1494. begin
  1495. if B then Result:=TrueS else BoolToStr:=FalseS;
  1496. end;
  1497. function StrToBoolDef(const S: string; Default: Boolean): Boolean;
  1498. begin
  1499. if not(TryStrToBool(S,Result)) then
  1500. Result:=Default;
  1501. end;
  1502. function TryStrToBool(const S: string; out Value: Boolean): Boolean;
  1503. Var
  1504. Temp : String;
  1505. I : Longint;
  1506. {$ifdef FPUNONE}
  1507. D : Longint;
  1508. {$else}
  1509. D : Double;
  1510. {$endif}
  1511. Code: word;
  1512. begin
  1513. Temp:=upcase(S);
  1514. Val(temp,D,code);
  1515. Result:=true;
  1516. If Code=0 then
  1517. {$ifdef FPUNONE}
  1518. Value:=(D<>0)
  1519. {$else}
  1520. Value:=(D<>0.0)
  1521. {$endif}
  1522. else
  1523. begin
  1524. CheckBoolStrs;
  1525. for I:=low(TrueBoolStrs) to High(TrueBoolStrs) do
  1526. if Temp=upcase(TrueBoolStrs[I]) then
  1527. begin
  1528. Value:=true;
  1529. exit;
  1530. end;
  1531. for I:=low(FalseBoolStrs) to High(FalseBoolStrs) do
  1532. if Temp=upcase(FalseBoolStrs[I]) then
  1533. begin
  1534. Value:=false;
  1535. exit;
  1536. end;
  1537. Result:=false;
  1538. end;
  1539. end;
  1540. {$ifndef FPUNONE}
  1541. Function FloatToTextFmt(Buffer: PChar; Value: Extended; format: PChar): Integer;
  1542. begin
  1543. Result:=FloatToTextFmt(Buffer,Value,Format,DefaultFormatSettings);
  1544. end;
  1545. Function FloatToTextFmt(Buffer: PChar; Value: Extended; format: PChar;FormatSettings : TFormatSettings): Integer;
  1546. Var
  1547. Digits: String[40]; { String Of Digits }
  1548. Exponent: String[8]; { Exponent strin }
  1549. FmtStart, FmtStop: PChar; { Start And End Of relevant part }
  1550. { Of format String }
  1551. ExpFmt, ExpSize: Integer; { Type And Length Of }
  1552. { exponential format chosen }
  1553. Placehold: Array[1..4] Of Integer; { Number Of placeholders In All }
  1554. { four Sections }
  1555. thousand: Boolean; { thousand separators? }
  1556. UnexpectedDigits: Integer; { Number Of unexpected Digits that }
  1557. { have To be inserted before the }
  1558. { First placeholder. }
  1559. DigitExponent: Integer; { Exponent Of First digit In }
  1560. { Digits Array. }
  1561. { Find end of format section starting at P. False, if empty }
  1562. Function GetSectionEnd(Var P: PChar): Boolean;
  1563. Var
  1564. C: Char;
  1565. SQ, DQ: Boolean;
  1566. Begin
  1567. Result := False;
  1568. SQ := False;
  1569. DQ := False;
  1570. C := P[0];
  1571. While (C<>#0) And ((C<>';') Or SQ Or DQ) Do
  1572. Begin
  1573. Result := True;
  1574. Case C Of
  1575. #34: If Not SQ Then DQ := Not DQ;
  1576. #39: If Not DQ Then SQ := Not SQ;
  1577. End;
  1578. Inc(P);
  1579. C := P[0];
  1580. End;
  1581. End;
  1582. { Find start and end of format section to apply. If section doesn't exist,
  1583. use section 1. If section 2 is used, the sign of value is ignored. }
  1584. Procedure GetSectionRange(section: Integer);
  1585. Var
  1586. Sec: Array[1..3] Of PChar;
  1587. SecOk: Array[1..3] Of Boolean;
  1588. Begin
  1589. Sec[1] := format;
  1590. SecOk[1] := GetSectionEnd(Sec[1]);
  1591. If section > 1 Then
  1592. Begin
  1593. Sec[2] := Sec[1];
  1594. If Sec[2][0] <> #0 Then
  1595. Inc(Sec[2]);
  1596. SecOk[2] := GetSectionEnd(Sec[2]);
  1597. If section > 2 Then
  1598. Begin
  1599. Sec[3] := Sec[2];
  1600. If Sec[3][0] <> #0 Then
  1601. Inc(Sec[3]);
  1602. SecOk[3] := GetSectionEnd(Sec[3]);
  1603. End;
  1604. End;
  1605. If Not SecOk[1] Then
  1606. FmtStart := Nil
  1607. Else
  1608. Begin
  1609. If Not SecOk[section] Then
  1610. section := 1
  1611. Else If section = 2 Then
  1612. Value := -Value; { Remove sign }
  1613. If section = 1 Then FmtStart := format Else
  1614. Begin
  1615. FmtStart := Sec[section - 1];
  1616. Inc(FmtStart);
  1617. End;
  1618. FmtStop := Sec[section];
  1619. End;
  1620. End;
  1621. { Find format section ranging from FmtStart to FmtStop. }
  1622. Procedure GetFormatOptions;
  1623. Var
  1624. Fmt: PChar;
  1625. SQ, DQ: Boolean;
  1626. area: Integer;
  1627. Begin
  1628. SQ := False;
  1629. DQ := False;
  1630. Fmt := FmtStart;
  1631. ExpFmt := 0;
  1632. area := 1;
  1633. thousand := False;
  1634. Placehold[1] := 0;
  1635. Placehold[2] := 0;
  1636. Placehold[3] := 0;
  1637. Placehold[4] := 0;
  1638. While Fmt < FmtStop Do
  1639. Begin
  1640. Case Fmt[0] Of
  1641. #34:
  1642. Begin
  1643. If Not SQ Then
  1644. DQ := Not DQ;
  1645. Inc(Fmt);
  1646. End;
  1647. #39:
  1648. Begin
  1649. If Not DQ Then
  1650. SQ := Not SQ;
  1651. Inc(Fmt);
  1652. End;
  1653. Else
  1654. { if not in quotes, then interpret}
  1655. If Not (SQ Or DQ) Then
  1656. Begin
  1657. Case Fmt[0] Of
  1658. '0':
  1659. Begin
  1660. Case area Of
  1661. 1:
  1662. area := 2;
  1663. 4:
  1664. Begin
  1665. area := 3;
  1666. Inc(Placehold[3], Placehold[4]);
  1667. Placehold[4] := 0;
  1668. End;
  1669. End;
  1670. Inc(Placehold[area]);
  1671. Inc(Fmt);
  1672. End;
  1673. '#':
  1674. Begin
  1675. If area=3 Then
  1676. area:=4;
  1677. Inc(Placehold[area]);
  1678. Inc(Fmt);
  1679. End;
  1680. '.':
  1681. Begin
  1682. If area<3 Then
  1683. area:=3;
  1684. Inc(Fmt);
  1685. End;
  1686. ',':
  1687. Begin
  1688. thousand := DefaultFormatSettings.ThousandSeparator<>#0;
  1689. Inc(Fmt);
  1690. End;
  1691. 'e', 'E':
  1692. If ExpFmt = 0 Then
  1693. Begin
  1694. If (Fmt[0]='E') Then
  1695. ExpFmt:=1
  1696. Else
  1697. ExpFmt := 3;
  1698. Inc(Fmt);
  1699. If (Fmt<FmtStop) Then
  1700. Begin
  1701. Case Fmt[0] Of
  1702. '+':
  1703. Begin
  1704. End;
  1705. '-':
  1706. Inc(ExpFmt);
  1707. Else
  1708. ExpFmt := 0;
  1709. End;
  1710. If ExpFmt <> 0 Then
  1711. Begin
  1712. Inc(Fmt);
  1713. ExpSize := 0;
  1714. While (Fmt<FmtStop) And
  1715. (ExpSize<4) And
  1716. (Fmt[0] In ['0'..'9']) Do
  1717. Begin
  1718. Inc(ExpSize);
  1719. Inc(Fmt);
  1720. End;
  1721. End;
  1722. End
  1723. Else
  1724. { just e/E without subsequent +/- -> not exponential format,
  1725. but we have to simply print e/E literally }
  1726. ExpFmt:=0;
  1727. End
  1728. Else
  1729. Inc(Fmt);
  1730. Else { Case }
  1731. Inc(Fmt);
  1732. End; { Case }
  1733. End { Begin }
  1734. Else
  1735. Inc(Fmt);
  1736. End; { Case }
  1737. End; { While .. Begin }
  1738. End;
  1739. Procedure FloatToStr;
  1740. Var
  1741. I, J, Exp, Width, Decimals, DecimalPoint, len: Integer;
  1742. Begin
  1743. If ExpFmt = 0 Then
  1744. Begin
  1745. { Fixpoint }
  1746. Decimals:=Placehold[3]+Placehold[4];
  1747. Width:=Placehold[1]+Placehold[2]+Decimals;
  1748. If (Decimals=0) Then
  1749. Str(Value:Width:0,Digits)
  1750. Else if Value>=0 then
  1751. Str(Value:Width+1:Decimals,Digits)
  1752. else
  1753. Str(Value:Width+2:Decimals,Digits);
  1754. len:=Length(Digits);
  1755. { Find the decimal point }
  1756. If (Decimals=0) Then
  1757. DecimalPoint:=len+1
  1758. Else
  1759. DecimalPoint:=len-Decimals;
  1760. { If value is very small, and no decimal places
  1761. are desired, remove the leading 0. }
  1762. If (Abs(Value) < 1) And (Placehold[2] = 0) Then
  1763. Begin
  1764. If (Placehold[1]=0) Then
  1765. Delete(Digits,DecimalPoint-1,1)
  1766. Else
  1767. Digits[DecimalPoint-1]:=' ';
  1768. End;
  1769. { Convert optional zeroes to spaces. }
  1770. I:=len;
  1771. J:=DecimalPoint+Placehold[3];
  1772. While (I>J) And (Digits[I]='0') Do
  1773. Begin
  1774. Digits[I] := ' ';
  1775. Dec(I);
  1776. End;
  1777. { If integer value and no obligatory decimal
  1778. places, remove decimal point. }
  1779. If (DecimalPoint < len) And (Digits[DecimalPoint + 1] = ' ') Then
  1780. Digits[DecimalPoint] := ' ';
  1781. { Convert spaces left from obligatory decimal point to zeroes.
  1782. MVC : If - sign is encountered, replace it too, and put at position 1}
  1783. I:=DecimalPoint-Placehold[2];
  1784. J:=0;
  1785. While (I<DecimalPoint) And (Digits[I] in [' ','-']) Do
  1786. Begin
  1787. If Digits[i]='-' then
  1788. J:=I;
  1789. Digits[I] := '0';
  1790. Inc(I);
  1791. End;
  1792. If (J<>0) then
  1793. Digits[1]:='-';
  1794. Exp := 0;
  1795. End
  1796. Else
  1797. Begin
  1798. { Scientific: exactly <Width> Digits With <Precision> Decimals
  1799. And adjusted Exponent. }
  1800. If Placehold[1]+Placehold[2]=0 Then
  1801. Placehold[1]:=1;
  1802. Decimals := Placehold[3] + Placehold[4];
  1803. Width:=Placehold[1]+Placehold[2]+Decimals;
  1804. { depending on the maximally supported precision, the exponent field }
  1805. { is longer/shorter }
  1806. {$ifdef FPC_HAS_TYPE_EXTENDED}
  1807. Str(Value:Width+8,Digits);
  1808. {$else FPC_HAS_TYPE_EXTENDED}
  1809. {$ifdef FPC_HAS_TYPE_DOUBLE}
  1810. Str(Value:Width+7,Digits);
  1811. {$else FPC_HAS_TYPE_DOUBLE}
  1812. Str(Value:Width+6,Digits);
  1813. {$endif FPC_HAS_TYPE_DOUBLE}
  1814. {$endif FPC_HAS_TYPE_EXTENDED}
  1815. { Find and cut out exponent. Always the
  1816. last 6 characters in the string.
  1817. -> 0000E+0000
  1818. *** No, not always the last 6 characters, this depends on
  1819. the maximally supported precision (JM)}
  1820. I:=Pos('E',Digits);
  1821. Val(Copy(Digits,I+1,255),Exp,J);
  1822. Exp:=Exp+1-(Placehold[1]+Placehold[2]);
  1823. Delete(Digits, I, 255);
  1824. { Str() always returns at least one digit after the decimal point.
  1825. If we don't want it, we have to remove it. }
  1826. If (Decimals=0) And (Placehold[1]+Placehold[2]<= 1) Then
  1827. Begin
  1828. If (Digits[4]>='5') Then
  1829. Begin
  1830. Inc(Digits[2]);
  1831. If (Digits[2]>'9') Then
  1832. Begin
  1833. Digits[2] := '1';
  1834. Inc(Exp);
  1835. End;
  1836. End;
  1837. Delete(Digits, 3, 2);
  1838. DecimalPoint := Length(Digits) + 1;
  1839. End
  1840. Else
  1841. Begin
  1842. { Move decimal point at the desired position }
  1843. Delete(Digits, 3, 1);
  1844. DecimalPoint:=2+Placehold[1]+Placehold[2];
  1845. If (Decimals<>0) Then
  1846. Insert('.',Digits,DecimalPoint);
  1847. End;
  1848. { Convert optional zeroes to spaces. }
  1849. I := Length(Digits);
  1850. J := DecimalPoint + Placehold[3];
  1851. While (I > J) And (Digits[I] = '0') Do
  1852. Begin
  1853. Digits[I] := ' ';
  1854. Dec(I);
  1855. End;
  1856. { If integer number and no obligatory decimal paces, remove decimal point }
  1857. If (DecimalPoint<Length(Digits)) And
  1858. (Digits[DecimalPoint+1]=' ') Then
  1859. Digits[DecimalPoint]:=' ';
  1860. If (Digits[1]=' ') Then
  1861. Begin
  1862. Delete(Digits, 1, 1);
  1863. Dec(DecimalPoint);
  1864. End;
  1865. { Calculate exponent string }
  1866. Str(Abs(Exp), Exponent);
  1867. While Length(Exponent)<ExpSize Do
  1868. Insert('0',Exponent,1);
  1869. If Exp >= 0 Then
  1870. Begin
  1871. If (ExpFmt In [1,3]) Then
  1872. Insert('+', Exponent, 1);
  1873. End
  1874. Else
  1875. Insert('-',Exponent,1);
  1876. If (ExpFmt<3) Then
  1877. Insert('E',Exponent,1)
  1878. Else
  1879. Insert('e',Exponent,1);
  1880. End;
  1881. DigitExponent:=DecimalPoint-2;
  1882. If (Digits[1]='-') Then
  1883. Dec(DigitExponent);
  1884. UnexpectedDigits:=DecimalPoint-1-(Placehold[1]+Placehold[2]);
  1885. End;
  1886. Function PutResult: LongInt;
  1887. Var
  1888. SQ, DQ: Boolean;
  1889. Fmt, Buf: PChar;
  1890. Dig, N: Integer;
  1891. Begin
  1892. SQ := False;
  1893. DQ := False;
  1894. Fmt := FmtStart;
  1895. Buf := Buffer;
  1896. Dig := 1;
  1897. While (Fmt<FmtStop) Do
  1898. Begin
  1899. //Write(Fmt[0]);
  1900. Case Fmt[0] Of
  1901. #34:
  1902. Begin
  1903. If Not SQ Then
  1904. DQ := Not DQ;
  1905. Inc(Fmt);
  1906. End;
  1907. #39:
  1908. Begin
  1909. If Not DQ Then
  1910. SQ := Not SQ;
  1911. Inc(Fmt);
  1912. End;
  1913. Else
  1914. If Not (SQ Or DQ) Then
  1915. Begin
  1916. Case Fmt[0] Of
  1917. '0', '#', '.':
  1918. Begin
  1919. If (Dig=1) And (UnexpectedDigits>0) Then
  1920. Begin
  1921. { Everything unexpected is written before the first digit }
  1922. For N := 1 To UnexpectedDigits Do
  1923. Begin
  1924. if (Digits[N]<>' ') Then
  1925. begin
  1926. Buf[0] := Digits[N];
  1927. Inc(Buf);
  1928. end;
  1929. If thousand And (Digits[N]<>'-') Then
  1930. Begin
  1931. If (DigitExponent Mod 3 = 0) And (DigitExponent>0) Then
  1932. Begin
  1933. Buf[0] := FormatSettings.ThousandSeparator;
  1934. Inc(Buf);
  1935. End;
  1936. Dec(DigitExponent);
  1937. End;
  1938. End;
  1939. Inc(Dig, UnexpectedDigits);
  1940. End;
  1941. If (Digits[Dig]<>' ') Then
  1942. Begin
  1943. If (Digits[Dig]='.') Then
  1944. Buf[0] := FormatSettings.DecimalSeparator
  1945. Else
  1946. Buf[0] := Digits[Dig];
  1947. Inc(Buf);
  1948. If thousand And (DigitExponent Mod 3 = 0) And (DigitExponent > 0) and (Digits[Dig]<>'-') Then
  1949. Begin
  1950. Buf[0] := FormatSettings.ThousandSeparator;
  1951. Inc(Buf);
  1952. End;
  1953. End;
  1954. Inc(Dig);
  1955. Dec(DigitExponent);
  1956. Inc(Fmt);
  1957. End;
  1958. 'e', 'E':
  1959. Begin
  1960. If ExpFmt <> 0 Then
  1961. Begin
  1962. Inc(Fmt);
  1963. If Fmt < FmtStop Then
  1964. Begin
  1965. If Fmt[0] In ['+', '-'] Then
  1966. Begin
  1967. Inc(Fmt, ExpSize);
  1968. For N:=1 To Length(Exponent) Do
  1969. Buf[N-1] := Exponent[N];
  1970. Inc(Buf,Length(Exponent));
  1971. ExpFmt:=0;
  1972. End;
  1973. Inc(Fmt);
  1974. End;
  1975. End
  1976. Else
  1977. Begin
  1978. { No legal exponential format.
  1979. Simply write the 'E' to the result. }
  1980. Buf[0] := Fmt[0];
  1981. Inc(Buf);
  1982. Inc(Fmt);
  1983. End;
  1984. End;
  1985. Else { Case }
  1986. { Usual character }
  1987. If (Fmt[0]<>',') Then
  1988. Begin
  1989. Buf[0] := Fmt[0];
  1990. Inc(Buf);
  1991. End;
  1992. Inc(Fmt);
  1993. End; { Case }
  1994. End
  1995. Else { IF }
  1996. Begin
  1997. { Character inside single or double quotes }
  1998. Buf[0] := Fmt[0];
  1999. Inc(Buf);
  2000. Inc(Fmt);
  2001. End;
  2002. End; { Case }
  2003. End; { While .. Begin }
  2004. Result:=PtrUInt(Buf)-PtrUInt(Buffer);
  2005. End;
  2006. Begin
  2007. If (Value>0) Then
  2008. GetSectionRange(1)
  2009. Else If (Value<0) Then
  2010. GetSectionRange(2)
  2011. Else
  2012. GetSectionRange(3);
  2013. If FmtStart = Nil Then
  2014. Begin
  2015. Result := FloatToText(Buffer, Value, ffGeneral, 15, 4, FormatSettings);
  2016. End
  2017. Else
  2018. Begin
  2019. GetFormatOptions;
  2020. If (ExpFmt = 0) And (Abs(Value) >= 1E18) Then
  2021. Result := FloatToText(Buffer, Value, ffGeneral, 15, 4, FormatSettings)
  2022. Else
  2023. Begin
  2024. FloatToStr;
  2025. Result := PutResult;
  2026. End;
  2027. End;
  2028. End;
  2029. Procedure FloatToDecimal(Out Result: TFloatRec; const Value; ValueType: TFloatValue; Precision, Decimals : integer);
  2030. var
  2031. Buffer: String[254]; //Though str func returns only 25 chars, this might change in the future
  2032. InfNan: string[3];
  2033. Error, N, L, Start, C: Integer;
  2034. GotNonZeroBeforeDot, BeforeDot : boolean;
  2035. begin
  2036. case ValueType of
  2037. fvExtended:
  2038. Str(Extended(Value):25, Buffer);
  2039. fvDouble,
  2040. fvReal:
  2041. Str(Double(Value):23, Buffer);
  2042. fvSingle:
  2043. Str(Single(Value):16, Buffer);
  2044. fvCurrency:
  2045. Str(Currency(Value):25, Buffer);
  2046. fvComp:
  2047. Str(Currency(Value):23, Buffer);
  2048. end;
  2049. N := 1;
  2050. L := Byte(Buffer[0]);
  2051. while Buffer[N]=' ' do
  2052. Inc(N);
  2053. Result.Negative := (Buffer[N] = '-');
  2054. if Result.Negative then
  2055. Inc(N)
  2056. else if (Buffer[N] = '+') then
  2057. inc(N);
  2058. { special cases for Inf and Nan }
  2059. if (L>=N+2) then
  2060. begin
  2061. InfNan:=copy(Buffer,N,3);
  2062. if (InfNan='Inf') then
  2063. begin
  2064. Result.Digits[0]:=#0;
  2065. Result.Exponent:=32767;
  2066. exit
  2067. end;
  2068. if (InfNan='Nan') then
  2069. begin
  2070. Result.Digits[0]:=#0;
  2071. Result.Exponent:=-32768;
  2072. exit
  2073. end;
  2074. end;
  2075. Start := N; //Start of digits
  2076. Result.Exponent := 0; BeforeDot := true;
  2077. GotNonZeroBeforeDot := false;
  2078. while (L>=N) and (Buffer[N]<>'E') do
  2079. begin
  2080. if Buffer[N]='.' then
  2081. BeforeDot := false
  2082. else
  2083. begin
  2084. if BeforeDot then
  2085. begin // Currently this is always 1 char
  2086. Inc(Result.Exponent);
  2087. Result.Digits[N-Start] := Buffer[N];
  2088. if Buffer[N] <> '0' then
  2089. GotNonZeroBeforeDot := true;
  2090. end
  2091. else
  2092. Result.Digits[N-Start-1] := Buffer[N]
  2093. end;
  2094. Inc(N);
  2095. end;
  2096. Inc(N); // Pass through 'E'
  2097. if N<=L then
  2098. begin
  2099. Val(Copy(Buffer, N, L-N+1), C, Error); // Get exponent after 'E'
  2100. Inc(Result.Exponent, C);
  2101. end;
  2102. // Calculate number of digits we have from str
  2103. if BeforeDot then
  2104. N := N - Start - 1
  2105. else
  2106. N := N - Start - 2;
  2107. L := SizeOf(Result.Digits);
  2108. if N<L then
  2109. FillChar(Result.Digits[N], L-N, '0'); //Zero remaining space
  2110. if Decimals + Result.Exponent < Precision Then //After this it is the same as in FloatToDecimal
  2111. N := Decimals + Result.Exponent
  2112. Else
  2113. N := Precision;
  2114. if N >= L Then
  2115. N := L-1;
  2116. if N = 0 Then
  2117. begin
  2118. if Result.Digits[0] >= '5' Then
  2119. begin
  2120. Result.Digits[0] := '1';
  2121. Result.Digits[1] := #0;
  2122. Inc(Result.Exponent);
  2123. end
  2124. Else
  2125. Result.Digits[0] := #0;
  2126. end //N=0
  2127. Else if N > 0 Then
  2128. begin
  2129. if Result.Digits[N] >= '5' Then
  2130. begin
  2131. Repeat
  2132. Result.Digits[N] := #0;
  2133. Dec(N);
  2134. Inc(Result.Digits[N]);
  2135. Until (N = 0) Or (Result.Digits[N] < ':');
  2136. If Result.Digits[0] = ':' Then
  2137. begin
  2138. Result.Digits[0] := '1';
  2139. Inc(Result.Exponent);
  2140. end;
  2141. end
  2142. Else
  2143. begin
  2144. Result.Digits[N] := '0';
  2145. While (N > -1) And (Result.Digits[N] = '0') Do
  2146. begin
  2147. Result.Digits[N] := #0;
  2148. Dec(N);
  2149. end;
  2150. end;
  2151. end //N>0
  2152. Else
  2153. Result.Digits[0] := #0;
  2154. if (Result.Digits[0] = #0) and
  2155. not GotNonZeroBeforeDot then
  2156. begin
  2157. Result.Exponent := 0;
  2158. Result.Negative := False;
  2159. end;
  2160. end;
  2161. Procedure FloatToDecimal(Out Result: TFloatRec; Value: Extended; Precision, Decimals : integer);
  2162. begin
  2163. FloatToDecimal(Result,Value,fvExtended,Precision,Decimals);
  2164. end;
  2165. Function FormatFloat(Const Format : String; Value : Extended; Const FormatSettings: TFormatSettings) : String;
  2166. Var
  2167. buf : Array[0..1024] of char;
  2168. Begin // not changed to pchar(pointer(). Possibly not safe
  2169. Buf[FloatToTextFmt(@Buf[0],Value,Pchar(Format),FormatSettings)]:=#0;
  2170. Result:=StrPas(@Buf[0]);
  2171. End;
  2172. Function FormatFloat(Const format: String; Value: Extended): String;
  2173. begin
  2174. Result:=FormatFloat(Format,Value,DefaultFormatSettings);
  2175. end;
  2176. Function FormatCurr(const Format: string; Value: Currency; Const FormatSettings: TFormatSettings): string;
  2177. begin
  2178. Result := FormatFloat(Format, Value,FormatSettings);
  2179. end;
  2180. function FormatCurr(const Format: string; Value: Currency): string;
  2181. begin
  2182. Result:=FormatCurr(Format,Value,DefaultFormatSettings);
  2183. end;
  2184. {$endif}
  2185. {==============================================================================}
  2186. { extra functions }
  2187. {==============================================================================}
  2188. { LeftStr returns Count left-most characters from S }
  2189. function LeftStr(const S: string; Count: integer): string;
  2190. begin
  2191. result := Copy(S, 1, Count);
  2192. end ;
  2193. { RightStr returns Count right-most characters from S }
  2194. function RightStr(const S: string; Count: integer): string;
  2195. begin
  2196. If Count>Length(S) then
  2197. Count:=Length(S);
  2198. result := Copy(S, 1 + Length(S) - Count, Count);
  2199. end;
  2200. { BCDToInt converts the BCD value Value to an integer }
  2201. function BCDToInt(Value: integer): integer;
  2202. var i, j, digit: integer;
  2203. begin
  2204. result := 0;
  2205. j := 1;
  2206. for i := 0 to SizeOf(Value) shl 1 - 1 do begin
  2207. digit := Value and 15;
  2208. if digit > $9 then
  2209. begin
  2210. if i = 0 then
  2211. begin
  2212. if digit in [$B, $D] then j := -1
  2213. end
  2214. else raise EConvertError.createfmt(SInvalidBCD,[Value]);
  2215. end
  2216. else
  2217. begin
  2218. result := result + j * digit;
  2219. j := j * 10;
  2220. end ;
  2221. Value := Value shr 4;
  2222. end ;
  2223. end ;
  2224. Function LastDelimiter(const Delimiters, S: string): Integer;
  2225. var
  2226. chs: TSysCharSet;
  2227. I: LongInt;
  2228. begin
  2229. chs := [];
  2230. for I := 1 to Length(Delimiters) do
  2231. Include(chs, Delimiters[I]);
  2232. Result:=Length(S);
  2233. While (Result>0) and not (S[Result] in chs) do
  2234. Dec(Result);
  2235. end;
  2236. Function StringReplace(const S, OldPattern, NewPattern: string; Flags: TReplaceFlags): string;
  2237. var
  2238. Srch,OldP,RemS: string; // Srch and Oldp can contain uppercase versions of S,OldPattern
  2239. P : Integer;
  2240. begin
  2241. Srch:=S;
  2242. OldP:=OldPattern;
  2243. if rfIgnoreCase in Flags then
  2244. begin
  2245. Srch:=AnsiUpperCase(Srch);
  2246. OldP:=AnsiUpperCase(OldP);
  2247. end;
  2248. RemS:=S;
  2249. Result:='';
  2250. while (Length(Srch)<>0) do
  2251. begin
  2252. P:=AnsiPos(OldP, Srch);
  2253. if P=0 then
  2254. begin
  2255. Result:=Result+RemS;
  2256. Srch:='';
  2257. end
  2258. else
  2259. begin
  2260. Result:=Result+Copy(RemS,1,P-1)+NewPattern;
  2261. P:=P+Length(OldP);
  2262. RemS:=Copy(RemS,P,Length(RemS)-P+1);
  2263. if not (rfReplaceAll in Flags) then
  2264. begin
  2265. Result:=Result+RemS;
  2266. Srch:='';
  2267. end
  2268. else
  2269. Srch:=Copy(Srch,P,Length(Srch)-P+1);
  2270. end;
  2271. end;
  2272. end;
  2273. Function IsDelimiter(const Delimiters, S: string; Index: Integer): Boolean;
  2274. begin
  2275. Result:=False;
  2276. If (Index>0) and (Index<=Length(S)) then
  2277. Result:=Pos(S[Index],Delimiters)<>0; // Note we don't do MBCS yet
  2278. end;
  2279. Function ByteToCharLen(const S: string; MaxLen: Integer): Integer;
  2280. begin
  2281. Result:=Length(S);
  2282. If Result>MaxLen then
  2283. Result:=MaxLen;
  2284. end;
  2285. Function ByteToCharIndex(const S: string; Index: Integer): Integer;
  2286. begin
  2287. Result:=Index;
  2288. end;
  2289. Function CharToByteLen(const S: string; MaxLen: Integer): Integer;
  2290. begin
  2291. Result:=Length(S);
  2292. If Result>MaxLen then
  2293. Result:=MaxLen;
  2294. end;
  2295. Function CharToByteIndex(const S: string; Index: Integer): Integer;
  2296. begin
  2297. Result:=Index;
  2298. end;
  2299. Function ByteType(const S: string; Index: Integer): TMbcsByteType;
  2300. begin
  2301. Result:=mbSingleByte;
  2302. end;
  2303. Function StrByteType(Str: PChar; Index: Cardinal): TMbcsByteType;
  2304. begin
  2305. Result:=mbSingleByte;
  2306. end;
  2307. Function StrCharLength(const Str: PChar): Integer;
  2308. begin
  2309. result:=widestringmanager.CharLengthPCharProc(Str);
  2310. end;
  2311. function StrNextChar(const Str: PChar): PChar;
  2312. begin
  2313. result:=Str+StrCharLength(Str);
  2314. end;
  2315. Function FindCmdLineSwitch(const Switch: string; const Chars: TSysCharSet;IgnoreCase: Boolean): Boolean;
  2316. Var
  2317. I,L : Integer;
  2318. S,T : String;
  2319. begin
  2320. Result:=False;
  2321. S:=Switch;
  2322. If IgnoreCase then
  2323. S:=UpperCase(S);
  2324. I:=ParamCount;
  2325. While (Not Result) and (I>0) do
  2326. begin
  2327. L:=Length(Paramstr(I));
  2328. If (L>0) and (ParamStr(I)[1] in Chars) then
  2329. begin
  2330. T:=Copy(ParamStr(I),2,L-1);
  2331. If IgnoreCase then
  2332. T:=UpperCase(T);
  2333. Result:=S=T;
  2334. end;
  2335. Dec(i);
  2336. end;
  2337. end;
  2338. Function FindCmdLineSwitch(const Switch: string; IgnoreCase: Boolean): Boolean;
  2339. begin
  2340. Result:=FindCmdLineSwitch(Switch,SwitchChars,IgnoreCase);
  2341. end;
  2342. Function FindCmdLineSwitch(const Switch: string): Boolean;
  2343. begin
  2344. Result:=FindCmdLineSwitch(Switch,SwitchChars,False);
  2345. end;
  2346. function WrapText(const Line, BreakStr: string; const BreakChars: TSysCharSet; MaxCol: Integer): string;
  2347. const
  2348. Quotes = ['''', '"'];
  2349. Var
  2350. L : String;
  2351. C,LQ,BC : Char;
  2352. P,BLen,Len : Integer;
  2353. HB,IBC : Boolean;
  2354. begin
  2355. Result:='';
  2356. L:=Line;
  2357. Blen:=Length(BreakStr);
  2358. If (BLen>0) then
  2359. BC:=BreakStr[1]
  2360. else
  2361. BC:=#0;
  2362. Len:=Length(L);
  2363. While (Len>0) do
  2364. begin
  2365. P:=1;
  2366. LQ:=#0;
  2367. HB:=False;
  2368. IBC:=False;
  2369. While ((P<=Len) and ((P<=MaxCol) or not IBC)) and ((LQ<>#0) or Not HB) do
  2370. begin
  2371. C:=L[P];
  2372. If (C=LQ) then
  2373. LQ:=#0
  2374. else If (C in Quotes) then
  2375. LQ:=C;
  2376. If (LQ<>#0) then
  2377. Inc(P)
  2378. else
  2379. begin
  2380. HB:=((C=BC) and (BreakStr=Copy(L,P,BLen)));
  2381. If HB then
  2382. Inc(P,Blen)
  2383. else
  2384. begin
  2385. If (P>MaxCol) then
  2386. IBC:=C in BreakChars;
  2387. Inc(P);
  2388. end;
  2389. end;
  2390. // Writeln('"',C,'" : IBC : ',IBC,' HB : ',HB,' LQ : ',LQ,' P>MaxCol : ',P>MaxCol);
  2391. end;
  2392. Result:=Result+Copy(L,1,P-1);
  2393. If Not HB then
  2394. Result:=Result+BreakStr;
  2395. Delete(L,1,P-1);
  2396. Len:=Length(L);
  2397. end;
  2398. end;
  2399. function WrapText(const Line: string; MaxCol: Integer): string;
  2400. begin
  2401. Result:=WrapText(Line,sLineBreak, [' ', '-', #9], MaxCol);
  2402. end;
  2403. {$ifndef FPC_NOGENERICANSIROUTINES}
  2404. {
  2405. Case Translation Tables
  2406. Can be used in internationalization support.
  2407. Although these tables can be obtained through system calls
  2408. cd it is better to not use those, since most implementation are not 100%
  2409. WARNING:
  2410. before modifying a translation table make sure that the current codepage
  2411. of the OS corresponds to the one you make changes to
  2412. }
  2413. const
  2414. { upper case translation table for character set 850 }
  2415. CP850UCT: array[128..255] of char =
  2416. (#128,#154,#144,#182,#142,#182,#143,#128,#210,#211,#212,#216,#215,#222,#142,#143,
  2417. #144,#146,#146,#226,#153,#227,#234,#235,'Y',#153,#154,#157,#156,#157,#158,#159,
  2418. #181,#214,#224,#233,#165,#165,#166,#167,#168,#169,#170,#171,#172,#173,#174,#175,
  2419. #176,#177,#178,#179,#180,#181,#182,#183,#184,#185,#186,#187,#188,#189,#190,#191,
  2420. #192,#193,#194,#195,#196,#197,#199,#199,#200,#201,#202,#203,#204,#205,#206,#207,
  2421. #208,#209,#210,#211,#212,#213,#214,#215,#216,#217,#218,#219,#220,#221,#222,#223,
  2422. #224,#225,#226,#227,#229,#229,#230,#237,#232,#233,#234,#235,#237,#237,#238,#239,
  2423. #240,#241,#242,#243,#244,#245,#246,#247,#248,#249,#250,#251,#252,#253,#254,#255);
  2424. { lower case translation table for character set 850 }
  2425. CP850LCT: array[128..255] of char =
  2426. (#135,#129,#130,#131,#132,#133,#134,#135,#136,#137,#138,#139,#140,#141,#132,#134,
  2427. #130,#145,#145,#147,#148,#149,#150,#151,#152,#148,#129,#155,#156,#155,#158,#159,
  2428. #160,#161,#162,#163,#164,#164,#166,#167,#168,#169,#170,#171,#172,#173,#174,#175,
  2429. #176,#177,#178,#179,#180,#160,#131,#133,#184,#185,#186,#187,#188,#189,#190,#191,
  2430. #192,#193,#194,#195,#196,#197,#198,#198,#200,#201,#202,#203,#204,#205,#206,#207,
  2431. #208,#209,#136,#137,#138,#213,#161,#140,#139,#217,#218,#219,#220,#221,#141,#223,
  2432. #162,#225,#147,#149,#228,#228,#230,#237,#232,#163,#150,#151,#236,#236,#238,#239,
  2433. #240,#241,#242,#243,#244,#245,#246,#247,#248,#249,#250,#251,#252,#253,#254,#255);
  2434. { upper case translation table for character set ISO 8859/1 Latin 1 }
  2435. CPISO88591UCT: array[192..255] of char =
  2436. ( #192, #193, #194, #195, #196, #197, #198, #199,
  2437. #200, #201, #202, #203, #204, #205, #206, #207,
  2438. #208, #209, #210, #211, #212, #213, #214, #215,
  2439. #216, #217, #218, #219, #220, #221, #222, #223,
  2440. #192, #193, #194, #195, #196, #197, #198, #199,
  2441. #200, #201, #202, #203, #204, #205, #206, #207,
  2442. #208, #209, #210, #211, #212, #213, #214, #247,
  2443. #216, #217, #218, #219, #220, #221, #222, #89 );
  2444. { lower case translation table for character set ISO 8859/1 Latin 1 }
  2445. CPISO88591LCT: array[192..255] of char =
  2446. ( #224, #225, #226, #227, #228, #229, #230, #231,
  2447. #232, #233, #234, #235, #236, #237, #238, #239,
  2448. #240, #241, #242, #243, #244, #245, #246, #215,
  2449. #248, #249, #250, #251, #252, #253, #254, #223,
  2450. #224, #225, #226, #227, #228, #229, #230, #231,
  2451. #232, #233, #234, #235, #236, #237, #238, #239,
  2452. #240, #241, #242, #243, #244, #245, #246, #247,
  2453. #248, #249, #250, #251, #252, #253, #254, #255 );
  2454. {$endif FPC_NOGENERICANSIROUTINES}
  2455. function sscanf(const s: string; const fmt : string;const Pointers : array of Pointer) : Integer;
  2456. var
  2457. i,j,n,m : SizeInt;
  2458. s1 : string;
  2459. function GetInt(unsigned : boolean=false) : Integer;
  2460. begin
  2461. s1 := '';
  2462. while (Length(s) > n) and (s[n] = ' ') do
  2463. inc(n);
  2464. { read sign }
  2465. if (Length(s)>= n) and (s[n] in ['+', '-']) then
  2466. begin
  2467. { don't accept - when reading unsigned }
  2468. if unsigned and (s[n]='-') then
  2469. begin
  2470. result:=length(s1);
  2471. exit;
  2472. end
  2473. else
  2474. begin
  2475. s1:=s1+s[n];
  2476. inc(n);
  2477. end;
  2478. end;
  2479. { read numbers }
  2480. while (Length(s) >= n) and
  2481. (s[n] in ['0'..'9']) do
  2482. begin
  2483. s1 := s1+s[n];
  2484. inc(n);
  2485. end;
  2486. Result := Length(s1);
  2487. end;
  2488. function GetFloat : Integer;
  2489. begin
  2490. s1 := '';
  2491. while (Length(s) > n) and (s[n] = ' ') do
  2492. inc(n);
  2493. while (Length(s) >= n) and
  2494. (s[n] in ['0'..'9', '+', '-', FormatSettings.DecimalSeparator, 'e', 'E']) do
  2495. begin
  2496. s1 := s1+s[n];
  2497. inc(n);
  2498. end;
  2499. Result := Length(s1);
  2500. end;
  2501. function GetString : Integer;
  2502. begin
  2503. s1 := '';
  2504. while (Length(s) > n) and (s[n] = ' ') do
  2505. inc(n);
  2506. while (Length(s) >= n) and (s[n] <> ' ')do
  2507. begin
  2508. s1 := s1+s[n];
  2509. inc(n);
  2510. end;
  2511. Result := Length(s1);
  2512. end;
  2513. function ScanStr(c : Char) : Boolean;
  2514. begin
  2515. while (Length(s) > n) and (s[n] <> c) do
  2516. inc(n);
  2517. inc(n);
  2518. If (n <= Length(s)) then
  2519. Result := True
  2520. else
  2521. Result := False;
  2522. end;
  2523. function GetFmt : Integer;
  2524. begin
  2525. Result := -1;
  2526. while true do
  2527. begin
  2528. while (Length(fmt) > m) and (fmt[m] = ' ') do
  2529. inc(m);
  2530. if (m >= Length(fmt)) then
  2531. break;
  2532. if (fmt[m] = '%') then
  2533. begin
  2534. inc(m);
  2535. case fmt[m] of
  2536. 'd':
  2537. Result:=vtInteger;
  2538. {$ifndef FPUNONE}
  2539. 'f':
  2540. Result:=vtExtended;
  2541. {$endif}
  2542. 's':
  2543. Result:=vtString;
  2544. 'c':
  2545. Result:=vtChar;
  2546. else
  2547. raise EFormatError.CreateFmt(SInvalidFormat,[fmt]);
  2548. end;
  2549. inc(m);
  2550. break;
  2551. end;
  2552. if not(ScanStr(fmt[m])) then
  2553. break;
  2554. inc(m);
  2555. end;
  2556. end;
  2557. begin
  2558. n := 1;
  2559. m := 1;
  2560. Result := 0;
  2561. for i:=0 to High(Pointers) do
  2562. begin
  2563. j := GetFmt;
  2564. case j of
  2565. vtInteger :
  2566. begin
  2567. if GetInt>0 then
  2568. begin
  2569. pLongint(Pointers[i])^:=StrToInt(s1);
  2570. inc(Result);
  2571. end
  2572. else
  2573. break;
  2574. end;
  2575. vtchar :
  2576. begin
  2577. if Length(s)>n then
  2578. begin
  2579. pchar(Pointers[i])^:=s[n];
  2580. inc(n);
  2581. inc(Result);
  2582. end
  2583. else
  2584. break;
  2585. end;
  2586. {$ifndef FPUNONE}
  2587. vtExtended :
  2588. begin
  2589. if GetFloat>0 then
  2590. begin
  2591. pextended(Pointers[i])^:=StrToFloat(s1);
  2592. inc(Result);
  2593. end
  2594. else
  2595. break;
  2596. end;
  2597. {$endif}
  2598. vtString :
  2599. begin
  2600. if GetString > 0 then
  2601. begin
  2602. pansistring(Pointers[i])^:=s1;
  2603. inc(Result);
  2604. end
  2605. else
  2606. break;
  2607. end;
  2608. else
  2609. break;
  2610. end;
  2611. end;
  2612. end;