cutils.pas 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168
  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. pstring = ^string;
  25. get_var_value_proc=function(const s:string):string of object;
  26. Tcharset=set of char;
  27. var
  28. internalerrorproc : procedure(i:longint);
  29. {# Returns the minimal value between @var(a) and @var(b) }
  30. function min(a,b : longint) : longint;{$ifdef USEINLINE}inline;{$endif}
  31. function min(a,b : int64) : int64;{$ifdef USEINLINE}inline;{$endif}
  32. {# Returns the maximum value between @var(a) and @var(b) }
  33. function max(a,b : longint) : longint;{$ifdef USEINLINE}inline;{$endif}
  34. function max(a,b : int64) : int64;{$ifdef USEINLINE}inline;{$endif}
  35. {# Returns the value in @var(x) swapped to different endian }
  36. Function SwapInt64(x : int64): int64;{$ifdef USEINLINE}inline;{$endif}
  37. {# Returns the value in @var(x) swapped to different endian }
  38. function SwapLong(x : longint): longint;{$ifdef USEINLINE}inline;{$endif}
  39. {# Returns the value in @va(x) swapped to different endian }
  40. function SwapWord(x : word): word;{$ifdef USEINLINE}inline;{$endif}
  41. {# Return value @var(i) aligned on @var(a) boundary }
  42. function align(i,a:longint):longint;{$ifdef USEINLINE}inline;{$endif}
  43. function used_align(varalign,minalign,maxalign:longint):longint;
  44. function size_2_align(len : longint) : longint;
  45. procedure Replace(var s:string;s1:string;const s2:string);
  46. procedure Replace(var s:AnsiString;s1:string;const s2:string);
  47. procedure ReplaceCase(var s:string;const s1,s2:string);
  48. function upper(const s : string) : string;
  49. function lower(const s : string) : string;
  50. function trimbspace(const s:string):string;
  51. function trimspace(const s:string):string;
  52. function space (b : longint): string;
  53. function PadSpace(const s:string;len:longint):string;
  54. function GetToken(var s:string;endchar:char):string;
  55. procedure uppervar(var s : string);
  56. function realtostr(e:extended):string;{$ifdef USEINLINE}inline;{$endif}
  57. function tostr(i : qword) : string;{$ifdef USEINLINE}inline;{$endif}overload;
  58. function tostr(i : int64) : string;{$ifdef USEINLINE}inline;{$endif}overload;
  59. function tostr(i : longint) : string;{$ifdef USEINLINE}inline;{$endif}overload;
  60. function tostr_with_plus(i : int64) : string;{$ifdef USEINLINE}inline;{$endif}
  61. function DStr(l:longint):string;
  62. {# Returns true if the string s is a number }
  63. function is_number(const s : string) : boolean;{$ifdef USEINLINE}inline;{$endif}
  64. {# Returns true if value is a power of 2, the actual
  65. exponent value is returned in power.
  66. }
  67. function ispowerof2(value : int64;out power : longint) : boolean;
  68. function backspace_quote(const s:string;const qchars:Tcharset):string;
  69. function octal_quote(const s:string;const qchars:Tcharset):string;
  70. function maybequoted(const s:string):string;
  71. {# If the string is quoted, in accordance with pascal, it is
  72. dequoted and returned in s, and the function returns true.
  73. If it is not quoted, or if the quoting is bad, s is not touched,
  74. and false is returned.
  75. }
  76. function DePascalQuote(var s: string): Boolean;
  77. function CompareText(S1, S2: string): longint;
  78. { releases the string p and assignes nil to p }
  79. { if p=nil then freemem isn't called }
  80. procedure stringdispose(var p : pstring);{$ifdef USEINLINE}inline;{$endif}
  81. { allocates mem for a copy of s, copies s to this mem and returns }
  82. { a pointer to this mem }
  83. function stringdup(const s : string) : pstring;{$ifdef USEINLINE}inline;{$endif}
  84. {# Allocates memory for the string @var(s) and copies s as zero
  85. terminated string to that allocated memory and returns a pointer
  86. to that mem
  87. }
  88. function strpnew(const s : string) : pchar;
  89. procedure strdispose(var p : pchar);
  90. function string_evaluate(s:string;get_var_value:get_var_value_proc;
  91. const vars:array of string):Pchar;
  92. {# makes the character @var(c) lowercase, with spanish, french and german
  93. character set
  94. }
  95. function lowercase(c : char) : char;
  96. { makes zero terminated string to a pascal string }
  97. { the data in p is modified and p is returned }
  98. function pchar2pstring(p : pchar) : pstring;
  99. { ambivalent to pchar2pstring }
  100. function pstring2pchar(p : pstring) : pchar;
  101. { Speed/Hash value }
  102. Function GetSpeedValue(Const s:String):cardinal;
  103. { Ansistring (pchar+length) support }
  104. procedure ansistringdispose(var p : pchar;length : longint);
  105. function compareansistrings(p1,p2 : pchar;length1,length2 : longint) : longint;
  106. function concatansistrings(p1,p2 : pchar;length1,length2 : longint) : pchar;
  107. {Lzw encode/decode to compress strings -> save memory.}
  108. function minilzw_encode(const s:string):string;
  109. function minilzw_decode(const s:string):string;
  110. implementation
  111. uses
  112. strings
  113. ;
  114. var
  115. uppertbl,
  116. lowertbl : array[char] of char;
  117. function min(a,b : longint) : longint;{$ifdef USEINLINE}inline;{$endif}
  118. {
  119. return the minimal of a and b
  120. }
  121. begin
  122. if a<=b then
  123. min:=a
  124. else
  125. min:=b;
  126. end;
  127. function min(a,b : int64) : int64;{$ifdef USEINLINE}inline;{$endif}
  128. {
  129. return the minimal of a and b
  130. }
  131. begin
  132. if a<=b then
  133. min:=a
  134. else
  135. min:=b;
  136. end;
  137. function max(a,b : longint) : longint;{$ifdef USEINLINE}inline;{$endif}
  138. {
  139. return the maximum of a and b
  140. }
  141. begin
  142. if a>=b then
  143. max:=a
  144. else
  145. max:=b;
  146. end;
  147. function max(a,b : int64) : int64;{$ifdef USEINLINE}inline;{$endif}
  148. {
  149. return the maximum of a and b
  150. }
  151. begin
  152. if a>=b then
  153. max:=a
  154. else
  155. max:=b;
  156. end;
  157. Function SwapLong(x : longint): longint;{$ifdef USEINLINE}inline;{$endif}
  158. var
  159. y : word;
  160. z : word;
  161. Begin
  162. y := x shr 16;
  163. y := word(longint(y) shl 8) or (y shr 8);
  164. z := x and $FFFF;
  165. z := word(longint(z) shl 8) or (z shr 8);
  166. SwapLong := (longint(z) shl 16) or longint(y);
  167. End;
  168. Function SwapInt64(x : int64): int64;{$ifdef USEINLINE}inline;{$endif}
  169. Begin
  170. result:=swaplong(longint(hi(x)));
  171. result:=result or (swaplong(longint(lo(x))) shl 32);
  172. End;
  173. Function SwapWord(x : word): word;{$ifdef USEINLINE}inline;{$endif}
  174. var
  175. z : byte;
  176. Begin
  177. z := x shr 8;
  178. x := x and $ff;
  179. x := (x shl 8);
  180. SwapWord := x or z;
  181. End;
  182. function align(i,a:longint):longint;{$ifdef USEINLINE}inline;{$endif}
  183. {
  184. return value <i> aligned <a> boundary
  185. }
  186. begin
  187. { for 0 and 1 no aligning is needed }
  188. if a<=1 then
  189. result:=i
  190. else
  191. begin
  192. if i<0 then
  193. result:=((i-a+1) div a) * a
  194. else
  195. result:=((i+a-1) div a) * a;
  196. end;
  197. end;
  198. function size_2_align(len : longint) : longint;
  199. begin
  200. if len>16 then
  201. size_2_align:=32
  202. else if len>8 then
  203. size_2_align:=16
  204. else if len>4 then
  205. size_2_align:=8
  206. else if len>2 then
  207. size_2_align:=4
  208. else if len>1 then
  209. size_2_align:=2
  210. else
  211. size_2_align:=1;
  212. end;
  213. function used_align(varalign,minalign,maxalign:longint):longint;
  214. begin
  215. { varalign : minimum alignment required for the variable
  216. minalign : Minimum alignment of this structure, 0 = undefined
  217. maxalign : Maximum alignment of this structure, 0 = undefined }
  218. if (minalign>0) and
  219. (varalign<minalign) then
  220. used_align:=minalign
  221. else
  222. begin
  223. if (maxalign>0) and
  224. (varalign>maxalign) then
  225. used_align:=maxalign
  226. else
  227. used_align:=varalign;
  228. end;
  229. end;
  230. procedure Replace(var s:string;s1:string;const s2:string);
  231. var
  232. last,
  233. i : longint;
  234. begin
  235. s1:=upper(s1);
  236. last:=0;
  237. repeat
  238. i:=pos(s1,upper(s));
  239. if i=last then
  240. i:=0;
  241. if (i>0) then
  242. begin
  243. Delete(s,i,length(s1));
  244. Insert(s2,s,i);
  245. last:=i;
  246. end;
  247. until (i=0);
  248. end;
  249. procedure Replace(var s:AnsiString;s1:string;const s2:string);
  250. var
  251. last,
  252. i : longint;
  253. begin
  254. s1:=upper(s1);
  255. last:=0;
  256. repeat
  257. i:=pos(s1,upper(s));
  258. if i=last then
  259. i:=0;
  260. if (i>0) then
  261. begin
  262. Delete(s,i,length(s1));
  263. Insert(s2,s,i);
  264. last:=i;
  265. end;
  266. until (i=0);
  267. end;
  268. procedure ReplaceCase(var s:string;const s1,s2:string);
  269. var
  270. last,
  271. i : longint;
  272. begin
  273. last:=0;
  274. repeat
  275. i:=pos(s1,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. function upper(const s : string) : string;
  287. {
  288. return uppercased string of s
  289. }
  290. var
  291. i : longint;
  292. begin
  293. for i:=1 to length(s) do
  294. upper[i]:=uppertbl[s[i]];
  295. upper[0]:=s[0];
  296. end;
  297. function lower(const s : string) : string;
  298. {
  299. return lowercased string of s
  300. }
  301. var
  302. i : longint;
  303. begin
  304. for i:=1 to length(s) do
  305. lower[i]:=lowertbl[s[i]];
  306. lower[0]:=s[0];
  307. end;
  308. procedure uppervar(var s : string);
  309. {
  310. uppercase string s
  311. }
  312. var
  313. i : longint;
  314. begin
  315. for i:=1 to length(s) do
  316. s[i]:=uppertbl[s[i]];
  317. end;
  318. procedure initupperlower;
  319. var
  320. c : char;
  321. begin
  322. for c:=#0 to #255 do
  323. begin
  324. lowertbl[c]:=c;
  325. uppertbl[c]:=c;
  326. case c of
  327. 'A'..'Z' :
  328. lowertbl[c]:=char(byte(c)+32);
  329. 'a'..'z' :
  330. uppertbl[c]:=char(byte(c)-32);
  331. end;
  332. end;
  333. end;
  334. function DStr(l:longint):string;
  335. var
  336. TmpStr : string[32];
  337. i : longint;
  338. begin
  339. Str(l,TmpStr);
  340. i:=Length(TmpStr);
  341. while (i>3) do
  342. begin
  343. dec(i,3);
  344. if TmpStr[i]<>'-' then
  345. insert('.',TmpStr,i+1);
  346. end;
  347. DStr:=TmpStr;
  348. end;
  349. function trimbspace(const s:string):string;
  350. {
  351. return s with all leading spaces and tabs removed
  352. }
  353. var
  354. i,j : longint;
  355. begin
  356. j:=1;
  357. i:=length(s);
  358. while (j<i) and (s[j] in [#9,' ']) do
  359. inc(j);
  360. trimbspace:=Copy(s,j,i-j+1);
  361. end;
  362. function trimspace(const s:string):string;
  363. {
  364. return s with all leading and ending spaces and tabs removed
  365. }
  366. var
  367. i,j : longint;
  368. begin
  369. i:=length(s);
  370. while (i>0) and (s[i] in [#9,' ']) do
  371. dec(i);
  372. j:=1;
  373. while (j<i) and (s[j] in [#9,' ']) do
  374. inc(j);
  375. trimspace:=Copy(s,j,i-j+1);
  376. end;
  377. function space (b : longint): string;
  378. var
  379. s: string;
  380. begin
  381. space[0] := chr(b);
  382. s[0] := chr(b);
  383. FillChar (S[1],b,' ');
  384. space:=s;
  385. end;
  386. function PadSpace(const s:string;len:longint):string;
  387. {
  388. return s with spaces add to the end
  389. }
  390. begin
  391. if length(s)<len then
  392. PadSpace:=s+Space(len-length(s))
  393. else
  394. PadSpace:=s;
  395. end;
  396. function GetToken(var s:string;endchar:char):string;
  397. var
  398. i : longint;
  399. begin
  400. GetToken:='';
  401. s:=TrimSpace(s);
  402. if (length(s)>0) and
  403. (s[1]='''') then
  404. begin
  405. i:=1;
  406. while (i<length(s)) do
  407. begin
  408. inc(i);
  409. if s[i]='''' then
  410. begin
  411. { Remove double quote }
  412. if (i<length(s)) and
  413. (s[i+1]='''') then
  414. begin
  415. Delete(s,i,1);
  416. inc(i);
  417. end
  418. else
  419. begin
  420. GetToken:=Copy(s,2,i-2);
  421. Delete(s,1,i);
  422. exit;
  423. end;
  424. end;
  425. end;
  426. GetToken:=s;
  427. s:='';
  428. end
  429. else
  430. begin
  431. i:=pos(EndChar,s);
  432. if i=0 then
  433. begin
  434. GetToken:=s;
  435. s:='';
  436. exit;
  437. end
  438. else
  439. begin
  440. GetToken:=Copy(s,1,i-1);
  441. Delete(s,1,i);
  442. exit;
  443. end;
  444. end;
  445. end;
  446. function realtostr(e:extended):string;{$ifdef USEINLINE}inline;{$endif}
  447. begin
  448. str(e,result);
  449. end;
  450. function tostr(i : qword) : string;{$ifdef USEINLINE}inline;{$endif}overload;
  451. {
  452. return string of value i
  453. }
  454. begin
  455. str(i,result);
  456. end;
  457. function tostr(i : int64) : string;{$ifdef USEINLINE}inline;{$endif}overload;
  458. {
  459. return string of value i
  460. }
  461. begin
  462. str(i,result);
  463. end;
  464. function tostr(i : longint) : string;{$ifdef USEINLINE}inline;{$endif}overload;
  465. {
  466. return string of value i
  467. }
  468. begin
  469. str(i,result);
  470. end;
  471. function tostr_with_plus(i : int64) : string;{$ifdef USEINLINE}inline;{$endif}
  472. {
  473. return string of value i, but always include a + when i>=0
  474. }
  475. begin
  476. str(i,result);
  477. if i>=0 then
  478. result:='+'+result;
  479. end;
  480. function is_number(const s : string) : boolean;{$ifdef USEINLINE}inline;{$endif}
  481. {
  482. is string a correct number ?
  483. }
  484. var
  485. w : integer;
  486. l : longint;
  487. begin
  488. val(s,l,w);
  489. is_number:=(w=0);
  490. end;
  491. function ispowerof2(value : int64;out power : longint) : boolean;
  492. {
  493. return if value is a power of 2. And if correct return the power
  494. }
  495. var
  496. hl : int64;
  497. i : longint;
  498. begin
  499. if value and (value - 1) <> 0 then
  500. begin
  501. ispowerof2 := false;
  502. exit
  503. end;
  504. hl:=1;
  505. ispowerof2:=true;
  506. for i:=0 to 63 do
  507. begin
  508. if hl=value then
  509. begin
  510. power:=i;
  511. exit;
  512. end;
  513. hl:=hl shl 1;
  514. end;
  515. ispowerof2:=false;
  516. end;
  517. function backspace_quote(const s:string;const qchars:Tcharset):string;
  518. var i:byte;
  519. begin
  520. backspace_quote:='';
  521. for i:=1 to length(s) do
  522. begin
  523. if (s[i]=#10) and (#10 in qchars) then
  524. backspace_quote:=backspace_quote+'\n'
  525. else if (s[i]=#13) and (#13 in qchars) then
  526. backspace_quote:=backspace_quote+'\r'
  527. else
  528. begin
  529. if s[i] in qchars then
  530. backspace_quote:=backspace_quote+'\';
  531. backspace_quote:=backspace_quote+s[i];
  532. end;
  533. end;
  534. end;
  535. function octal_quote(const s:string;const qchars:Tcharset):string;
  536. var i:byte;
  537. begin
  538. octal_quote:='';
  539. for i:=1 to length(s) do
  540. begin
  541. if s[i] in qchars then
  542. begin
  543. if ord(s[i])<64 then
  544. octal_quote:=octal_quote+'\'+octstr(ord(s[i]),3)
  545. else
  546. octal_quote:=octal_quote+'\'+octstr(ord(s[i]),4);
  547. end
  548. else
  549. octal_quote:=octal_quote+s[i];
  550. end;
  551. end;
  552. function maybequoted(const s:string):string;
  553. var
  554. s1 : string;
  555. i : integer;
  556. quoted : boolean;
  557. begin
  558. quoted:=false;
  559. s1:='"';
  560. for i:=1 to length(s) do
  561. begin
  562. case s[i] of
  563. '"' :
  564. begin
  565. quoted:=true;
  566. s1:=s1+'\"';
  567. end;
  568. ' ',
  569. #128..#255 :
  570. begin
  571. quoted:=true;
  572. s1:=s1+s[i];
  573. end;
  574. else
  575. s1:=s1+s[i];
  576. end;
  577. end;
  578. if quoted then
  579. maybequoted:=s1+'"'
  580. else
  581. maybequoted:=s;
  582. end;
  583. function DePascalQuote(var s: string): Boolean;
  584. var
  585. destPos, sourcePos, len: Integer;
  586. t: string;
  587. ch: Char;
  588. begin
  589. DePascalQuote:= false;
  590. len:= length(s);
  591. if (len >= 1) and (s[1] = '''') then
  592. begin
  593. {Remove quotes, exchange '' against ' }
  594. destPos := 0;
  595. sourcepos:=1;
  596. while (sourcepos<len) do
  597. begin
  598. inc(sourcePos);
  599. ch := s[sourcePos];
  600. if ch = '''' then
  601. begin
  602. inc(sourcePos);
  603. if (sourcePos <= len) and (s[sourcePos] = '''') then
  604. {Add the quote as part of string}
  605. else
  606. begin
  607. SetLength(t, destPos);
  608. s:= t;
  609. Exit(true);
  610. end;
  611. end;
  612. inc(destPos);
  613. t[destPos] := ch;
  614. end;
  615. end;
  616. end;
  617. function pchar2pstring(p : pchar) : pstring;
  618. var
  619. w,i : longint;
  620. begin
  621. w:=strlen(p);
  622. for i:=w-1 downto 0 do
  623. p[i+1]:=p[i];
  624. p[0]:=chr(w);
  625. pchar2pstring:=pstring(p);
  626. end;
  627. function pstring2pchar(p : pstring) : pchar;
  628. var
  629. w,i : longint;
  630. begin
  631. w:=length(p^);
  632. for i:=1 to w do
  633. p^[i-1]:=p^[i];
  634. p^[w]:=#0;
  635. pstring2pchar:=pchar(p);
  636. end;
  637. function lowercase(c : char) : char;
  638. begin
  639. case c of
  640. #65..#90 : c := chr(ord (c) + 32);
  641. #154 : c:=#129; { german }
  642. #142 : c:=#132; { german }
  643. #153 : c:=#148; { german }
  644. #144 : c:=#130; { french }
  645. #128 : c:=#135; { french }
  646. #143 : c:=#134; { swedish/norge (?) }
  647. #165 : c:=#164; { spanish }
  648. #228 : c:=#229; { greek }
  649. #226 : c:=#231; { greek }
  650. #232 : c:=#227; { greek }
  651. end;
  652. lowercase := c;
  653. end;
  654. function strpnew(const s : string) : pchar;
  655. var
  656. p : pchar;
  657. begin
  658. getmem(p,length(s)+1);
  659. strpcopy(p,s);
  660. strpnew:=p;
  661. end;
  662. procedure strdispose(var p : pchar);
  663. begin
  664. if assigned(p) then
  665. begin
  666. freemem(p,strlen(p)+1);
  667. p:=nil;
  668. end;
  669. end;
  670. procedure stringdispose(var p : pstring);{$ifdef USEINLINE}inline;{$endif}
  671. begin
  672. if assigned(p) then
  673. begin
  674. freemem(p,length(p^)+1);
  675. p:=nil;
  676. end;
  677. end;
  678. function stringdup(const s : string) : pstring;{$ifdef USEINLINE}inline;{$endif}
  679. begin
  680. getmem(result,length(s)+1);
  681. result^:=s;
  682. end;
  683. function CompareText(S1, S2: string): longint;
  684. begin
  685. UpperVar(S1);
  686. UpperVar(S2);
  687. if S1<S2 then
  688. CompareText:=-1
  689. else
  690. if S1>S2 then
  691. CompareText:= 1
  692. else
  693. CompareText:=0;
  694. end;
  695. function string_evaluate(s:string;get_var_value:get_var_value_proc;
  696. const vars:array of string):Pchar;
  697. {S contains a prototype of a stabstring. Stabstr_evaluate will expand
  698. variables and parameters.
  699. Output is s in ASCIIZ format, with the following expanded:
  700. ${varname} - The variable name is expanded.
  701. $n - The parameter n is expanded.
  702. $$ - Is expanded to $
  703. }
  704. const maxvalue=9;
  705. maxdata=1023;
  706. var i,j:byte;
  707. varname:string[63];
  708. varno,varcounter:byte;
  709. varvalues:array[0..9] of Pstring;
  710. {1 kb of parameters is the limit. 256 extra bytes are allocated to
  711. ensure buffer integrity.}
  712. varvaluedata:array[0..maxdata+256] of char;
  713. varptr:Pchar;
  714. len:cardinal;
  715. r:Pchar;
  716. begin
  717. {Two pass approach, first, calculate the length and receive variables.}
  718. i:=1;
  719. len:=0;
  720. varcounter:=0;
  721. varptr:=@varvaluedata;
  722. while i<=length(s) do
  723. begin
  724. if (s[i]='$') and (i<length(s)) then
  725. begin
  726. if s[i+1]='$' then
  727. begin
  728. inc(len);
  729. inc(i);
  730. end
  731. else if (s[i+1]='{') and (length(s)>2) and (i<length(s)-2) then
  732. begin
  733. varname:='';
  734. inc(i,2);
  735. repeat
  736. inc(varname[0]);
  737. varname[length(varname)]:=s[i];
  738. s[i]:=char(varcounter);
  739. inc(i);
  740. until s[i]='}';
  741. varvalues[varcounter]:=Pstring(varptr);
  742. if varptr>@varvaluedata+maxdata then
  743. internalerrorproc(200411152);
  744. Pstring(varptr)^:=get_var_value(varname);
  745. inc(len,length(Pstring(varptr)^));
  746. inc(varptr,length(Pstring(varptr)^)+1);
  747. inc(varcounter);
  748. end
  749. else if s[i+1] in ['0'..'9'] then
  750. begin
  751. inc(len,length(vars[byte(s[i+1])-byte('1')]));
  752. inc(i);
  753. end;
  754. end
  755. else
  756. inc(len);
  757. inc(i);
  758. end;
  759. {Second pass, writeout stabstring.}
  760. getmem(r,len+1);
  761. string_evaluate:=r;
  762. i:=1;
  763. while i<=length(s) do
  764. begin
  765. if (s[i]='$') and (i<length(s)) then
  766. begin
  767. if s[i+1]='$' then
  768. begin
  769. r^:='$';
  770. inc(r);
  771. inc(i);
  772. end
  773. else if (s[i+1]='{') and (length(s)>2) and (i<length(s)-2) then
  774. begin
  775. varname:='';
  776. inc(i,2);
  777. varno:=byte(s[i]);
  778. repeat
  779. inc(i);
  780. until s[i]='}';
  781. for j:=1 to length(varvalues[varno]^) do
  782. begin
  783. r^:=varvalues[varno]^[j];
  784. inc(r);
  785. end;
  786. end
  787. else if s[i+1] in ['0'..'9'] then
  788. begin
  789. for j:=1 to length(vars[byte(s[i+1])-byte('1')]) do
  790. begin
  791. r^:=vars[byte(s[i+1])-byte('1')][j];
  792. inc(r);
  793. end;
  794. inc(i);
  795. end
  796. end
  797. else
  798. begin
  799. r^:=s[i];
  800. inc(r);
  801. end;
  802. inc(i);
  803. end;
  804. r^:=#0;
  805. end;
  806. {*****************************************************************************
  807. GetSpeedValue
  808. *****************************************************************************}
  809. var
  810. Crc32Tbl : array[0..255] of cardinal;
  811. procedure MakeCRC32Tbl;
  812. var
  813. crc : cardinal;
  814. i,n : integer;
  815. begin
  816. for i:=0 to 255 do
  817. begin
  818. crc:=i;
  819. for n:=1 to 8 do
  820. if odd(longint(crc)) then
  821. crc:=cardinal(crc shr 1) xor cardinal($edb88320)
  822. else
  823. crc:=cardinal(crc shr 1);
  824. Crc32Tbl[i]:=crc;
  825. end;
  826. end;
  827. Function GetSpeedValue(Const s:String):cardinal;
  828. var
  829. i : integer;
  830. InitCrc : cardinal;
  831. begin
  832. InitCrc:=cardinal($ffffffff);
  833. for i:=1 to Length(s) do
  834. InitCrc:=Crc32Tbl[byte(InitCrc) xor ord(s[i])] xor (InitCrc shr 8);
  835. GetSpeedValue:=InitCrc;
  836. end;
  837. {*****************************************************************************
  838. Ansistring (PChar+Length)
  839. *****************************************************************************}
  840. procedure ansistringdispose(var p : pchar;length : longint);
  841. begin
  842. if assigned(p) then
  843. begin
  844. freemem(p,length+1);
  845. p:=nil;
  846. end;
  847. end;
  848. { enable ansistring comparison }
  849. { 0 means equal }
  850. { 1 means p1 > p2 }
  851. { -1 means p1 < p2 }
  852. function compareansistrings(p1,p2 : pchar;length1,length2 : longint) : longint;
  853. var
  854. i,j : longint;
  855. begin
  856. compareansistrings:=0;
  857. j:=min(length1,length2);
  858. i:=0;
  859. while (i<j) do
  860. begin
  861. if p1[i]>p2[i] then
  862. begin
  863. compareansistrings:=1;
  864. exit;
  865. end
  866. else
  867. if p1[i]<p2[i] then
  868. begin
  869. compareansistrings:=-1;
  870. exit;
  871. end;
  872. inc(i);
  873. end;
  874. if length1>length2 then
  875. compareansistrings:=1
  876. else
  877. if length1<length2 then
  878. compareansistrings:=-1;
  879. end;
  880. function concatansistrings(p1,p2 : pchar;length1,length2 : longint) : pchar;
  881. var
  882. p : pchar;
  883. begin
  884. getmem(p,length1+length2+1);
  885. move(p1[0],p[0],length1);
  886. move(p2[0],p[length1],length2+1);
  887. concatansistrings:=p;
  888. end;
  889. {*****************************************************************************
  890. Ultra basic KISS Lzw (de)compressor
  891. *****************************************************************************}
  892. {This is an extremely basic implementation of the Lzw algorithm. It
  893. compresses 7-bit ASCII strings into 8-bit compressed strings.
  894. The Lzw dictionary is preinitialized with 0..127, therefore this
  895. part of the dictionary does not need to be stored in the arrays.
  896. The Lzw code size is allways 8 bit, so we do not need complex code
  897. that can write partial bytes.}
  898. function minilzw_encode(const s:string):string;
  899. var t,u,i:byte;
  900. c:char;
  901. data:array[128..255] of char;
  902. previous:array[128..255] of byte;
  903. lzwptr:byte;
  904. next_avail:set of 0..255;
  905. label l1;
  906. begin
  907. minilzw_encode:='';
  908. if s<>'' then
  909. begin
  910. lzwptr:=127;
  911. t:=byte(s[1]);
  912. i:=2;
  913. u:=128;
  914. next_avail:=[];
  915. while i<=length(s) do
  916. begin
  917. c:=s[i];
  918. if not(t in next_avail) or (u>lzwptr) then goto l1;
  919. while (previous[u]<>t) or (data[u]<>c) do
  920. begin
  921. inc(u);
  922. if u>lzwptr then goto l1;
  923. end;
  924. t:=u;
  925. inc(i);
  926. continue;
  927. l1:
  928. {It's a pity that we still need those awfull tricks
  929. with this modern compiler. Without this performance
  930. of the entire procedure drops about 3 times.}
  931. inc(minilzw_encode[0]);
  932. minilzw_encode[length(minilzw_encode)]:=char(t);
  933. if lzwptr=255 then
  934. begin
  935. lzwptr:=127;
  936. next_avail:=[];
  937. end
  938. else
  939. begin
  940. inc(lzwptr);
  941. data[lzwptr]:=c;
  942. previous[lzwptr]:=t;
  943. include(next_avail,t);
  944. end;
  945. t:=byte(c);
  946. u:=128;
  947. inc(i);
  948. end;
  949. inc(minilzw_encode[0]);
  950. minilzw_encode[length(minilzw_encode)]:=char(t);
  951. end;
  952. end;
  953. function minilzw_decode(const s:string):string;
  954. var oldc,newc,c:char;
  955. i,j:byte;
  956. data:array[128..255] of char;
  957. previous:array[128..255] of byte;
  958. lzwptr:byte;
  959. t:string;
  960. begin
  961. minilzw_decode:='';
  962. if s<>'' then
  963. begin
  964. lzwptr:=127;
  965. oldc:=s[1];
  966. c:=oldc;
  967. i:=2;
  968. minilzw_decode:=oldc;
  969. while i<=length(s) do
  970. begin
  971. newc:=s[i];
  972. if byte(newc)>lzwptr then
  973. begin
  974. t:=c;
  975. c:=oldc;
  976. end
  977. else
  978. begin
  979. c:=newc;
  980. t:='';
  981. end;
  982. while c>=#128 do
  983. begin
  984. inc(t[0]);
  985. t[length(t)]:=data[byte(c)];
  986. byte(c):=previous[byte(c)];
  987. end;
  988. inc(minilzw_decode[0]);
  989. minilzw_decode[length(minilzw_decode)]:=c;
  990. for j:=length(t) downto 1 do
  991. begin
  992. inc(minilzw_decode[0]);
  993. minilzw_decode[length(minilzw_decode)]:=t[j];
  994. end;
  995. if lzwptr=255 then
  996. lzwptr:=127
  997. else
  998. begin
  999. inc(lzwptr);
  1000. previous[lzwptr]:=byte(oldc);
  1001. data[lzwptr]:=c;
  1002. end;
  1003. oldc:=newc;
  1004. inc(i);
  1005. end;
  1006. end;
  1007. end;
  1008. procedure defaulterror(i:longint);
  1009. begin
  1010. writeln('Internal error ',i);
  1011. runerror(255);
  1012. end;
  1013. initialization
  1014. internalerrorproc:=@defaulterror;
  1015. makecrc32tbl;
  1016. initupperlower;
  1017. end.