cutils.pas 37 KB

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