cutils.pas 37 KB

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