cutils.pas 30 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157
  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. begin
  499. GetToken:='';
  500. s:=TrimSpace(s);
  501. if (length(s)>0) and
  502. (s[1]='''') then
  503. begin
  504. i:=1;
  505. while (i<length(s)) do
  506. begin
  507. inc(i);
  508. if s[i]='''' then
  509. begin
  510. { Remove double quote }
  511. if (i<length(s)) and
  512. (s[i+1]='''') then
  513. begin
  514. Delete(s,i,1);
  515. inc(i);
  516. end
  517. else
  518. begin
  519. GetToken:=Copy(s,2,i-2);
  520. Delete(s,1,i);
  521. exit;
  522. end;
  523. end;
  524. end;
  525. GetToken:=s;
  526. s:='';
  527. end
  528. else
  529. begin
  530. i:=pos(EndChar,s);
  531. if i=0 then
  532. begin
  533. GetToken:=s;
  534. s:='';
  535. exit;
  536. end
  537. else
  538. begin
  539. GetToken:=Copy(s,1,i-1);
  540. Delete(s,1,i);
  541. exit;
  542. end;
  543. end;
  544. end;
  545. function realtostr(e:extended):string;{$ifdef USEINLINE}inline;{$endif}
  546. begin
  547. str(e,result);
  548. end;
  549. function tostr(i : qword) : string;{$ifdef USEINLINE}inline;{$endif}overload;
  550. {
  551. return string of value i
  552. }
  553. begin
  554. str(i,result);
  555. end;
  556. function tostr(i : int64) : string;{$ifdef USEINLINE}inline;{$endif}overload;
  557. {
  558. return string of value i
  559. }
  560. begin
  561. str(i,result);
  562. end;
  563. function tostr(i : longint) : string;{$ifdef USEINLINE}inline;{$endif}overload;
  564. {
  565. return string of value i
  566. }
  567. begin
  568. str(i,result);
  569. end;
  570. function tostr_with_plus(i : int64) : string;{$ifdef USEINLINE}inline;{$endif}
  571. {
  572. return string of value i, but always include a + when i>=0
  573. }
  574. begin
  575. str(i,result);
  576. if i>=0 then
  577. result:='+'+result;
  578. end;
  579. function is_number(const s : string) : boolean;{$ifdef USEINLINE}inline;{$endif}
  580. {
  581. is string a correct number ?
  582. }
  583. var
  584. w : integer;
  585. l : longint;
  586. begin
  587. val(s,l,w);
  588. // remove warning
  589. l:=l;
  590. is_number:=(w=0);
  591. end;
  592. function ispowerof2(value : int64;out power : longint) : boolean;
  593. {
  594. return if value is a power of 2. And if correct return the power
  595. }
  596. var
  597. hl : int64;
  598. i : longint;
  599. begin
  600. if value and (value - 1) <> 0 then
  601. begin
  602. ispowerof2 := false;
  603. exit
  604. end;
  605. hl:=1;
  606. ispowerof2:=true;
  607. for i:=0 to 63 do
  608. begin
  609. if hl=value then
  610. begin
  611. power:=i;
  612. exit;
  613. end;
  614. hl:=hl shl 1;
  615. end;
  616. ispowerof2:=false;
  617. end;
  618. function nextpowerof2(value : int64; out power: longint) : int64;
  619. {
  620. returns the power of 2 >= value
  621. }
  622. var
  623. i : longint;
  624. begin
  625. result := 0;
  626. power := -1;
  627. if ((value <= 0) or
  628. (value >= $4000000000000000)) then
  629. exit;
  630. result := 1;
  631. for i:=0 to 63 do
  632. begin
  633. if result>=value then
  634. begin
  635. power := i;
  636. exit;
  637. end;
  638. result:=result shl 1;
  639. end;
  640. end;
  641. function backspace_quote(const s:string;const qchars:Tcharset):string;
  642. var i:byte;
  643. begin
  644. backspace_quote:='';
  645. for i:=1 to length(s) do
  646. begin
  647. if (s[i]=#10) and (#10 in qchars) then
  648. backspace_quote:=backspace_quote+'\n'
  649. else if (s[i]=#13) and (#13 in qchars) then
  650. backspace_quote:=backspace_quote+'\r'
  651. else
  652. begin
  653. if s[i] in qchars then
  654. backspace_quote:=backspace_quote+'\';
  655. backspace_quote:=backspace_quote+s[i];
  656. end;
  657. end;
  658. end;
  659. function octal_quote(const s:string;const qchars:Tcharset):string;
  660. var i:byte;
  661. begin
  662. octal_quote:='';
  663. for i:=1 to length(s) do
  664. begin
  665. if s[i] in qchars then
  666. begin
  667. if ord(s[i])<64 then
  668. octal_quote:=octal_quote+'\'+octstr(ord(s[i]),3)
  669. else
  670. octal_quote:=octal_quote+'\'+octstr(ord(s[i]),4);
  671. end
  672. else
  673. octal_quote:=octal_quote+s[i];
  674. end;
  675. end;
  676. function maybequoted(const s:string):string;
  677. const
  678. {$IFDEF MSWINDOWS}
  679. FORBIDDEN_CHARS = ['!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
  680. '{', '}', '''', '`', '~'];
  681. {$ELSE}
  682. FORBIDDEN_CHARS = ['!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
  683. '{', '}', '''', ':', '\', '`', '~'];
  684. {$ENDIF}
  685. var
  686. s1 : string;
  687. i : integer;
  688. quoted : boolean;
  689. begin
  690. quoted:=false;
  691. s1:='"';
  692. for i:=1 to length(s) do
  693. begin
  694. case s[i] of
  695. '"' :
  696. begin
  697. quoted:=true;
  698. s1:=s1+'\"';
  699. end;
  700. ' ',
  701. #128..#255 :
  702. begin
  703. quoted:=true;
  704. s1:=s1+s[i];
  705. end;
  706. else begin
  707. if s[i] in FORBIDDEN_CHARS then
  708. quoted:=True;
  709. s1:=s1+s[i];
  710. end;
  711. end;
  712. end;
  713. if quoted then
  714. maybequoted:=s1+'"'
  715. else
  716. maybequoted:=s;
  717. end;
  718. function DePascalQuote(var s: string): Boolean;
  719. var
  720. destPos, sourcePos, len: Integer;
  721. t: string;
  722. ch: Char;
  723. begin
  724. DePascalQuote:= false;
  725. len:= length(s);
  726. if (len >= 1) and (s[1] = '''') then
  727. begin
  728. {Remove quotes, exchange '' against ' }
  729. destPos := 0;
  730. sourcepos:=1;
  731. while (sourcepos<len) do
  732. begin
  733. inc(sourcePos);
  734. ch := s[sourcePos];
  735. if ch = '''' then
  736. begin
  737. inc(sourcePos);
  738. if (sourcePos <= len) and (s[sourcePos] = '''') then
  739. {Add the quote as part of string}
  740. else
  741. begin
  742. SetLength(t, destPos);
  743. s:= t;
  744. Exit(true);
  745. end;
  746. end;
  747. inc(destPos);
  748. t[destPos] := ch;
  749. end;
  750. end;
  751. end;
  752. function pchar2pshortstring(p : pchar) : pshortstring;
  753. var
  754. w,i : longint;
  755. begin
  756. w:=strlen(p);
  757. for i:=w-1 downto 0 do
  758. p[i+1]:=p[i];
  759. p[0]:=chr(w);
  760. pchar2pshortstring:=pshortstring(p);
  761. end;
  762. function pshortstring2pchar(p : pshortstring) : pchar;
  763. var
  764. w,i : longint;
  765. begin
  766. w:=length(p^);
  767. for i:=1 to w do
  768. p^[i-1]:=p^[i];
  769. p^[w]:=#0;
  770. pshortstring2pchar:=pchar(p);
  771. end;
  772. function lowercase(c : char) : char;
  773. begin
  774. case c of
  775. #65..#90 : c := chr(ord (c) + 32);
  776. #154 : c:=#129; { german }
  777. #142 : c:=#132; { german }
  778. #153 : c:=#148; { german }
  779. #144 : c:=#130; { french }
  780. #128 : c:=#135; { french }
  781. #143 : c:=#134; { swedish/norge (?) }
  782. #165 : c:=#164; { spanish }
  783. #228 : c:=#229; { greek }
  784. #226 : c:=#231; { greek }
  785. #232 : c:=#227; { greek }
  786. end;
  787. lowercase := c;
  788. end;
  789. function strpnew(const s : string) : pchar;
  790. var
  791. p : pchar;
  792. begin
  793. getmem(p,length(s)+1);
  794. move(s[1],p^,length(s));
  795. p[length(s)]:=#0;
  796. result:=p;
  797. end;
  798. procedure stringdispose(var p : pshortstring);{$ifdef USEINLINE}inline;{$endif}
  799. begin
  800. if assigned(p) then
  801. begin
  802. freemem(p);
  803. p:=nil;
  804. end;
  805. end;
  806. function stringdup(const s : string) : pshortstring;{$ifdef USEINLINE}inline;{$endif}
  807. begin
  808. getmem(result,length(s)+1);
  809. result^:=s;
  810. end;
  811. function CompareStr(const S1, S2: string): Integer;
  812. var
  813. count, count1, count2: integer;
  814. begin
  815. result := 0;
  816. Count1 := Length(S1);
  817. Count2 := Length(S2);
  818. if Count1>Count2 then
  819. Count:=Count2
  820. else
  821. Count:=Count1;
  822. result := CompareChar(S1[1],S2[1], Count);
  823. if result=0 then
  824. result:=Count1-Count2;
  825. end;
  826. function CompareText(S1, S2: string): integer;
  827. begin
  828. UpperVar(S1);
  829. UpperVar(S2);
  830. Result:=CompareStr(S1,S2);
  831. end;
  832. {*****************************************************************************
  833. Ansistring (PChar+Length)
  834. *****************************************************************************}
  835. procedure ansistringdispose(var p : pchar;length : longint);
  836. begin
  837. if assigned(p) then
  838. begin
  839. freemem(p);
  840. p:=nil;
  841. end;
  842. end;
  843. { enable ansistring comparison }
  844. { 0 means equal }
  845. { 1 means p1 > p2 }
  846. { -1 means p1 < p2 }
  847. function compareansistrings(p1,p2 : pchar;length1,length2 : longint) : longint;
  848. var
  849. i,j : longint;
  850. begin
  851. compareansistrings:=0;
  852. j:=min(length1,length2);
  853. i:=0;
  854. while (i<j) do
  855. begin
  856. if p1[i]>p2[i] then
  857. begin
  858. compareansistrings:=1;
  859. exit;
  860. end
  861. else
  862. if p1[i]<p2[i] then
  863. begin
  864. compareansistrings:=-1;
  865. exit;
  866. end;
  867. inc(i);
  868. end;
  869. if length1>length2 then
  870. compareansistrings:=1
  871. else
  872. if length1<length2 then
  873. compareansistrings:=-1;
  874. end;
  875. function concatansistrings(p1,p2 : pchar;length1,length2 : longint) : pchar;
  876. var
  877. p : pchar;
  878. begin
  879. getmem(p,length1+length2+1);
  880. move(p1[0],p[0],length1);
  881. move(p2[0],p[length1],length2+1);
  882. concatansistrings:=p;
  883. end;
  884. {*****************************************************************************
  885. Ultra basic KISS Lzw (de)compressor
  886. *****************************************************************************}
  887. {This is an extremely basic implementation of the Lzw algorithm. It
  888. compresses 7-bit ASCII strings into 8-bit compressed strings.
  889. The Lzw dictionary is preinitialized with 0..127, therefore this
  890. part of the dictionary does not need to be stored in the arrays.
  891. The Lzw code size is allways 8 bit, so we do not need complex code
  892. that can write partial bytes.}
  893. function minilzw_encode(const s:string):string;
  894. var t,u,i:byte;
  895. c:char;
  896. data:array[128..255] of char;
  897. previous:array[128..255] of byte;
  898. lzwptr:byte;
  899. next_avail:set of 0..255;
  900. label l1;
  901. begin
  902. minilzw_encode:='';
  903. if s<>'' then
  904. begin
  905. lzwptr:=127;
  906. t:=byte(s[1]);
  907. i:=2;
  908. u:=128;
  909. next_avail:=[];
  910. while i<=length(s) do
  911. begin
  912. c:=s[i];
  913. if not(t in next_avail) or (u>lzwptr) then goto l1;
  914. while (previous[u]<>t) or (data[u]<>c) do
  915. begin
  916. inc(u);
  917. if u>lzwptr then goto l1;
  918. end;
  919. t:=u;
  920. inc(i);
  921. continue;
  922. l1:
  923. {It's a pity that we still need those awfull tricks
  924. with this modern compiler. Without this performance
  925. of the entire procedure drops about 3 times.}
  926. inc(minilzw_encode[0]);
  927. minilzw_encode[length(minilzw_encode)]:=char(t);
  928. if lzwptr=255 then
  929. begin
  930. lzwptr:=127;
  931. next_avail:=[];
  932. end
  933. else
  934. begin
  935. inc(lzwptr);
  936. data[lzwptr]:=c;
  937. previous[lzwptr]:=t;
  938. include(next_avail,t);
  939. end;
  940. t:=byte(c);
  941. u:=128;
  942. inc(i);
  943. end;
  944. inc(minilzw_encode[0]);
  945. minilzw_encode[length(minilzw_encode)]:=char(t);
  946. end;
  947. end;
  948. function minilzw_decode(const s:string):string;
  949. var oldc,newc,c:char;
  950. i,j:byte;
  951. data:array[128..255] of char;
  952. previous:array[128..255] of byte;
  953. lzwptr:byte;
  954. t:string;
  955. begin
  956. minilzw_decode:='';
  957. if s<>'' then
  958. begin
  959. lzwptr:=127;
  960. oldc:=s[1];
  961. c:=oldc;
  962. i:=2;
  963. minilzw_decode:=oldc;
  964. while i<=length(s) do
  965. begin
  966. newc:=s[i];
  967. if byte(newc)>lzwptr then
  968. begin
  969. t:=c;
  970. c:=oldc;
  971. end
  972. else
  973. begin
  974. c:=newc;
  975. t:='';
  976. end;
  977. while c>=#128 do
  978. begin
  979. inc(t[0]);
  980. t[length(t)]:=data[byte(c)];
  981. byte(c):=previous[byte(c)];
  982. end;
  983. inc(minilzw_decode[0]);
  984. minilzw_decode[length(minilzw_decode)]:=c;
  985. for j:=length(t) downto 1 do
  986. begin
  987. inc(minilzw_decode[0]);
  988. minilzw_decode[length(minilzw_decode)]:=t[j];
  989. end;
  990. if lzwptr=255 then
  991. lzwptr:=127
  992. else
  993. begin
  994. inc(lzwptr);
  995. previous[lzwptr]:=byte(oldc);
  996. data[lzwptr]:=c;
  997. end;
  998. oldc:=newc;
  999. inc(i);
  1000. end;
  1001. end;
  1002. end;
  1003. procedure defaulterror(i:longint);
  1004. begin
  1005. writeln('Internal error ',i);
  1006. runerror(255);
  1007. end;
  1008. initialization
  1009. internalerrorproc:=@defaulterror;
  1010. initupperlower;
  1011. end.