cutils.pas 35 KB

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