cutils.pas 38 KB

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