cutils.pas 42 KB

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