cutils.pas 31 KB

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