cutils.pas 31 KB

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