cutils.pas 36 KB

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