cutils.pas 37 KB

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