sysstr.inc 82 KB

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