sysstr.inc 78 KB

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