cutils.pas 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 by Florian Klaempfl
  4. This unit implements some support functions
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published
  7. by the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. {# This unit contains some generic support functions which are used
  19. in the different parts of the compiler.
  20. }
  21. unit cutils;
  22. {$i fpcdefs.inc}
  23. interface
  24. type
  25. pstring = ^string;
  26. {# Returns the minimal value between @var(a) and @var(b) }
  27. function min(a,b : longint) : longint;
  28. {# Returns the maximum value between @var(a) and @var(b) }
  29. function max(a,b : longint) : longint;
  30. {# Returns the value in @var(x) swapped to different endian }
  31. function SwapLong(x : longint): longint;
  32. {# Returns the value in @va(x) swapped to different endian }
  33. function SwapWord(x : word): word;
  34. {# Return value @var(i) aligned on @var(a) boundary }
  35. function align(i,a:longint):longint;
  36. function used_align(varalign,minalign,maxalign:longint):longint;
  37. function size_2_align(len : longint) : longint;
  38. procedure Replace(var s:string;s1:string;const s2:string);
  39. procedure ReplaceCase(var s:string;const s1,s2:string);
  40. function upper(const s : string) : string;
  41. function lower(const s : string) : string;
  42. function trimbspace(const s:string):string;
  43. function trimspace(const s:string):string;
  44. function space (b : longint): string;
  45. function PadSpace(const s:string;len:longint):string;
  46. function GetToken(var s:string;endchar:char):string;
  47. procedure uppervar(var s : string);
  48. function hexstr(val : cardinal;cnt : cardinal) : string;
  49. function tostru(i:cardinal) : string;
  50. function tostr(i : longint) : string;
  51. function int64tostr(i : int64) : string;
  52. function tostr_with_plus(i : longint) : string;
  53. function DStr(l:longint):string;
  54. procedure valint(S : string;var V : longint;var code : integer);
  55. {# Returns true if the string s is a number }
  56. function is_number(const s : string) : boolean;
  57. {# Returns true if value is a power of 2, the actual
  58. exponent value is returned in power.
  59. }
  60. function ispowerof2(value : int64;var power : longint) : boolean;
  61. function maybequoted(const s:string):string;
  62. function CompareText(S1, S2: string): longint;
  63. { releases the string p and assignes nil to p }
  64. { if p=nil then freemem isn't called }
  65. procedure stringdispose(var p : pstring);
  66. { allocates mem for a copy of s, copies s to this mem and returns }
  67. { a pointer to this mem }
  68. function stringdup(const s : string) : pstring;
  69. {# Allocates memory for the string @var(s) and copies s as zero
  70. terminated string to that allocated memory and returns a pointer
  71. to that mem
  72. }
  73. function strpnew(const s : string) : pchar;
  74. procedure strdispose(var p : pchar);
  75. {# makes the character @var(c) lowercase, with spanish, french and german
  76. character set
  77. }
  78. function lowercase(c : char) : char;
  79. { makes zero terminated string to a pascal string }
  80. { the data in p is modified and p is returned }
  81. function pchar2pstring(p : pchar) : pstring;
  82. { ambivalent to pchar2pstring }
  83. function pstring2pchar(p : pstring) : pchar;
  84. { Speed/Hash value }
  85. Function GetSpeedValue(Const s:String):cardinal;
  86. { Ansistring (pchar+length) support }
  87. procedure ansistringdispose(var p : pchar;length : longint);
  88. function compareansistrings(p1,p2 : pchar;length1,length2 : longint) : longint;
  89. function concatansistrings(p1,p2 : pchar;length1,length2 : longint) : pchar;
  90. {*****************************************************************************
  91. File Functions
  92. *****************************************************************************}
  93. function DeleteFile(const fn:string):boolean;
  94. implementation
  95. uses
  96. {$ifdef delphi}
  97. sysutils
  98. {$else}
  99. strings
  100. {$endif}
  101. ;
  102. var
  103. uppertbl,
  104. lowertbl : array[char] of char;
  105. function min(a,b : longint) : longint;
  106. {
  107. return the minimal of a and b
  108. }
  109. begin
  110. if a>b then
  111. min:=b
  112. else
  113. min:=a;
  114. end;
  115. function max(a,b : longint) : longint;
  116. {
  117. return the maximum of a and b
  118. }
  119. begin
  120. if a<b then
  121. max:=b
  122. else
  123. max:=a;
  124. end;
  125. Function SwapLong(x : longint): longint;
  126. var
  127. y : word;
  128. z : word;
  129. Begin
  130. y := (x shr 16) and $FFFF;
  131. y := ((y shl 8) and $FFFF) or ((y shr 8) and $ff);
  132. z := x and $FFFF;
  133. z := ((z shl 8) and $FFFF) or ((z shr 8) and $ff);
  134. SwapLong := (longint(z) shl 16) or longint(y);
  135. End;
  136. Function SwapWord(x : word): word;
  137. var
  138. z : byte;
  139. Begin
  140. z := (x shr 8) and $ff;
  141. x := x and $ff;
  142. x := (x shl 8);
  143. SwapWord := x or z;
  144. End;
  145. function align(i,a:longint):longint;
  146. {
  147. return value <i> aligned <a> boundary
  148. }
  149. begin
  150. { for 0 and 1 no aligning is needed }
  151. if a<=1 then
  152. align:=i
  153. else
  154. align:=((i+a-1) div a) * a;
  155. end;
  156. function size_2_align(len : longint) : longint;
  157. begin
  158. if len>16 then
  159. size_2_align:=32
  160. else if len>8 then
  161. size_2_align:=16
  162. else if len>4 then
  163. size_2_align:=8
  164. else if len>2 then
  165. size_2_align:=4
  166. else if len>1 then
  167. size_2_align:=2
  168. else
  169. size_2_align:=1;
  170. end;
  171. function used_align(varalign,minalign,maxalign:longint):longint;
  172. begin
  173. { varalign : minimum alignment required for the variable
  174. minalign : Minimum alignment of this structure, 0 = undefined
  175. maxalign : Maximum alignment of this structure, 0 = undefined }
  176. if (minalign>0) and
  177. (varalign<minalign) then
  178. used_align:=minalign
  179. else
  180. begin
  181. if (maxalign>0) and
  182. (varalign>maxalign) then
  183. used_align:=maxalign
  184. else
  185. used_align:=varalign;
  186. end;
  187. end;
  188. procedure Replace(var s:string;s1:string;const s2:string);
  189. var
  190. last,
  191. i : longint;
  192. begin
  193. s1:=upper(s1);
  194. last:=0;
  195. repeat
  196. i:=pos(s1,upper(s));
  197. if i=last then
  198. i:=0;
  199. if (i>0) then
  200. begin
  201. Delete(s,i,length(s1));
  202. Insert(s2,s,i);
  203. last:=i;
  204. end;
  205. until (i=0);
  206. end;
  207. procedure ReplaceCase(var s:string;const s1,s2:string);
  208. var
  209. last,
  210. i : longint;
  211. begin
  212. last:=0;
  213. repeat
  214. i:=pos(s1,s);
  215. if i=last then
  216. i:=0;
  217. if (i>0) then
  218. begin
  219. Delete(s,i,length(s1));
  220. Insert(s2,s,i);
  221. last:=i;
  222. end;
  223. until (i=0);
  224. end;
  225. function upper(const s : string) : string;
  226. {
  227. return uppercased string of s
  228. }
  229. var
  230. i : longint;
  231. begin
  232. for i:=1 to length(s) do
  233. upper[i]:=uppertbl[s[i]];
  234. upper[0]:=s[0];
  235. end;
  236. function lower(const s : string) : string;
  237. {
  238. return lowercased string of s
  239. }
  240. var
  241. i : longint;
  242. begin
  243. for i:=1 to length(s) do
  244. lower[i]:=lowertbl[s[i]];
  245. lower[0]:=s[0];
  246. end;
  247. procedure uppervar(var s : string);
  248. {
  249. uppercase string s
  250. }
  251. var
  252. i : longint;
  253. begin
  254. for i:=1 to length(s) do
  255. s[i]:=uppertbl[s[i]];
  256. end;
  257. procedure initupperlower;
  258. var
  259. c : char;
  260. begin
  261. for c:=#0 to #255 do
  262. begin
  263. lowertbl[c]:=c;
  264. uppertbl[c]:=c;
  265. case c of
  266. 'A'..'Z' :
  267. lowertbl[c]:=char(byte(c)+32);
  268. 'a'..'z' :
  269. uppertbl[c]:=char(byte(c)-32);
  270. end;
  271. end;
  272. end;
  273. function hexstr(val : cardinal;cnt : cardinal) : string;
  274. const
  275. HexTbl : array[0..15] of char='0123456789ABCDEF';
  276. var
  277. i,j : cardinal;
  278. begin
  279. { calculate required length }
  280. i:=0;
  281. j:=val;
  282. while (j>0) do
  283. begin
  284. inc(i);
  285. j:=j shr 4;
  286. end;
  287. { generate fillers }
  288. j:=0;
  289. while (i+j<cnt) do
  290. begin
  291. inc(j);
  292. hexstr[j]:='0';
  293. end;
  294. { generate hex }
  295. inc(j,i);
  296. hexstr[0]:=chr(j);
  297. while (val>0) do
  298. begin
  299. hexstr[j]:=hextbl[val and $f];
  300. dec(j);
  301. val:=val shr 4;
  302. end;
  303. end;
  304. function tostru(i:cardinal):string;
  305. {
  306. return string of value i, but for cardinals
  307. }
  308. var
  309. hs : string;
  310. begin
  311. str(i,hs);
  312. tostru:=hs;
  313. end;
  314. function DStr(l:longint):string;
  315. var
  316. TmpStr : string[32];
  317. i : longint;
  318. begin
  319. Str(l,TmpStr);
  320. i:=Length(TmpStr);
  321. while (i>3) do
  322. begin
  323. dec(i,3);
  324. if TmpStr[i]<>'-' then
  325. insert('.',TmpStr,i+1);
  326. end;
  327. DStr:=TmpStr;
  328. end;
  329. function trimbspace(const s:string):string;
  330. {
  331. return s with all leading spaces and tabs removed
  332. }
  333. var
  334. i,j : longint;
  335. begin
  336. j:=1;
  337. i:=length(s);
  338. while (j<i) and (s[j] in [#9,' ']) do
  339. inc(j);
  340. trimbspace:=Copy(s,j,i-j+1);
  341. end;
  342. function trimspace(const s:string):string;
  343. {
  344. return s with all leading and ending spaces and tabs removed
  345. }
  346. var
  347. i,j : longint;
  348. begin
  349. i:=length(s);
  350. while (i>0) and (s[i] in [#9,' ']) do
  351. dec(i);
  352. j:=1;
  353. while (j<i) and (s[j] in [#9,' ']) do
  354. inc(j);
  355. trimspace:=Copy(s,j,i-j+1);
  356. end;
  357. function space (b : longint): string;
  358. var
  359. s: string;
  360. begin
  361. space[0] := chr(b);
  362. s[0] := chr(b);
  363. FillChar (S[1],b,' ');
  364. space:=s;
  365. end;
  366. function PadSpace(const s:string;len:longint):string;
  367. {
  368. return s with spaces add to the end
  369. }
  370. begin
  371. if length(s)<len then
  372. PadSpace:=s+Space(len-length(s))
  373. else
  374. PadSpace:=s;
  375. end;
  376. function GetToken(var s:string;endchar:char):string;
  377. var
  378. i : longint;
  379. begin
  380. s:=TrimSpace(s);
  381. i:=pos(EndChar,s);
  382. if i=0 then
  383. begin
  384. GetToken:=s;
  385. s:='';
  386. end
  387. else
  388. begin
  389. GetToken:=Copy(s,1,i-1);
  390. Delete(s,1,i);
  391. end;
  392. end;
  393. function tostr(i : longint) : string;
  394. {
  395. return string of value i
  396. }
  397. var
  398. hs : string;
  399. begin
  400. str(i,result);
  401. end;
  402. function int64tostr(i : int64) : string;
  403. {
  404. return string of value i
  405. }
  406. var
  407. hs : string;
  408. begin
  409. str(i,hs);
  410. int64tostr:=hs;
  411. end;
  412. function tostr_with_plus(i : longint) : string;
  413. {
  414. return string of value i, but always include a + when i>=0
  415. }
  416. var
  417. hs : string;
  418. begin
  419. str(i,hs);
  420. if i>=0 then
  421. tostr_with_plus:='+'+hs
  422. else
  423. tostr_with_plus:=hs;
  424. end;
  425. procedure valint(S : string;var V : longint;var code : integer);
  426. {
  427. val() with support for octal, which is not supported under tp7
  428. }
  429. {$ifndef FPC}
  430. var
  431. vs : longint;
  432. c : byte;
  433. begin
  434. if s[1]='%' then
  435. begin
  436. vs:=0;
  437. longint(v):=0;
  438. for c:=2 to length(s) do
  439. begin
  440. if s[c]='0' then
  441. vs:=vs shl 1
  442. else
  443. if s[c]='1' then
  444. vs:=vs shl 1+1
  445. else
  446. begin
  447. code:=c;
  448. exit;
  449. end;
  450. end;
  451. code:=0;
  452. longint(v):=vs;
  453. end
  454. else
  455. system.val(S,V,code);
  456. end;
  457. {$else not FPC}
  458. begin
  459. system.val(S,V,code);
  460. end;
  461. {$endif not FPC}
  462. function is_number(const s : string) : boolean;
  463. {
  464. is string a correct number ?
  465. }
  466. var
  467. w : integer;
  468. l : longint;
  469. begin
  470. valint(s,l,w);
  471. is_number:=(w=0);
  472. end;
  473. function ispowerof2(value : int64;var power : longint) : boolean;
  474. {
  475. return if value is a power of 2. And if correct return the power
  476. }
  477. var
  478. hl : int64;
  479. i : longint;
  480. begin
  481. if value and (value - 1) <> 0 then
  482. begin
  483. ispowerof2 := false;
  484. exit
  485. end;
  486. hl:=1;
  487. ispowerof2:=true;
  488. for i:=0 to 63 do
  489. begin
  490. if hl=value then
  491. begin
  492. power:=i;
  493. exit;
  494. end;
  495. hl:=hl shl 1;
  496. end;
  497. ispowerof2:=false;
  498. end;
  499. function maybequoted(const s:string):string;
  500. var
  501. s1 : string;
  502. i : integer;
  503. begin
  504. if (pos('"',s)>0) then
  505. begin
  506. s1:='"';
  507. for i:=1 to length(s) do
  508. begin
  509. if s[i]='"' then
  510. s1:=s1+'\"'
  511. else
  512. s1:=s1+s[i];
  513. end;
  514. maybequoted:=s1+'"';
  515. end
  516. else if (pos(' ',s)>0) then
  517. maybequoted:='"'+s+'"'
  518. else
  519. maybequoted:=s;
  520. end;
  521. function pchar2pstring(p : pchar) : pstring;
  522. var
  523. w,i : longint;
  524. begin
  525. w:=strlen(p);
  526. for i:=w-1 downto 0 do
  527. p[i+1]:=p[i];
  528. p[0]:=chr(w);
  529. pchar2pstring:=pstring(p);
  530. end;
  531. function pstring2pchar(p : pstring) : pchar;
  532. var
  533. w,i : longint;
  534. begin
  535. w:=length(p^);
  536. for i:=1 to w do
  537. p^[i-1]:=p^[i];
  538. p^[w]:=#0;
  539. pstring2pchar:=pchar(p);
  540. end;
  541. function lowercase(c : char) : char;
  542. begin
  543. case c of
  544. #65..#90 : c := chr(ord (c) + 32);
  545. #154 : c:=#129; { german }
  546. #142 : c:=#132; { german }
  547. #153 : c:=#148; { german }
  548. #144 : c:=#130; { french }
  549. #128 : c:=#135; { french }
  550. #143 : c:=#134; { swedish/norge (?) }
  551. #165 : c:=#164; { spanish }
  552. #228 : c:=#229; { greek }
  553. #226 : c:=#231; { greek }
  554. #232 : c:=#227; { greek }
  555. end;
  556. lowercase := c;
  557. end;
  558. function strpnew(const s : string) : pchar;
  559. var
  560. p : pchar;
  561. begin
  562. getmem(p,length(s)+1);
  563. strpcopy(p,s);
  564. strpnew:=p;
  565. end;
  566. procedure strdispose(var p : pchar);
  567. begin
  568. if assigned(p) then
  569. begin
  570. freemem(p,strlen(p)+1);
  571. p:=nil;
  572. end;
  573. end;
  574. procedure stringdispose(var p : pstring);
  575. begin
  576. if assigned(p) then
  577. freemem(p,length(p^)+1);
  578. p:=nil;
  579. end;
  580. function stringdup(const s : string) : pstring;
  581. var
  582. p : pstring;
  583. begin
  584. getmem(p,length(s)+1);
  585. p^:=s;
  586. stringdup:=p;
  587. end;
  588. function CompareText(S1, S2: string): longint;
  589. begin
  590. UpperVar(S1);
  591. UpperVar(S2);
  592. if S1<S2 then
  593. CompareText:=-1
  594. else
  595. if S1>S2 then
  596. CompareText:= 1
  597. else
  598. CompareText:=0;
  599. end;
  600. {*****************************************************************************
  601. GetSpeedValue
  602. *****************************************************************************}
  603. {$ifdef ver1_0}
  604. {$R-}
  605. {$endif}
  606. var
  607. Crc32Tbl : array[0..255] of cardinal;
  608. procedure MakeCRC32Tbl;
  609. var
  610. crc : cardinal;
  611. i,n : integer;
  612. begin
  613. for i:=0 to 255 do
  614. begin
  615. crc:=i;
  616. for n:=1 to 8 do
  617. if odd(longint(crc)) then
  618. crc:=cardinal(crc shr 1) xor cardinal($edb88320)
  619. else
  620. crc:=cardinal(crc shr 1);
  621. Crc32Tbl[i]:=crc;
  622. end;
  623. end;
  624. Function GetSpeedValue(Const s:String):cardinal;
  625. var
  626. i : integer;
  627. InitCrc : cardinal;
  628. begin
  629. if Crc32Tbl[1]=0 then
  630. MakeCrc32Tbl;
  631. InitCrc:=cardinal($ffffffff);
  632. for i:=1 to Length(s) do
  633. InitCrc:=Crc32Tbl[byte(InitCrc) xor ord(s[i])] xor (InitCrc shr 8);
  634. GetSpeedValue:=InitCrc;
  635. end;
  636. {*****************************************************************************
  637. Ansistring (PChar+Length)
  638. *****************************************************************************}
  639. procedure ansistringdispose(var p : pchar;length : longint);
  640. begin
  641. if assigned(p) then
  642. freemem(p,length+1);
  643. p:=nil;
  644. end;
  645. { enable ansistring comparison }
  646. { 0 means equal }
  647. { 1 means p1 > p2 }
  648. { -1 means p1 < p2 }
  649. function compareansistrings(p1,p2 : pchar;length1,length2 : longint) : longint;
  650. var
  651. i,j : longint;
  652. begin
  653. compareansistrings:=0;
  654. j:=min(length1,length2);
  655. i:=0;
  656. while (i<j) do
  657. begin
  658. if p1[i]>p2[i] then
  659. begin
  660. compareansistrings:=1;
  661. exit;
  662. end
  663. else
  664. if p1[i]<p2[i] then
  665. begin
  666. compareansistrings:=-1;
  667. exit;
  668. end;
  669. inc(i);
  670. end;
  671. if length1>length2 then
  672. compareansistrings:=1
  673. else
  674. if length1<length2 then
  675. compareansistrings:=-1;
  676. end;
  677. function concatansistrings(p1,p2 : pchar;length1,length2 : longint) : pchar;
  678. var
  679. p : pchar;
  680. begin
  681. getmem(p,length1+length2+1);
  682. move(p1[0],p[0],length1);
  683. move(p2[0],p[length1],length2+1);
  684. concatansistrings:=p;
  685. end;
  686. {*****************************************************************************
  687. File Functions
  688. *****************************************************************************}
  689. function DeleteFile(const fn:string):boolean;
  690. var
  691. f : file;
  692. begin
  693. {$I-}
  694. assign(f,fn);
  695. erase(f);
  696. {$I-}
  697. DeleteFile:=(IOResult=0);
  698. end;
  699. initialization
  700. initupperlower;
  701. end.
  702. {
  703. $Log$
  704. Revision 1.23 2002-10-05 12:43:24 carl
  705. * fixes for Delphi 6 compilation
  706. (warning : Some features do not work under Delphi)
  707. Revision 1.22 2002/09/05 19:29:42 peter
  708. * memdebug enhancements
  709. Revision 1.21 2002/07/26 11:16:35 jonas
  710. * fixed (actual and potential) range errors
  711. Revision 1.20 2002/07/07 11:13:34 carl
  712. * range check error fix (patch from Sergey)
  713. Revision 1.19 2002/07/07 09:52:32 florian
  714. * powerpc target fixed, very simple units can be compiled
  715. * some basic stuff for better callparanode handling, far from being finished
  716. Revision 1.18 2002/07/01 18:46:22 peter
  717. * internal linker
  718. * reorganized aasm layer
  719. Revision 1.17 2002/05/18 13:34:07 peter
  720. * readded missing revisions
  721. Revision 1.16 2002/05/16 19:46:36 carl
  722. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  723. + try to fix temp allocation (still in ifdef)
  724. + generic constructor calls
  725. + start of tassembler / tmodulebase class cleanup
  726. Revision 1.14 2002/04/12 17:16:35 carl
  727. + more documentation of basic unit
  728. }