2
0

cutils.pas 43 KB

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