sysstr.inc 54 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266
  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. TempValue: extended;
  772. Begin
  773. S:=StrPas(Buffer);
  774. P:=Pos(ThousandSeparator,S);
  775. While (P<>0) do
  776. begin
  777. Delete(S,P,1);
  778. P:=Pos(ThousandSeparator,S);
  779. end;
  780. P:=Pos(DecimalSeparator,S);
  781. If (P<>0) Then
  782. S[P] := '.';
  783. case ValueType of
  784. fvCurrency:
  785. begin
  786. // needed for platforms where Currency = Int64
  787. Val(S,TempValue,E);
  788. Currency(Value) := TempValue;
  789. end;
  790. fvExtended:
  791. Val(S,Extended(Value),E);
  792. fvDouble:
  793. Val(S,Double(Value),E);
  794. fvSingle:
  795. Val(S,Single(Value),E);
  796. fvComp:
  797. Val(S,Comp(Value),E);
  798. fvReal:
  799. Val(S,Real(Value),E);
  800. end;
  801. Result:=(E=0);
  802. End;
  803. Function TryStrToFloat(Const S : String; Var Value: Single): Boolean;
  804. Begin
  805. Result := TextToFloat(PChar(S), Value, fvSingle);
  806. End;
  807. Function TryStrToFloat(Const S : String; Var Value: Double): Boolean;
  808. Begin
  809. Result := TextToFloat(PChar(S), Value, fvDouble);
  810. End;
  811. {$ifdef FPC_HAS_TYPE_EXTENDED}
  812. Function TryStrToFloat(Const S : String; Var Value: Extended): Boolean;
  813. Begin
  814. Result := TextToFloat(PChar(S), Value);
  815. End;
  816. {$endif FPC_HAS_TYPE_EXTENDED}
  817. Function FloatToStr(Value: Extended): String;
  818. Begin
  819. Result := FloatToStrF(Value, ffGeneral, 15, 0);
  820. End;
  821. Function FloatToText(Buffer: PChar; Value: Extended; format: TFloatFormat; Precision, Digits: Integer): Longint;
  822. Var
  823. Tmp: String[40];
  824. Begin
  825. Tmp := FloatToStrF(Value, format, Precision, Digits);
  826. Result := Length(Tmp);
  827. Move(Tmp[1], Buffer[0], Result);
  828. End;
  829. Function FloatToStrF(Value: Extended; format: TFloatFormat; Precision, Digits: Integer): String;
  830. Var
  831. P: Integer;
  832. Negative, TooSmall, TooLarge: Boolean;
  833. Begin
  834. Case format Of
  835. ffGeneral:
  836. Begin
  837. If (Precision = -1) Or (Precision > 15) Then Precision := 15;
  838. TooSmall := (Abs(Value) < 0.00001) and (Value>0.0);
  839. If Not TooSmall Then
  840. Begin
  841. Str(Value:digits:precision, Result);
  842. P := Pos('.', Result);
  843. if P<>0 then
  844. Result[P] := DecimalSeparator;
  845. TooLarge := P > Precision + 1;
  846. End;
  847. If TooSmall Or TooLarge Then
  848. begin
  849. Result := FloatToStrF(Value, ffExponent, Precision, Digits);
  850. // Strip unneeded zeroes.
  851. P:=Pos('E',result)-1;
  852. If P<>-1 then
  853. While (P>1) and (Result[P]='0') do
  854. begin
  855. system.Delete(Result,P,1);
  856. Dec(P);
  857. end;
  858. end
  859. else if (P<>0) then // we have a decimalseparator
  860. begin
  861. P := Length(Result);
  862. While (P>0) and (Result[P] = '0') Do
  863. Dec(P);
  864. If (P>0) and (Result[P]=DecimalSeparator) Then
  865. Dec(P);
  866. SetLength(Result, P);
  867. end;
  868. End;
  869. ffExponent:
  870. Begin
  871. If (Precision = -1) Or (Precision > 15) Then Precision := 15;
  872. Str(Value:Precision + 8, Result);
  873. Result[3] := DecimalSeparator;
  874. P:=4;
  875. While (P>0) and (Digits < P) And (Result[Precision + 5] = '0') do
  876. Begin
  877. If P<>1 then
  878. system.Delete(Result, Precision + 5, 1)
  879. else
  880. system.Delete(Result, Precision + 3, 3);
  881. Dec(P);
  882. end;
  883. If Result[1] = ' ' Then
  884. System.Delete(Result, 1, 1);
  885. End;
  886. ffFixed:
  887. Begin
  888. If Digits = -1 Then Digits := 2
  889. Else If Digits > 18 Then Digits := 18;
  890. Str(Value:0:Digits, Result);
  891. If Result[1] = ' ' Then
  892. System.Delete(Result, 1, 1);
  893. P := Pos('.', Result);
  894. If P <> 0 Then Result[P] := DecimalSeparator;
  895. End;
  896. ffNumber:
  897. Begin
  898. If Digits = -1 Then Digits := 2
  899. Else If Digits > 15 Then Digits := 15;
  900. Str(Value:0:Digits, Result);
  901. If Result[1] = ' ' Then System.Delete(Result, 1, 1);
  902. P := Pos('.', Result);
  903. If P <> 0 Then
  904. Result[P] := DecimalSeparator
  905. else
  906. P := Length(Result)+1;
  907. Dec(P, 3);
  908. While (P > 1) Do
  909. Begin
  910. If Result[P - 1] <> '-' Then Insert(ThousandSeparator, Result, P);
  911. Dec(P, 3);
  912. End;
  913. End;
  914. ffCurrency:
  915. Begin
  916. If Value < 0 Then
  917. Begin
  918. Negative := True;
  919. Value := -Value;
  920. End
  921. Else Negative := False;
  922. If Digits = -1 Then Digits := CurrencyDecimals
  923. Else If Digits > 18 Then Digits := 18;
  924. Str(Value:0:Digits, Result);
  925. If Result[1] = ' ' Then System.Delete(Result, 1, 1);
  926. P := Pos('.', Result);
  927. If P <> 0 Then Result[P] := DecimalSeparator;
  928. Dec(P, 3);
  929. While (P > 1) Do
  930. Begin
  931. Insert(ThousandSeparator, Result, P);
  932. Dec(P, 3);
  933. End;
  934. If Not Negative Then
  935. Begin
  936. Case CurrencyFormat Of
  937. 0: Result := CurrencyString + Result;
  938. 1: Result := Result + CurrencyString;
  939. 2: Result := CurrencyString + ' ' + Result;
  940. 3: Result := Result + ' ' + CurrencyString;
  941. End
  942. End
  943. Else
  944. Begin
  945. Case NegCurrFormat Of
  946. 0: Result := '(' + CurrencyString + Result + ')';
  947. 1: Result := '-' + CurrencyString + Result;
  948. 2: Result := CurrencyString + '-' + Result;
  949. 3: Result := CurrencyString + Result + '-';
  950. 4: Result := '(' + Result + CurrencyString + ')';
  951. 5: Result := '-' + Result + CurrencyString;
  952. 6: Result := Result + '-' + CurrencyString;
  953. 7: Result := Result + CurrencyString + '-';
  954. 8: Result := '-' + Result + ' ' + CurrencyString;
  955. 9: Result := '-' + CurrencyString + ' ' + Result;
  956. 10: Result := CurrencyString + ' ' + Result + '-';
  957. End;
  958. End;
  959. End;
  960. End;
  961. End;
  962. Function CurrToStrF(Value: Currency; Format: TFloatFormat; Digits: Integer): string;
  963. begin
  964. result:=FloatToStrF(Value,Format,19,Digits);
  965. end;
  966. Function FloatToDateTime (Const Value : Extended) : TDateTime;
  967. begin
  968. If (Value<MinDateTime) or (Value>MaxDateTime) then
  969. Raise EConvertError.CreateFmt (SInvalidDateTime,[Value]);
  970. Result:=Value;
  971. end;
  972. function TryFloatToCurr(const Value: Extended; var AResult: Currency): Boolean;
  973. begin
  974. Result:=(Value>=MinCurrency) and (Value<=MaxCurrency);
  975. if Result then
  976. AResult := Value;
  977. end;
  978. function FloatToCurr(const Value: Extended): Currency;
  979. begin
  980. if not TryFloatToCurr(Value, Result) then
  981. Raise EConvertError.CreateFmt(SInvalidCurrency, [FloatToStr(Value)]);
  982. end;
  983. Function CurrToStr(Value: Currency): string;
  984. begin
  985. Result:=FloatToStrF(Value,ffNumber,15,2);
  986. end;
  987. function StrToCurr(const S: string): Currency;
  988. begin
  989. if not TextToFloat(PChar(S), Result, fvCurrency) then
  990. Raise EConvertError.createfmt(SInValidFLoat,[S]);
  991. end;
  992. Function TryStrToCurr(Const S : String; Var Value: Currency): Boolean;
  993. Begin
  994. Result := TextToFloat(PChar(S), Value, fvCurrency);
  995. End;
  996. function StrToCurrDef(const S: string; Default : Currency): Currency;
  997. begin
  998. if not TextToFloat(PChar(S), Result, fvCurrency) then
  999. Result:=Default;
  1000. end;
  1001. function StrToBool(const S: string): Boolean;
  1002. Var
  1003. Temp : String;
  1004. D : Double;
  1005. Code: word;
  1006. begin
  1007. Temp:=upcase(S);
  1008. Val(temp,D,code);
  1009. If Code=0 then
  1010. Result:=(D<>0.0)
  1011. else If Temp='TRUE' then
  1012. result:=true
  1013. else if Temp='FALSE' then
  1014. result:=false
  1015. else
  1016. Raise EConvertError.CreateFmt(SInvalidBoolean,[S]);
  1017. end;
  1018. function BoolToStr(B: Boolean): string;
  1019. begin
  1020. If B then
  1021. Result:='TRUE'
  1022. else
  1023. Result:='FALSE';
  1024. end;
  1025. Function FloatToTextFmt(Buffer: PChar; Value: Extended; format: PChar): Integer;
  1026. Var
  1027. Digits: String[40]; { String Of Digits }
  1028. Exponent: String[8]; { Exponent strin }
  1029. FmtStart, FmtStop: PChar; { Start And End Of relevant part }
  1030. { Of format String }
  1031. ExpFmt, ExpSize: Integer; { Type And Length Of }
  1032. { exponential format chosen }
  1033. Placehold: Array[1..4] Of Integer; { Number Of placeholders In All }
  1034. { four Sections }
  1035. thousand: Boolean; { thousand separators? }
  1036. UnexpectedDigits: Integer; { Number Of unexpected Digits that }
  1037. { have To be inserted before the }
  1038. { First placeholder. }
  1039. DigitExponent: Integer; { Exponent Of First digit In }
  1040. { Digits Array. }
  1041. { Find end of format section starting at P. False, if empty }
  1042. Function GetSectionEnd(Var P: PChar): Boolean;
  1043. Var
  1044. C: Char;
  1045. SQ, DQ: Boolean;
  1046. Begin
  1047. Result := False;
  1048. SQ := False;
  1049. DQ := False;
  1050. C := P[0];
  1051. While (C<>#0) And ((C<>';') Or SQ Or DQ) Do
  1052. Begin
  1053. Result := True;
  1054. Case C Of
  1055. #34: If Not SQ Then DQ := Not DQ;
  1056. #39: If Not DQ Then SQ := Not SQ;
  1057. End;
  1058. Inc(P);
  1059. C := P[0];
  1060. End;
  1061. End;
  1062. { Find start and end of format section to apply. If section doesn't exist,
  1063. use section 1. If section 2 is used, the sign of value is ignored. }
  1064. Procedure GetSectionRange(section: Integer);
  1065. Var
  1066. Sec: Array[1..3] Of PChar;
  1067. SecOk: Array[1..3] Of Boolean;
  1068. Begin
  1069. Sec[1] := format;
  1070. SecOk[1] := GetSectionEnd(Sec[1]);
  1071. If section > 1 Then
  1072. Begin
  1073. Sec[2] := Sec[1];
  1074. If Sec[2][0] <> #0 Then
  1075. Inc(Sec[2]);
  1076. SecOk[2] := GetSectionEnd(Sec[2]);
  1077. If section > 2 Then
  1078. Begin
  1079. Sec[3] := Sec[2];
  1080. If Sec[3][0] <> #0 Then
  1081. Inc(Sec[3]);
  1082. SecOk[3] := GetSectionEnd(Sec[3]);
  1083. End;
  1084. End;
  1085. If Not SecOk[1] Then
  1086. FmtStart := Nil
  1087. Else
  1088. Begin
  1089. If Not SecOk[section] Then
  1090. section := 1
  1091. Else If section = 2 Then
  1092. Value := -Value; { Remove sign }
  1093. If section = 1 Then FmtStart := format Else
  1094. Begin
  1095. FmtStart := Sec[section - 1];
  1096. Inc(FmtStart);
  1097. End;
  1098. FmtStop := Sec[section];
  1099. End;
  1100. End;
  1101. { Find format section ranging from FmtStart to FmtStop. }
  1102. Procedure GetFormatOptions;
  1103. Var
  1104. Fmt: PChar;
  1105. SQ, DQ: Boolean;
  1106. area: Integer;
  1107. Begin
  1108. SQ := False;
  1109. DQ := False;
  1110. Fmt := FmtStart;
  1111. ExpFmt := 0;
  1112. area := 1;
  1113. thousand := False;
  1114. Placehold[1] := 0;
  1115. Placehold[2] := 0;
  1116. Placehold[3] := 0;
  1117. Placehold[4] := 0;
  1118. While Fmt < FmtStop Do
  1119. Begin
  1120. Case Fmt[0] Of
  1121. #34:
  1122. Begin
  1123. If Not SQ Then
  1124. DQ := Not DQ;
  1125. Inc(Fmt);
  1126. End;
  1127. #39:
  1128. Begin
  1129. If Not DQ Then
  1130. SQ := Not SQ;
  1131. Inc(Fmt);
  1132. End;
  1133. Else
  1134. { This was 'if not SQ or DQ'. Looked wrong... }
  1135. If Not SQ Or DQ Then
  1136. Begin
  1137. Case Fmt[0] Of
  1138. '0':
  1139. Begin
  1140. Case area Of
  1141. 1:
  1142. area := 2;
  1143. 4:
  1144. Begin
  1145. area := 3;
  1146. Inc(Placehold[3], Placehold[4]);
  1147. Placehold[4] := 0;
  1148. End;
  1149. End;
  1150. Inc(Placehold[area]);
  1151. Inc(Fmt);
  1152. End;
  1153. '#':
  1154. Begin
  1155. If area=3 Then
  1156. area:=4;
  1157. Inc(Placehold[area]);
  1158. Inc(Fmt);
  1159. End;
  1160. '.':
  1161. Begin
  1162. If area<3 Then
  1163. area:=3;
  1164. Inc(Fmt);
  1165. End;
  1166. ',':
  1167. Begin
  1168. thousand := True;
  1169. Inc(Fmt);
  1170. End;
  1171. 'e', 'E':
  1172. If ExpFmt = 0 Then
  1173. Begin
  1174. If (Fmt[0]='E') Then
  1175. ExpFmt:=1
  1176. Else
  1177. ExpFmt := 3;
  1178. Inc(Fmt);
  1179. If (Fmt<FmtStop) Then
  1180. Begin
  1181. Case Fmt[0] Of
  1182. '+':
  1183. Begin
  1184. End;
  1185. '-':
  1186. Inc(ExpFmt);
  1187. Else
  1188. ExpFmt := 0;
  1189. End;
  1190. If ExpFmt <> 0 Then
  1191. Begin
  1192. Inc(Fmt);
  1193. ExpSize := 0;
  1194. While (Fmt<FmtStop) And
  1195. (ExpSize<4) And
  1196. (Fmt[0] In ['0'..'9']) Do
  1197. Begin
  1198. Inc(ExpSize);
  1199. Inc(Fmt);
  1200. End;
  1201. End;
  1202. End;
  1203. End
  1204. Else
  1205. Inc(Fmt);
  1206. Else { Case }
  1207. Inc(Fmt);
  1208. End; { Case }
  1209. End; { Begin }
  1210. End; { Case }
  1211. End; { While .. Begin }
  1212. End;
  1213. Procedure FloatToStr;
  1214. Var
  1215. I, J, Exp, Width, Decimals, DecimalPoint, len: Integer;
  1216. Begin
  1217. If ExpFmt = 0 Then
  1218. Begin
  1219. { Fixpoint }
  1220. Decimals:=Placehold[3]+Placehold[4];
  1221. Width:=Placehold[1]+Placehold[2]+Decimals;
  1222. If (Decimals=0) Then
  1223. Str(Value:Width:0,Digits)
  1224. Else
  1225. Str(Value:Width+1:Decimals,Digits);
  1226. len:=Length(Digits);
  1227. { Find the decimal point }
  1228. If (Decimals=0) Then
  1229. DecimalPoint:=len+1
  1230. Else
  1231. DecimalPoint:=len-Decimals;
  1232. { If value is very small, and no decimal places
  1233. are desired, remove the leading 0. }
  1234. If (Abs(Value) < 1) And (Placehold[2] = 0) Then
  1235. Begin
  1236. If (Placehold[1]=0) Then
  1237. Delete(Digits,DecimalPoint-1,1)
  1238. Else
  1239. Digits[DecimalPoint-1]:=' ';
  1240. End;
  1241. { Convert optional zeroes to spaces. }
  1242. I:=len;
  1243. J:=DecimalPoint+Placehold[3];
  1244. While (I>J) And (Digits[I]='0') Do
  1245. Begin
  1246. Digits[I] := ' ';
  1247. Dec(I);
  1248. End;
  1249. { If integer value and no obligatory decimal
  1250. places, remove decimal point. }
  1251. If (DecimalPoint < len) And (Digits[DecimalPoint + 1] = ' ') Then
  1252. Digits[DecimalPoint] := ' ';
  1253. { Convert spaces left from obligatory decimal point to zeroes. }
  1254. I:=DecimalPoint-Placehold[2];
  1255. While (I<DecimalPoint) And (Digits[I]=' ') Do
  1256. Begin
  1257. Digits[I] := '0';
  1258. Inc(I);
  1259. End;
  1260. Exp := 0;
  1261. End
  1262. Else
  1263. Begin
  1264. { Scientific: exactly <Width> Digits With <Precision> Decimals
  1265. And adjusted Exponent. }
  1266. If Placehold[1]+Placehold[2]=0 Then
  1267. Placehold[1]:=1;
  1268. Decimals := Placehold[3] + Placehold[4];
  1269. Width:=Placehold[1]+Placehold[2]+Decimals;
  1270. Str(Value:Width+8,Digits);
  1271. { Find and cut out exponent. Always the
  1272. last 6 characters in the string.
  1273. -> 0000E+0000 }
  1274. I:=Length(Digits)-5;
  1275. Val(Copy(Digits,I+1,5),Exp,J);
  1276. Exp:=Exp+1-(Placehold[1]+Placehold[2]);
  1277. Delete(Digits, I, 6);
  1278. { Str() always returns at least one digit after the decimal point.
  1279. If we don't want it, we have to remove it. }
  1280. If (Decimals=0) And (Placehold[1]+Placehold[2]<= 1) Then
  1281. Begin
  1282. If (Digits[4]>='5') Then
  1283. Begin
  1284. Inc(Digits[2]);
  1285. If (Digits[2]>'9') Then
  1286. Begin
  1287. Digits[2] := '1';
  1288. Inc(Exp);
  1289. End;
  1290. End;
  1291. Delete(Digits, 3, 2);
  1292. DecimalPoint := Length(Digits) + 1;
  1293. End
  1294. Else
  1295. Begin
  1296. { Move decimal point at the desired position }
  1297. Delete(Digits, 3, 1);
  1298. DecimalPoint:=2+Placehold[1]+Placehold[2];
  1299. If (Decimals<>0) Then
  1300. Insert('.',Digits,DecimalPoint);
  1301. End;
  1302. { Convert optional zeroes to spaces. }
  1303. I := Length(Digits);
  1304. J := DecimalPoint + Placehold[3];
  1305. While (I > J) And (Digits[I] = '0') Do
  1306. Begin
  1307. Digits[I] := ' ';
  1308. Dec(I);
  1309. End;
  1310. { If integer number and no obligatory decimal paces, remove decimal point }
  1311. If (DecimalPoint<Length(Digits)) And
  1312. (Digits[DecimalPoint+1]=' ') Then
  1313. Digits[DecimalPoint]:=' ';
  1314. If (Digits[1]=' ') Then
  1315. Begin
  1316. Delete(Digits, 1, 1);
  1317. Dec(DecimalPoint);
  1318. End;
  1319. { Calculate exponent string }
  1320. Str(Abs(Exp), Exponent);
  1321. While Length(Exponent)<ExpSize Do
  1322. Insert('0',Exponent,1);
  1323. If Exp >= 0 Then
  1324. Begin
  1325. If (ExpFmt In [1,3]) Then
  1326. Insert('+', Exponent, 1);
  1327. End
  1328. Else
  1329. Insert('-',Exponent,1);
  1330. If (ExpFmt<3) Then
  1331. Insert('E',Exponent,1)
  1332. Else
  1333. Insert('e',Exponent,1);
  1334. End;
  1335. DigitExponent:=DecimalPoint-2;
  1336. If (Digits[1]='-') Then
  1337. Dec(DigitExponent);
  1338. UnexpectedDigits:=DecimalPoint-1-(Placehold[1]+Placehold[2]);
  1339. End;
  1340. Function PutResult: LongInt;
  1341. Var
  1342. SQ, DQ: Boolean;
  1343. Fmt, Buf: PChar;
  1344. Dig, N: Integer;
  1345. Begin
  1346. SQ := False;
  1347. DQ := False;
  1348. Fmt := FmtStart;
  1349. Buf := Buffer;
  1350. Dig := 1;
  1351. While (Fmt<FmtStop) Do
  1352. Begin
  1353. //Write(Fmt[0]);
  1354. Case Fmt[0] Of
  1355. #34:
  1356. Begin
  1357. If Not SQ Then
  1358. DQ := Not DQ;
  1359. Inc(Fmt);
  1360. End;
  1361. #39:
  1362. Begin
  1363. If Not DQ Then
  1364. SQ := Not SQ;
  1365. Inc(Fmt);
  1366. End;
  1367. Else
  1368. If Not (SQ Or DQ) Then
  1369. Begin
  1370. Case Fmt[0] Of
  1371. '0', '#', '.':
  1372. Begin
  1373. If (Dig=1) And (UnexpectedDigits>0) Then
  1374. Begin
  1375. { Everything unexpected is written before the first digit }
  1376. For N := 1 To UnexpectedDigits Do
  1377. Begin
  1378. Buf[0] := Digits[N];
  1379. Inc(Buf);
  1380. If thousand And (Digits[N]<>'-') Then
  1381. Begin
  1382. If (DigitExponent Mod 3 = 0) And (DigitExponent>0) Then
  1383. Begin
  1384. Buf[0] := ThousandSeparator;
  1385. Inc(Buf);
  1386. End;
  1387. Dec(DigitExponent);
  1388. End;
  1389. End;
  1390. Inc(Dig, UnexpectedDigits);
  1391. End;
  1392. If (Digits[Dig]<>' ') Then
  1393. Begin
  1394. If (Digits[Dig]='.') Then
  1395. Buf[0] := DecimalSeparator
  1396. Else
  1397. Buf[0] := Digits[Dig];
  1398. Inc(Buf);
  1399. If thousand And (DigitExponent Mod 3 = 0) And (DigitExponent > 0) Then
  1400. Begin
  1401. Buf[0] := ThousandSeparator;
  1402. Inc(Buf);
  1403. End;
  1404. End;
  1405. Inc(Dig);
  1406. Dec(DigitExponent);
  1407. Inc(Fmt);
  1408. End;
  1409. 'e', 'E':
  1410. Begin
  1411. If ExpFmt <> 0 Then
  1412. Begin
  1413. Inc(Fmt);
  1414. If Fmt < FmtStop Then
  1415. Begin
  1416. If Fmt[0] In ['+', '-'] Then
  1417. Begin
  1418. Inc(Fmt, ExpSize);
  1419. For N:=1 To Length(Exponent) Do
  1420. Buf[N-1] := Exponent[N];
  1421. Inc(Buf,Length(Exponent));
  1422. ExpFmt:=0;
  1423. End;
  1424. Inc(Fmt);
  1425. End;
  1426. End
  1427. Else
  1428. Begin
  1429. { No legal exponential format.
  1430. Simply write the 'E' to the result. }
  1431. Buf[0] := Fmt[0];
  1432. Inc(Buf);
  1433. Inc(Fmt);
  1434. End;
  1435. End;
  1436. Else { Case }
  1437. { Usual character }
  1438. If (Fmt[0]<>',') Then
  1439. Begin
  1440. Buf[0] := Fmt[0];
  1441. Inc(Buf);
  1442. End;
  1443. Inc(Fmt);
  1444. End; { Case }
  1445. End
  1446. Else { IF }
  1447. Begin
  1448. { Character inside single or double quotes }
  1449. Buf[0] := Fmt[0];
  1450. Inc(Buf);
  1451. Inc(Fmt);
  1452. End;
  1453. End; { Case }
  1454. End; { While .. Begin }
  1455. Result:=PtrInt(Buf)-PtrInt(Buffer);
  1456. End;
  1457. Begin
  1458. If (Value>0) Then
  1459. GetSectionRange(1)
  1460. Else If (Value<0) Then
  1461. GetSectionRange(2)
  1462. Else
  1463. GetSectionRange(3);
  1464. If FmtStart = Nil Then
  1465. Begin
  1466. Result := FloatToText(Buffer, Value, ffGeneral, 15, 4);
  1467. End
  1468. Else
  1469. Begin
  1470. GetFormatOptions;
  1471. If (ExpFmt = 0) And (Abs(Value) >= 1E18) Then
  1472. Result := FloatToText(Buffer, Value, ffGeneral, 15, 4)
  1473. Else
  1474. Begin
  1475. FloatToStr;
  1476. Result := PutResult;
  1477. End;
  1478. End;
  1479. End;
  1480. Procedure FloatToDecimal(Var Result: TFloatRec; Value: Extended; Precision, Decimals : integer);
  1481. Var
  1482. Buffer: String[24];
  1483. Error, N: Integer;
  1484. Begin
  1485. Str(Value:23, Buffer);
  1486. Result.Negative := (Buffer[1] = '-');
  1487. Val(Copy(Buffer, 19, 5), Result.Exponent, Error);
  1488. Inc(Result. Exponent);
  1489. Result.Digits[0] := Buffer[2];
  1490. Move(Buffer[4], Result.Digits[1], 14);
  1491. If Decimals + Result.Exponent < Precision Then
  1492. N := Decimals + Result.Exponent
  1493. Else
  1494. N := Precision;
  1495. If N > 15 Then
  1496. N := 15;
  1497. If N = 0 Then
  1498. Begin
  1499. If Result.Digits[0] >= '5' Then
  1500. Begin
  1501. Result.Digits[0] := '1';
  1502. Result.Digits[1] := #0;
  1503. Inc(Result.Exponent);
  1504. End
  1505. Else
  1506. Result.Digits[0] := #0;
  1507. End
  1508. Else If N > 0 Then
  1509. Begin
  1510. If Result.Digits[N] >= '5' Then
  1511. Begin
  1512. Repeat
  1513. Result.Digits[N] := #0;
  1514. Dec(N);
  1515. Inc(Result.Digits[N]);
  1516. Until (N = 0) Or (Result.Digits[N] < ':');
  1517. If Result.Digits[0] = ':' Then
  1518. Begin
  1519. Result.Digits[0] := '1';
  1520. Inc(Result.Exponent);
  1521. End;
  1522. End
  1523. Else
  1524. Begin
  1525. Result.Digits[N] := '0';
  1526. While (Result.Digits[N] = '0') And (N > -1) Do
  1527. Begin
  1528. Result.Digits[N] := #0;
  1529. Dec(N);
  1530. End;
  1531. End;
  1532. End
  1533. Else
  1534. Result.Digits[0] := #0;
  1535. If Result.Digits[0] = #0 Then
  1536. Begin
  1537. Result.Exponent := 0;
  1538. Result.Negative := False;
  1539. End;
  1540. End;
  1541. Function FormatFloat(Const format: String; Value: Extended): String;
  1542. Var
  1543. buf : Array[0..1024] of char;
  1544. Begin
  1545. Buf[FloatToTextFmt(@Buf[0],Value,Pchar(Format))]:=#0;
  1546. Result:=StrPas(@Buf);
  1547. End;
  1548. function FormatCurr(const Format: string; Value: Currency): string;
  1549. begin
  1550. Result := FormatFloat(Format, Value);
  1551. end;
  1552. {==============================================================================}
  1553. { extra functions }
  1554. {==============================================================================}
  1555. { LeftStr returns Count left-most characters from S }
  1556. function LeftStr(const S: string; Count: integer): string;
  1557. begin
  1558. result := Copy(S, 1, Count);
  1559. end ;
  1560. { RightStr returns Count right-most characters from S }
  1561. function RightStr(const S: string; Count: integer): string;
  1562. begin
  1563. If Count>Length(S) then
  1564. Count:=Length(S);
  1565. result := Copy(S, 1 + Length(S) - Count, Count);
  1566. end;
  1567. { BCDToInt converts the BCD value Value to an integer }
  1568. function BCDToInt(Value: integer): integer;
  1569. var i, j: integer;
  1570. begin
  1571. result := 0;
  1572. j := 1;
  1573. for i := 0 to SizeOf(Value) shr 1 - 1 do begin
  1574. result := result + j * (Value and 15);
  1575. j := j * 10;
  1576. Value := Value shr 4;
  1577. end ;
  1578. end ;
  1579. Function LastDelimiter(const Delimiters, S: string): Integer;
  1580. begin
  1581. Result:=Length(S);
  1582. While (Result>0) and (Pos(S[Result],Delimiters)=0) do
  1583. Dec(Result);
  1584. end;
  1585. Function StringReplace(const S, OldPattern, NewPattern: string; Flags: TReplaceFlags): string;
  1586. var
  1587. Srch,OldP,RemS: string; // Srch and Oldp can contain uppercase versions of S,OldPattern
  1588. P : Integer;
  1589. begin
  1590. Srch:=S;
  1591. OldP:=OldPattern;
  1592. if rfIgnoreCase in Flags then
  1593. begin
  1594. Srch:=AnsiUpperCase(Srch);
  1595. OldP:=AnsiUpperCase(OldP);
  1596. end;
  1597. RemS:=S;
  1598. Result:='';
  1599. while (Length(Srch)<>0) do
  1600. begin
  1601. P:=AnsiPos(OldP, Srch);
  1602. if P=0 then
  1603. begin
  1604. Result:=Result+RemS;
  1605. Srch:='';
  1606. end
  1607. else
  1608. begin
  1609. Result:=Result+Copy(RemS,1,P-1)+NewPattern;
  1610. P:=P+Length(OldP);
  1611. RemS:=Copy(RemS,P,Length(RemS)-P+1);
  1612. if not (rfReplaceAll in Flags) then
  1613. begin
  1614. Result:=Result+RemS;
  1615. Srch:='';
  1616. end
  1617. else
  1618. Srch:=Copy(Srch,P,Length(Srch)-P+1);
  1619. end;
  1620. end;
  1621. end;
  1622. Function IsDelimiter(const Delimiters, S: string; Index: Integer): Boolean;
  1623. begin
  1624. Result:=False;
  1625. If (Index>0) and (Index<=Length(S)) then
  1626. Result:=Pos(S[Index],Delimiters)<>0; // Note we don't do MBCS yet
  1627. end;
  1628. Function ByteToCharLen(const S: string; MaxLen: Integer): Integer;
  1629. begin
  1630. Result:=Length(S);
  1631. If Result>MaxLen then
  1632. Result:=MaxLen;
  1633. end;
  1634. Function ByteToCharIndex(const S: string; Index: Integer): Integer;
  1635. begin
  1636. Result:=Index;
  1637. end;
  1638. Function CharToByteLen(const S: string; MaxLen: Integer): Integer;
  1639. begin
  1640. Result:=Length(S);
  1641. If Result>MaxLen then
  1642. Result:=MaxLen;
  1643. end;
  1644. Function CharToByteIndex(const S: string; Index: Integer): Integer;
  1645. begin
  1646. Result:=Index;
  1647. end;
  1648. Function ByteType(const S: string; Index: Integer): TMbcsByteType;
  1649. begin
  1650. Result:=mbSingleByte;
  1651. end;
  1652. Function StrByteType(Str: PChar; Index: Cardinal): TMbcsByteType;
  1653. begin
  1654. Result:=mbSingleByte;
  1655. end;
  1656. Function StrCharLength(const Str: PChar): Integer;
  1657. begin
  1658. result:=widestringmanager.CharLengthPCharProc(Str);
  1659. end;
  1660. Function FindCmdLineSwitch(const Switch: string; const Chars: TSysCharSet;IgnoreCase: Boolean): Boolean;
  1661. Var
  1662. I,L : Integer;
  1663. S,T : String;
  1664. begin
  1665. Result:=False;
  1666. S:=Switch;
  1667. If IgnoreCase then
  1668. S:=UpperCase(S);
  1669. I:=ParamCount;
  1670. While (Not Result) and (I>0) do
  1671. begin
  1672. L:=Length(Paramstr(I));
  1673. If (L>0) and (ParamStr(I)[1] in Chars) then
  1674. begin
  1675. T:=Copy(ParamStr(I),2,L-1);
  1676. If IgnoreCase then
  1677. T:=UpperCase(T);
  1678. Result:=S=T;
  1679. end;
  1680. Dec(i);
  1681. end;
  1682. end;
  1683. Function FindCmdLineSwitch(const Switch: string; IgnoreCase: Boolean): Boolean;
  1684. begin
  1685. Result:=FindCmdLineSwitch(Switch,SwitchChars,IgnoreCase);
  1686. end;
  1687. Function FindCmdLineSwitch(const Switch: string): Boolean;
  1688. begin
  1689. Result:=FindCmdLineSwitch(Switch,SwitchChars,False);
  1690. end;
  1691. function WrapText(const Line, BreakStr: string; const BreakChars: TSysCharSet; MaxCol: Integer): string;
  1692. const
  1693. Quotes = ['''', '"'];
  1694. Var
  1695. L : String;
  1696. C,LQ,BC : Char;
  1697. P,BLen,Len : Integer;
  1698. HB,IBC : Boolean;
  1699. begin
  1700. Result:='';
  1701. L:=Line;
  1702. Blen:=Length(BreakStr);
  1703. If (BLen>0) then
  1704. BC:=BreakStr[1]
  1705. else
  1706. BC:=#0;
  1707. Len:=Length(L);
  1708. While (Len>0) do
  1709. begin
  1710. P:=1;
  1711. LQ:=#0;
  1712. HB:=False;
  1713. IBC:=False;
  1714. While ((P<=Len) and ((P<=MaxCol) or not IBC)) and ((LQ<>#0) or Not HB) do
  1715. begin
  1716. C:=L[P];
  1717. If (C=LQ) then
  1718. LQ:=#0
  1719. else If (C in Quotes) then
  1720. LQ:=C;
  1721. If (LQ<>#0) then
  1722. Inc(P)
  1723. else
  1724. begin
  1725. HB:=((C=BC) and (BreakStr=Copy(L,P,BLen)));
  1726. If HB then
  1727. Inc(P,Blen)
  1728. else
  1729. begin
  1730. If (P>MaxCol) then
  1731. IBC:=C in BreakChars;
  1732. Inc(P);
  1733. end;
  1734. end;
  1735. // Writeln('"',C,'" : IBC : ',IBC,' HB : ',HB,' LQ : ',LQ,' P>MaxCol : ',P>MaxCol);
  1736. end;
  1737. Result:=Result+Copy(L,1,P-1);
  1738. If Not HB then
  1739. Result:=Result+BreakStr;
  1740. Delete(L,1,P-1);
  1741. Len:=Length(L);
  1742. end;
  1743. end;
  1744. function WrapText(const Line: string; MaxCol: Integer): string;
  1745. begin
  1746. Result:=WrapText(Line,sLineBreak, [' ', '-', #9], MaxCol);
  1747. end;
  1748. {
  1749. Case Translation Tables
  1750. Can be used in internationalization support.
  1751. Although these tables can be obtained through system calls
  1752. it is better to not use those, since most implementation are not 100%
  1753. WARNING:
  1754. before modifying a translation table make sure that the current codepage
  1755. of the OS corresponds to the one you make changes to
  1756. }
  1757. const
  1758. { upper case translation table for character set 850 }
  1759. CP850UCT: array[128..255] of char =
  1760. ('€', 'š', '�', '¶', 'Ž', '¶', '�', '€', 'Ò', 'Ó', 'Ô', 'Ø', '×', 'Þ', 'Ž', '�',
  1761. '�', '’', '’', 'â', '™', 'ã', 'ê', 'ë', 'Y', '™', 'š', '�', 'œ', '�', 'ž', 'Ÿ',
  1762. 'µ', 'Ö', 'à', 'é', '¥', '¥', '¦', '§', '¨', '©', 'ª', '«', '¬', '­', '®', '¯',
  1763. '°', '±', '²', '³', '´', 'µ', '¶', '·', '¸', '¹', 'º', '»', '¼', '½', '¾', '¿',
  1764. 'À', 'Á', 'Â', 'Ã', 'Ä', 'Å', 'Ç', 'Ç', 'È', 'É', 'Ê', 'Ë', 'Ì', 'Í', 'Î', 'Ï',
  1765. 'Ð', 'Ñ', 'Ò', 'Ó', 'Ô', 'Õ', 'Ö', '×', 'Ø', 'Ù', 'Ú', 'Û', 'Ü', 'Ý', 'Þ', 'ß',
  1766. 'à', 'á', 'â', 'ã', 'å', 'å', 'æ', 'í', 'è', 'é', 'ê', 'ë', 'í', 'í', 'î', 'ï',
  1767. 'ð', 'ñ', 'ò', 'ó', 'ô', 'õ', 'ö', '÷', 'ø', 'ù', 'ú', 'û', 'ü', 'ý', 'þ', 'ÿ');
  1768. { lower case translation table for character set 850 }
  1769. CP850LCT: array[128..255] of char =
  1770. ('‡', '�', '‚', 'ƒ', '„', '…', '†', '‡', 'ˆ', '‰', 'Š', '‹', 'Œ', '�', '„', '†',
  1771. '‚', '‘', '‘', '“', '”', '•', '–', '—', '˜', '”', '�', '›', 'œ', '›', 'ž', 'Ÿ',
  1772. ' ', '¡', '¢', '£', '¤', '¤', '¦', '§', '¨', '©', 'ª', '«', '¬', '­', '®', '¯',
  1773. '°', '±', '²', '³', '´', ' ', 'ƒ', '…', '¸', '¹', 'º', '»', '¼', '½', '¾', '¿',
  1774. 'À', 'Á', 'Â', 'Ã', 'Ä', 'Å', 'Æ', 'Æ', 'È', 'É', 'Ê', 'Ë', 'Ì', 'Í', 'Î', 'Ï',
  1775. 'Ð', 'Ñ', 'ˆ', '‰', 'Š', 'Õ', '¡', 'Œ', '‹', 'Ù', 'Ú', 'Û', 'Ü', 'Ý', '�', 'ß',
  1776. '¢', 'á', '“', '•', 'ä', 'ä', 'æ', 'í', 'è', '£', '–', '—', 'ì', 'ì', 'î', 'ï',
  1777. 'ð', 'ñ', 'ò', 'ó', 'ô', 'õ', 'ö', '÷', 'ø', 'ù', 'ú', 'û', 'ü', 'ý', 'þ', 'ÿ');
  1778. { upper case translation table for character set ISO 8859/1 Latin 1 }
  1779. CPISO88591UCT: array[192..255] of char =
  1780. ( #192, #193, #194, #195, #196, #197, #198, #199,
  1781. #200, #201, #202, #203, #204, #205, #206, #207,
  1782. #208, #209, #210, #211, #212, #213, #214, #215,
  1783. #216, #217, #218, #219, #220, #221, #222, #223,
  1784. #192, #193, #194, #195, #196, #197, #198, #199,
  1785. #200, #201, #202, #203, #204, #205, #206, #207,
  1786. #208, #209, #210, #211, #212, #213, #214, #247,
  1787. #216, #217, #218, #219, #220, #221, #222, #89 );
  1788. { lower case translation table for character set ISO 8859/1 Latin 1 }
  1789. CPISO88591LCT: array[192..255] of char =
  1790. ( #224, #225, #226, #227, #228, #229, #230, #231,
  1791. #232, #233, #234, #235, #236, #237, #238, #239,
  1792. #240, #241, #242, #243, #244, #245, #246, #215,
  1793. #248, #249, #250, #251, #252, #253, #254, #223,
  1794. #224, #225, #226, #227, #228, #229, #230, #231,
  1795. #232, #233, #234, #235, #236, #237, #238, #239,
  1796. #240, #241, #242, #243, #244, #245, #246, #247,
  1797. #248, #249, #250, #251, #252, #253, #254, #255 );
  1798. function sscanf(const s: string; const fmt : string;const Pointers : array of Pointer) : Integer;
  1799. var
  1800. i,j,n,m : SizeInt;
  1801. s1 : string;
  1802. function GetInt(unsigned : boolean=false) : Integer;
  1803. begin
  1804. s1 := '';
  1805. while (s[n] = ' ') and (Length(s) > n) do
  1806. inc(n);
  1807. { read sign }
  1808. if (Length(s)>= n) and (s[n] in ['+', '-']) then
  1809. begin
  1810. { don't accept - when reading unsigned }
  1811. if unsigned and (s[n]='-') then
  1812. begin
  1813. result:=length(s1);
  1814. exit;
  1815. end
  1816. else
  1817. begin
  1818. s1:=s1+s[n];
  1819. inc(n);
  1820. end;
  1821. end;
  1822. { read numbers }
  1823. while (s[n] in ['0'..'9'])
  1824. and (Length(s) >= n) do
  1825. begin
  1826. s1 := s1+s[n];
  1827. inc(n);
  1828. end;
  1829. Result := Length(s1);
  1830. end;
  1831. function GetFloat : Integer;
  1832. begin
  1833. s1 := '';
  1834. while (s[n] = ' ') and (Length(s) > n) do
  1835. inc(n);
  1836. while (s[n] in ['0'..'9', '+', '-', '.', 'e', 'E'])
  1837. and (Length(s) >= n) do
  1838. begin
  1839. s1 := s1+s[n];
  1840. inc(n);
  1841. end;
  1842. Result := Length(s1);
  1843. end;
  1844. function GetString : Integer;
  1845. begin
  1846. s1 := '';
  1847. while (s[n] = ' ') and (Length(s) > n) do
  1848. inc(n);
  1849. while (s[n] <> ' ') and (Length(s) >= n) do
  1850. begin
  1851. s1 := s1+s[n];
  1852. inc(n);
  1853. end;
  1854. Result := Length(s1);
  1855. end;
  1856. function ScanStr(c : Char) : Boolean;
  1857. begin
  1858. while (s[n] <> c) and (Length(s) > n) do
  1859. inc(n);
  1860. inc(n);
  1861. If (n <= Length(s)) then
  1862. Result := True
  1863. else
  1864. Result := False;
  1865. end;
  1866. function GetFmt : Integer;
  1867. begin
  1868. Result := -1;
  1869. while true do
  1870. begin
  1871. while (fmt[m] = ' ') and (Length(fmt) > m) do
  1872. inc(m);
  1873. if (m >= Length(fmt)) then
  1874. break;
  1875. if (fmt[m] = '%') then
  1876. begin
  1877. inc(m);
  1878. case fmt[m] of
  1879. 'd':
  1880. Result:=vtInteger;
  1881. 'f':
  1882. Result:=vtExtended;
  1883. 's':
  1884. Result:=vtString;
  1885. 'c':
  1886. Result:=vtChar;
  1887. else
  1888. raise EFormatError.CreateFmt(SInvalidFormat,[fmt]);
  1889. end;
  1890. inc(m);
  1891. break;
  1892. end;
  1893. if not(ScanStr(fmt[m])) then
  1894. break;
  1895. inc(m);
  1896. end;
  1897. end;
  1898. begin
  1899. n := 1;
  1900. m := 1;
  1901. Result := 0;
  1902. for i:=0 to High(Pointers) do
  1903. begin
  1904. j := GetFmt;
  1905. case j of
  1906. vtInteger :
  1907. begin
  1908. if GetInt>0 then
  1909. begin
  1910. plongint(Pointers[i])^:=StrToInt(s1);
  1911. inc(Result);
  1912. end
  1913. else
  1914. break;
  1915. end;
  1916. vtchar :
  1917. begin
  1918. if Length(s)>n then
  1919. begin
  1920. pchar(Pointers[i])^:=s[n];
  1921. inc(n);
  1922. inc(Result);
  1923. end
  1924. else
  1925. break;
  1926. end;
  1927. vtExtended :
  1928. begin
  1929. if GetFloat>0 then
  1930. begin
  1931. pextended(Pointers[i])^:=StrToFloat(s1);
  1932. inc(Result);
  1933. end
  1934. else
  1935. break;
  1936. end;
  1937. vtString :
  1938. begin
  1939. if GetString > 0 then
  1940. begin
  1941. pansistring(Pointers[i])^:=s1;
  1942. inc(Result);
  1943. end
  1944. else
  1945. break;
  1946. end;
  1947. else
  1948. break;
  1949. end;
  1950. end;
  1951. end;