cutils.pas 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401
  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. {# Return value @var(i) aligned on @var(a) boundary }
  35. function align(i,a:longint):longint;{$ifdef USEINLINE}inline;{$endif}
  36. {# Return @var(b) with the bit order reversed }
  37. function reverse_byte(b: byte): byte;
  38. function used_align(varalign,minalign,maxalign:shortint):shortint;
  39. function isbetteralignedthan(new, org, limit: cardinal): boolean;
  40. function size_2_align(len : longint) : shortint;
  41. function packedbitsloadsize(bitlen: int64) : int64;
  42. procedure Replace(var s:string;s1:string;const s2:string);
  43. procedure Replace(var s:AnsiString;s1:string;const s2:AnsiString);
  44. procedure ReplaceCase(var s:string;const s1,s2:string);
  45. Function MatchPattern(const pattern,what:string):boolean;
  46. function upper(const c : char) : char;
  47. function upper(const s : string) : string;
  48. function upper(const s : ansistring) : ansistring;
  49. function lower(const c : char) : char;
  50. function lower(const s : string) : string;
  51. function lower(const s : ansistring) : ansistring;
  52. function trimbspace(const s:string):string;
  53. function trimspace(const s:string):string;
  54. function space (b : longint): string;
  55. function PadSpace(const s:string;len:longint):string;
  56. function GetToken(var s:string;endchar:char):string;
  57. procedure uppervar(var s : string);
  58. function realtostr(e:extended):string;{$ifdef USEINLINE}inline;{$endif}
  59. function tostr(i : qword) : string;{$ifdef USEINLINE}inline;{$endif}overload;
  60. function tostr(i : int64) : string;{$ifdef USEINLINE}inline;{$endif}overload;
  61. function tostr(i : longint) : string;{$ifdef USEINLINE}inline;{$endif}overload;
  62. function tostr_with_plus(i : int64) : string;{$ifdef USEINLINE}inline;{$endif}
  63. function DStr(l:longint):string;
  64. {# Returns true if the string s is a number }
  65. function is_number(const s : string) : boolean;{$ifdef USEINLINE}inline;{$endif}
  66. {# Returns true if value is a power of 2, the actual
  67. exponent value is returned in power.
  68. }
  69. function ispowerof2(value : int64;out power : longint) : boolean;
  70. function nextpowerof2(value : int64; out power: longint) : int64;
  71. function backspace_quote(const s:string;const qchars:Tcharset):string;
  72. function octal_quote(const s:string;const qchars:Tcharset):string;
  73. function maybequoted(const s:string):string;
  74. function maybequoted(const s:ansistring):ansistring;
  75. {# If the string is quoted, in accordance with pascal, it is
  76. dequoted and returned in s, and the function returns true.
  77. If it is not quoted, or if the quoting is bad, s is not touched,
  78. and false is returned.
  79. }
  80. function DePascalQuote(var s: ansistring): Boolean;
  81. function CompareStr(const S1, S2: string): Integer;
  82. function CompareText(S1, S2: string): integer;
  83. { releases the string p and assignes nil to p }
  84. { if p=nil then freemem isn't called }
  85. procedure stringdispose(var p : pshortstring);{$ifdef USEINLINE}inline;{$endif}
  86. { allocates mem for a copy of s, copies s to this mem and returns }
  87. { a pointer to this mem }
  88. function stringdup(const s : string) : pshortstring;{$ifdef USEINLINE}inline;{$endif}
  89. {# Allocates memory for the string @var(s) and copies s as zero
  90. terminated string to that allocated memory and returns a pointer
  91. to that mem
  92. }
  93. function strpnew(const s : string) : pchar;
  94. {# makes the character @var(c) lowercase, with spanish, french and german
  95. character set
  96. }
  97. function lowercase(c : char) : char;
  98. { makes zero terminated string to a pascal string }
  99. { the data in p is modified and p is returned }
  100. function pchar2pshortstring(p : pchar) : pshortstring;
  101. { ambivalent to pchar2pshortstring }
  102. function pshortstring2pchar(p : pshortstring) : pchar;
  103. { Ansistring (pchar+length) support }
  104. procedure ansistringdispose(var p : pchar;length : longint);
  105. function compareansistrings(p1,p2 : pchar;length1,length2 : longint) : longint;
  106. function concatansistrings(p1,p2 : pchar;length1,length2 : longint) : pchar;
  107. {Lzw encode/decode to compress strings -> save memory.}
  108. function minilzw_encode(const s:string):string;
  109. function minilzw_decode(const s:string):string;
  110. Function nextafter(x,y:double):double;
  111. {$ifdef ver2_0}
  112. { RTL routines not available yet in 2.0.x }
  113. function SwapEndian(const AValue: SmallInt): SmallInt;
  114. function SwapEndian(const AValue: Word): Word;
  115. function SwapEndian(const AValue: LongInt): LongInt;
  116. function SwapEndian(const AValue: DWord): DWord;
  117. function SwapEndian(const AValue: Int64): Int64;
  118. function SwapEndian(const AValue: QWord): QWord;
  119. {$endif ver2_0}
  120. implementation
  121. uses
  122. SysUtils;
  123. var
  124. uppertbl,
  125. lowertbl : array[char] of char;
  126. function min(a,b : longint) : longint;{$ifdef USEINLINE}inline;{$endif}
  127. {
  128. return the minimal of a and b
  129. }
  130. begin
  131. if a<=b then
  132. min:=a
  133. else
  134. min:=b;
  135. end;
  136. function min(a,b : int64) : int64;{$ifdef USEINLINE}inline;{$endif}
  137. {
  138. return the minimal of a and b
  139. }
  140. begin
  141. if a<=b then
  142. min:=a
  143. else
  144. min:=b;
  145. end;
  146. function max(a,b : longint) : longint;{$ifdef USEINLINE}inline;{$endif}
  147. {
  148. return the maximum of a and b
  149. }
  150. begin
  151. if a>=b then
  152. max:=a
  153. else
  154. max:=b;
  155. end;
  156. function max(a,b : int64) : int64;{$ifdef USEINLINE}inline;{$endif}
  157. {
  158. return the maximum of a and b
  159. }
  160. begin
  161. if a>=b then
  162. max:=a
  163. else
  164. max:=b;
  165. end;
  166. function reverse_byte(b: byte): byte;
  167. const
  168. reverse_nible:array[0..15] of 0..15 =
  169. (%0000,%1000,%0100,%1100,%0010,%1010,%0110,%1110,
  170. %0001,%1001,%0101,%1101,%0011,%1011,%0111,%1111);
  171. begin
  172. reverse_byte:=(reverse_nible[b and $f] shl 4) or reverse_nible[b shr 4];
  173. end;
  174. function align(i,a:longint):longint;{$ifdef USEINLINE}inline;{$endif}
  175. {
  176. return value <i> aligned <a> boundary
  177. }
  178. begin
  179. { for 0 and 1 no aligning is needed }
  180. if a<=1 then
  181. result:=i
  182. else
  183. begin
  184. if i<0 then
  185. result:=((i-a+1) div a) * a
  186. else
  187. result:=((i+a-1) div a) * a;
  188. end;
  189. end;
  190. function size_2_align(len : longint) : shortint;
  191. begin
  192. if len>16 then
  193. size_2_align:=32
  194. else if len>8 then
  195. size_2_align:=16
  196. else if len>4 then
  197. size_2_align:=8
  198. else if len>2 then
  199. size_2_align:=4
  200. else if len>1 then
  201. size_2_align:=2
  202. else
  203. size_2_align:=1;
  204. end;
  205. function packedbitsloadsize(bitlen: int64) : int64;
  206. begin
  207. case bitlen of
  208. 1,2,4,8:
  209. result := 1;
  210. { 10 bits can never be split over 3 bytes via 1-8-1, because it }
  211. { always starts at a multiple of 10 bits. Same for the others. }
  212. 3,5,6,7,9,10,12,16:
  213. result := 2;
  214. {$ifdef cpu64bit}
  215. { performance penalty for unaligned 8 byte access is much }
  216. { higher than for unaligned 4 byte access, at least on ppc, }
  217. { so use 4 bytes even in some cases where a value could }
  218. { always loaded using a single 8 byte load (e.g. in case of }
  219. { 28 bit values) }
  220. 11,13,14,15,17..32:
  221. result := 4;
  222. else
  223. result := 8;
  224. {$else cpu64bit}
  225. else
  226. result := 4;
  227. {$endif cpu64bit}
  228. end;
  229. end;
  230. function isbetteralignedthan(new, org, limit: cardinal): boolean;
  231. var
  232. cnt: cardinal;
  233. begin
  234. cnt:=2;
  235. while (cnt <= limit) do
  236. begin
  237. if (org and (cnt-1)) > (new and (cnt-1)) then
  238. begin
  239. result:=true;
  240. exit;
  241. end
  242. else if (org and (cnt-1)) < (new and (cnt-1)) then
  243. begin
  244. result:=false;
  245. exit;
  246. end;
  247. cnt:=cnt*2;
  248. end;
  249. result:=false;
  250. end;
  251. function used_align(varalign,minalign,maxalign:shortint):shortint;
  252. begin
  253. { varalign : minimum alignment required for the variable
  254. minalign : Minimum alignment of this structure, 0 = undefined
  255. maxalign : Maximum alignment of this structure, 0 = undefined }
  256. if (minalign>0) and
  257. (varalign<minalign) then
  258. used_align:=minalign
  259. else
  260. begin
  261. if (maxalign>0) and
  262. (varalign>maxalign) then
  263. used_align:=maxalign
  264. else
  265. used_align:=varalign;
  266. end;
  267. end;
  268. procedure Replace(var s:string;s1:string;const s2:string);
  269. var
  270. last,
  271. i : longint;
  272. begin
  273. s1:=upper(s1);
  274. last:=0;
  275. repeat
  276. i:=pos(s1,upper(s));
  277. if i=last then
  278. i:=0;
  279. if (i>0) then
  280. begin
  281. Delete(s,i,length(s1));
  282. Insert(s2,s,i);
  283. last:=i;
  284. end;
  285. until (i=0);
  286. end;
  287. procedure Replace(var s:AnsiString;s1:string;const s2:AnsiString);
  288. var
  289. last,
  290. i : longint;
  291. begin
  292. s1:=upper(s1);
  293. last:=0;
  294. repeat
  295. i:=pos(s1,upper(s));
  296. if i=last then
  297. i:=0;
  298. if (i>0) then
  299. begin
  300. Delete(s,i,length(s1));
  301. Insert(s2,s,i);
  302. last:=i;
  303. end;
  304. until (i=0);
  305. end;
  306. procedure ReplaceCase(var s:string;const s1,s2:string);
  307. var
  308. last,
  309. i : longint;
  310. begin
  311. last:=0;
  312. repeat
  313. i:=pos(s1,s);
  314. if i=last then
  315. i:=0;
  316. if (i>0) then
  317. begin
  318. Delete(s,i,length(s1));
  319. Insert(s2,s,i);
  320. last:=i;
  321. end;
  322. until (i=0);
  323. end;
  324. Function MatchPattern(const pattern,what:string):boolean;
  325. var
  326. found : boolean;
  327. i1,i2 : longint;
  328. begin
  329. i1:=0;
  330. i2:=0;
  331. if pattern='' then
  332. begin
  333. result:=(what='');
  334. exit;
  335. end;
  336. found:=true;
  337. repeat
  338. inc(i1);
  339. if (i1>length(pattern)) then
  340. break;
  341. inc(i2);
  342. if (i2>length(what)) then
  343. break;
  344. case pattern[i1] of
  345. '?' :
  346. found:=true;
  347. '*' :
  348. begin
  349. found:=true;
  350. if (i1=length(pattern)) then
  351. i2:=length(what)
  352. else
  353. if (i1<length(pattern)) and (pattern[i1+1]<>what[i2]) then
  354. begin
  355. if i2<length(what) then
  356. dec(i1)
  357. end
  358. else
  359. if i2>1 then
  360. dec(i2);
  361. end;
  362. else
  363. found:=(pattern[i1]=what[i2]) or (what[i2]='?');
  364. end;
  365. until not found;
  366. if found then
  367. begin
  368. found:=(i2>=length(what)) and
  369. (
  370. (i1>length(pattern)) or
  371. ((i1=length(pattern)) and
  372. (pattern[i1]='*'))
  373. );
  374. end;
  375. result:=found;
  376. end;
  377. function upper(const c : char) : char;
  378. {
  379. return uppercase of c
  380. }
  381. begin
  382. upper:=uppertbl[c];
  383. end;
  384. function upper(const s : string) : string;
  385. {
  386. return uppercased string of s
  387. }
  388. var
  389. i : longint;
  390. begin
  391. for i:=1 to length(s) do
  392. upper[i]:=uppertbl[s[i]];
  393. upper[0]:=s[0];
  394. end;
  395. function upper(const s : ansistring) : ansistring;
  396. {
  397. return uppercased string of s
  398. }
  399. var
  400. i : longint;
  401. begin
  402. setlength(upper,length(s));
  403. for i:=1 to length(s) do
  404. upper[i]:=uppertbl[s[i]];
  405. end;
  406. function lower(const c : char) : char;
  407. {
  408. return lowercase of c
  409. }
  410. begin
  411. lower:=lowertbl[c];
  412. end;
  413. function lower(const s : string) : string;
  414. {
  415. return lowercased string of s
  416. }
  417. var
  418. i : longint;
  419. begin
  420. for i:=1 to length(s) do
  421. lower[i]:=lowertbl[s[i]];
  422. lower[0]:=s[0];
  423. end;
  424. function lower(const s : ansistring) : ansistring;
  425. {
  426. return lowercased string of s
  427. }
  428. var
  429. i : longint;
  430. begin
  431. setlength(lower,length(s));
  432. for i:=1 to length(s) do
  433. lower[i]:=lowertbl[s[i]];
  434. end;
  435. procedure uppervar(var s : string);
  436. {
  437. uppercase string s
  438. }
  439. var
  440. i : longint;
  441. begin
  442. for i:=1 to length(s) do
  443. s[i]:=uppertbl[s[i]];
  444. end;
  445. procedure initupperlower;
  446. var
  447. c : char;
  448. begin
  449. for c:=#0 to #255 do
  450. begin
  451. lowertbl[c]:=c;
  452. uppertbl[c]:=c;
  453. case c of
  454. 'A'..'Z' :
  455. lowertbl[c]:=char(byte(c)+32);
  456. 'a'..'z' :
  457. uppertbl[c]:=char(byte(c)-32);
  458. end;
  459. end;
  460. end;
  461. function DStr(l:longint):string;
  462. var
  463. TmpStr : string[32];
  464. i : longint;
  465. begin
  466. Str(l,TmpStr);
  467. i:=Length(TmpStr);
  468. while (i>3) do
  469. begin
  470. dec(i,3);
  471. if TmpStr[i]<>'-' then
  472. insert('.',TmpStr,i+1);
  473. end;
  474. DStr:=TmpStr;
  475. end;
  476. function trimbspace(const s:string):string;
  477. {
  478. return s with all leading spaces and tabs removed
  479. }
  480. var
  481. i,j : longint;
  482. begin
  483. j:=1;
  484. i:=length(s);
  485. while (j<i) and (s[j] in [#9,' ']) do
  486. inc(j);
  487. trimbspace:=Copy(s,j,i-j+1);
  488. end;
  489. function trimspace(const s:string):string;
  490. {
  491. return s with all leading and ending spaces and tabs removed
  492. }
  493. var
  494. i,j : longint;
  495. begin
  496. i:=length(s);
  497. while (i>0) and (s[i] in [#9,' ']) do
  498. dec(i);
  499. j:=1;
  500. while (j<i) and (s[j] in [#9,' ']) do
  501. inc(j);
  502. trimspace:=Copy(s,j,i-j+1);
  503. end;
  504. function space (b : longint): string;
  505. var
  506. s: string;
  507. begin
  508. space[0] := chr(b);
  509. s[0] := chr(b);
  510. FillChar (S[1],b,' ');
  511. space:=s;
  512. end;
  513. function PadSpace(const s:string;len:longint):string;
  514. {
  515. return s with spaces add to the end
  516. }
  517. begin
  518. if length(s)<len then
  519. PadSpace:=s+Space(len-length(s))
  520. else
  521. PadSpace:=s;
  522. end;
  523. function GetToken(var s:string;endchar:char):string;
  524. var
  525. i : longint;
  526. quote : char;
  527. begin
  528. GetToken:='';
  529. s:=TrimSpace(s);
  530. if (length(s)>0) and
  531. (s[1] in ['''','"']) then
  532. begin
  533. quote:=s[1];
  534. i:=1;
  535. while (i<length(s)) do
  536. begin
  537. inc(i);
  538. if s[i]=quote then
  539. begin
  540. { Remove double quote }
  541. if (i<length(s)) and
  542. (s[i+1]=quote) then
  543. begin
  544. Delete(s,i,1);
  545. inc(i);
  546. end
  547. else
  548. begin
  549. GetToken:=Copy(s,2,i-2);
  550. Delete(s,1,i);
  551. exit;
  552. end;
  553. end;
  554. end;
  555. GetToken:=s;
  556. s:='';
  557. end
  558. else
  559. begin
  560. i:=pos(EndChar,s);
  561. if i=0 then
  562. begin
  563. GetToken:=s;
  564. s:='';
  565. exit;
  566. end
  567. else
  568. begin
  569. GetToken:=Copy(s,1,i-1);
  570. Delete(s,1,i);
  571. exit;
  572. end;
  573. end;
  574. end;
  575. function realtostr(e:extended):string;{$ifdef USEINLINE}inline;{$endif}
  576. begin
  577. str(e,result);
  578. end;
  579. function tostr(i : qword) : string;{$ifdef USEINLINE}inline;{$endif}overload;
  580. {
  581. return string of value i
  582. }
  583. begin
  584. str(i,result);
  585. end;
  586. function tostr(i : int64) : string;{$ifdef USEINLINE}inline;{$endif}overload;
  587. {
  588. return string of value i
  589. }
  590. begin
  591. str(i,result);
  592. end;
  593. function tostr(i : longint) : string;{$ifdef USEINLINE}inline;{$endif}overload;
  594. {
  595. return string of value i
  596. }
  597. begin
  598. str(i,result);
  599. end;
  600. function tostr_with_plus(i : int64) : string;{$ifdef USEINLINE}inline;{$endif}
  601. {
  602. return string of value i, but always include a + when i>=0
  603. }
  604. begin
  605. str(i,result);
  606. if i>=0 then
  607. result:='+'+result;
  608. end;
  609. function is_number(const s : string) : boolean;{$ifdef USEINLINE}inline;{$endif}
  610. {
  611. is string a correct number ?
  612. }
  613. var
  614. w : integer;
  615. l : longint;
  616. begin
  617. val(s,l,w);
  618. // remove warning
  619. l:=l;
  620. is_number:=(w=0);
  621. end;
  622. function ispowerof2(value : int64;out power : longint) : boolean;
  623. {
  624. return if value is a power of 2. And if correct return the power
  625. }
  626. var
  627. hl : int64;
  628. i : longint;
  629. begin
  630. if value and (value - 1) <> 0 then
  631. begin
  632. ispowerof2 := false;
  633. exit
  634. end;
  635. hl:=1;
  636. ispowerof2:=true;
  637. for i:=0 to 63 do
  638. begin
  639. if hl=value then
  640. begin
  641. power:=i;
  642. exit;
  643. end;
  644. hl:=hl shl 1;
  645. end;
  646. ispowerof2:=false;
  647. end;
  648. function nextpowerof2(value : int64; out power: longint) : int64;
  649. {
  650. returns the power of 2 >= value
  651. }
  652. var
  653. i : longint;
  654. begin
  655. result := 0;
  656. power := -1;
  657. if ((value <= 0) or
  658. (value >= $4000000000000000)) then
  659. exit;
  660. result := 1;
  661. for i:=0 to 63 do
  662. begin
  663. if result>=value then
  664. begin
  665. power := i;
  666. exit;
  667. end;
  668. result:=result shl 1;
  669. end;
  670. end;
  671. function backspace_quote(const s:string;const qchars:Tcharset):string;
  672. var i:byte;
  673. begin
  674. backspace_quote:='';
  675. for i:=1 to length(s) do
  676. begin
  677. if (s[i]=#10) and (#10 in qchars) then
  678. backspace_quote:=backspace_quote+'\n'
  679. else if (s[i]=#13) and (#13 in qchars) then
  680. backspace_quote:=backspace_quote+'\r'
  681. else
  682. begin
  683. if s[i] in qchars then
  684. backspace_quote:=backspace_quote+'\';
  685. backspace_quote:=backspace_quote+s[i];
  686. end;
  687. end;
  688. end;
  689. function octal_quote(const s:string;const qchars:Tcharset):string;
  690. var i:byte;
  691. begin
  692. octal_quote:='';
  693. for i:=1 to length(s) do
  694. begin
  695. if s[i] in qchars then
  696. begin
  697. if ord(s[i])<64 then
  698. octal_quote:=octal_quote+'\'+octstr(ord(s[i]),3)
  699. else
  700. octal_quote:=octal_quote+'\'+octstr(ord(s[i]),4);
  701. end
  702. else
  703. octal_quote:=octal_quote+s[i];
  704. end;
  705. end;
  706. function maybequoted(const s:ansistring):ansistring;
  707. const
  708. {$IFDEF MSWINDOWS}
  709. FORBIDDEN_CHARS = ['!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
  710. '{', '}', '''', '`', '~'];
  711. {$ELSE}
  712. FORBIDDEN_CHARS = ['!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
  713. '{', '}', '''', ':', '\', '`', '~'];
  714. {$ENDIF}
  715. var
  716. s1 : ansistring;
  717. i : integer;
  718. quoted : boolean;
  719. begin
  720. quoted:=false;
  721. s1:='"';
  722. for i:=1 to length(s) do
  723. begin
  724. case s[i] of
  725. '"' :
  726. begin
  727. quoted:=true;
  728. s1:=s1+'\"';
  729. end;
  730. ' ',
  731. #128..#255 :
  732. begin
  733. quoted:=true;
  734. s1:=s1+s[i];
  735. end;
  736. else begin
  737. if s[i] in FORBIDDEN_CHARS then
  738. quoted:=True;
  739. s1:=s1+s[i];
  740. end;
  741. end;
  742. end;
  743. if quoted then
  744. maybequoted:=s1+'"'
  745. else
  746. maybequoted:=s;
  747. end;
  748. function maybequoted(const s:string):string;
  749. const
  750. {$IFDEF MSWINDOWS}
  751. FORBIDDEN_CHARS = ['!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
  752. '{', '}', '''', '`', '~'];
  753. {$ELSE}
  754. FORBIDDEN_CHARS = ['!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
  755. '{', '}', '''', ':', '\', '`', '~'];
  756. {$ENDIF}
  757. var
  758. s1 : string;
  759. i : integer;
  760. quoted : boolean;
  761. begin
  762. quoted:=false;
  763. s1:='"';
  764. for i:=1 to length(s) do
  765. begin
  766. case s[i] of
  767. '"' :
  768. begin
  769. quoted:=true;
  770. s1:=s1+'\"';
  771. end;
  772. ' ',
  773. #128..#255 :
  774. begin
  775. quoted:=true;
  776. s1:=s1+s[i];
  777. end;
  778. else begin
  779. if s[i] in FORBIDDEN_CHARS then
  780. quoted:=True;
  781. s1:=s1+s[i];
  782. end;
  783. end;
  784. end;
  785. if quoted then
  786. maybequoted:=s1+'"'
  787. else
  788. maybequoted:=s;
  789. end;
  790. function DePascalQuote(var s: ansistring): Boolean;
  791. var
  792. destPos, sourcePos, len: Integer;
  793. t: string;
  794. ch: Char;
  795. begin
  796. DePascalQuote:= false;
  797. len:= length(s);
  798. if (len >= 1) and (s[1] = '''') then
  799. begin
  800. {Remove quotes, exchange '' against ' }
  801. destPos := 0;
  802. sourcepos:=1;
  803. while (sourcepos<len) do
  804. begin
  805. inc(sourcePos);
  806. ch := s[sourcePos];
  807. if ch = '''' then
  808. begin
  809. inc(sourcePos);
  810. if (sourcePos <= len) and (s[sourcePos] = '''') then
  811. {Add the quote as part of string}
  812. else
  813. begin
  814. SetLength(t, destPos);
  815. s:= t;
  816. Exit(true);
  817. end;
  818. end;
  819. inc(destPos);
  820. t[destPos] := ch;
  821. end;
  822. end;
  823. end;
  824. function pchar2pshortstring(p : pchar) : pshortstring;
  825. var
  826. w,i : longint;
  827. begin
  828. w:=strlen(p);
  829. for i:=w-1 downto 0 do
  830. p[i+1]:=p[i];
  831. p[0]:=chr(w);
  832. pchar2pshortstring:=pshortstring(p);
  833. end;
  834. function pshortstring2pchar(p : pshortstring) : pchar;
  835. var
  836. w,i : longint;
  837. begin
  838. w:=length(p^);
  839. for i:=1 to w do
  840. p^[i-1]:=p^[i];
  841. p^[w]:=#0;
  842. pshortstring2pchar:=pchar(p);
  843. end;
  844. function lowercase(c : char) : char;
  845. begin
  846. case c of
  847. #65..#90 : c := chr(ord (c) + 32);
  848. #154 : c:=#129; { german }
  849. #142 : c:=#132; { german }
  850. #153 : c:=#148; { german }
  851. #144 : c:=#130; { french }
  852. #128 : c:=#135; { french }
  853. #143 : c:=#134; { swedish/norge (?) }
  854. #165 : c:=#164; { spanish }
  855. #228 : c:=#229; { greek }
  856. #226 : c:=#231; { greek }
  857. #232 : c:=#227; { greek }
  858. end;
  859. lowercase := c;
  860. end;
  861. function strpnew(const s : string) : pchar;
  862. var
  863. p : pchar;
  864. begin
  865. getmem(p,length(s)+1);
  866. move(s[1],p^,length(s));
  867. p[length(s)]:=#0;
  868. result:=p;
  869. end;
  870. procedure stringdispose(var p : pshortstring);{$ifdef USEINLINE}inline;{$endif}
  871. begin
  872. if assigned(p) then
  873. begin
  874. freemem(p);
  875. p:=nil;
  876. end;
  877. end;
  878. function stringdup(const s : string) : pshortstring;{$ifdef USEINLINE}inline;{$endif}
  879. begin
  880. getmem(result,length(s)+1);
  881. result^:=s;
  882. end;
  883. function CompareStr(const S1, S2: string): Integer;
  884. var
  885. count, count1, count2: integer;
  886. begin
  887. result := 0;
  888. Count1 := Length(S1);
  889. Count2 := Length(S2);
  890. if Count1>Count2 then
  891. Count:=Count2
  892. else
  893. Count:=Count1;
  894. result := CompareChar(S1[1],S2[1], Count);
  895. if result=0 then
  896. result:=Count1-Count2;
  897. end;
  898. function CompareText(S1, S2: string): integer;
  899. begin
  900. UpperVar(S1);
  901. UpperVar(S2);
  902. Result:=CompareStr(S1,S2);
  903. end;
  904. {*****************************************************************************
  905. Ansistring (PChar+Length)
  906. *****************************************************************************}
  907. procedure ansistringdispose(var p : pchar;length : longint);
  908. begin
  909. if assigned(p) then
  910. begin
  911. freemem(p);
  912. p:=nil;
  913. end;
  914. end;
  915. { enable ansistring comparison }
  916. { 0 means equal }
  917. { 1 means p1 > p2 }
  918. { -1 means p1 < p2 }
  919. function compareansistrings(p1,p2 : pchar;length1,length2 : longint) : longint;
  920. var
  921. i,j : longint;
  922. begin
  923. compareansistrings:=0;
  924. j:=min(length1,length2);
  925. i:=0;
  926. while (i<j) do
  927. begin
  928. if p1[i]>p2[i] then
  929. begin
  930. compareansistrings:=1;
  931. exit;
  932. end
  933. else
  934. if p1[i]<p2[i] then
  935. begin
  936. compareansistrings:=-1;
  937. exit;
  938. end;
  939. inc(i);
  940. end;
  941. if length1>length2 then
  942. compareansistrings:=1
  943. else
  944. if length1<length2 then
  945. compareansistrings:=-1;
  946. end;
  947. function concatansistrings(p1,p2 : pchar;length1,length2 : longint) : pchar;
  948. var
  949. p : pchar;
  950. begin
  951. getmem(p,length1+length2+1);
  952. move(p1[0],p[0],length1);
  953. move(p2[0],p[length1],length2+1);
  954. concatansistrings:=p;
  955. end;
  956. {*****************************************************************************
  957. Ultra basic KISS Lzw (de)compressor
  958. *****************************************************************************}
  959. {This is an extremely basic implementation of the Lzw algorithm. It
  960. compresses 7-bit ASCII strings into 8-bit compressed strings.
  961. The Lzw dictionary is preinitialized with 0..127, therefore this
  962. part of the dictionary does not need to be stored in the arrays.
  963. The Lzw code size is allways 8 bit, so we do not need complex code
  964. that can write partial bytes.}
  965. function minilzw_encode(const s:string):string;
  966. var t,u,i:byte;
  967. c:char;
  968. data:array[128..255] of char;
  969. previous:array[128..255] of byte;
  970. lzwptr:byte;
  971. next_avail:set of 0..255;
  972. label l1;
  973. begin
  974. minilzw_encode:='';
  975. fillchar(data,sizeof(data),#0);
  976. fillchar(previous,sizeof(previous),#0);
  977. if s<>'' then
  978. begin
  979. lzwptr:=127;
  980. t:=byte(s[1]);
  981. i:=2;
  982. u:=128;
  983. next_avail:=[];
  984. while i<=length(s) do
  985. begin
  986. c:=s[i];
  987. if not(t in next_avail) or (u>lzwptr) then goto l1;
  988. while (previous[u]<>t) or (data[u]<>c) do
  989. begin
  990. inc(u);
  991. if u>lzwptr then goto l1;
  992. end;
  993. t:=u;
  994. inc(i);
  995. continue;
  996. l1:
  997. {It's a pity that we still need those awfull tricks
  998. with this modern compiler. Without this performance
  999. of the entire procedure drops about 3 times.}
  1000. inc(minilzw_encode[0]);
  1001. minilzw_encode[length(minilzw_encode)]:=char(t);
  1002. if lzwptr=255 then
  1003. begin
  1004. lzwptr:=127;
  1005. next_avail:=[];
  1006. end
  1007. else
  1008. begin
  1009. inc(lzwptr);
  1010. data[lzwptr]:=c;
  1011. previous[lzwptr]:=t;
  1012. include(next_avail,t);
  1013. end;
  1014. t:=byte(c);
  1015. u:=128;
  1016. inc(i);
  1017. end;
  1018. inc(minilzw_encode[0]);
  1019. minilzw_encode[length(minilzw_encode)]:=char(t);
  1020. end;
  1021. end;
  1022. function minilzw_decode(const s:string):string;
  1023. var oldc,newc,c:char;
  1024. i,j:byte;
  1025. data:array[128..255] of char;
  1026. previous:array[128..255] of byte;
  1027. lzwptr:byte;
  1028. t:string;
  1029. begin
  1030. minilzw_decode:='';
  1031. fillchar(data,sizeof(data),#0);
  1032. fillchar(previous,sizeof(previous),#0);
  1033. if s<>'' then
  1034. begin
  1035. lzwptr:=127;
  1036. oldc:=s[1];
  1037. c:=oldc;
  1038. i:=2;
  1039. minilzw_decode:=oldc;
  1040. while i<=length(s) do
  1041. begin
  1042. newc:=s[i];
  1043. if byte(newc)>lzwptr then
  1044. begin
  1045. t:=c;
  1046. c:=oldc;
  1047. end
  1048. else
  1049. begin
  1050. c:=newc;
  1051. t:='';
  1052. end;
  1053. while c>=#128 do
  1054. begin
  1055. inc(t[0]);
  1056. t[length(t)]:=data[byte(c)];
  1057. byte(c):=previous[byte(c)];
  1058. end;
  1059. inc(minilzw_decode[0]);
  1060. minilzw_decode[length(minilzw_decode)]:=c;
  1061. for j:=length(t) downto 1 do
  1062. begin
  1063. inc(minilzw_decode[0]);
  1064. minilzw_decode[length(minilzw_decode)]:=t[j];
  1065. end;
  1066. if lzwptr=255 then
  1067. lzwptr:=127
  1068. else
  1069. begin
  1070. inc(lzwptr);
  1071. previous[lzwptr]:=byte(oldc);
  1072. data[lzwptr]:=c;
  1073. end;
  1074. oldc:=newc;
  1075. inc(i);
  1076. end;
  1077. end;
  1078. end;
  1079. procedure defaulterror(i:longint);
  1080. begin
  1081. writeln('Internal error ',i);
  1082. runerror(255);
  1083. end;
  1084. Function Nextafter(x,y:double):double;
  1085. // Returns the double precision number closest to x in
  1086. // the direction toward y.
  1087. // Initial direct translation by Soeren Haastrup from
  1088. // www.netlib.org/fdlibm/s_nextafter.c according to
  1089. // ====================================================
  1090. // Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
  1091. // Developed at SunSoft, a Sun Microsystems, Inc. business.
  1092. // Permission to use, copy, modify, and distribute this
  1093. // software is freely granted, provided that this notice
  1094. // is preserved.
  1095. // ====================================================
  1096. // and with all signaling policies preserved as is.
  1097. type
  1098. {$ifdef ENDIAN_LITTLE}
  1099. twoword=record
  1100. lo,hi:longword; // Little Endian split of a double.
  1101. end;
  1102. {$else}
  1103. twoword=record
  1104. hi,lo:longword; // Little Endian split of a double.
  1105. end;
  1106. {$endif}
  1107. var
  1108. hx,hy,ix,iy:longint;
  1109. lx,ly:longword;
  1110. Begin
  1111. hx:=twoword(x).hi; // high and low words of x and y
  1112. lx:=twoword(x).lo;
  1113. hy:=twoword(y).hi;
  1114. ly:=twoword(y).lo;
  1115. ix:=hx and $7fffffff; // absolute values
  1116. iy:=hy and $7fffffff;
  1117. // Case x=NAN or y=NAN
  1118. if ( (ix>=$7ff00000) and (((ix-$7ff00000) or lx) <> 0) )
  1119. or ( (iy>=$7ff00000) and (((iy-$7ff00000) OR ly) <> 0) )
  1120. then exit(x+y);
  1121. // Case x=y
  1122. if x=y then exit(x); // (implies Nextafter(0,-0) is 0 and not -0...)
  1123. // Case x=0
  1124. if (ix or lx)=0
  1125. then begin
  1126. twoword(x).hi:=hy and $80000000; // return +-minimalSubnormal
  1127. twoword(x).lo:=1;
  1128. y:=x*x; // set underflow flag (ignored in FPC as default)
  1129. if y=x
  1130. then exit(y)
  1131. else exit(x);
  1132. end;
  1133. // all other cases
  1134. if hx>=0 // x>0
  1135. then begin
  1136. if (hx>hy) or ( (hx=hy) and (lx>ly) ) // x>y , return x-ulp
  1137. then begin
  1138. if (lx=0) then hx:=hx-1;
  1139. lx:=lx-1;
  1140. end
  1141. else begin // x<y, return x+ulp
  1142. lx:=lx+1;
  1143. if lx=0 then hx:=hx+1;
  1144. end
  1145. end
  1146. else begin // x<0
  1147. if (hy>=0) or (hx>=hy) or ( (hx=hy) and (lx>ly)) // x<y, return x-ulp
  1148. then begin
  1149. if (lx=0) then hx:=hx-1;
  1150. lx:=lx-1;
  1151. end
  1152. else begin // x>y , return x+ulp
  1153. lx:=lx+1;
  1154. if lx=0 then hx:=hx+1;
  1155. end
  1156. end;
  1157. // finally check if overflow or underflow just happend
  1158. hy:=hx and $7ff00000;
  1159. if (hy>= $7ff00000) then exit(x+x); // overflow and signal
  1160. if (hy<$0010000) // underflow
  1161. then begin
  1162. y:=x*x; // raise underflow flag
  1163. if y<>x
  1164. then begin
  1165. twoword(y).hi:=hx;
  1166. twoword(y).lo:=lx;
  1167. exit(y);
  1168. end
  1169. end;
  1170. twoword(x).hi:=hx;
  1171. twoword(x).lo:=lx;
  1172. nextafter:=x;
  1173. end;
  1174. {$ifdef ver2_0}
  1175. function SwapEndian(const AValue: SmallInt): SmallInt;
  1176. begin
  1177. Result := (AValue shr 8) or (AValue shl 8);
  1178. end;
  1179. function SwapEndian(const AValue: Word): Word;
  1180. begin
  1181. Result := (AValue shr 8) or (AValue shl 8);
  1182. end;
  1183. function SwapEndian(const AValue: LongInt): LongInt;
  1184. begin
  1185. Result := (AValue shl 24)
  1186. or ((AValue and $0000FF00) shl 8)
  1187. or ((AValue and $00FF0000) shr 8)
  1188. or (AValue shr 24);
  1189. end;
  1190. function SwapEndian(const AValue: DWord): DWord;
  1191. begin
  1192. Result := (AValue shl 24)
  1193. or ((AValue and $0000FF00) shl 8)
  1194. or ((AValue and $00FF0000) shr 8)
  1195. or (AValue shr 24);
  1196. end;
  1197. function SwapEndian(const AValue: Int64): Int64;
  1198. begin
  1199. Result := (AValue shl 56)
  1200. or ((AValue and $000000000000FF00) shl 40)
  1201. or ((AValue and $0000000000FF0000) shl 24)
  1202. or ((AValue and $00000000FF000000) shl 8)
  1203. or ((AValue and $000000FF00000000) shr 8)
  1204. or ((AValue and $0000FF0000000000) shr 24)
  1205. or ((AValue and $00FF000000000000) shr 40)
  1206. or (AValue shr 56);
  1207. end;
  1208. function SwapEndian(const AValue: QWord): QWord;
  1209. begin
  1210. Result := (AValue shl 56)
  1211. or ((AValue and $000000000000FF00) shl 40)
  1212. or ((AValue and $0000000000FF0000) shl 24)
  1213. or ((AValue and $00000000FF000000) shl 8)
  1214. or ((AValue and $000000FF00000000) shr 8)
  1215. or ((AValue and $0000FF0000000000) shr 24)
  1216. or ((AValue and $00FF000000000000) shr 40)
  1217. or (AValue shr 56);
  1218. end;
  1219. {$endif ver2_0}
  1220. initialization
  1221. internalerrorproc:=@defaulterror;
  1222. initupperlower;
  1223. end.