cutils.pas 40 KB

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