sysstr.inc 50 KB

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