cutils.pas 40 KB

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