cutils.pas 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420
  1. {
  2. Copyright (c) 1998-2002 by Florian Klaempfl
  3. This unit implements some support functions
  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
  6. by 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. }
  17. {# This unit contains some generic support functions which are used
  18. in the different parts of the compiler.
  19. }
  20. unit cutils;
  21. {$i fpcdefs.inc}
  22. interface
  23. type
  24. Tcharset=set of char;
  25. var
  26. internalerrorproc : procedure(i:longint);
  27. {# Returns the minimal value between @var(a) and @var(b) }
  28. function min(a,b : longint) : longint;{$ifdef USEINLINE}inline;{$endif}
  29. function min(a,b : int64) : int64;{$ifdef USEINLINE}inline;{$endif}
  30. {# Returns the maximum value between @var(a) and @var(b) }
  31. function max(a,b : longint) : longint;{$ifdef USEINLINE}inline;{$endif}
  32. function max(a,b : int64) : int64;{$ifdef USEINLINE}inline;{$endif}
  33. {# Return value @var(i) aligned on @var(a) boundary }
  34. function align(i,a:longint):longint;{$ifdef USEINLINE}inline;{$endif}
  35. { if you have an address aligned using "oldalignment" and add an
  36. offset of (a multiple of) offset to it, this function calculates
  37. the new minimally guaranteed alignment
  38. }
  39. function newalignment(oldalignment: longint; offset: int64): longint;
  40. {# Return @var(b) with the bit order reversed }
  41. function reverse_byte(b: byte): byte;
  42. function used_align(varalign,minalign,maxalign:shortint):shortint;
  43. function isbetteralignedthan(new, org, limit: cardinal): boolean;
  44. function size_2_align(len : longint) : shortint;
  45. function packedbitsloadsize(bitlen: int64) : int64;
  46. procedure Replace(var s:string;s1:string;const s2:string);
  47. procedure Replace(var s:AnsiString;s1:string;const s2:AnsiString);
  48. procedure ReplaceCase(var s:string;const s1,s2:string);
  49. Function MatchPattern(const pattern,what:string):boolean;
  50. function upper(const c : char) : char;
  51. function upper(const s : string) : string;
  52. function upper(const s : ansistring) : ansistring;
  53. function lower(const c : char) : char;
  54. function lower(const s : string) : string;
  55. function lower(const s : ansistring) : ansistring;
  56. function trimbspace(const s:string):string;
  57. function trimspace(const s:string):string;
  58. function space (b : longint): string;
  59. function PadSpace(const s:string;len:longint):string;
  60. function GetToken(var s:string;endchar:char):string;
  61. procedure uppervar(var s : string);
  62. function realtostr(e:extended):string;{$ifdef USEINLINE}inline;{$endif}
  63. function tostr(i : qword) : string;{$ifdef USEINLINE}inline;{$endif}overload;
  64. function tostr(i : int64) : string;{$ifdef USEINLINE}inline;{$endif}overload;
  65. function tostr(i : longint) : string;{$ifdef USEINLINE}inline;{$endif}overload;
  66. function tostr_with_plus(i : int64) : string;{$ifdef USEINLINE}inline;{$endif}
  67. function DStr(l:longint):string;
  68. {# Returns true if the string s is a number }
  69. function is_number(const s : string) : boolean;{$ifdef USEINLINE}inline;{$endif}
  70. {# Returns true if value is a power of 2, the actual
  71. exponent value is returned in power.
  72. }
  73. function ispowerof2(value : int64;out power : longint) : boolean;
  74. function nextpowerof2(value : int64; out power: longint) : int64;
  75. function backspace_quote(const s:string;const qchars:Tcharset):string;
  76. function octal_quote(const s:string;const qchars:Tcharset):string;
  77. function maybequoted(const s:string):string;
  78. function maybequoted(const s:ansistring):ansistring;
  79. {# If the string is quoted, in accordance with pascal, it is
  80. dequoted and returned in s, and the function returns true.
  81. If it is not quoted, or if the quoting is bad, s is not touched,
  82. and false is returned.
  83. }
  84. function DePascalQuote(var s: ansistring): Boolean;
  85. function CompareStr(const S1, S2: string): Integer;
  86. function CompareText(S1, S2: string): integer;
  87. { releases the string p and assignes nil to p }
  88. { if p=nil then freemem isn't called }
  89. procedure stringdispose(var p : pshortstring);{$ifdef USEINLINE}inline;{$endif}
  90. { allocates mem for a copy of s, copies s to this mem and returns }
  91. { a pointer to this mem }
  92. function stringdup(const s : string) : pshortstring;{$ifdef USEINLINE}inline;{$endif}
  93. {# Allocates memory for the string @var(s) and copies s as zero
  94. terminated string to that allocated memory and returns a pointer
  95. to that mem
  96. }
  97. function strpnew(const s : string) : pchar;
  98. {# makes the character @var(c) lowercase, with spanish, french and german
  99. character set
  100. }
  101. function lowercase(c : char) : char;
  102. { makes zero terminated string to a pascal string }
  103. { the data in p is modified and p is returned }
  104. function pchar2pshortstring(p : pchar) : pshortstring;
  105. { inverse of pchar2pshortstring }
  106. function pshortstring2pchar(p : pshortstring) : pchar;
  107. { Ansistring (pchar+length) support }
  108. procedure ansistringdispose(var p : pchar;length : longint);
  109. function compareansistrings(p1,p2 : pchar;length1,length2 : longint) : longint;
  110. function concatansistrings(p1,p2 : pchar;length1,length2 : longint) : pchar;
  111. {Lzw encode/decode to compress strings -> save memory.}
  112. function minilzw_encode(const s:string):string;
  113. function minilzw_decode(const s:string):string;
  114. Function nextafter(x,y:double):double;
  115. {$ifdef ver2_0}
  116. { RTL routines not available yet in 2.0.x }
  117. function SwapEndian(const AValue: SmallInt): SmallInt;
  118. function SwapEndian(const AValue: Word): Word;
  119. function SwapEndian(const AValue: LongInt): LongInt;
  120. function SwapEndian(const AValue: DWord): DWord;
  121. function SwapEndian(const AValue: Int64): Int64;
  122. function SwapEndian(const AValue: QWord): QWord;
  123. {$endif ver2_0}
  124. implementation
  125. uses
  126. SysUtils;
  127. var
  128. uppertbl,
  129. lowertbl : array[char] of char;
  130. function min(a,b : longint) : longint;{$ifdef USEINLINE}inline;{$endif}
  131. {
  132. return the minimal of a and b
  133. }
  134. begin
  135. if a<=b then
  136. min:=a
  137. else
  138. min:=b;
  139. end;
  140. function min(a,b : int64) : int64;{$ifdef USEINLINE}inline;{$endif}
  141. {
  142. return the minimal of a and b
  143. }
  144. begin
  145. if a<=b then
  146. min:=a
  147. else
  148. min:=b;
  149. end;
  150. function max(a,b : longint) : longint;{$ifdef USEINLINE}inline;{$endif}
  151. {
  152. return the maximum of a and b
  153. }
  154. begin
  155. if a>=b then
  156. max:=a
  157. else
  158. max:=b;
  159. end;
  160. function max(a,b : int64) : int64;{$ifdef USEINLINE}inline;{$endif}
  161. {
  162. return the maximum of a and b
  163. }
  164. begin
  165. if a>=b then
  166. max:=a
  167. else
  168. max:=b;
  169. end;
  170. function newalignment(oldalignment: longint; offset: int64): longint;
  171. var
  172. localoffset: longint;
  173. begin
  174. localoffset:=longint(offset);
  175. while (localoffset mod oldalignment)<>0 do
  176. oldalignment:=oldalignment div 2;
  177. newalignment:=oldalignment;
  178. end;
  179. function reverse_byte(b: byte): byte;
  180. const
  181. reverse_nible:array[0..15] of 0..15 =
  182. (%0000,%1000,%0100,%1100,%0010,%1010,%0110,%1110,
  183. %0001,%1001,%0101,%1101,%0011,%1011,%0111,%1111);
  184. begin
  185. reverse_byte:=(reverse_nible[b and $f] shl 4) or reverse_nible[b shr 4];
  186. end;
  187. function align(i,a:longint):longint;{$ifdef USEINLINE}inline;{$endif}
  188. {
  189. return value <i> aligned <a> boundary
  190. }
  191. begin
  192. { for 0 and 1 no aligning is needed }
  193. if a<=1 then
  194. result:=i
  195. else
  196. begin
  197. if i<0 then
  198. result:=((i-a+1) div a) * a
  199. else
  200. result:=((i+a-1) div a) * a;
  201. end;
  202. end;
  203. function size_2_align(len : longint) : shortint;
  204. begin
  205. if len>16 then
  206. size_2_align:=32
  207. else if len>8 then
  208. size_2_align:=16
  209. else if len>4 then
  210. size_2_align:=8
  211. else if len>2 then
  212. size_2_align:=4
  213. else if len>1 then
  214. size_2_align:=2
  215. else
  216. size_2_align:=1;
  217. end;
  218. function packedbitsloadsize(bitlen: int64) : int64;
  219. begin
  220. case bitlen of
  221. 1,2,4,8:
  222. result := 1;
  223. { 10 bits can never be split over 3 bytes via 1-8-1, because it }
  224. { always starts at a multiple of 10 bits. Same for the others. }
  225. 3,5,6,7,9,10,12,16:
  226. result := 2;
  227. {$ifdef cpu64bitalu}
  228. { performance penalty for unaligned 8 byte access is much }
  229. { higher than for unaligned 4 byte access, at least on ppc, }
  230. { so use 4 bytes even in some cases where a value could }
  231. { always loaded using a single 8 byte load (e.g. in case of }
  232. { 28 bit values) }
  233. 11,13,14,15,17..32:
  234. result := 4;
  235. else
  236. result := 8;
  237. {$else cpu64bitalu}
  238. else
  239. result := 4;
  240. {$endif cpu64bitalu}
  241. end;
  242. end;
  243. function isbetteralignedthan(new, org, limit: cardinal): boolean;
  244. var
  245. cnt: cardinal;
  246. begin
  247. cnt:=2;
  248. while (cnt <= limit) do
  249. begin
  250. if (org and (cnt-1)) > (new and (cnt-1)) then
  251. begin
  252. result:=true;
  253. exit;
  254. end
  255. else if (org and (cnt-1)) < (new and (cnt-1)) then
  256. begin
  257. result:=false;
  258. exit;
  259. end;
  260. cnt:=cnt*2;
  261. end;
  262. result:=false;
  263. end;
  264. function used_align(varalign,minalign,maxalign:shortint):shortint;
  265. begin
  266. { varalign : minimum alignment required for the variable
  267. minalign : Minimum alignment of this structure, 0 = undefined
  268. maxalign : Maximum alignment of this structure, 0 = undefined }
  269. if (minalign>0) and
  270. (varalign<minalign) then
  271. used_align:=minalign
  272. else
  273. begin
  274. if (maxalign>0) and
  275. (varalign>maxalign) then
  276. used_align:=maxalign
  277. else
  278. used_align:=varalign;
  279. end;
  280. end;
  281. procedure Replace(var s:string;s1:string;const s2:string);
  282. var
  283. last,
  284. i : longint;
  285. begin
  286. s1:=upper(s1);
  287. last:=0;
  288. repeat
  289. i:=pos(s1,upper(s));
  290. if i=last then
  291. i:=0;
  292. if (i>0) then
  293. begin
  294. Delete(s,i,length(s1));
  295. Insert(s2,s,i);
  296. last:=i;
  297. end;
  298. until (i=0);
  299. end;
  300. procedure Replace(var s:AnsiString;s1:string;const s2:AnsiString);
  301. var
  302. last,
  303. i : longint;
  304. begin
  305. s1:=upper(s1);
  306. last:=0;
  307. repeat
  308. i:=pos(s1,upper(s));
  309. if i=last then
  310. i:=0;
  311. if (i>0) then
  312. begin
  313. Delete(s,i,length(s1));
  314. Insert(s2,s,i);
  315. last:=i;
  316. end;
  317. until (i=0);
  318. end;
  319. procedure ReplaceCase(var s:string;const s1,s2:string);
  320. var
  321. last,
  322. i : longint;
  323. begin
  324. last:=0;
  325. repeat
  326. i:=pos(s1,s);
  327. if i=last then
  328. i:=0;
  329. if (i>0) then
  330. begin
  331. Delete(s,i,length(s1));
  332. Insert(s2,s,i);
  333. last:=i;
  334. end;
  335. until (i=0);
  336. end;
  337. Function MatchPattern(const pattern,what:string):boolean;
  338. var
  339. found : boolean;
  340. i1,i2 : longint;
  341. begin
  342. i1:=0;
  343. i2:=0;
  344. if pattern='' then
  345. begin
  346. result:=(what='');
  347. exit;
  348. end;
  349. found:=true;
  350. repeat
  351. inc(i1);
  352. if (i1>length(pattern)) then
  353. break;
  354. inc(i2);
  355. if (i2>length(what)) then
  356. break;
  357. case pattern[i1] of
  358. '?' :
  359. found:=true;
  360. '*' :
  361. begin
  362. found:=true;
  363. if (i1=length(pattern)) then
  364. i2:=length(what)
  365. else
  366. if (i1<length(pattern)) and (pattern[i1+1]<>what[i2]) then
  367. begin
  368. if i2<length(what) then
  369. dec(i1)
  370. end
  371. else
  372. if i2>1 then
  373. dec(i2);
  374. end;
  375. else
  376. found:=(pattern[i1]=what[i2]) or (what[i2]='?');
  377. end;
  378. until not found;
  379. if found then
  380. begin
  381. found:=(i2>=length(what)) and
  382. (
  383. (i1>length(pattern)) or
  384. ((i1=length(pattern)) and
  385. (pattern[i1]='*'))
  386. );
  387. end;
  388. result:=found;
  389. end;
  390. function upper(const c : char) : char;
  391. {
  392. return uppercase of c
  393. }
  394. begin
  395. upper:=uppertbl[c];
  396. end;
  397. function upper(const s : string) : string;
  398. {
  399. return uppercased string of s
  400. }
  401. var
  402. i : longint;
  403. begin
  404. for i:=1 to length(s) do
  405. upper[i]:=uppertbl[s[i]];
  406. upper[0]:=s[0];
  407. end;
  408. function upper(const s : ansistring) : ansistring;
  409. {
  410. return uppercased string of s
  411. }
  412. var
  413. i : longint;
  414. begin
  415. setlength(upper,length(s));
  416. for i:=1 to length(s) do
  417. upper[i]:=uppertbl[s[i]];
  418. end;
  419. function lower(const c : char) : char;
  420. {
  421. return lowercase of c
  422. }
  423. begin
  424. lower:=lowertbl[c];
  425. end;
  426. function lower(const s : string) : string;
  427. {
  428. return lowercased string of s
  429. }
  430. var
  431. i : longint;
  432. begin
  433. for i:=1 to length(s) do
  434. lower[i]:=lowertbl[s[i]];
  435. lower[0]:=s[0];
  436. end;
  437. function lower(const s : ansistring) : ansistring;
  438. {
  439. return lowercased string of s
  440. }
  441. var
  442. i : longint;
  443. begin
  444. setlength(lower,length(s));
  445. for i:=1 to length(s) do
  446. lower[i]:=lowertbl[s[i]];
  447. end;
  448. procedure uppervar(var s : string);
  449. {
  450. uppercase string s
  451. }
  452. var
  453. i : longint;
  454. begin
  455. for i:=1 to length(s) do
  456. s[i]:=uppertbl[s[i]];
  457. end;
  458. procedure initupperlower;
  459. var
  460. c : char;
  461. begin
  462. for c:=#0 to #255 do
  463. begin
  464. lowertbl[c]:=c;
  465. uppertbl[c]:=c;
  466. case c of
  467. 'A'..'Z' :
  468. lowertbl[c]:=char(byte(c)+32);
  469. 'a'..'z' :
  470. uppertbl[c]:=char(byte(c)-32);
  471. end;
  472. end;
  473. end;
  474. function DStr(l:longint):string;
  475. var
  476. TmpStr : string[32];
  477. i : longint;
  478. begin
  479. Str(l,TmpStr);
  480. i:=Length(TmpStr);
  481. while (i>3) do
  482. begin
  483. dec(i,3);
  484. if TmpStr[i]<>'-' then
  485. insert('.',TmpStr,i+1);
  486. end;
  487. DStr:=TmpStr;
  488. end;
  489. function trimbspace(const s:string):string;
  490. {
  491. return s with all leading spaces and tabs removed
  492. }
  493. var
  494. i,j : longint;
  495. begin
  496. j:=1;
  497. i:=length(s);
  498. while (j<i) and (s[j] in [#9,' ']) do
  499. inc(j);
  500. trimbspace:=Copy(s,j,i-j+1);
  501. end;
  502. function trimspace(const s:string):string;
  503. {
  504. return s with all leading and ending spaces and tabs removed
  505. }
  506. var
  507. i,j : longint;
  508. begin
  509. i:=length(s);
  510. while (i>0) and (s[i] in [#9,' ']) do
  511. dec(i);
  512. j:=1;
  513. while (j<i) and (s[j] in [#9,' ']) do
  514. inc(j);
  515. trimspace:=Copy(s,j,i-j+1);
  516. end;
  517. function space (b : longint): string;
  518. var
  519. s: string;
  520. begin
  521. space[0] := chr(b);
  522. s[0] := chr(b);
  523. FillChar (S[1],b,' ');
  524. space:=s;
  525. end;
  526. function PadSpace(const s:string;len:longint):string;
  527. {
  528. return s with spaces add to the end
  529. }
  530. begin
  531. if length(s)<len then
  532. PadSpace:=s+Space(len-length(s))
  533. else
  534. PadSpace:=s;
  535. end;
  536. function GetToken(var s:string;endchar:char):string;
  537. var
  538. i : longint;
  539. quote : char;
  540. begin
  541. GetToken:='';
  542. s:=TrimSpace(s);
  543. if (length(s)>0) and
  544. (s[1] in ['''','"']) then
  545. begin
  546. quote:=s[1];
  547. i:=1;
  548. while (i<length(s)) do
  549. begin
  550. inc(i);
  551. if s[i]=quote then
  552. begin
  553. { Remove double quote }
  554. if (i<length(s)) and
  555. (s[i+1]=quote) then
  556. begin
  557. Delete(s,i,1);
  558. inc(i);
  559. end
  560. else
  561. begin
  562. GetToken:=Copy(s,2,i-2);
  563. Delete(s,1,i);
  564. exit;
  565. end;
  566. end;
  567. end;
  568. GetToken:=s;
  569. s:='';
  570. end
  571. else
  572. begin
  573. i:=pos(EndChar,s);
  574. if i=0 then
  575. begin
  576. GetToken:=s;
  577. s:='';
  578. exit;
  579. end
  580. else
  581. begin
  582. GetToken:=Copy(s,1,i-1);
  583. Delete(s,1,i);
  584. exit;
  585. end;
  586. end;
  587. end;
  588. function realtostr(e:extended):string;{$ifdef USEINLINE}inline;{$endif}
  589. begin
  590. str(e,result);
  591. end;
  592. function tostr(i : qword) : string;{$ifdef USEINLINE}inline;{$endif}overload;
  593. {
  594. return string of value i
  595. }
  596. begin
  597. str(i,result);
  598. end;
  599. function tostr(i : int64) : string;{$ifdef USEINLINE}inline;{$endif}overload;
  600. {
  601. return string of value i
  602. }
  603. begin
  604. str(i,result);
  605. end;
  606. function tostr(i : longint) : string;{$ifdef USEINLINE}inline;{$endif}overload;
  607. {
  608. return string of value i
  609. }
  610. begin
  611. str(i,result);
  612. end;
  613. function tostr_with_plus(i : int64) : string;{$ifdef USEINLINE}inline;{$endif}
  614. {
  615. return string of value i, but always include a + when i>=0
  616. }
  617. begin
  618. str(i,result);
  619. if i>=0 then
  620. result:='+'+result;
  621. end;
  622. function is_number(const s : string) : boolean;{$ifdef USEINLINE}inline;{$endif}
  623. {
  624. is string a correct number ?
  625. }
  626. var
  627. w : integer;
  628. l : longint;
  629. begin
  630. val(s,l,w);
  631. // remove warning
  632. l:=l;
  633. is_number:=(w=0);
  634. end;
  635. function ispowerof2(value : int64;out power : longint) : boolean;
  636. {
  637. return if value is a power of 2. And if correct return the power
  638. }
  639. var
  640. hl : int64;
  641. i : longint;
  642. begin
  643. if value and (value - 1) <> 0 then
  644. begin
  645. ispowerof2 := false;
  646. exit
  647. end;
  648. hl:=1;
  649. ispowerof2:=true;
  650. for i:=0 to 63 do
  651. begin
  652. if hl=value then
  653. begin
  654. power:=i;
  655. exit;
  656. end;
  657. hl:=hl shl 1;
  658. end;
  659. ispowerof2:=false;
  660. end;
  661. function nextpowerof2(value : int64; out power: longint) : int64;
  662. {
  663. returns the power of 2 >= value
  664. }
  665. var
  666. i : longint;
  667. begin
  668. result := 0;
  669. power := -1;
  670. if ((value <= 0) or
  671. (value >= $4000000000000000)) then
  672. exit;
  673. result := 1;
  674. for i:=0 to 63 do
  675. begin
  676. if result>=value then
  677. begin
  678. power := i;
  679. exit;
  680. end;
  681. result:=result shl 1;
  682. end;
  683. end;
  684. function backspace_quote(const s:string;const qchars:Tcharset):string;
  685. var i:byte;
  686. begin
  687. backspace_quote:='';
  688. for i:=1 to length(s) do
  689. begin
  690. if (s[i]=#10) and (#10 in qchars) then
  691. backspace_quote:=backspace_quote+'\n'
  692. else if (s[i]=#13) and (#13 in qchars) then
  693. backspace_quote:=backspace_quote+'\r'
  694. else
  695. begin
  696. if s[i] in qchars then
  697. backspace_quote:=backspace_quote+'\';
  698. backspace_quote:=backspace_quote+s[i];
  699. end;
  700. end;
  701. end;
  702. function octal_quote(const s:string;const qchars:Tcharset):string;
  703. var i:byte;
  704. begin
  705. octal_quote:='';
  706. for i:=1 to length(s) do
  707. begin
  708. if s[i] in qchars then
  709. begin
  710. if ord(s[i])<64 then
  711. octal_quote:=octal_quote+'\'+octstr(ord(s[i]),3)
  712. else
  713. octal_quote:=octal_quote+'\'+octstr(ord(s[i]),4);
  714. end
  715. else
  716. octal_quote:=octal_quote+s[i];
  717. end;
  718. end;
  719. function maybequoted(const s:ansistring):ansistring;
  720. const
  721. {$IFDEF MSWINDOWS}
  722. FORBIDDEN_CHARS = ['!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
  723. '{', '}', '''', '`', '~'];
  724. {$ELSE}
  725. FORBIDDEN_CHARS = ['!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
  726. '{', '}', '''', ':', '\', '`', '~'];
  727. {$ENDIF}
  728. var
  729. s1 : ansistring;
  730. i : integer;
  731. quoted : boolean;
  732. begin
  733. quoted:=false;
  734. s1:='"';
  735. for i:=1 to length(s) do
  736. begin
  737. case s[i] of
  738. '"' :
  739. begin
  740. quoted:=true;
  741. s1:=s1+'\"';
  742. end;
  743. ' ',
  744. #128..#255 :
  745. begin
  746. quoted:=true;
  747. s1:=s1+s[i];
  748. end;
  749. else begin
  750. if s[i] in FORBIDDEN_CHARS then
  751. quoted:=True;
  752. s1:=s1+s[i];
  753. end;
  754. end;
  755. end;
  756. if quoted then
  757. maybequoted:=s1+'"'
  758. else
  759. maybequoted:=s;
  760. end;
  761. function maybequoted(const s:string):string;
  762. const
  763. {$IFDEF MSWINDOWS}
  764. FORBIDDEN_CHARS = ['!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
  765. '{', '}', '''', '`', '~'];
  766. {$ELSE}
  767. FORBIDDEN_CHARS = ['!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
  768. '{', '}', '''', ':', '\', '`', '~'];
  769. {$ENDIF}
  770. var
  771. s1 : string;
  772. i : integer;
  773. quoted : boolean;
  774. begin
  775. quoted:=false;
  776. s1:='"';
  777. for i:=1 to length(s) do
  778. begin
  779. case s[i] of
  780. '"' :
  781. begin
  782. quoted:=true;
  783. s1:=s1+'\"';
  784. end;
  785. ' ',
  786. #128..#255 :
  787. begin
  788. quoted:=true;
  789. s1:=s1+s[i];
  790. end;
  791. else begin
  792. if s[i] in FORBIDDEN_CHARS then
  793. quoted:=True;
  794. s1:=s1+s[i];
  795. end;
  796. end;
  797. end;
  798. if quoted then
  799. maybequoted:=s1+'"'
  800. else
  801. maybequoted:=s;
  802. end;
  803. function DePascalQuote(var s: ansistring): Boolean;
  804. var
  805. destPos, sourcePos, len: Integer;
  806. t: string;
  807. ch: Char;
  808. begin
  809. DePascalQuote:= false;
  810. len:= length(s);
  811. if (len >= 1) and (s[1] = '''') then
  812. begin
  813. {Remove quotes, exchange '' against ' }
  814. destPos := 0;
  815. sourcepos:=1;
  816. while (sourcepos<len) do
  817. begin
  818. inc(sourcePos);
  819. ch := s[sourcePos];
  820. if ch = '''' then
  821. begin
  822. inc(sourcePos);
  823. if (sourcePos <= len) and (s[sourcePos] = '''') then
  824. {Add the quote as part of string}
  825. else
  826. begin
  827. SetLength(t, destPos);
  828. s:= t;
  829. Exit(true);
  830. end;
  831. end;
  832. inc(destPos);
  833. t[destPos] := ch;
  834. end;
  835. end;
  836. end;
  837. function pchar2pshortstring(p : pchar) : pshortstring;
  838. var
  839. w,i : longint;
  840. begin
  841. w:=strlen(p);
  842. for i:=w-1 downto 0 do
  843. p[i+1]:=p[i];
  844. p[0]:=chr(w);
  845. pchar2pshortstring:=pshortstring(p);
  846. end;
  847. function pshortstring2pchar(p : pshortstring) : pchar;
  848. var
  849. w,i : longint;
  850. begin
  851. w:=length(p^);
  852. for i:=1 to w do
  853. p^[i-1]:=p^[i];
  854. p^[w]:=#0;
  855. pshortstring2pchar:=pchar(p);
  856. end;
  857. function lowercase(c : char) : char;
  858. begin
  859. case c of
  860. #65..#90 : c := chr(ord (c) + 32);
  861. #154 : c:=#129; { german }
  862. #142 : c:=#132; { german }
  863. #153 : c:=#148; { german }
  864. #144 : c:=#130; { french }
  865. #128 : c:=#135; { french }
  866. #143 : c:=#134; { swedish/norge (?) }
  867. #165 : c:=#164; { spanish }
  868. #228 : c:=#229; { greek }
  869. #226 : c:=#231; { greek }
  870. #232 : c:=#227; { greek }
  871. end;
  872. lowercase := c;
  873. end;
  874. function strpnew(const s : string) : pchar;
  875. var
  876. p : pchar;
  877. begin
  878. getmem(p,length(s)+1);
  879. move(s[1],p^,length(s));
  880. p[length(s)]:=#0;
  881. result:=p;
  882. end;
  883. procedure stringdispose(var p : pshortstring);{$ifdef USEINLINE}inline;{$endif}
  884. begin
  885. if assigned(p) then
  886. begin
  887. freemem(p);
  888. p:=nil;
  889. end;
  890. end;
  891. function stringdup(const s : string) : pshortstring;{$ifdef USEINLINE}inline;{$endif}
  892. begin
  893. getmem(result,length(s)+1);
  894. result^:=s;
  895. end;
  896. function CompareStr(const S1, S2: string): Integer;
  897. var
  898. count, count1, count2: integer;
  899. begin
  900. result := 0;
  901. Count1 := Length(S1);
  902. Count2 := Length(S2);
  903. if Count1>Count2 then
  904. Count:=Count2
  905. else
  906. Count:=Count1;
  907. result := CompareChar(S1[1],S2[1], Count);
  908. if result=0 then
  909. result:=Count1-Count2;
  910. end;
  911. function CompareText(S1, S2: string): integer;
  912. begin
  913. UpperVar(S1);
  914. UpperVar(S2);
  915. Result:=CompareStr(S1,S2);
  916. end;
  917. {*****************************************************************************
  918. Ansistring (PChar+Length)
  919. *****************************************************************************}
  920. procedure ansistringdispose(var p : pchar;length : longint);
  921. begin
  922. if assigned(p) then
  923. begin
  924. freemem(p);
  925. p:=nil;
  926. end;
  927. end;
  928. { enable ansistring comparison }
  929. { 0 means equal }
  930. { 1 means p1 > p2 }
  931. { -1 means p1 < p2 }
  932. function compareansistrings(p1,p2 : pchar;length1,length2 : longint) : longint;
  933. var
  934. i,j : longint;
  935. begin
  936. compareansistrings:=0;
  937. j:=min(length1,length2);
  938. i:=0;
  939. while (i<j) do
  940. begin
  941. if p1[i]>p2[i] then
  942. begin
  943. compareansistrings:=1;
  944. exit;
  945. end
  946. else
  947. if p1[i]<p2[i] then
  948. begin
  949. compareansistrings:=-1;
  950. exit;
  951. end;
  952. inc(i);
  953. end;
  954. if length1>length2 then
  955. compareansistrings:=1
  956. else
  957. if length1<length2 then
  958. compareansistrings:=-1;
  959. end;
  960. function concatansistrings(p1,p2 : pchar;length1,length2 : longint) : pchar;
  961. var
  962. p : pchar;
  963. begin
  964. getmem(p,length1+length2+1);
  965. move(p1[0],p[0],length1);
  966. move(p2[0],p[length1],length2+1);
  967. concatansistrings:=p;
  968. end;
  969. {*****************************************************************************
  970. Ultra basic KISS Lzw (de)compressor
  971. *****************************************************************************}
  972. {This is an extremely basic implementation of the Lzw algorithm. It
  973. compresses 7-bit ASCII strings into 8-bit compressed strings.
  974. The Lzw dictionary is preinitialized with 0..127, therefore this
  975. part of the dictionary does not need to be stored in the arrays.
  976. The Lzw code size is allways 8 bit, so we do not need complex code
  977. that can write partial bytes.}
  978. function minilzw_encode(const s:string):string;
  979. var t,u,i:byte;
  980. c:char;
  981. data:array[128..255] of char;
  982. previous:array[128..255] of byte;
  983. lzwptr:byte;
  984. next_avail:set of 0..255;
  985. label l1;
  986. begin
  987. minilzw_encode:='';
  988. fillchar(data,sizeof(data),#0);
  989. fillchar(previous,sizeof(previous),#0);
  990. if s<>'' then
  991. begin
  992. lzwptr:=127;
  993. t:=byte(s[1]);
  994. i:=2;
  995. u:=128;
  996. next_avail:=[];
  997. while i<=length(s) do
  998. begin
  999. c:=s[i];
  1000. if not(t in next_avail) or (u>lzwptr) then goto l1;
  1001. while (previous[u]<>t) or (data[u]<>c) do
  1002. begin
  1003. inc(u);
  1004. if u>lzwptr then goto l1;
  1005. end;
  1006. t:=u;
  1007. inc(i);
  1008. continue;
  1009. l1:
  1010. {It's a pity that we still need those awfull tricks
  1011. with this modern compiler. Without this performance
  1012. of the entire procedure drops about 3 times.}
  1013. inc(minilzw_encode[0]);
  1014. minilzw_encode[length(minilzw_encode)]:=char(t);
  1015. if lzwptr=255 then
  1016. begin
  1017. lzwptr:=127;
  1018. next_avail:=[];
  1019. end
  1020. else
  1021. begin
  1022. inc(lzwptr);
  1023. data[lzwptr]:=c;
  1024. previous[lzwptr]:=t;
  1025. include(next_avail,t);
  1026. end;
  1027. t:=byte(c);
  1028. u:=128;
  1029. inc(i);
  1030. end;
  1031. inc(minilzw_encode[0]);
  1032. minilzw_encode[length(minilzw_encode)]:=char(t);
  1033. end;
  1034. end;
  1035. function minilzw_decode(const s:string):string;
  1036. var oldc,newc,c:char;
  1037. i,j:byte;
  1038. data:array[128..255] of char;
  1039. previous:array[128..255] of byte;
  1040. lzwptr:byte;
  1041. t:string;
  1042. begin
  1043. minilzw_decode:='';
  1044. fillchar(data,sizeof(data),#0);
  1045. fillchar(previous,sizeof(previous),#0);
  1046. if s<>'' then
  1047. begin
  1048. lzwptr:=127;
  1049. oldc:=s[1];
  1050. c:=oldc;
  1051. i:=2;
  1052. minilzw_decode:=oldc;
  1053. while i<=length(s) do
  1054. begin
  1055. newc:=s[i];
  1056. if byte(newc)>lzwptr then
  1057. begin
  1058. t:=c;
  1059. c:=oldc;
  1060. end
  1061. else
  1062. begin
  1063. c:=newc;
  1064. t:='';
  1065. end;
  1066. while c>=#128 do
  1067. begin
  1068. inc(t[0]);
  1069. t[length(t)]:=data[byte(c)];
  1070. byte(c):=previous[byte(c)];
  1071. end;
  1072. inc(minilzw_decode[0]);
  1073. minilzw_decode[length(minilzw_decode)]:=c;
  1074. for j:=length(t) downto 1 do
  1075. begin
  1076. inc(minilzw_decode[0]);
  1077. minilzw_decode[length(minilzw_decode)]:=t[j];
  1078. end;
  1079. if lzwptr=255 then
  1080. lzwptr:=127
  1081. else
  1082. begin
  1083. inc(lzwptr);
  1084. previous[lzwptr]:=byte(oldc);
  1085. data[lzwptr]:=c;
  1086. end;
  1087. oldc:=newc;
  1088. inc(i);
  1089. end;
  1090. end;
  1091. end;
  1092. procedure defaulterror(i:longint);
  1093. begin
  1094. writeln('Internal error ',i);
  1095. runerror(255);
  1096. end;
  1097. Function Nextafter(x,y:double):double;
  1098. // Returns the double precision number closest to x in
  1099. // the direction toward y.
  1100. // Initial direct translation by Soeren Haastrup from
  1101. // www.netlib.org/fdlibm/s_nextafter.c according to
  1102. // ====================================================
  1103. // Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
  1104. // Developed at SunSoft, a Sun Microsystems, Inc. business.
  1105. // Permission to use, copy, modify, and distribute this
  1106. // software is freely granted, provided that this notice
  1107. // is preserved.
  1108. // ====================================================
  1109. // and with all signaling policies preserved as is.
  1110. type
  1111. {$if defined(ENDIAN_LITTLE) and not defined(FPC_DOUBLE_HILO_SWAPPED)}
  1112. twoword=record
  1113. lo,hi:longword; // Little Endian split of a double.
  1114. end;
  1115. {$else}
  1116. twoword=record
  1117. hi,lo:longword; // Big Endian split of a double.
  1118. end;
  1119. {$endif}
  1120. var
  1121. hx,hy,ix,iy:longint;
  1122. lx,ly:longword;
  1123. Begin
  1124. hx:=twoword(x).hi; // high and low words of x and y
  1125. lx:=twoword(x).lo;
  1126. hy:=twoword(y).hi;
  1127. ly:=twoword(y).lo;
  1128. ix:=hx and $7fffffff; // absolute values
  1129. iy:=hy and $7fffffff;
  1130. // Case x=NAN or y=NAN
  1131. if ( (ix>=$7ff00000) and ((longword(ix-$7ff00000) or lx) <> 0) )
  1132. or ( (iy>=$7ff00000) and ((longword(iy-$7ff00000) OR ly) <> 0) )
  1133. then exit(x+y);
  1134. // Case x=y
  1135. if x=y then exit(x); // (implies Nextafter(0,-0) is 0 and not -0...)
  1136. // Case x=0
  1137. if (longword(ix) or lx)=0
  1138. then begin
  1139. twoword(x).hi:=hy and $80000000; // return +-minimalSubnormal
  1140. twoword(x).lo:=1;
  1141. y:=x*x; // set underflow flag (ignored in FPC as default)
  1142. if y=x
  1143. then exit(y)
  1144. else exit(x);
  1145. end;
  1146. // all other cases
  1147. if hx>=0 // x>0
  1148. then begin
  1149. if (hx>hy) or ( (hx=hy) and (lx>ly) ) // x>y , return x-ulp
  1150. then begin
  1151. if (lx=0) then hx:=hx-1;
  1152. lx:=lx-1;
  1153. end
  1154. else begin // x<y, return x+ulp
  1155. lx:=lx+1;
  1156. if lx=0 then hx:=hx+1;
  1157. end
  1158. end
  1159. else begin // x<0
  1160. if (hy>=0) or (hx>=hy) or ( (hx=hy) and (lx>ly)) // x<y, return x-ulp
  1161. then begin
  1162. if (lx=0) then hx:=hx-1;
  1163. lx:=lx-1;
  1164. end
  1165. else begin // x>y , return x+ulp
  1166. lx:=lx+1;
  1167. if lx=0 then hx:=hx+1;
  1168. end
  1169. end;
  1170. // finally check if overflow or underflow just happend
  1171. hy:=hx and $7ff00000;
  1172. if (hy>= $7ff00000) then exit(x+x); // overflow and signal
  1173. if (hy<$0010000) // underflow
  1174. then begin
  1175. y:=x*x; // raise underflow flag
  1176. if y<>x
  1177. then begin
  1178. twoword(y).hi:=hx;
  1179. twoword(y).lo:=lx;
  1180. exit(y);
  1181. end
  1182. end;
  1183. twoword(x).hi:=hx;
  1184. twoword(x).lo:=lx;
  1185. nextafter:=x;
  1186. end;
  1187. {$ifdef ver2_0}
  1188. function SwapEndian(const AValue: SmallInt): SmallInt;
  1189. begin
  1190. { the extra Word type cast is necessary because the "AValue shr 8" }
  1191. { is turned into "longint(AValue) shr 8", so if AValue < 0 then }
  1192. { the sign bits from the upper 16 bits are shifted in rather than }
  1193. { zeroes. }
  1194. Result := SmallInt((Word(AValue) shr 8) or (Word(AValue) shl 8));
  1195. end;
  1196. function SwapEndian(const AValue: Word): Word;
  1197. begin
  1198. Result := (AValue shr 8) or (AValue shl 8);
  1199. end;
  1200. function SwapEndian(const AValue: LongInt): LongInt;
  1201. begin
  1202. Result := (AValue shl 24)
  1203. or ((AValue and $0000FF00) shl 8)
  1204. or ((AValue and $00FF0000) shr 8)
  1205. or (AValue shr 24);
  1206. end;
  1207. function SwapEndian(const AValue: DWord): DWord;
  1208. begin
  1209. Result := (AValue shl 24)
  1210. or ((AValue and $0000FF00) shl 8)
  1211. or ((AValue and $00FF0000) shr 8)
  1212. or (AValue shr 24);
  1213. end;
  1214. function SwapEndian(const AValue: Int64): Int64;
  1215. begin
  1216. Result := (AValue shl 56)
  1217. or ((AValue and $000000000000FF00) shl 40)
  1218. or ((AValue and $0000000000FF0000) shl 24)
  1219. or ((AValue and $00000000FF000000) shl 8)
  1220. or ((AValue and $000000FF00000000) shr 8)
  1221. or ((AValue and $0000FF0000000000) shr 24)
  1222. or ((AValue and $00FF000000000000) shr 40)
  1223. or (AValue shr 56);
  1224. end;
  1225. function SwapEndian(const AValue: QWord): QWord;
  1226. begin
  1227. Result := (AValue shl 56)
  1228. or ((AValue and $000000000000FF00) shl 40)
  1229. or ((AValue and $0000000000FF0000) shl 24)
  1230. or ((AValue and $00000000FF000000) shl 8)
  1231. or ((AValue and $000000FF00000000) shr 8)
  1232. or ((AValue and $0000FF0000000000) shr 24)
  1233. or ((AValue and $00FF000000000000) shr 40)
  1234. or (AValue shr 56);
  1235. end;
  1236. {$endif ver2_0}
  1237. initialization
  1238. internalerrorproc:=@defaulterror;
  1239. initupperlower;
  1240. end.