cutils.pas 36 KB

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