sysstr.inc 77 KB

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