cutils.pas 32 KB

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