cutils.pas 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159
  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. { Ansistring (pchar+length) support }
  105. procedure ansistringdispose(var p : pchar;length : longint);
  106. function compareansistrings(p1,p2 : pchar;length1,length2 : longint) : longint;
  107. function concatansistrings(p1,p2 : pchar;length1,length2 : longint) : pchar;
  108. {Lzw encode/decode to compress strings -> save memory.}
  109. function minilzw_encode(const s:string):string;
  110. function minilzw_decode(const s:string):string;
  111. implementation
  112. uses
  113. SysUtils;
  114. var
  115. uppertbl,
  116. lowertbl : array[char] of char;
  117. function min(a,b : longint) : longint;{$ifdef USEINLINE}inline;{$endif}
  118. {
  119. return the minimal of a and b
  120. }
  121. begin
  122. if a<=b then
  123. min:=a
  124. else
  125. min:=b;
  126. end;
  127. function min(a,b : int64) : int64;{$ifdef USEINLINE}inline;{$endif}
  128. {
  129. return the minimal of a and b
  130. }
  131. begin
  132. if a<=b then
  133. min:=a
  134. else
  135. min:=b;
  136. end;
  137. function max(a,b : longint) : longint;{$ifdef USEINLINE}inline;{$endif}
  138. {
  139. return the maximum of a and b
  140. }
  141. begin
  142. if a>=b then
  143. max:=a
  144. else
  145. max:=b;
  146. end;
  147. function max(a,b : int64) : int64;{$ifdef USEINLINE}inline;{$endif}
  148. {
  149. return the maximum of a and b
  150. }
  151. begin
  152. if a>=b then
  153. max:=a
  154. else
  155. max:=b;
  156. end;
  157. Function SwapLong(x : longint): longint;{$ifdef USEINLINE}inline;{$endif}
  158. var
  159. y : word;
  160. z : word;
  161. Begin
  162. y := x shr 16;
  163. y := word(longint(y) shl 8) or (y shr 8);
  164. z := x and $FFFF;
  165. z := word(longint(z) shl 8) or (z shr 8);
  166. SwapLong := (longint(z) shl 16) or longint(y);
  167. End;
  168. Function SwapInt64(x : int64): int64;{$ifdef USEINLINE}inline;{$endif}
  169. Begin
  170. result:=swaplong(longint(hi(x)));
  171. result:=result or (swaplong(longint(lo(x))) shl 32);
  172. End;
  173. Function SwapQWord(x : qword) : qword;{$ifdef USEINLINE}inline;{$endif}
  174. Begin
  175. result:=swaplong(longint(hi(x)));
  176. result:=result or (swaplong(longint(lo(x))) shl 32);
  177. End;
  178. Function SwapWord(x : word): word;{$ifdef USEINLINE}inline;{$endif}
  179. var
  180. z : byte;
  181. Begin
  182. z := x shr 8;
  183. x := x and $ff;
  184. x := (x shl 8);
  185. SwapWord := x or z;
  186. End;
  187. function align(i,a:longint):longint;{$ifdef USEINLINE}inline;{$endif}
  188. {
  189. return value <i> aligned <a> boundary
  190. }
  191. begin
  192. { for 0 and 1 no aligning is needed }
  193. if a<=1 then
  194. result:=i
  195. else
  196. begin
  197. if i<0 then
  198. result:=((i-a+1) div a) * a
  199. else
  200. result:=((i+a-1) div a) * a;
  201. end;
  202. end;
  203. function size_2_align(len : longint) : shortint;
  204. begin
  205. if len>16 then
  206. size_2_align:=32
  207. else if len>8 then
  208. size_2_align:=16
  209. else if len>4 then
  210. size_2_align:=8
  211. else if len>2 then
  212. size_2_align:=4
  213. else if len>1 then
  214. size_2_align:=2
  215. else
  216. size_2_align:=1;
  217. end;
  218. function packedbitsloadsize(bitlen: int64) : int64;
  219. begin
  220. case bitlen of
  221. 1,2,4,8:
  222. result := 1;
  223. { 10 bits can never be split over 3 bytes via 1-8-1, because it }
  224. { always starts at a multiple of 10 bits. Same for the others. }
  225. 3,5,7,9,10,12,16:
  226. result := 2;
  227. {$ifdef cpu64bit}
  228. 11,13,14,15,17..26,28,32:
  229. result := 4;
  230. else
  231. result := 8;
  232. {$else cpu64bit}
  233. else
  234. result := 4;
  235. {$endif cpu64bit}
  236. end;
  237. end;
  238. function isbetteralignedthan(new, org, limit: cardinal): boolean;
  239. var
  240. cnt: cardinal;
  241. begin
  242. cnt:=2;
  243. while (cnt <= limit) do
  244. begin
  245. if (org and (cnt-1)) > (new and (cnt-1)) then
  246. begin
  247. result:=true;
  248. exit;
  249. end
  250. else if (org and (cnt-1)) < (new and (cnt-1)) then
  251. begin
  252. result:=false;
  253. exit;
  254. end;
  255. cnt:=cnt*2;
  256. end;
  257. result:=false;
  258. end;
  259. function used_align(varalign,minalign,maxalign:shortint):shortint;
  260. begin
  261. { varalign : minimum alignment required for the variable
  262. minalign : Minimum alignment of this structure, 0 = undefined
  263. maxalign : Maximum alignment of this structure, 0 = undefined }
  264. if (minalign>0) and
  265. (varalign<minalign) then
  266. used_align:=minalign
  267. else
  268. begin
  269. if (maxalign>0) and
  270. (varalign>maxalign) then
  271. used_align:=maxalign
  272. else
  273. used_align:=varalign;
  274. end;
  275. end;
  276. procedure Replace(var s:string;s1:string;const s2:string);
  277. var
  278. last,
  279. i : longint;
  280. begin
  281. s1:=upper(s1);
  282. last:=0;
  283. repeat
  284. i:=pos(s1,upper(s));
  285. if i=last then
  286. i:=0;
  287. if (i>0) then
  288. begin
  289. Delete(s,i,length(s1));
  290. Insert(s2,s,i);
  291. last:=i;
  292. end;
  293. until (i=0);
  294. end;
  295. procedure Replace(var s:AnsiString;s1:string;const s2:string);
  296. var
  297. last,
  298. i : longint;
  299. begin
  300. s1:=upper(s1);
  301. last:=0;
  302. repeat
  303. i:=pos(s1,upper(s));
  304. if i=last then
  305. i:=0;
  306. if (i>0) then
  307. begin
  308. Delete(s,i,length(s1));
  309. Insert(s2,s,i);
  310. last:=i;
  311. end;
  312. until (i=0);
  313. end;
  314. procedure ReplaceCase(var s:string;const s1,s2:string);
  315. var
  316. last,
  317. i : longint;
  318. begin
  319. last:=0;
  320. repeat
  321. i:=pos(s1,s);
  322. if i=last then
  323. i:=0;
  324. if (i>0) then
  325. begin
  326. Delete(s,i,length(s1));
  327. Insert(s2,s,i);
  328. last:=i;
  329. end;
  330. until (i=0);
  331. end;
  332. Function MatchPattern(const pattern,what:string):boolean;
  333. var
  334. found : boolean;
  335. i1,i2 : longint;
  336. begin
  337. i1:=0;
  338. i2:=0;
  339. if pattern='' then
  340. begin
  341. result:=(what='');
  342. exit;
  343. end;
  344. found:=true;
  345. repeat
  346. inc(i1);
  347. if (i1>length(pattern)) then
  348. break;
  349. inc(i2);
  350. if (i2>length(what)) then
  351. break;
  352. case pattern[i1] of
  353. '?' :
  354. found:=true;
  355. '*' :
  356. begin
  357. found:=true;
  358. if (i1=length(pattern)) then
  359. i2:=length(what)
  360. else
  361. if (i1<length(pattern)) and (pattern[i1+1]<>what[i2]) then
  362. begin
  363. if i2<length(what) then
  364. dec(i1)
  365. end
  366. else
  367. if i2>1 then
  368. dec(i2);
  369. end;
  370. else
  371. found:=(pattern[i1]=what[i2]) or (what[i2]='?');
  372. end;
  373. until not found;
  374. if found then
  375. begin
  376. found:=(i2>=length(what)) and
  377. (
  378. (i1>length(pattern)) or
  379. ((i1=length(pattern)) and
  380. (pattern[i1]='*'))
  381. );
  382. end;
  383. result:=found;
  384. end;
  385. function upper(const s : string) : string;
  386. {
  387. return uppercased string of s
  388. }
  389. var
  390. i : longint;
  391. begin
  392. for i:=1 to length(s) do
  393. upper[i]:=uppertbl[s[i]];
  394. upper[0]:=s[0];
  395. end;
  396. function lower(const s : string) : string;
  397. {
  398. return lowercased string of s
  399. }
  400. var
  401. i : longint;
  402. begin
  403. for i:=1 to length(s) do
  404. lower[i]:=lowertbl[s[i]];
  405. lower[0]:=s[0];
  406. end;
  407. procedure uppervar(var s : string);
  408. {
  409. uppercase string s
  410. }
  411. var
  412. i : longint;
  413. begin
  414. for i:=1 to length(s) do
  415. s[i]:=uppertbl[s[i]];
  416. end;
  417. procedure initupperlower;
  418. var
  419. c : char;
  420. begin
  421. for c:=#0 to #255 do
  422. begin
  423. lowertbl[c]:=c;
  424. uppertbl[c]:=c;
  425. case c of
  426. 'A'..'Z' :
  427. lowertbl[c]:=char(byte(c)+32);
  428. 'a'..'z' :
  429. uppertbl[c]:=char(byte(c)-32);
  430. end;
  431. end;
  432. end;
  433. function DStr(l:longint):string;
  434. var
  435. TmpStr : string[32];
  436. i : longint;
  437. begin
  438. Str(l,TmpStr);
  439. i:=Length(TmpStr);
  440. while (i>3) do
  441. begin
  442. dec(i,3);
  443. if TmpStr[i]<>'-' then
  444. insert('.',TmpStr,i+1);
  445. end;
  446. DStr:=TmpStr;
  447. end;
  448. function trimbspace(const s:string):string;
  449. {
  450. return s with all leading spaces and tabs removed
  451. }
  452. var
  453. i,j : longint;
  454. begin
  455. j:=1;
  456. i:=length(s);
  457. while (j<i) and (s[j] in [#9,' ']) do
  458. inc(j);
  459. trimbspace:=Copy(s,j,i-j+1);
  460. end;
  461. function trimspace(const s:string):string;
  462. {
  463. return s with all leading and ending spaces and tabs removed
  464. }
  465. var
  466. i,j : longint;
  467. begin
  468. i:=length(s);
  469. while (i>0) and (s[i] in [#9,' ']) do
  470. dec(i);
  471. j:=1;
  472. while (j<i) and (s[j] in [#9,' ']) do
  473. inc(j);
  474. trimspace:=Copy(s,j,i-j+1);
  475. end;
  476. function space (b : longint): string;
  477. var
  478. s: string;
  479. begin
  480. space[0] := chr(b);
  481. s[0] := chr(b);
  482. FillChar (S[1],b,' ');
  483. space:=s;
  484. end;
  485. function PadSpace(const s:string;len:longint):string;
  486. {
  487. return s with spaces add to the end
  488. }
  489. begin
  490. if length(s)<len then
  491. PadSpace:=s+Space(len-length(s))
  492. else
  493. PadSpace:=s;
  494. end;
  495. function GetToken(var s:string;endchar:char):string;
  496. var
  497. i : longint;
  498. quote : char;
  499. begin
  500. GetToken:='';
  501. s:=TrimSpace(s);
  502. if (length(s)>0) and
  503. (s[1] in ['''','"']) then
  504. begin
  505. quote:=s[1];
  506. i:=1;
  507. while (i<length(s)) do
  508. begin
  509. inc(i);
  510. if s[i]=quote then
  511. begin
  512. { Remove double quote }
  513. if (i<length(s)) and
  514. (s[i+1]=quote) 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. Ansistring (PChar+Length)
  836. *****************************************************************************}
  837. procedure ansistringdispose(var p : pchar;length : longint);
  838. begin
  839. if assigned(p) then
  840. begin
  841. freemem(p);
  842. p:=nil;
  843. end;
  844. end;
  845. { enable ansistring comparison }
  846. { 0 means equal }
  847. { 1 means p1 > p2 }
  848. { -1 means p1 < p2 }
  849. function compareansistrings(p1,p2 : pchar;length1,length2 : longint) : longint;
  850. var
  851. i,j : longint;
  852. begin
  853. compareansistrings:=0;
  854. j:=min(length1,length2);
  855. i:=0;
  856. while (i<j) do
  857. begin
  858. if p1[i]>p2[i] then
  859. begin
  860. compareansistrings:=1;
  861. exit;
  862. end
  863. else
  864. if p1[i]<p2[i] then
  865. begin
  866. compareansistrings:=-1;
  867. exit;
  868. end;
  869. inc(i);
  870. end;
  871. if length1>length2 then
  872. compareansistrings:=1
  873. else
  874. if length1<length2 then
  875. compareansistrings:=-1;
  876. end;
  877. function concatansistrings(p1,p2 : pchar;length1,length2 : longint) : pchar;
  878. var
  879. p : pchar;
  880. begin
  881. getmem(p,length1+length2+1);
  882. move(p1[0],p[0],length1);
  883. move(p2[0],p[length1],length2+1);
  884. concatansistrings:=p;
  885. end;
  886. {*****************************************************************************
  887. Ultra basic KISS Lzw (de)compressor
  888. *****************************************************************************}
  889. {This is an extremely basic implementation of the Lzw algorithm. It
  890. compresses 7-bit ASCII strings into 8-bit compressed strings.
  891. The Lzw dictionary is preinitialized with 0..127, therefore this
  892. part of the dictionary does not need to be stored in the arrays.
  893. The Lzw code size is allways 8 bit, so we do not need complex code
  894. that can write partial bytes.}
  895. function minilzw_encode(const s:string):string;
  896. var t,u,i:byte;
  897. c:char;
  898. data:array[128..255] of char;
  899. previous:array[128..255] of byte;
  900. lzwptr:byte;
  901. next_avail:set of 0..255;
  902. label l1;
  903. begin
  904. minilzw_encode:='';
  905. if s<>'' then
  906. begin
  907. lzwptr:=127;
  908. t:=byte(s[1]);
  909. i:=2;
  910. u:=128;
  911. next_avail:=[];
  912. while i<=length(s) do
  913. begin
  914. c:=s[i];
  915. if not(t in next_avail) or (u>lzwptr) then goto l1;
  916. while (previous[u]<>t) or (data[u]<>c) do
  917. begin
  918. inc(u);
  919. if u>lzwptr then goto l1;
  920. end;
  921. t:=u;
  922. inc(i);
  923. continue;
  924. l1:
  925. {It's a pity that we still need those awfull tricks
  926. with this modern compiler. Without this performance
  927. of the entire procedure drops about 3 times.}
  928. inc(minilzw_encode[0]);
  929. minilzw_encode[length(minilzw_encode)]:=char(t);
  930. if lzwptr=255 then
  931. begin
  932. lzwptr:=127;
  933. next_avail:=[];
  934. end
  935. else
  936. begin
  937. inc(lzwptr);
  938. data[lzwptr]:=c;
  939. previous[lzwptr]:=t;
  940. include(next_avail,t);
  941. end;
  942. t:=byte(c);
  943. u:=128;
  944. inc(i);
  945. end;
  946. inc(minilzw_encode[0]);
  947. minilzw_encode[length(minilzw_encode)]:=char(t);
  948. end;
  949. end;
  950. function minilzw_decode(const s:string):string;
  951. var oldc,newc,c:char;
  952. i,j:byte;
  953. data:array[128..255] of char;
  954. previous:array[128..255] of byte;
  955. lzwptr:byte;
  956. t:string;
  957. begin
  958. minilzw_decode:='';
  959. if s<>'' then
  960. begin
  961. lzwptr:=127;
  962. oldc:=s[1];
  963. c:=oldc;
  964. i:=2;
  965. minilzw_decode:=oldc;
  966. while i<=length(s) do
  967. begin
  968. newc:=s[i];
  969. if byte(newc)>lzwptr then
  970. begin
  971. t:=c;
  972. c:=oldc;
  973. end
  974. else
  975. begin
  976. c:=newc;
  977. t:='';
  978. end;
  979. while c>=#128 do
  980. begin
  981. inc(t[0]);
  982. t[length(t)]:=data[byte(c)];
  983. byte(c):=previous[byte(c)];
  984. end;
  985. inc(minilzw_decode[0]);
  986. minilzw_decode[length(minilzw_decode)]:=c;
  987. for j:=length(t) downto 1 do
  988. begin
  989. inc(minilzw_decode[0]);
  990. minilzw_decode[length(minilzw_decode)]:=t[j];
  991. end;
  992. if lzwptr=255 then
  993. lzwptr:=127
  994. else
  995. begin
  996. inc(lzwptr);
  997. previous[lzwptr]:=byte(oldc);
  998. data[lzwptr]:=c;
  999. end;
  1000. oldc:=newc;
  1001. inc(i);
  1002. end;
  1003. end;
  1004. end;
  1005. procedure defaulterror(i:longint);
  1006. begin
  1007. writeln('Internal error ',i);
  1008. runerror(255);
  1009. end;
  1010. initialization
  1011. internalerrorproc:=@defaulterror;
  1012. initupperlower;
  1013. end.