sysstr.inc 54 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246
  1. {
  2. *********************************************************************
  3. Copyright (C) 1997, 1998 Gertjan Schouten
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. *********************************************************************
  16. System Utilities For Free Pascal
  17. }
  18. { NewStr creates a new PString and assigns S to it
  19. if length(s) = 0 NewStr returns Nil }
  20. function NewStr(const S: string): PString;
  21. begin
  22. if (S='') then
  23. Result:=nil
  24. else
  25. begin
  26. new(result);
  27. if (Result<>nil) then
  28. Result^:=s;
  29. end;
  30. end;
  31. { DisposeStr frees the memory occupied by S }
  32. procedure DisposeStr(S: PString);
  33. begin
  34. if S <> Nil then
  35. begin
  36. dispose(s);
  37. S:=nil;
  38. end;
  39. end;
  40. { AssignStr assigns S to P^ }
  41. procedure AssignStr(var P: PString; const S: string);
  42. begin
  43. P^ := s;
  44. end ;
  45. { AppendStr appends S to Dest }
  46. procedure AppendStr(var Dest: String; const S: string);
  47. begin
  48. Dest := Dest + S;
  49. end ;
  50. { UpperCase returns a copy of S where all lowercase characters ( from a to z )
  51. have been converted to uppercase }
  52. Function UpperCase(Const S : String) : String;
  53. Var
  54. i : Integer;
  55. P : PChar;
  56. begin
  57. Result := S;
  58. UniqueString(Result);
  59. P:=Pchar(Result);
  60. for i := 1 to Length(Result) do
  61. begin
  62. if (P^ in ['a'..'z']) then P^ := char(byte(p^) - 32);
  63. Inc(P);
  64. end;
  65. end;
  66. { LowerCase returns a copy of S where all uppercase characters ( from A to Z )
  67. have been converted to lowercase }
  68. Function Lowercase(Const S : String) : String;
  69. Var
  70. i : Integer;
  71. P : PChar;
  72. begin
  73. Result := S;
  74. UniqueString(Result);
  75. P:=Pchar(Result);
  76. for i := 1 to Length(Result) do
  77. begin
  78. if (P^ in ['A'..'Z']) then P^ := char(byte(p^) + 32);
  79. Inc(P);
  80. end;
  81. end;
  82. { CompareStr compares S1 and S2, the result is the based on
  83. substraction of the ascii values of the characters in S1 and S2
  84. case result
  85. S1 < S2 < 0
  86. S1 > S2 > 0
  87. S1 = S2 = 0 }
  88. function CompareStr(const S1, S2: string): Integer;
  89. var count, count1, count2: integer;
  90. begin
  91. result := 0;
  92. Count1 := Length(S1);
  93. Count2 := Length(S2);
  94. if Count1>Count2 then
  95. Count:=Count2
  96. else
  97. Count:=Count1;
  98. result := CompareMemRange(Pointer(S1),Pointer(S2), Count);
  99. if result=0 then
  100. result:=Count1-Count2;
  101. end;
  102. { CompareMemRange returns the result of comparison of Length bytes at P1 and P2
  103. case result
  104. P1 < P2 < 0
  105. P1 > P2 > 0
  106. P1 = P2 = 0 }
  107. function CompareMemRange(P1, P2: Pointer; Length: cardinal): integer;
  108. var
  109. i: cardinal;
  110. begin
  111. i := 0;
  112. result := 0;
  113. while (result=0) and (I<length) do
  114. begin
  115. result:=byte(P1^)-byte(P2^);
  116. P1:=pchar(P1)+1; // VP compat.
  117. P2:=pchar(P2)+1;
  118. i := i + 1;
  119. end ;
  120. end ;
  121. function CompareMem(P1, P2: Pointer; Length: cardinal): Boolean;
  122. var
  123. i: cardinal;
  124. begin
  125. Result:=True;
  126. I:=0;
  127. If (P1)<>(P2) then
  128. While Result and (i<Length) do
  129. begin
  130. Result:=PByte(P1)^=PByte(P2)^;
  131. Inc(I);
  132. Inc(pchar(P1));
  133. Inc(pchar(P2));
  134. end;
  135. end;
  136. { CompareText compares S1 and S2, the result is the based on
  137. substraction of the ascii values of characters in S1 and S2
  138. comparison is case-insensitive
  139. case result
  140. S1 < S2 < 0
  141. S1 > S2 > 0
  142. S1 = S2 = 0 }
  143. function CompareText(const S1, S2: string): integer;
  144. var
  145. i, count, count1, count2: integer; Chr1, Chr2: byte;
  146. begin
  147. result := 0;
  148. Count1 := Length(S1);
  149. Count2 := Length(S2);
  150. if (Count1>Count2) then
  151. Count := Count2
  152. else
  153. Count := Count1;
  154. i := 0;
  155. while (result=0) and (i<count) do
  156. begin
  157. inc (i);
  158. Chr1 := byte(s1[i]);
  159. Chr2 := byte(s2[i]);
  160. if Chr1 in [97..122] then
  161. dec(Chr1,32);
  162. if Chr2 in [97..122] then
  163. dec(Chr2,32);
  164. result := Chr1 - Chr2;
  165. end ;
  166. if (result = 0) then
  167. result:=(count1-count2);
  168. end;
  169. function SameText(const s1,s2:String):Boolean;
  170. begin
  171. Result:=CompareText(S1,S2)=0;
  172. end;
  173. {==============================================================================}
  174. { Ansi string functions }
  175. { these functions rely on the character set loaded by the OS }
  176. {==============================================================================}
  177. function GenericAnsiUpperCase(const s: string): string;
  178. var
  179. len, i: integer;
  180. begin
  181. len := length(s);
  182. SetLength(result, len);
  183. for i := 1 to len do
  184. result[i] := UpperCaseTable[ord(s[i])];
  185. end;
  186. function GenericAnsiLowerCase(const s: string): string;
  187. var
  188. len, i: integer;
  189. begin
  190. len := length(s);
  191. SetLength(result, len);
  192. for i := 1 to len do
  193. result[i] := LowerCaseTable[ord(s[i])];
  194. end;
  195. function GenericAnsiCompareStr(const S1, S2: string): PtrInt;
  196. Var
  197. I,L1,L2 : SizeInt;
  198. begin
  199. Result:=0;
  200. L1:=Length(S1);
  201. L2:=Length(S2);
  202. I:=1;
  203. While (Result=0) and ((I<=L1) and (I<=L2)) do
  204. begin
  205. Result:=Ord(S1[I])-Ord(S2[I]); //!! Must be replaced by ansi characters !!
  206. Inc(I);
  207. end;
  208. If Result=0 Then
  209. Result:=L1-L2;
  210. end;
  211. function GenericAnsiCompareText(const S1, S2: string): PtrInt;
  212. Var
  213. I,L1,L2 : SizeInt;
  214. begin
  215. Result:=0;
  216. L1:=Length(S1);
  217. L2:=Length(S2);
  218. I:=1;
  219. While (Result=0) and ((I<=L1) and (I<=L2)) do
  220. begin
  221. Result:=Ord(LowerCaseTable[Ord(S1[I])])-Ord(LowerCaseTable[Ord(S2[I])]); //!! Must be replaced by ansi characters !!
  222. Inc(I);
  223. end;
  224. If Result=0 Then
  225. Result:=L1-L2;
  226. end;
  227. function AnsiSameText(const s1,s2:String):Boolean;{$ifdef SYSUTILSINLINE}inline;{$endif}
  228. begin
  229. AnsiSameText:=AnsiCompareText(S1,S2)=0;
  230. end;
  231. function AnsiSameStr(const s1,s2:String):Boolean;{$ifdef SYSUTILSINLINE}inline;{$endif}
  232. begin
  233. AnsiSameStr:=AnsiCompareStr(S1,S2)=0;
  234. end;
  235. function GenericAnsiStrComp(S1, S2: PChar): PtrInt;
  236. begin
  237. Result:=0;
  238. If S1=Nil then
  239. begin
  240. If S2=Nil Then Exit;
  241. result:=-1;
  242. exit;
  243. end;
  244. If S2=Nil then
  245. begin
  246. Result:=1;
  247. exit;
  248. end;
  249. Repeat
  250. Result:=Ord(S1[0])-Ord(S2[0]); //!! Must be replaced by ansi characters !!
  251. Inc(S1);
  252. Inc(S2);
  253. Until (Result<>0) or ((S1[0]=#0) or (S2[0]=#0))
  254. end;
  255. function GenericAnsiStrIComp(S1, S2: PChar): PtrInt;
  256. begin
  257. Result:=0;
  258. If S1=Nil then
  259. begin
  260. If S2=Nil Then Exit;
  261. result:=-1;
  262. exit;
  263. end;
  264. If S2=Nil then
  265. begin
  266. Result:=1;
  267. exit;
  268. end;
  269. Repeat
  270. Result:=Ord(LowerCaseTable[Ord(S1[0])])-Ord(LowerCaseTable[Ord(S2[0])]); //!! Must be replaced by ansi characters !!
  271. Inc(S1);
  272. Inc(S2);
  273. Until (Result<>0) or ((S1[0]=#0) or (S2[0]=#0))
  274. end;
  275. function GenericAnsiStrLComp(S1, S2: PChar; MaxLen: PtrUInt): PtrInt;
  276. Var I : cardinal;
  277. begin
  278. Result:=0;
  279. If MaxLen=0 then exit;
  280. If S1=Nil then
  281. begin
  282. If S2=Nil Then Exit;
  283. result:=-1;
  284. exit;
  285. end;
  286. If S2=Nil then
  287. begin
  288. Result:=1;
  289. exit;
  290. end;
  291. I:=0;
  292. Repeat
  293. Result:=Ord(S1[0])-Ord(S2[0]); //!! Must be replaced by ansi characters !!
  294. Inc(S1);
  295. Inc(S2);
  296. Inc(I);
  297. Until (Result<>0) or ((S1[0]=#0) or (S2[0]=#0)) or (I=MaxLen)
  298. end;
  299. function GenericAnsiStrLIComp(S1, S2: PChar; MaxLen: PtrUInt): PtrInt;
  300. Var I : cardinal;
  301. begin
  302. Result:=0;
  303. If MaxLen=0 then exit;
  304. If S1=Nil then
  305. begin
  306. If S2=Nil Then Exit;
  307. result:=-1;
  308. exit;
  309. end;
  310. If S2=Nil then
  311. begin
  312. Result:=1;
  313. exit;
  314. end;
  315. I:=0;
  316. Repeat
  317. Result:=Ord(LowerCaseTable[Ord(S1[0])])-Ord(LowerCaseTable[Ord(S2[0])]); //!! Must be replaced by ansi characters !!
  318. Inc(S1);
  319. Inc(S2);
  320. Inc(I);
  321. Until (Result<>0) or ((S1[0]=#0) or (S2[0]=#0)) or (I=MaxLen)
  322. end;
  323. function GenericAnsiStrLower(Str: PChar): PChar;
  324. begin
  325. result := Str;
  326. if Str <> Nil then begin
  327. while Str^ <> #0 do begin
  328. Str^ := LowerCaseTable[byte(Str^)];
  329. Str := Str + 1;
  330. end;
  331. end;
  332. end;
  333. function GenericAnsiStrUpper(Str: PChar): PChar;
  334. begin
  335. result := Str;
  336. if Str <> Nil then begin
  337. while Str^ <> #0 do begin
  338. Str^ := UpperCaseTable[byte(Str^)];
  339. Str := Str + 1;
  340. end ;
  341. end ;
  342. end ;
  343. function AnsiLastChar(const S: string): PChar;
  344. begin
  345. //!! No multibyte yet, so we return the last one.
  346. result:=StrEnd(Pchar(S));
  347. Dec(Result);
  348. end ;
  349. function AnsiStrLastChar(Str: PChar): PChar;
  350. begin
  351. //!! No multibyte yet, so we return the last one.
  352. result:=StrEnd(Str);
  353. Dec(Result);
  354. end ;
  355. function AnsiUpperCase(const s: string): string;{$ifdef SYSUTILSINLINE}inline;{$endif}
  356. begin
  357. result:=widestringmanager.UpperAnsiStringProc(s);
  358. end;
  359. function AnsiLowerCase(const s: string): string;{$ifdef SYSUTILSINLINE}inline;{$endif}
  360. begin
  361. result:=widestringmanager.LowerAnsiStringProc(s);
  362. end;
  363. function AnsiCompareStr(const S1, S2: string): integer;{$ifdef SYSUTILSINLINE}inline;{$endif}
  364. begin
  365. result:=widestringmanager.CompareStrAnsiStringProc(s1,s2);
  366. end;
  367. function AnsiCompareText(const S1, S2: string): integer;{$ifdef SYSUTILSINLINE}inline;{$endif}
  368. begin
  369. result:=widestringmanager.CompareTextAnsiStringProc(s1,s2);
  370. end;
  371. function AnsiStrComp(S1, S2: PChar): integer;{$ifdef SYSUTILSINLINE}inline;{$endif}
  372. begin
  373. result:=widestringmanager.StrCompAnsiStringProc(s1,s2);
  374. end;
  375. function AnsiStrIComp(S1, S2: PChar): integer;{$ifdef SYSUTILSINLINE}inline;{$endif}
  376. begin
  377. result:=widestringmanager.StrICompAnsiStringProc(s1,s2);
  378. end;
  379. function AnsiStrLComp(S1, S2: PChar; MaxLen: cardinal): integer;{$ifdef SYSUTILSINLINE}inline;{$endif}
  380. begin
  381. result:=widestringmanager.StrLCompAnsiStringProc(s1,s2,maxlen);
  382. end;
  383. function AnsiStrLIComp(S1, S2: PChar; MaxLen: cardinal): integer;{$ifdef SYSUTILSINLINE}inline;{$endif}
  384. begin
  385. result:=widestringmanager.StrLICompAnsiStringProc(s1,s2,maxlen);
  386. end;
  387. function AnsiStrLower(Str: PChar): PChar;{$ifdef SYSUTILSINLINE}inline;{$endif}
  388. begin
  389. result:=widestringmanager.StrLowerAnsiStringProc(Str);
  390. end;
  391. function AnsiStrUpper(Str: PChar): PChar;{$ifdef SYSUTILSINLINE}inline;{$endif}
  392. begin
  393. result:=widestringmanager.StrUpperAnsiStringProc(Str);
  394. end;
  395. {==============================================================================}
  396. { End of Ansi functions }
  397. {==============================================================================}
  398. { Trim returns a copy of S with blanks characters on the left and right stripped off }
  399. Const WhiteSpace = [#0..' '];
  400. function Trim(const S: string): string;
  401. var Ofs, Len: integer;
  402. begin
  403. len := Length(S);
  404. while (Len>0) and (S[Len] in WhiteSpace) do
  405. dec(Len);
  406. Ofs := 1;
  407. while (Ofs<=Len) and (S[Ofs] in WhiteSpace) do
  408. Inc(Ofs);
  409. result := Copy(S, Ofs, 1 + Len - Ofs);
  410. end ;
  411. { TrimLeft returns a copy of S with all blank characters on the left stripped off }
  412. function TrimLeft(const S: string): string;
  413. var i,l:integer;
  414. begin
  415. l := length(s);
  416. i := 1;
  417. while (i<=l) and (s[i] in whitespace) do
  418. inc(i);
  419. Result := copy(s, i, l);
  420. end ;
  421. { TrimRight returns a copy of S with all blank characters on the right stripped off }
  422. function TrimRight(const S: string): string;
  423. var l:integer;
  424. begin
  425. l := length(s);
  426. while (l>0) and (s[l] in whitespace) do
  427. dec(l);
  428. result := copy(s,1,l);
  429. end ;
  430. { QuotedStr returns S quoted left and right and every single quote in S
  431. replaced by two quotes }
  432. function QuotedStr(const S: string): string;
  433. begin
  434. result := AnsiQuotedStr(s, '''');
  435. end ;
  436. { AnsiQuotedStr returns S quoted left and right by Quote,
  437. and every single occurance of Quote replaced by two }
  438. function AnsiQuotedStr(const S: string; Quote: char): string;
  439. var i, j, count: integer;
  440. begin
  441. result := '' + Quote;
  442. count := length(s);
  443. i := 0;
  444. j := 0;
  445. while i < count do begin
  446. i := i + 1;
  447. if S[i] = Quote then begin
  448. result := result + copy(S, 1 + j, i - j) + Quote;
  449. j := i;
  450. end ;
  451. end ;
  452. if i <> j then
  453. result := result + copy(S, 1 + j, i - j);
  454. result := result + Quote;
  455. end ;
  456. { AnsiExtractQuotedStr returns a copy of Src with quote characters
  457. deleted to the left and right and double occurances
  458. of Quote replaced by a single Quote }
  459. function AnsiExtractQuotedStr(var Src: PChar; Quote: Char): string;
  460. var
  461. P,Q,R: PChar;
  462. begin
  463. P := Src;
  464. Q := StrEnd(P);
  465. result:='';
  466. if P=Q then exit;
  467. if P^<>quote then exit;
  468. inc(p);
  469. setlength(result,(Q-P)+1);
  470. R:=@Result[1];
  471. while P <> Q do
  472. begin
  473. R^:=P^;
  474. inc(R);
  475. if (P^ = Quote) then
  476. begin
  477. P := P + 1;
  478. if (p^ <> Quote) then
  479. begin
  480. dec(R);
  481. break;
  482. end;
  483. end;
  484. P := P + 1;
  485. end ;
  486. src:=p;
  487. SetLength(result, (R-pchar(@Result[1])));
  488. end ;
  489. { AdjustLineBreaks returns S with all CR characters not followed by LF
  490. replaced with CR/LF }
  491. // under Linux all CR characters or CR/LF combinations should be replaced with LF
  492. function AdjustLineBreaks(const S: string): string;
  493. begin
  494. Result:=AdjustLineBreaks(S,DefaultTextLineBreakStyle);
  495. end;
  496. function AdjustLineBreaks(const S: string; Style: TTextLineBreakStyle): string;
  497. var
  498. Source,Dest: PChar;
  499. DestLen: Integer;
  500. I,J,L: Longint;
  501. begin
  502. Source:=Pointer(S);
  503. L:=Length(S);
  504. DestLen:=L;
  505. I:=1;
  506. while (I<=L) do
  507. begin
  508. case S[i] of
  509. #10: if (Style=tlbsCRLF) then
  510. Inc(DestLen);
  511. #13: if (Style=tlbsCRLF) then
  512. if (I<L) and (S[i+1]=#10) then
  513. Inc(I)
  514. else
  515. Inc(DestLen)
  516. else if (I<L) and (S[I+1]=#10) then
  517. Dec(DestLen);
  518. end;
  519. Inc(I);
  520. end;
  521. if (DestLen=L) then
  522. Result:=S
  523. else
  524. begin
  525. SetLength(Result, DestLen);
  526. FillChar(Result[1],DestLen,0);
  527. Dest := Pointer(Result);
  528. J:=0;
  529. I:=0;
  530. While I<L do
  531. case Source[I] of
  532. #10: begin
  533. if Style=tlbsCRLF then
  534. begin
  535. Dest[j]:=#13;
  536. Inc(J);
  537. end;
  538. Dest[J] := #10;
  539. Inc(J);
  540. Inc(I);
  541. end;
  542. #13: begin
  543. if Style=tlbsCRLF then
  544. begin
  545. Dest[j] := #13;
  546. Inc(J);
  547. end;
  548. Dest[j]:=#10;
  549. Inc(J);
  550. Inc(I);
  551. if Source[I]=#10 then
  552. Inc(I);
  553. end;
  554. else
  555. Dest[j]:=Source[i];
  556. Inc(J);
  557. Inc(I);
  558. end;
  559. end;
  560. end;
  561. { IsValidIdent returns true if the first character of Ident is in:
  562. 'A' to 'Z', 'a' to 'z' or '_' and the following characters are
  563. on of: 'A' to 'Z', 'a' to 'z', '0'..'9' or '_' }
  564. function IsValidIdent(const Ident: string): boolean;
  565. var i, len: integer;
  566. begin
  567. result := false;
  568. len := length(Ident);
  569. if len <> 0 then begin
  570. result := Ident[1] in ['A'..'Z', 'a'..'z', '_'];
  571. i := 1;
  572. while (result) and (i < len) do begin
  573. i := i + 1;
  574. result := result and (Ident[i] in ['A'..'Z', 'a'..'z', '0'..'9', '_']);
  575. end ;
  576. end ;
  577. end ;
  578. { IntToStr returns a string representing the value of Value }
  579. function IntToStr(Value: integer): string;
  580. begin
  581. System.Str(Value, result);
  582. end ;
  583. function IntToStr(Value: int64): string;
  584. begin
  585. System.Str(Value, result);
  586. end ;
  587. function IntToStr(Value: QWord): string;
  588. begin
  589. System.Str(Value, result);
  590. end ;
  591. { IntToHex returns a string representing the hexadecimal value of Value }
  592. const
  593. HexDigits: array[0..15] of char = '0123456789ABCDEF';
  594. function IntToHex(Value: integer; Digits: integer): string;
  595. var i: integer;
  596. begin
  597. SetLength(result, digits);
  598. for i := 0 to digits - 1 do
  599. begin
  600. result[digits - i] := HexDigits[value and 15];
  601. value := value shr 4;
  602. end ;
  603. while value <> 0 do begin
  604. result := HexDigits[value and 15] + result;
  605. value := value shr 4;
  606. end;
  607. end ;
  608. function IntToHex(Value: int64; Digits: integer): string;
  609. var i: integer;
  610. begin
  611. SetLength(result, digits);
  612. for i := 0 to digits - 1 do
  613. begin
  614. result[digits - i] := HexDigits[value and 15];
  615. value := value shr 4;
  616. end ;
  617. while value <> 0 do begin
  618. result := HexDigits[value and 15] + result;
  619. value := value shr 4;
  620. end;
  621. end ;
  622. function TryStrToInt(const s: string; var i : integer) : boolean;
  623. var Error : word;
  624. begin
  625. Val(s, i, Error);
  626. TryStrToInt:=Error=0
  627. end;
  628. { StrToInt converts the string S to an integer value,
  629. if S does not represent a valid integer value EConvertError is raised }
  630. function StrToInt(const S: string): integer;
  631. var Error: word;
  632. begin
  633. Val(S, result, Error);
  634. if Error <> 0 then raise EConvertError.createfmt(SInvalidInteger,[S]);
  635. end ;
  636. function StrToInt64(const S: string): int64;
  637. var Error: word;
  638. begin
  639. Val(S, result, Error);
  640. if Error <> 0 then raise EConvertError.createfmt(SInvalidInteger,[S]);
  641. end;
  642. function TryStrToInt64(const s: string; var i : int64) : boolean;
  643. var Error : word;
  644. begin
  645. Val(s, i, Error);
  646. TryStrToInt64:=Error=0
  647. end;
  648. { StrToIntDef converts the string S to an integer value,
  649. Default is returned in case S does not represent a valid integer value }
  650. function StrToIntDef(const S: string; Default: integer): integer;
  651. var Error: word;
  652. begin
  653. Val(S, result, Error);
  654. if Error <> 0 then result := Default;
  655. end ;
  656. { StrToIntDef converts the string S to an integer value,
  657. Default is returned in case S does not represent a valid integer value }
  658. function StrToInt64Def(const S: string; Default: int64): int64;
  659. var Error: word;
  660. begin
  661. Val(S, result, Error);
  662. if Error <> 0 then result := Default;
  663. end ;
  664. { LoadStr returns the string resource Ident. }
  665. function LoadStr(Ident: integer): string;
  666. begin
  667. result:='';
  668. end ;
  669. { FmtLoadStr returns the string resource Ident and formats it accordingly }
  670. function FmtLoadStr(Ident: integer; const Args: array of const): string;
  671. begin
  672. result:='';
  673. end;
  674. Const
  675. feInvalidFormat = 1;
  676. feMissingArgument = 2;
  677. feInvalidArgIndex = 3;
  678. {$ifdef fmtdebug}
  679. Procedure Log (Const S: String);
  680. begin
  681. Writeln (S);
  682. end;
  683. {$endif}
  684. Procedure DoFormatError (ErrCode : Longint);
  685. Var
  686. S : String;
  687. begin
  688. //!! must be changed to contain format string...
  689. S:='';
  690. Case ErrCode of
  691. feInvalidFormat : raise EConvertError.Createfmt(SInvalidFormat,[s]);
  692. feMissingArgument : raise EConvertError.Createfmt(SArgumentMissing,[s]);
  693. feInvalidArgIndex : raise EConvertError.Createfmt(SInvalidArgIndex,[s]);
  694. end;
  695. end;
  696. { we've no templates, but with includes we can simulate this :) }
  697. {$macro on}
  698. {$define INFORMAT}
  699. {$define TFormatString:=ansistring}
  700. {$define TFormatChar:=char}
  701. Function Format (Const Fmt : AnsiString; const Args : Array of const) : AnsiString;
  702. {$i sysformt.inc}
  703. {$undef TFormatString}
  704. {$undef TFormatChar}
  705. {$undef INFORMAT}
  706. {$macro off}
  707. Function FormatBuf (Var Buffer; BufLen : Cardinal;
  708. Const Fmt; fmtLen : Cardinal;
  709. Const Args : Array of const) : Cardinal;
  710. Var S,F : String;
  711. begin
  712. Setlength(F,fmtlen);
  713. if fmtlen > 0 then
  714. Move(fmt,F[1],fmtlen);
  715. S:=Format (F,Args);
  716. If Cardinal(Length(S))<Buflen then
  717. Result:=Length(S)
  718. else
  719. Result:=Buflen;
  720. Move(S[1],Buffer,Result);
  721. end;
  722. Procedure FmtStr(Var Res: String; Const Fmt : String; Const args: Array of const);
  723. begin
  724. Res:=Format(fmt,Args);
  725. end;
  726. Function StrFmt(Buffer,Fmt : PChar; Const args: Array of const) : Pchar;
  727. begin
  728. Buffer[FormatBuf(Buffer^,Maxint,Fmt^,strlen(fmt),args)]:=#0;
  729. Result:=Buffer;
  730. end;
  731. Function StrLFmt(Buffer : PCHar; Maxlen : Cardinal;Fmt : PChar; Const args: Array of const) : Pchar;
  732. begin
  733. Buffer[FormatBuf(Buffer^,MaxLen,Fmt^,strlen(fmt),args)]:=#0;
  734. Result:=Buffer;
  735. end;
  736. Function StrToFloat(Const S: String): Extended;
  737. Begin
  738. If Not TextToFloat(Pchar(S),Result) then
  739. Raise EConvertError.createfmt(SInValidFLoat,[S]);
  740. End;
  741. function StrToFloatDef(const S: string; const Default: Extended): Extended;
  742. begin
  743. if not TextToFloat(PChar(S),Result,fvExtended) then
  744. Result:=Default;
  745. end;
  746. Function TextToFloat(Buffer: PChar; Var Value: Extended): Boolean;
  747. Var
  748. E,P : Integer;
  749. S : String;
  750. Begin
  751. S:=StrPas(Buffer);
  752. P:=Pos(DecimalSeparator,S);
  753. If (P<>0) Then
  754. S[P] := '.';
  755. Val(trim(S),Value,E);
  756. Result:=(E=0);
  757. End;
  758. Function TextToFloat(Buffer: PChar; Var Value; ValueType: TFloatValue): Boolean;
  759. Var
  760. E,P : Integer;
  761. S : String;
  762. Begin
  763. S:=StrPas(Buffer);
  764. P:=Pos(ThousandSeparator,S);
  765. While (P<>0) do
  766. begin
  767. Delete(S,P,1);
  768. P:=Pos(ThousandSeparator,S);
  769. end;
  770. P:=Pos(DecimalSeparator,S);
  771. If (P<>0) Then
  772. S[P] := '.';
  773. case ValueType of
  774. fvCurrency:
  775. Val(S,Currency(Value),E);
  776. fvExtended:
  777. Val(S,Extended(Value),E);
  778. fvDouble:
  779. Val(S,Double(Value),E);
  780. fvSingle:
  781. Val(S,Single(Value),E);
  782. fvComp:
  783. Val(S,Comp(Value),E);
  784. fvReal:
  785. Val(S,Real(Value),E);
  786. end;
  787. Result:=(E=0);
  788. End;
  789. Function TryStrToFloat(Const S : String; Var Value: Single): Boolean;
  790. Begin
  791. Result := TextToFloat(PChar(S), Value, fvSingle);
  792. End;
  793. Function TryStrToFloat(Const S : String; Var Value: Double): Boolean;
  794. Begin
  795. Result := TextToFloat(PChar(S), Value, fvDouble);
  796. End;
  797. {$ifdef FPC_HAS_TYPE_EXTENDED}
  798. Function TryStrToFloat(Const S : String; Var Value: Extended): Boolean;
  799. Begin
  800. Result := TextToFloat(PChar(S), Value);
  801. End;
  802. {$endif FPC_HAS_TYPE_EXTENDED}
  803. Function FloatToStr(Value: Extended): String;
  804. Begin
  805. Result := FloatToStrF(Value, ffGeneral, 15, 0);
  806. End;
  807. Function FloatToText(Buffer: PChar; Value: Extended; format: TFloatFormat; Precision, Digits: Integer): Longint;
  808. Var
  809. Tmp: String[40];
  810. Begin
  811. Tmp := FloatToStrF(Value, format, Precision, Digits);
  812. Result := Length(Tmp);
  813. Move(Tmp[1], Buffer[0], Result);
  814. End;
  815. Function FloatToStrF(Value: Extended; format: TFloatFormat; Precision, Digits: Integer): String;
  816. Var
  817. P: Integer;
  818. Negative, TooSmall, TooLarge: Boolean;
  819. Begin
  820. Case format Of
  821. ffGeneral:
  822. Begin
  823. If (Precision = -1) Or (Precision > 15) Then Precision := 15;
  824. TooSmall := (Abs(Value) < 0.00001) and (Value>0.0);
  825. If Not TooSmall Then
  826. Begin
  827. Str(Value:digits:precision, Result);
  828. P := Pos('.', Result);
  829. if P<>0 then
  830. Result[P] := DecimalSeparator;
  831. TooLarge := P > Precision + 1;
  832. End;
  833. If TooSmall Or TooLarge Then
  834. begin
  835. Result := FloatToStrF(Value, ffExponent, Precision, Digits);
  836. // Strip unneeded zeroes.
  837. P:=Pos('E',result)-1;
  838. If P<>-1 then
  839. While (P>1) and (Result[P]='0') do
  840. begin
  841. system.Delete(Result,P,1);
  842. Dec(P);
  843. end;
  844. end
  845. else if (P<>0) then // we have a decimalseparator
  846. begin
  847. P := Length(Result);
  848. While (P>0) and (Result[P] = '0') Do
  849. Dec(P);
  850. If (P>0) and (Result[P]=DecimalSeparator) Then
  851. Dec(P);
  852. SetLength(Result, P);
  853. end;
  854. End;
  855. ffExponent:
  856. Begin
  857. If (Precision = -1) Or (Precision > 15) Then Precision := 15;
  858. Str(Value:Precision + 8, Result);
  859. Result[3] := DecimalSeparator;
  860. P:=4;
  861. While (P>0) and (Digits < P) And (Result[Precision + 5] = '0') do
  862. Begin
  863. If P<>1 then
  864. system.Delete(Result, Precision + 5, 1)
  865. else
  866. system.Delete(Result, Precision + 3, 3);
  867. Dec(P);
  868. end;
  869. If Result[1] = ' ' Then
  870. System.Delete(Result, 1, 1);
  871. End;
  872. ffFixed:
  873. Begin
  874. If Digits = -1 Then Digits := 2
  875. Else If Digits > 18 Then Digits := 18;
  876. Str(Value:0:Digits, Result);
  877. If Result[1] = ' ' Then
  878. System.Delete(Result, 1, 1);
  879. P := Pos('.', Result);
  880. If P <> 0 Then Result[P] := DecimalSeparator;
  881. End;
  882. ffNumber:
  883. Begin
  884. If Digits = -1 Then Digits := 2
  885. Else If Digits > 15 Then Digits := 15;
  886. Str(Value:0:Digits, Result);
  887. If Result[1] = ' ' Then System.Delete(Result, 1, 1);
  888. P := Pos('.', Result);
  889. If P <> 0 Then
  890. Result[P] := DecimalSeparator
  891. else
  892. P := Length(Result)+1;
  893. Dec(P, 3);
  894. While (P > 1) Do
  895. Begin
  896. If Result[P - 1] <> '-' Then Insert(ThousandSeparator, Result, P);
  897. Dec(P, 3);
  898. End;
  899. End;
  900. ffCurrency:
  901. Begin
  902. If Value < 0 Then
  903. Begin
  904. Negative := True;
  905. Value := -Value;
  906. End
  907. Else Negative := False;
  908. If Digits = -1 Then Digits := CurrencyDecimals
  909. Else If Digits > 18 Then Digits := 18;
  910. Str(Value:0:Digits, Result);
  911. If Result[1] = ' ' Then System.Delete(Result, 1, 1);
  912. P := Pos('.', Result);
  913. If P <> 0 Then Result[P] := DecimalSeparator;
  914. Dec(P, 3);
  915. While (P > 1) Do
  916. Begin
  917. Insert(ThousandSeparator, Result, P);
  918. Dec(P, 3);
  919. End;
  920. If Not Negative Then
  921. Begin
  922. Case CurrencyFormat Of
  923. 0: Result := CurrencyString + Result;
  924. 1: Result := Result + CurrencyString;
  925. 2: Result := CurrencyString + ' ' + Result;
  926. 3: Result := Result + ' ' + CurrencyString;
  927. End
  928. End
  929. Else
  930. Begin
  931. Case NegCurrFormat Of
  932. 0: Result := '(' + CurrencyString + Result + ')';
  933. 1: Result := '-' + CurrencyString + Result;
  934. 2: Result := CurrencyString + '-' + Result;
  935. 3: Result := CurrencyString + Result + '-';
  936. 4: Result := '(' + Result + CurrencyString + ')';
  937. 5: Result := '-' + Result + CurrencyString;
  938. 6: Result := Result + '-' + CurrencyString;
  939. 7: Result := Result + CurrencyString + '-';
  940. 8: Result := '-' + Result + ' ' + CurrencyString;
  941. 9: Result := '-' + CurrencyString + ' ' + Result;
  942. 10: Result := CurrencyString + ' ' + Result + '-';
  943. End;
  944. End;
  945. End;
  946. End;
  947. End;
  948. Function FloatToDateTime (Const Value : Extended) : TDateTime;
  949. begin
  950. If (Value<MinDateTime) or (Value>MaxDateTime) then
  951. Raise EConvertError.CreateFmt (SInvalidDateTime,[Value]);
  952. Result:=Value;
  953. end;
  954. function TryFloatToCurr(const Value: Extended; var AResult: Currency): Boolean;
  955. begin
  956. Result:=(Value>=MinCurrency) and (Value<=MaxCurrency);
  957. if Result then
  958. AResult := Value;
  959. end;
  960. function FloatToCurr(const Value: Extended): Currency;
  961. begin
  962. if not TryFloatToCurr(Value, Result) then
  963. Raise EConvertError.CreateFmt(SInvalidCurrency, [FloatToStr(Value)]);
  964. end;
  965. Function CurrToStr(Value: Currency): string;
  966. begin
  967. Result:=FloatToStrF(Value,ffNumber,15,2);
  968. end;
  969. function StrToCurr(const S: string): Currency;
  970. begin
  971. if not TextToFloat(PChar(S), Result, fvCurrency) then
  972. Raise EConvertError.createfmt(SInValidFLoat,[S]);
  973. end;
  974. Function TryStrToCurr(Const S : String; Var Value: Currency): Boolean;
  975. Begin
  976. Result := TextToFloat(PChar(S), Value, fvCurrency);
  977. End;
  978. function StrToCurrDef(const S: string; Default : Currency): Currency;
  979. begin
  980. if not TextToFloat(PChar(S), Result, fvCurrency) then
  981. Result:=Default;
  982. end;
  983. function StrToBool(const S: string): Boolean;
  984. Var
  985. Temp : String;
  986. D : Double;
  987. Code: word;
  988. begin
  989. Temp:=upcase(S);
  990. Val(temp,D,code);
  991. If Code=0 then
  992. Result:=(D<>0.0)
  993. else If Temp='TRUE' then
  994. result:=true
  995. else if Temp='FALSE' then
  996. result:=false
  997. else
  998. Raise EConvertError.CreateFmt(SInvalidBoolean,[S]);
  999. end;
  1000. function BoolToStr(B: Boolean): string;
  1001. begin
  1002. If B then
  1003. Result:='TRUE'
  1004. else
  1005. Result:='FALSE';
  1006. end;
  1007. Function FloatToTextFmt(Buffer: PChar; Value: Extended; format: PChar): Integer;
  1008. Var
  1009. Digits: String[40]; { String Of Digits }
  1010. Exponent: String[8]; { Exponent strin }
  1011. FmtStart, FmtStop: PChar; { Start And End Of relevant part }
  1012. { Of format String }
  1013. ExpFmt, ExpSize: Integer; { Type And Length Of }
  1014. { exponential format chosen }
  1015. Placehold: Array[1..4] Of Integer; { Number Of placeholders In All }
  1016. { four Sections }
  1017. thousand: Boolean; { thousand separators? }
  1018. UnexpectedDigits: Integer; { Number Of unexpected Digits that }
  1019. { have To be inserted before the }
  1020. { First placeholder. }
  1021. DigitExponent: Integer; { Exponent Of First digit In }
  1022. { Digits Array. }
  1023. { Find end of format section starting at P. False, if empty }
  1024. Function GetSectionEnd(Var P: PChar): Boolean;
  1025. Var
  1026. C: Char;
  1027. SQ, DQ: Boolean;
  1028. Begin
  1029. Result := False;
  1030. SQ := False;
  1031. DQ := False;
  1032. C := P[0];
  1033. While (C<>#0) And ((C<>';') Or SQ Or DQ) Do
  1034. Begin
  1035. Result := True;
  1036. Case C Of
  1037. #34: If Not SQ Then DQ := Not DQ;
  1038. #39: If Not DQ Then SQ := Not SQ;
  1039. End;
  1040. Inc(P);
  1041. C := P[0];
  1042. End;
  1043. End;
  1044. { Find start and end of format section to apply. If section doesn't exist,
  1045. use section 1. If section 2 is used, the sign of value is ignored. }
  1046. Procedure GetSectionRange(section: Integer);
  1047. Var
  1048. Sec: Array[1..3] Of PChar;
  1049. SecOk: Array[1..3] Of Boolean;
  1050. Begin
  1051. Sec[1] := format;
  1052. SecOk[1] := GetSectionEnd(Sec[1]);
  1053. If section > 1 Then
  1054. Begin
  1055. Sec[2] := Sec[1];
  1056. If Sec[2][0] <> #0 Then
  1057. Inc(Sec[2]);
  1058. SecOk[2] := GetSectionEnd(Sec[2]);
  1059. If section > 2 Then
  1060. Begin
  1061. Sec[3] := Sec[2];
  1062. If Sec[3][0] <> #0 Then
  1063. Inc(Sec[3]);
  1064. SecOk[3] := GetSectionEnd(Sec[3]);
  1065. End;
  1066. End;
  1067. If Not SecOk[1] Then
  1068. FmtStart := Nil
  1069. Else
  1070. Begin
  1071. If Not SecOk[section] Then
  1072. section := 1
  1073. Else If section = 2 Then
  1074. Value := -Value; { Remove sign }
  1075. If section = 1 Then FmtStart := format Else
  1076. Begin
  1077. FmtStart := Sec[section - 1];
  1078. Inc(FmtStart);
  1079. End;
  1080. FmtStop := Sec[section];
  1081. End;
  1082. End;
  1083. { Find format section ranging from FmtStart to FmtStop. }
  1084. Procedure GetFormatOptions;
  1085. Var
  1086. Fmt: PChar;
  1087. SQ, DQ: Boolean;
  1088. area: Integer;
  1089. Begin
  1090. SQ := False;
  1091. DQ := False;
  1092. Fmt := FmtStart;
  1093. ExpFmt := 0;
  1094. area := 1;
  1095. thousand := False;
  1096. Placehold[1] := 0;
  1097. Placehold[2] := 0;
  1098. Placehold[3] := 0;
  1099. Placehold[4] := 0;
  1100. While Fmt < FmtStop Do
  1101. Begin
  1102. Case Fmt[0] Of
  1103. #34:
  1104. Begin
  1105. If Not SQ Then
  1106. DQ := Not DQ;
  1107. Inc(Fmt);
  1108. End;
  1109. #39:
  1110. Begin
  1111. If Not DQ Then
  1112. SQ := Not SQ;
  1113. Inc(Fmt);
  1114. End;
  1115. Else
  1116. { This was 'if not SQ or DQ'. Looked wrong... }
  1117. If Not SQ Or DQ Then
  1118. Begin
  1119. Case Fmt[0] Of
  1120. '0':
  1121. Begin
  1122. Case area Of
  1123. 1:
  1124. area := 2;
  1125. 4:
  1126. Begin
  1127. area := 3;
  1128. Inc(Placehold[3], Placehold[4]);
  1129. Placehold[4] := 0;
  1130. End;
  1131. End;
  1132. Inc(Placehold[area]);
  1133. Inc(Fmt);
  1134. End;
  1135. '#':
  1136. Begin
  1137. If area=3 Then
  1138. area:=4;
  1139. Inc(Placehold[area]);
  1140. Inc(Fmt);
  1141. End;
  1142. '.':
  1143. Begin
  1144. If area<3 Then
  1145. area:=3;
  1146. Inc(Fmt);
  1147. End;
  1148. ',':
  1149. Begin
  1150. thousand := True;
  1151. Inc(Fmt);
  1152. End;
  1153. 'e', 'E':
  1154. If ExpFmt = 0 Then
  1155. Begin
  1156. If (Fmt[0]='E') Then
  1157. ExpFmt:=1
  1158. Else
  1159. ExpFmt := 3;
  1160. Inc(Fmt);
  1161. If (Fmt<FmtStop) Then
  1162. Begin
  1163. Case Fmt[0] Of
  1164. '+':
  1165. Begin
  1166. End;
  1167. '-':
  1168. Inc(ExpFmt);
  1169. Else
  1170. ExpFmt := 0;
  1171. End;
  1172. If ExpFmt <> 0 Then
  1173. Begin
  1174. Inc(Fmt);
  1175. ExpSize := 0;
  1176. While (Fmt<FmtStop) And
  1177. (ExpSize<4) And
  1178. (Fmt[0] In ['0'..'9']) Do
  1179. Begin
  1180. Inc(ExpSize);
  1181. Inc(Fmt);
  1182. End;
  1183. End;
  1184. End;
  1185. End
  1186. Else
  1187. Inc(Fmt);
  1188. Else { Case }
  1189. Inc(Fmt);
  1190. End; { Case }
  1191. End; { Begin }
  1192. End; { Case }
  1193. End; { While .. Begin }
  1194. End;
  1195. Procedure FloatToStr;
  1196. Var
  1197. I, J, Exp, Width, Decimals, DecimalPoint, len: Integer;
  1198. Begin
  1199. If ExpFmt = 0 Then
  1200. Begin
  1201. { Fixpoint }
  1202. Decimals:=Placehold[3]+Placehold[4];
  1203. Width:=Placehold[1]+Placehold[2]+Decimals;
  1204. If (Decimals=0) Then
  1205. Str(Value:Width:0,Digits)
  1206. Else
  1207. Str(Value:Width+1:Decimals,Digits);
  1208. len:=Length(Digits);
  1209. { Find the decimal point }
  1210. If (Decimals=0) Then
  1211. DecimalPoint:=len+1
  1212. Else
  1213. DecimalPoint:=len-Decimals;
  1214. { If value is very small, and no decimal places
  1215. are desired, remove the leading 0. }
  1216. If (Abs(Value) < 1) And (Placehold[2] = 0) Then
  1217. Begin
  1218. If (Placehold[1]=0) Then
  1219. Delete(Digits,DecimalPoint-1,1)
  1220. Else
  1221. Digits[DecimalPoint-1]:=' ';
  1222. End;
  1223. { Convert optional zeroes to spaces. }
  1224. I:=len;
  1225. J:=DecimalPoint+Placehold[3];
  1226. While (I>J) And (Digits[I]='0') Do
  1227. Begin
  1228. Digits[I] := ' ';
  1229. Dec(I);
  1230. End;
  1231. { If integer value and no obligatory decimal
  1232. places, remove decimal point. }
  1233. If (DecimalPoint < len) And (Digits[DecimalPoint + 1] = ' ') Then
  1234. Digits[DecimalPoint] := ' ';
  1235. { Convert spaces left from obligatory decimal point to zeroes. }
  1236. I:=DecimalPoint-Placehold[2];
  1237. While (I<DecimalPoint) And (Digits[I]=' ') Do
  1238. Begin
  1239. Digits[I] := '0';
  1240. Inc(I);
  1241. End;
  1242. Exp := 0;
  1243. End
  1244. Else
  1245. Begin
  1246. { Scientific: exactly <Width> Digits With <Precision> Decimals
  1247. And adjusted Exponent. }
  1248. If Placehold[1]+Placehold[2]=0 Then
  1249. Placehold[1]:=1;
  1250. Decimals := Placehold[3] + Placehold[4];
  1251. Width:=Placehold[1]+Placehold[2]+Decimals;
  1252. Str(Value:Width+8,Digits);
  1253. { Find and cut out exponent. Always the
  1254. last 6 characters in the string.
  1255. -> 0000E+0000 }
  1256. I:=Length(Digits)-5;
  1257. Val(Copy(Digits,I+1,5),Exp,J);
  1258. Exp:=Exp+1-(Placehold[1]+Placehold[2]);
  1259. Delete(Digits, I, 6);
  1260. { Str() always returns at least one digit after the decimal point.
  1261. If we don't want it, we have to remove it. }
  1262. If (Decimals=0) And (Placehold[1]+Placehold[2]<= 1) Then
  1263. Begin
  1264. If (Digits[4]>='5') Then
  1265. Begin
  1266. Inc(Digits[2]);
  1267. If (Digits[2]>'9') Then
  1268. Begin
  1269. Digits[2] := '1';
  1270. Inc(Exp);
  1271. End;
  1272. End;
  1273. Delete(Digits, 3, 2);
  1274. DecimalPoint := Length(Digits) + 1;
  1275. End
  1276. Else
  1277. Begin
  1278. { Move decimal point at the desired position }
  1279. Delete(Digits, 3, 1);
  1280. DecimalPoint:=2+Placehold[1]+Placehold[2];
  1281. If (Decimals<>0) Then
  1282. Insert('.',Digits,DecimalPoint);
  1283. End;
  1284. { Convert optional zeroes to spaces. }
  1285. I := Length(Digits);
  1286. J := DecimalPoint + Placehold[3];
  1287. While (I > J) And (Digits[I] = '0') Do
  1288. Begin
  1289. Digits[I] := ' ';
  1290. Dec(I);
  1291. End;
  1292. { If integer number and no obligatory decimal paces, remove decimal point }
  1293. If (DecimalPoint<Length(Digits)) And
  1294. (Digits[DecimalPoint+1]=' ') Then
  1295. Digits[DecimalPoint]:=' ';
  1296. If (Digits[1]=' ') Then
  1297. Begin
  1298. Delete(Digits, 1, 1);
  1299. Dec(DecimalPoint);
  1300. End;
  1301. { Calculate exponent string }
  1302. Str(Abs(Exp), Exponent);
  1303. While Length(Exponent)<ExpSize Do
  1304. Insert('0',Exponent,1);
  1305. If Exp >= 0 Then
  1306. Begin
  1307. If (ExpFmt In [1,3]) Then
  1308. Insert('+', Exponent, 1);
  1309. End
  1310. Else
  1311. Insert('-',Exponent,1);
  1312. If (ExpFmt<3) Then
  1313. Insert('E',Exponent,1)
  1314. Else
  1315. Insert('e',Exponent,1);
  1316. End;
  1317. DigitExponent:=DecimalPoint-2;
  1318. If (Digits[1]='-') Then
  1319. Dec(DigitExponent);
  1320. UnexpectedDigits:=DecimalPoint-1-(Placehold[1]+Placehold[2]);
  1321. End;
  1322. Function PutResult: LongInt;
  1323. Var
  1324. SQ, DQ: Boolean;
  1325. Fmt, Buf: PChar;
  1326. Dig, N: Integer;
  1327. Begin
  1328. SQ := False;
  1329. DQ := False;
  1330. Fmt := FmtStart;
  1331. Buf := Buffer;
  1332. Dig := 1;
  1333. While (Fmt<FmtStop) Do
  1334. Begin
  1335. //Write(Fmt[0]);
  1336. Case Fmt[0] Of
  1337. #34:
  1338. Begin
  1339. If Not SQ Then
  1340. DQ := Not DQ;
  1341. Inc(Fmt);
  1342. End;
  1343. #39:
  1344. Begin
  1345. If Not DQ Then
  1346. SQ := Not SQ;
  1347. Inc(Fmt);
  1348. End;
  1349. Else
  1350. If Not (SQ Or DQ) Then
  1351. Begin
  1352. Case Fmt[0] Of
  1353. '0', '#', '.':
  1354. Begin
  1355. If (Dig=1) And (UnexpectedDigits>0) Then
  1356. Begin
  1357. { Everything unexpected is written before the first digit }
  1358. For N := 1 To UnexpectedDigits Do
  1359. Begin
  1360. Buf[0] := Digits[N];
  1361. Inc(Buf);
  1362. If thousand And (Digits[N]<>'-') Then
  1363. Begin
  1364. If (DigitExponent Mod 3 = 0) And (DigitExponent>0) Then
  1365. Begin
  1366. Buf[0] := ThousandSeparator;
  1367. Inc(Buf);
  1368. End;
  1369. Dec(DigitExponent);
  1370. End;
  1371. End;
  1372. Inc(Dig, UnexpectedDigits);
  1373. End;
  1374. If (Digits[Dig]<>' ') Then
  1375. Begin
  1376. If (Digits[Dig]='.') Then
  1377. Buf[0] := DecimalSeparator
  1378. Else
  1379. Buf[0] := Digits[Dig];
  1380. Inc(Buf);
  1381. If thousand And (DigitExponent Mod 3 = 0) And (DigitExponent > 0) Then
  1382. Begin
  1383. Buf[0] := ThousandSeparator;
  1384. Inc(Buf);
  1385. End;
  1386. End;
  1387. Inc(Dig);
  1388. Dec(DigitExponent);
  1389. Inc(Fmt);
  1390. End;
  1391. 'e', 'E':
  1392. Begin
  1393. If ExpFmt <> 0 Then
  1394. Begin
  1395. Inc(Fmt);
  1396. If Fmt < FmtStop Then
  1397. Begin
  1398. If Fmt[0] In ['+', '-'] Then
  1399. Begin
  1400. Inc(Fmt, ExpSize);
  1401. For N:=1 To Length(Exponent) Do
  1402. Buf[N-1] := Exponent[N];
  1403. Inc(Buf,Length(Exponent));
  1404. ExpFmt:=0;
  1405. End;
  1406. Inc(Fmt);
  1407. End;
  1408. End
  1409. Else
  1410. Begin
  1411. { No legal exponential format.
  1412. Simply write the 'E' to the result. }
  1413. Buf[0] := Fmt[0];
  1414. Inc(Buf);
  1415. Inc(Fmt);
  1416. End;
  1417. End;
  1418. Else { Case }
  1419. { Usual character }
  1420. If (Fmt[0]<>',') Then
  1421. Begin
  1422. Buf[0] := Fmt[0];
  1423. Inc(Buf);
  1424. End;
  1425. Inc(Fmt);
  1426. End; { Case }
  1427. End
  1428. Else { IF }
  1429. Begin
  1430. { Character inside single or double quotes }
  1431. Buf[0] := Fmt[0];
  1432. Inc(Buf);
  1433. Inc(Fmt);
  1434. End;
  1435. End; { Case }
  1436. End; { While .. Begin }
  1437. Result:=PtrInt(Buf)-PtrInt(Buffer);
  1438. End;
  1439. Begin
  1440. If (Value>0) Then
  1441. GetSectionRange(1)
  1442. Else If (Value<0) Then
  1443. GetSectionRange(2)
  1444. Else
  1445. GetSectionRange(3);
  1446. If FmtStart = Nil Then
  1447. Begin
  1448. Result := FloatToText(Buffer, Value, ffGeneral, 15, 4);
  1449. End
  1450. Else
  1451. Begin
  1452. GetFormatOptions;
  1453. If (ExpFmt = 0) And (Abs(Value) >= 1E18) Then
  1454. Result := FloatToText(Buffer, Value, ffGeneral, 15, 4)
  1455. Else
  1456. Begin
  1457. FloatToStr;
  1458. Result := PutResult;
  1459. End;
  1460. End;
  1461. End;
  1462. Procedure FloatToDecimal(Var Result: TFloatRec; Value: Extended; Precision, Decimals : integer);
  1463. Var
  1464. Buffer: String[24];
  1465. Error, N: Integer;
  1466. Begin
  1467. Str(Value:23, Buffer);
  1468. Result.Negative := (Buffer[1] = '-');
  1469. Val(Copy(Buffer, 19, 5), Result.Exponent, Error);
  1470. Inc(Result. Exponent);
  1471. Result.Digits[0] := Buffer[2];
  1472. Move(Buffer[4], Result.Digits[1], 14);
  1473. If Decimals + Result.Exponent < Precision Then
  1474. N := Decimals + Result.Exponent
  1475. Else
  1476. N := Precision;
  1477. If N > 15 Then
  1478. N := 15;
  1479. If N = 0 Then
  1480. Begin
  1481. If Result.Digits[0] >= '5' Then
  1482. Begin
  1483. Result.Digits[0] := '1';
  1484. Result.Digits[1] := #0;
  1485. Inc(Result.Exponent);
  1486. End
  1487. Else
  1488. Result.Digits[0] := #0;
  1489. End
  1490. Else If N > 0 Then
  1491. Begin
  1492. If Result.Digits[N] >= '5' Then
  1493. Begin
  1494. Repeat
  1495. Result.Digits[N] := #0;
  1496. Dec(N);
  1497. Inc(Result.Digits[N]);
  1498. Until (N = 0) Or (Result.Digits[N] < ':');
  1499. If Result.Digits[0] = ':' Then
  1500. Begin
  1501. Result.Digits[0] := '1';
  1502. Inc(Result.Exponent);
  1503. End;
  1504. End
  1505. Else
  1506. Begin
  1507. Result.Digits[N] := '0';
  1508. While (Result.Digits[N] = '0') And (N > -1) Do
  1509. Begin
  1510. Result.Digits[N] := #0;
  1511. Dec(N);
  1512. End;
  1513. End;
  1514. End
  1515. Else
  1516. Result.Digits[0] := #0;
  1517. If Result.Digits[0] = #0 Then
  1518. Begin
  1519. Result.Exponent := 0;
  1520. Result.Negative := False;
  1521. End;
  1522. End;
  1523. Function FormatFloat(Const format: String; Value: Extended): String;
  1524. Var
  1525. buf : Array[0..1024] of char;
  1526. Begin
  1527. Buf[FloatToTextFmt(@Buf[0],Value,Pchar(Format))]:=#0;
  1528. Result:=StrPas(@Buf);
  1529. End;
  1530. function FormatCurr(const Format: string; Value: Currency): string;
  1531. begin
  1532. Result := FormatFloat(Format, Value);
  1533. end;
  1534. {==============================================================================}
  1535. { extra functions }
  1536. {==============================================================================}
  1537. { LeftStr returns Count left-most characters from S }
  1538. function LeftStr(const S: string; Count: integer): string;
  1539. begin
  1540. result := Copy(S, 1, Count);
  1541. end ;
  1542. { RightStr returns Count right-most characters from S }
  1543. function RightStr(const S: string; Count: integer): string;
  1544. begin
  1545. If Count>Length(S) then
  1546. Count:=Length(S);
  1547. result := Copy(S, 1 + Length(S) - Count, Count);
  1548. end;
  1549. { BCDToInt converts the BCD value Value to an integer }
  1550. function BCDToInt(Value: integer): integer;
  1551. var i, j: integer;
  1552. begin
  1553. result := 0;
  1554. j := 1;
  1555. for i := 0 to SizeOf(Value) shr 1 - 1 do begin
  1556. result := result + j * (Value and 15);
  1557. j := j * 10;
  1558. Value := Value shr 4;
  1559. end ;
  1560. end ;
  1561. Function LastDelimiter(const Delimiters, S: string): Integer;
  1562. begin
  1563. Result:=Length(S);
  1564. While (Result>0) and (Pos(S[Result],Delimiters)=0) do
  1565. Dec(Result);
  1566. end;
  1567. Function StringReplace(const S, OldPattern, NewPattern: string; Flags: TReplaceFlags): string;
  1568. var
  1569. Srch,OldP,RemS: string; // Srch and Oldp can contain uppercase versions of S,OldPattern
  1570. P : Integer;
  1571. begin
  1572. Srch:=S;
  1573. OldP:=OldPattern;
  1574. if rfIgnoreCase in Flags then
  1575. begin
  1576. Srch:=UpperCase(Srch);
  1577. OldP:=UpperCase(OldP);
  1578. end;
  1579. RemS:=S;
  1580. Result:='';
  1581. while (Length(Srch)<>0) do
  1582. begin
  1583. P:=Pos(OldP, Srch);
  1584. if P=0 then
  1585. begin
  1586. Result:=Result+RemS;
  1587. Srch:='';
  1588. end
  1589. else
  1590. begin
  1591. Result:=Result+Copy(RemS,1,P-1)+NewPattern;
  1592. P:=P+Length(OldP);
  1593. RemS:=Copy(RemS,P,Length(RemS)-P+1);
  1594. if not (rfReplaceAll in Flags) then
  1595. begin
  1596. Result:=Result+RemS;
  1597. Srch:='';
  1598. end
  1599. else
  1600. Srch:=Copy(Srch,P,Length(Srch)-P+1);
  1601. end;
  1602. end;
  1603. end;
  1604. Function IsDelimiter(const Delimiters, S: string; Index: Integer): Boolean;
  1605. begin
  1606. Result:=False;
  1607. If (Index>0) and (Index<=Length(S)) then
  1608. Result:=Pos(S[Index],Delimiters)<>0; // Note we don't do MBCS yet
  1609. end;
  1610. Function ByteToCharLen(const S: string; MaxLen: Integer): Integer;
  1611. begin
  1612. Result:=Length(S);
  1613. If Result>MaxLen then
  1614. Result:=MaxLen;
  1615. end;
  1616. Function ByteToCharIndex(const S: string; Index: Integer): Integer;
  1617. begin
  1618. Result:=Index;
  1619. end;
  1620. Function CharToByteLen(const S: string; MaxLen: Integer): Integer;
  1621. begin
  1622. Result:=Length(S);
  1623. If Result>MaxLen then
  1624. Result:=MaxLen;
  1625. end;
  1626. Function CharToByteIndex(const S: string; Index: Integer): Integer;
  1627. begin
  1628. Result:=Index;
  1629. end;
  1630. Function ByteType(const S: string; Index: Integer): TMbcsByteType;
  1631. begin
  1632. Result:=mbSingleByte;
  1633. end;
  1634. Function StrByteType(Str: PChar; Index: Cardinal): TMbcsByteType;
  1635. begin
  1636. Result:=mbSingleByte;
  1637. end;
  1638. Function StrCharLength(const Str: PChar): Integer;
  1639. begin
  1640. result:=widestringmanager.CharLengthPCharProc(Str);
  1641. end;
  1642. Function FindCmdLineSwitch(const Switch: string; const Chars: TSysCharSet;IgnoreCase: Boolean): Boolean;
  1643. Var
  1644. I,L : Integer;
  1645. S,T : String;
  1646. begin
  1647. Result:=False;
  1648. S:=Switch;
  1649. If IgnoreCase then
  1650. S:=UpperCase(S);
  1651. I:=ParamCount;
  1652. While (Not Result) and (I>0) do
  1653. begin
  1654. L:=Length(Paramstr(I));
  1655. If (L>0) and (ParamStr(I)[1] in Chars) then
  1656. begin
  1657. T:=Copy(ParamStr(I),2,L-1);
  1658. If IgnoreCase then
  1659. T:=UpperCase(T);
  1660. Result:=S=T;
  1661. end;
  1662. Dec(i);
  1663. end;
  1664. end;
  1665. Function FindCmdLineSwitch(const Switch: string; IgnoreCase: Boolean): Boolean;
  1666. begin
  1667. Result:=FindCmdLineSwitch(Switch,SwitchChars,IgnoreCase);
  1668. end;
  1669. Function FindCmdLineSwitch(const Switch: string): Boolean;
  1670. begin
  1671. Result:=FindCmdLineSwitch(Switch,SwitchChars,False);
  1672. end;
  1673. function WrapText(const Line, BreakStr: string; const BreakChars: TSysCharSet; MaxCol: Integer): string;
  1674. const
  1675. Quotes = ['''', '"'];
  1676. Var
  1677. L : String;
  1678. C,LQ,BC : Char;
  1679. P,BLen,Len : Integer;
  1680. HB,IBC : Boolean;
  1681. begin
  1682. Result:='';
  1683. L:=Line;
  1684. Blen:=Length(BreakStr);
  1685. If (BLen>0) then
  1686. BC:=BreakStr[1]
  1687. else
  1688. BC:=#0;
  1689. Len:=Length(L);
  1690. While (Len>0) do
  1691. begin
  1692. P:=1;
  1693. LQ:=#0;
  1694. HB:=False;
  1695. IBC:=False;
  1696. While ((P<=Len) and ((P<=MaxCol) or not IBC)) and ((LQ<>#0) or Not HB) do
  1697. begin
  1698. C:=L[P];
  1699. If (C=LQ) then
  1700. LQ:=#0
  1701. else If (C in Quotes) then
  1702. LQ:=C;
  1703. If (LQ<>#0) then
  1704. Inc(P)
  1705. else
  1706. begin
  1707. HB:=((C=BC) and (BreakStr=Copy(L,P,BLen)));
  1708. If HB then
  1709. Inc(P,Blen)
  1710. else
  1711. begin
  1712. If (P>MaxCol) then
  1713. IBC:=C in BreakChars;
  1714. Inc(P);
  1715. end;
  1716. end;
  1717. // Writeln('"',C,'" : IBC : ',IBC,' HB : ',HB,' LQ : ',LQ,' P>MaxCol : ',P>MaxCol);
  1718. end;
  1719. Result:=Result+Copy(L,1,P-1);
  1720. If Not HB then
  1721. Result:=Result+BreakStr;
  1722. Delete(L,1,P-1);
  1723. Len:=Length(L);
  1724. end;
  1725. end;
  1726. function WrapText(const Line: string; MaxCol: Integer): string;
  1727. begin
  1728. Result:=WrapText(Line,sLineBreak, [' ', '-', #9], MaxCol);
  1729. end;
  1730. {
  1731. Case Translation Tables
  1732. Can be used in internationalization support.
  1733. Although these tables can be obtained through system calls
  1734. it is better to not use those, since most implementation are not 100%
  1735. WARNING:
  1736. before modifying a translation table make sure that the current codepage
  1737. of the OS corresponds to the one you make changes to
  1738. }
  1739. const
  1740. { upper case translation table for character set 850 }
  1741. CP850UCT: array[128..255] of char =
  1742. ('€', 'š', '�', '¶', 'Ž', '¶', '�', '€', 'Ò', 'Ó', 'Ô', 'Ø', '×', 'Þ', 'Ž', '�',
  1743. '�', '’', '’', 'â', '™', 'ã', 'ê', 'ë', 'Y', '™', 'š', '�', 'œ', '�', 'ž', 'Ÿ',
  1744. 'µ', 'Ö', 'à', 'é', '¥', '¥', '¦', '§', '¨', '©', 'ª', '«', '¬', '­', '®', '¯',
  1745. '°', '±', '²', '³', '´', 'µ', '¶', '·', '¸', '¹', 'º', '»', '¼', '½', '¾', '¿',
  1746. 'À', 'Á', 'Â', 'Ã', 'Ä', 'Å', 'Ç', 'Ç', 'È', 'É', 'Ê', 'Ë', 'Ì', 'Í', 'Î', 'Ï',
  1747. 'Ð', 'Ñ', 'Ò', 'Ó', 'Ô', 'Õ', 'Ö', '×', 'Ø', 'Ù', 'Ú', 'Û', 'Ü', 'Ý', 'Þ', 'ß',
  1748. 'à', 'á', 'â', 'ã', 'å', 'å', 'æ', 'í', 'è', 'é', 'ê', 'ë', 'í', 'í', 'î', 'ï',
  1749. 'ð', 'ñ', 'ò', 'ó', 'ô', 'õ', 'ö', '÷', 'ø', 'ù', 'ú', 'û', 'ü', 'ý', 'þ', 'ÿ');
  1750. { lower case translation table for character set 850 }
  1751. CP850LCT: array[128..255] of char =
  1752. ('‡', '�', '‚', 'ƒ', '„', '…', '†', '‡', 'ˆ', '‰', 'Š', '‹', 'Œ', '�', '„', '†',
  1753. '‚', '‘', '‘', '“', '”', '•', '–', '—', '˜', '”', '�', '›', 'œ', '›', 'ž', 'Ÿ',
  1754. ' ', '¡', '¢', '£', '¤', '¤', '¦', '§', '¨', '©', 'ª', '«', '¬', '­', '®', '¯',
  1755. '°', '±', '²', '³', '´', ' ', 'ƒ', '…', '¸', '¹', 'º', '»', '¼', '½', '¾', '¿',
  1756. 'À', 'Á', 'Â', 'Ã', 'Ä', 'Å', 'Æ', 'Æ', 'È', 'É', 'Ê', 'Ë', 'Ì', 'Í', 'Î', 'Ï',
  1757. 'Ð', 'Ñ', 'ˆ', '‰', 'Š', 'Õ', '¡', 'Œ', '‹', 'Ù', 'Ú', 'Û', 'Ü', 'Ý', '�', 'ß',
  1758. '¢', 'á', '“', '•', 'ä', 'ä', 'æ', 'í', 'è', '£', '–', '—', 'ì', 'ì', 'î', 'ï',
  1759. 'ð', 'ñ', 'ò', 'ó', 'ô', 'õ', 'ö', '÷', 'ø', 'ù', 'ú', 'û', 'ü', 'ý', 'þ', 'ÿ');
  1760. { upper case translation table for character set ISO 8859/1 Latin 1 }
  1761. CPISO88591UCT: array[192..255] of char =
  1762. ( #192, #193, #194, #195, #196, #197, #198, #199,
  1763. #200, #201, #202, #203, #204, #205, #206, #207,
  1764. #208, #209, #210, #211, #212, #213, #214, #215,
  1765. #216, #217, #218, #219, #220, #221, #222, #223,
  1766. #192, #193, #194, #195, #196, #197, #198, #199,
  1767. #200, #201, #202, #203, #204, #205, #206, #207,
  1768. #208, #209, #210, #211, #212, #213, #214, #247,
  1769. #216, #217, #218, #219, #220, #221, #222, #89 );
  1770. { lower case translation table for character set ISO 8859/1 Latin 1 }
  1771. CPISO88591LCT: array[192..255] of char =
  1772. ( #224, #225, #226, #227, #228, #229, #230, #231,
  1773. #232, #233, #234, #235, #236, #237, #238, #239,
  1774. #240, #241, #242, #243, #244, #245, #246, #215,
  1775. #248, #249, #250, #251, #252, #253, #254, #223,
  1776. #224, #225, #226, #227, #228, #229, #230, #231,
  1777. #232, #233, #234, #235, #236, #237, #238, #239,
  1778. #240, #241, #242, #243, #244, #245, #246, #247,
  1779. #248, #249, #250, #251, #252, #253, #254, #255 );
  1780. function sscanf(const s: string; const fmt : string;const Pointers : array of Pointer) : Integer;
  1781. var
  1782. i,j,n,m : SizeInt;
  1783. s1 : string;
  1784. function GetInt(unsigned : boolean=false) : Integer;
  1785. begin
  1786. s1 := '';
  1787. while (s[n] = ' ') and (Length(s) > n) do
  1788. inc(n);
  1789. { read sign }
  1790. if (Length(s)>= n) and (s[n] in ['+', '-']) then
  1791. begin
  1792. { don't accept - when reading unsigned }
  1793. if unsigned and (s[n]='-') then
  1794. begin
  1795. result:=length(s1);
  1796. exit;
  1797. end
  1798. else
  1799. begin
  1800. s1:=s1+s[n];
  1801. inc(n);
  1802. end;
  1803. end;
  1804. { read numbers }
  1805. while (s[n] in ['0'..'9'])
  1806. and (Length(s) >= n) do
  1807. begin
  1808. s1 := s1+s[n];
  1809. inc(n);
  1810. end;
  1811. Result := Length(s1);
  1812. end;
  1813. function GetFloat : Integer;
  1814. begin
  1815. s1 := '';
  1816. while (s[n] = ' ') and (Length(s) > n) do
  1817. inc(n);
  1818. while (s[n] in ['0'..'9', '+', '-', '.', 'e', 'E'])
  1819. and (Length(s) >= n) do
  1820. begin
  1821. s1 := s1+s[n];
  1822. inc(n);
  1823. end;
  1824. Result := Length(s1);
  1825. end;
  1826. function GetString : Integer;
  1827. begin
  1828. s1 := '';
  1829. while (s[n] = ' ') and (Length(s) > n) do
  1830. inc(n);
  1831. while (s[n] <> ' ') and (Length(s) >= n) do
  1832. begin
  1833. s1 := s1+s[n];
  1834. inc(n);
  1835. end;
  1836. Result := Length(s1);
  1837. end;
  1838. function ScanStr(c : Char) : Boolean;
  1839. begin
  1840. while (s[n] <> c) and (Length(s) > n) do
  1841. inc(n);
  1842. inc(n);
  1843. If (n <= Length(s)) then
  1844. Result := True
  1845. else
  1846. Result := False;
  1847. end;
  1848. function GetFmt : Integer;
  1849. begin
  1850. Result := -1;
  1851. while true do
  1852. begin
  1853. while (fmt[m] = ' ') and (Length(fmt) > m) do
  1854. inc(m);
  1855. if (m >= Length(fmt)) then
  1856. break;
  1857. if (fmt[m] = '%') then
  1858. begin
  1859. inc(m);
  1860. case fmt[m] of
  1861. 'd':
  1862. Result:=vtInteger;
  1863. 'f':
  1864. Result:=vtExtended;
  1865. 's':
  1866. Result:=vtString;
  1867. 'c':
  1868. Result:=vtChar;
  1869. else
  1870. raise EFormatError.CreateFmt(SInvalidFormat,[fmt]);
  1871. end;
  1872. inc(m);
  1873. break;
  1874. end;
  1875. if not(ScanStr(fmt[m])) then
  1876. break;
  1877. inc(m);
  1878. end;
  1879. end;
  1880. begin
  1881. n := 1;
  1882. m := 1;
  1883. Result := 0;
  1884. for i:=0 to High(Pointers) do
  1885. begin
  1886. j := GetFmt;
  1887. case j of
  1888. vtInteger :
  1889. begin
  1890. if GetInt>0 then
  1891. begin
  1892. plongint(Pointers[i])^:=StrToInt(s1);
  1893. inc(Result);
  1894. end
  1895. else
  1896. break;
  1897. end;
  1898. vtchar :
  1899. begin
  1900. if Length(s)>n then
  1901. begin
  1902. pchar(Pointers[i])^:=s[n];
  1903. inc(n);
  1904. inc(Result);
  1905. end
  1906. else
  1907. break;
  1908. end;
  1909. vtExtended :
  1910. begin
  1911. if GetFloat>0 then
  1912. begin
  1913. pextended(Pointers[i])^:=StrToFloat(s1);
  1914. inc(Result);
  1915. end
  1916. else
  1917. break;
  1918. end;
  1919. vtString :
  1920. begin
  1921. if GetString > 0 then
  1922. begin
  1923. pansistring(Pointers[i])^:=s1;
  1924. inc(Result);
  1925. end
  1926. else
  1927. break;
  1928. end;
  1929. else
  1930. break;
  1931. end;
  1932. end;
  1933. end;