cutils.pas 38 KB

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