cutils.pas 31 KB

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