sysstr.inc 83 KB

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