sysstr.inc 82 KB

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