sysstr.inc 71 KB

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