sysstr.inc 82 KB

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