sysstr.inc 83 KB

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