sysstr.inc 54 KB

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