sysstr.inc 79 KB

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