2
0

sysstr.inc 77 KB

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