cutils.pas 31 KB

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