cutils.pas 42 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601
  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. setlength(upper,length(s));
  554. for i:=1 to length(s) do
  555. upper[i]:=uppertbl[s[i]];
  556. end;
  557. function lower(const c : char) : char;
  558. {
  559. return lowercase of c
  560. }
  561. begin
  562. lower:=lowertbl[c];
  563. end;
  564. function lower(const s : string) : string;
  565. {
  566. return lowercased string of s
  567. }
  568. var
  569. i : longint;
  570. begin
  571. for i:=1 to length(s) do
  572. lower[i]:=lowertbl[s[i]];
  573. lower[0]:=s[0];
  574. end;
  575. function lower(const s : ansistring) : ansistring;
  576. {
  577. return lowercased string of s
  578. }
  579. var
  580. i : longint;
  581. begin
  582. setlength(lower,length(s));
  583. for i:=1 to length(s) do
  584. lower[i]:=lowertbl[s[i]];
  585. end;
  586. procedure uppervar(var s : string);
  587. {
  588. uppercase string s
  589. }
  590. var
  591. i : longint;
  592. begin
  593. for i:=1 to length(s) do
  594. s[i]:=uppertbl[s[i]];
  595. end;
  596. procedure initupperlower;
  597. var
  598. c : char;
  599. begin
  600. for c:=#0 to #255 do
  601. begin
  602. lowertbl[c]:=c;
  603. uppertbl[c]:=c;
  604. case c of
  605. 'A'..'Z' :
  606. lowertbl[c]:=char(byte(c)+32);
  607. 'a'..'z' :
  608. uppertbl[c]:=char(byte(c)-32);
  609. end;
  610. end;
  611. end;
  612. function DStr(l:longint):string;
  613. var
  614. TmpStr : string[32];
  615. i : longint;
  616. begin
  617. Str(l,TmpStr);
  618. i:=Length(TmpStr);
  619. while (i>3) do
  620. begin
  621. dec(i,3);
  622. if TmpStr[i]<>'-' then
  623. insert('.',TmpStr,i+1);
  624. end;
  625. DStr:=TmpStr;
  626. end;
  627. function rpos(const needle: char; const haystack: shortstring): longint;
  628. begin
  629. result:=length(haystack);
  630. while (result>0) do
  631. begin
  632. if haystack[result]=needle then
  633. exit;
  634. dec(result);
  635. end;
  636. end;
  637. function rpos(const needle: shortstring; const haystack: shortstring): longint;
  638. begin
  639. result:=0;
  640. if (length(needle)=0) or
  641. (length(needle)>length(haystack)) then
  642. exit;
  643. result:=length(haystack)-length(needle);
  644. repeat
  645. if (haystack[result]=needle[1]) and
  646. (copy(haystack,result,length(needle))=needle) then
  647. exit;
  648. dec(result);
  649. until result=0;
  650. end;
  651. function trimbspace(const s:string):string;
  652. {
  653. return s with all leading spaces and tabs removed
  654. }
  655. var
  656. i,j : longint;
  657. begin
  658. j:=1;
  659. i:=length(s);
  660. while (j<i) and (s[j] in [#9,' ']) do
  661. inc(j);
  662. trimbspace:=Copy(s,j,i-j+1);
  663. end;
  664. function trimspace(const s:string):string;
  665. {
  666. return s with all leading and ending spaces and tabs removed
  667. }
  668. var
  669. i,j : longint;
  670. begin
  671. i:=length(s);
  672. while (i>0) and (s[i] in [#9,' ']) do
  673. dec(i);
  674. j:=1;
  675. while (j<i) and (s[j] in [#9,' ']) do
  676. inc(j);
  677. trimspace:=Copy(s,j,i-j+1);
  678. end;
  679. function space (b : longint): string;
  680. var
  681. s: string;
  682. begin
  683. space[0] := chr(b);
  684. s[0] := chr(b);
  685. FillChar (S[1],b,' ');
  686. space:=s;
  687. end;
  688. function PadSpace(const s:string;len:longint):string;
  689. {
  690. return s with spaces add to the end
  691. }
  692. begin
  693. if length(s)<len then
  694. PadSpace:=s+Space(len-length(s))
  695. else
  696. PadSpace:=s;
  697. end;
  698. function GetToken(var s:string;endchar:char):string;
  699. var
  700. i : longint;
  701. quote : char;
  702. begin
  703. GetToken:='';
  704. s:=TrimSpace(s);
  705. if (length(s)>0) and
  706. (s[1] in ['''','"']) then
  707. begin
  708. quote:=s[1];
  709. i:=1;
  710. while (i<length(s)) do
  711. begin
  712. inc(i);
  713. if s[i]=quote then
  714. begin
  715. { Remove double quote }
  716. if (i<length(s)) and
  717. (s[i+1]=quote) then
  718. begin
  719. Delete(s,i,1);
  720. inc(i);
  721. end
  722. else
  723. begin
  724. GetToken:=Copy(s,2,i-2);
  725. Delete(s,1,i);
  726. exit;
  727. end;
  728. end;
  729. end;
  730. GetToken:=s;
  731. s:='';
  732. end
  733. else
  734. begin
  735. i:=pos(EndChar,s);
  736. if i=0 then
  737. begin
  738. GetToken:=s;
  739. s:='';
  740. exit;
  741. end
  742. else
  743. begin
  744. GetToken:=Copy(s,1,i-1);
  745. Delete(s,1,i);
  746. exit;
  747. end;
  748. end;
  749. end;
  750. function realtostr(e:extended):string;{$ifdef USEINLINE}inline;{$endif}
  751. begin
  752. str(e,result);
  753. end;
  754. function tostr(i : qword) : string;{$ifdef USEINLINE}inline;{$endif}overload;
  755. {
  756. return string of value i
  757. }
  758. begin
  759. str(i,result);
  760. end;
  761. function tostr(i : int64) : string;{$ifdef USEINLINE}inline;{$endif}overload;
  762. {
  763. return string of value i
  764. }
  765. begin
  766. str(i,result);
  767. end;
  768. function tostr(i : longint) : string;{$ifdef USEINLINE}inline;{$endif}overload;
  769. {
  770. return string of value i
  771. }
  772. begin
  773. str(i,result);
  774. end;
  775. function tostr_with_plus(i : int64) : string;{$ifdef USEINLINE}inline;{$endif}
  776. {
  777. return string of value i, but always include a + when i>=0
  778. }
  779. begin
  780. str(i,result);
  781. if i>=0 then
  782. result:='+'+result;
  783. end;
  784. function is_number(const s : string) : boolean;{$ifdef USEINLINE}inline;{$endif}
  785. {
  786. is string a correct number ?
  787. }
  788. var
  789. w : integer;
  790. l : longint;
  791. begin
  792. val(s,l,w);
  793. // remove warning
  794. l:=l;
  795. is_number:=(w=0);
  796. end;
  797. function ispowerof2(value : int64;out power : longint) : boolean;
  798. {
  799. return if value is a power of 2. And if correct return the power
  800. }
  801. begin
  802. if (value <= 0) or (value and (value - 1) <> 0) then
  803. exit(false);
  804. power:=BsfQWord(value);
  805. result:=true;
  806. end;
  807. function ispowerof2(const value: Tconstexprint; out power: longint): boolean;
  808. begin
  809. if value.signed or
  810. (value.uvalue<=high(int64)) then
  811. result:=ispowerof2(value.svalue,power)
  812. else if not value.signed and
  813. (value.svalue=low(int64)) then
  814. begin
  815. result:=true;
  816. power:=63;
  817. end
  818. else
  819. result:=false;
  820. end;
  821. function isabspowerof2(const value : Tconstexprint;out power : longint) : boolean;
  822. begin
  823. if ispowerof2(value,power) then
  824. result:=true
  825. else if value.signed and (value.svalue<0) and (value.svalue<>low(int64)) and ispowerof2(-value.svalue,power) then
  826. result:=true
  827. else
  828. result:=false;
  829. end;
  830. function nextpowerof2(value : int64; out power: longint) : int64;
  831. {
  832. returns the power of 2 >= value
  833. }
  834. var
  835. i : longint;
  836. begin
  837. result := 0;
  838. power := -1;
  839. if ((value <= 0) or
  840. (value >= $4000000000000000)) then
  841. exit;
  842. result := 1;
  843. for i:=0 to 63 do
  844. begin
  845. if result>=value then
  846. begin
  847. power := i;
  848. exit;
  849. end;
  850. result:=result shl 1;
  851. end;
  852. end;
  853. {$ifdef VER2_6}
  854. const
  855. PopCntData : array[0..15] of byte = (0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4);
  856. function PopCnt(AValue : Byte): Byte;
  857. begin
  858. Result:=PopCntData[AValue and $f]+PopCntData[(AValue shr 4) and $f];
  859. end;
  860. function PopCnt(AValue : Word): Word;
  861. var
  862. i : SizeInt;
  863. begin
  864. Result:=0;
  865. for i:=0 to 3 do
  866. begin
  867. inc(Result,PopCntData[AValue and $f]);
  868. AValue:=AValue shr 4;
  869. end;
  870. end;
  871. function PopCnt(AValue : DWord): DWord;
  872. var
  873. i : SizeInt;
  874. begin
  875. Result:=0;
  876. for i:=0 to 7 do
  877. begin
  878. inc(Result,PopCntData[AValue and $f]);
  879. AValue:=AValue shr 4;
  880. end;
  881. end;
  882. function PopCnt(Const AValue : QWord): QWord;
  883. begin
  884. Result:=PopCnt(lo(AValue))+PopCnt(hi(AValue))
  885. end;
  886. {$endif VER2_6}
  887. function backspace_quote(const s:string;const qchars:Tcharset):string;
  888. var i:byte;
  889. begin
  890. backspace_quote:='';
  891. for i:=1 to length(s) do
  892. begin
  893. if (s[i]=#10) and (#10 in qchars) then
  894. backspace_quote:=backspace_quote+'\n'
  895. else if (s[i]=#13) and (#13 in qchars) then
  896. backspace_quote:=backspace_quote+'\r'
  897. else
  898. begin
  899. if s[i] in qchars then
  900. backspace_quote:=backspace_quote+'\';
  901. backspace_quote:=backspace_quote+s[i];
  902. end;
  903. end;
  904. end;
  905. function octal_quote(const s:string;const qchars:Tcharset):string;
  906. var i:byte;
  907. begin
  908. octal_quote:='';
  909. for i:=1 to length(s) do
  910. begin
  911. if s[i] in qchars then
  912. begin
  913. if ord(s[i])<64 then
  914. octal_quote:=octal_quote+'\'+octstr(ord(s[i]),3)
  915. else
  916. octal_quote:=octal_quote+'\'+octstr(ord(s[i]),4);
  917. end
  918. else
  919. octal_quote:=octal_quote+s[i];
  920. end;
  921. end;
  922. function DePascalQuote(var s: ansistring): Boolean;
  923. var
  924. destPos, sourcePos, len: Integer;
  925. t: string;
  926. ch: Char;
  927. begin
  928. DePascalQuote:= false;
  929. len:= length(s);
  930. if (len >= 1) and (s[1] = '''') then
  931. begin
  932. {Remove quotes, exchange '' against ' }
  933. destPos := 0;
  934. sourcepos:=1;
  935. while (sourcepos<len) do
  936. begin
  937. inc(sourcePos);
  938. ch := s[sourcePos];
  939. if ch = '''' then
  940. begin
  941. inc(sourcePos);
  942. if (sourcePos <= len) and (s[sourcePos] = '''') then
  943. {Add the quote as part of string}
  944. else
  945. begin
  946. SetLength(t, destPos);
  947. s:= t;
  948. Exit(true);
  949. end;
  950. end;
  951. inc(destPos);
  952. t[destPos] := ch;
  953. end;
  954. end;
  955. end;
  956. function pchar2pshortstring(p : pchar) : pshortstring;
  957. var
  958. w,i : longint;
  959. begin
  960. w:=strlen(p);
  961. for i:=w-1 downto 0 do
  962. p[i+1]:=p[i];
  963. p[0]:=chr(w);
  964. pchar2pshortstring:=pshortstring(p);
  965. end;
  966. function pshortstring2pchar(p : pshortstring) : pchar;
  967. var
  968. w,i : longint;
  969. begin
  970. w:=length(p^);
  971. for i:=1 to w do
  972. p^[i-1]:=p^[i];
  973. p^[w]:=#0;
  974. pshortstring2pchar:=pchar(p);
  975. end;
  976. function ansistring2pchar(const a: ansistring) : pchar;
  977. var
  978. len: ptrint;
  979. begin
  980. len:=length(a);
  981. getmem(result,len+1);
  982. if (len<>0) then
  983. move(a[1],result[0],len);
  984. result[len]:=#0;
  985. end;
  986. function lowercase(c : char) : char;
  987. begin
  988. case c of
  989. #65..#90 : c := chr(ord (c) + 32);
  990. #154 : c:=#129; { german }
  991. #142 : c:=#132; { german }
  992. #153 : c:=#148; { german }
  993. #144 : c:=#130; { french }
  994. #128 : c:=#135; { french }
  995. #143 : c:=#134; { swedish/norge (?) }
  996. #165 : c:=#164; { spanish }
  997. #228 : c:=#229; { greek }
  998. #226 : c:=#231; { greek }
  999. #232 : c:=#227; { greek }
  1000. end;
  1001. lowercase := c;
  1002. end;
  1003. function strpnew(const s : string) : pchar;
  1004. var
  1005. p : pchar;
  1006. begin
  1007. getmem(p,length(s)+1);
  1008. move(s[1],p^,length(s));
  1009. p[length(s)]:=#0;
  1010. result:=p;
  1011. end;
  1012. function strpnew(const s: ansistring): pchar;
  1013. var
  1014. p : pchar;
  1015. begin
  1016. getmem(p,length(s)+1);
  1017. move(s[1],p^,length(s)+1);
  1018. result:=p;
  1019. end;
  1020. procedure stringdispose(var p : pshortstring);{$ifdef USEINLINE}inline;{$endif}
  1021. begin
  1022. if assigned(p) then
  1023. begin
  1024. freemem(p);
  1025. p:=nil;
  1026. end;
  1027. end;
  1028. function stringdup(const s : string) : pshortstring;{$ifdef USEINLINE}inline;{$endif}
  1029. begin
  1030. getmem(result,length(s)+1);
  1031. result^:=s;
  1032. end;
  1033. function CompareStr(const S1, S2: string): Integer;
  1034. var
  1035. count, count1, count2: integer;
  1036. begin
  1037. result := 0;
  1038. Count1 := Length(S1);
  1039. Count2 := Length(S2);
  1040. if Count1>Count2 then
  1041. Count:=Count2
  1042. else
  1043. Count:=Count1;
  1044. result := CompareChar(S1[1],S2[1], Count);
  1045. if result=0 then
  1046. result:=Count1-Count2;
  1047. end;
  1048. function CompareText(S1, S2: string): integer;
  1049. begin
  1050. UpperVar(S1);
  1051. UpperVar(S2);
  1052. Result:=CompareStr(S1,S2);
  1053. end;
  1054. function CompareVersionStrings(s1,s2: string): longint;
  1055. var
  1056. start1, start2,
  1057. i1, i2,
  1058. num1,num2,
  1059. res,
  1060. err : longint;
  1061. begin
  1062. i1:=1;
  1063. i2:=1;
  1064. repeat
  1065. start1:=i1;
  1066. start2:=i2;
  1067. while (i1<=length(s1)) and
  1068. (s1[i1] in ['0'..'9']) do
  1069. inc(i1);
  1070. while (i2<=length(s2)) and
  1071. (s2[i2] in ['0'..'9']) do
  1072. inc(i2);
  1073. { one of the strings misses digits -> other is the largest version }
  1074. if i1=start1 then
  1075. if i2=start2 then
  1076. exit(0)
  1077. else
  1078. exit(-1)
  1079. else if i2=start2 then
  1080. exit(1);
  1081. { get version number part }
  1082. val(copy(s1,start1,i1-start1),num1,err);
  1083. val(copy(s2,start2,i2-start2),num2,err);
  1084. { different -> done }
  1085. res:=num1-num2;
  1086. if res<>0 then
  1087. exit(res);
  1088. { if one of the two is at the end while the other isn't, add a '.0' }
  1089. if (i1>length(s1)) and
  1090. (i2<=length(s2)) then
  1091. s1:=s1+'.0'
  1092. else if i2>length(s2) then
  1093. s2:=s2+'.0';
  1094. { compare non-numerical characters normally }
  1095. while (i1<=length(s1)) and
  1096. not(s1[i1] in ['0'..'9']) and
  1097. (i2<=length(s2)) and
  1098. not(s2[i2] in ['0'..'9']) do
  1099. begin
  1100. res:=ord(s1[i1])-ord(s2[i2]);
  1101. if res<>0 then
  1102. exit(res);
  1103. inc(i1);
  1104. inc(i2);
  1105. end;
  1106. { both should be digits again now, otherwise pick the one with the
  1107. digits as the largest (it more likely means that the input was
  1108. ill-formatted though) }
  1109. if (i1<=length(s1)) and
  1110. not(s1[i1] in ['0'..'9']) then
  1111. exit(-1);
  1112. if (i2<=length(s2)) and
  1113. not(s2[i2] in ['0'..'9']) then
  1114. exit(1);
  1115. until false;
  1116. end;
  1117. {*****************************************************************************
  1118. Ansistring (PChar+Length)
  1119. *****************************************************************************}
  1120. procedure ansistringdispose(var p : pchar;length : longint);
  1121. begin
  1122. if assigned(p) then
  1123. begin
  1124. freemem(p);
  1125. p:=nil;
  1126. end;
  1127. end;
  1128. { enable ansistring comparison }
  1129. { 0 means equal }
  1130. { 1 means p1 > p2 }
  1131. { -1 means p1 < p2 }
  1132. function compareansistrings(p1,p2 : pchar;length1,length2 : longint) : longint;
  1133. var
  1134. i,j : longint;
  1135. begin
  1136. compareansistrings:=0;
  1137. j:=min(length1,length2);
  1138. i:=0;
  1139. while (i<j) do
  1140. begin
  1141. if p1[i]>p2[i] then
  1142. begin
  1143. compareansistrings:=1;
  1144. exit;
  1145. end
  1146. else
  1147. if p1[i]<p2[i] then
  1148. begin
  1149. compareansistrings:=-1;
  1150. exit;
  1151. end;
  1152. inc(i);
  1153. end;
  1154. if length1>length2 then
  1155. compareansistrings:=1
  1156. else
  1157. if length1<length2 then
  1158. compareansistrings:=-1;
  1159. end;
  1160. function concatansistrings(p1,p2 : pchar;length1,length2 : longint) : pchar;
  1161. var
  1162. p : pchar;
  1163. begin
  1164. getmem(p,length1+length2+1);
  1165. move(p1[0],p[0],length1);
  1166. move(p2[0],p[length1],length2+1);
  1167. concatansistrings:=p;
  1168. end;
  1169. {*****************************************************************************
  1170. Ultra basic KISS Lzw (de)compressor
  1171. *****************************************************************************}
  1172. {This is an extremely basic implementation of the Lzw algorithm. It
  1173. compresses 7-bit ASCII strings into 8-bit compressed strings.
  1174. The Lzw dictionary is preinitialized with 0..127, therefore this
  1175. part of the dictionary does not need to be stored in the arrays.
  1176. The Lzw code size is allways 8 bit, so we do not need complex code
  1177. that can write partial bytes.}
  1178. function minilzw_encode(const s:string):string;
  1179. var t,u,i:byte;
  1180. c:char;
  1181. data:array[128..255] of char;
  1182. previous:array[128..255] of byte;
  1183. lzwptr:byte;
  1184. next_avail:set of 0..255;
  1185. label l1;
  1186. begin
  1187. minilzw_encode:='';
  1188. fillchar(data,sizeof(data),#0);
  1189. fillchar(previous,sizeof(previous),#0);
  1190. if s<>'' then
  1191. begin
  1192. lzwptr:=127;
  1193. t:=byte(s[1]);
  1194. i:=2;
  1195. u:=128;
  1196. next_avail:=[];
  1197. while i<=length(s) do
  1198. begin
  1199. c:=s[i];
  1200. if not(t in next_avail) or (u>lzwptr) then goto l1;
  1201. while (previous[u]<>t) or (data[u]<>c) do
  1202. begin
  1203. inc(u);
  1204. if u>lzwptr then goto l1;
  1205. end;
  1206. t:=u;
  1207. inc(i);
  1208. continue;
  1209. l1:
  1210. {It's a pity that we still need those awfull tricks
  1211. with this modern compiler. Without this performance
  1212. of the entire procedure drops about 3 times.}
  1213. inc(minilzw_encode[0]);
  1214. minilzw_encode[length(minilzw_encode)]:=char(t);
  1215. if lzwptr=255 then
  1216. begin
  1217. lzwptr:=127;
  1218. next_avail:=[];
  1219. end
  1220. else
  1221. begin
  1222. inc(lzwptr);
  1223. data[lzwptr]:=c;
  1224. previous[lzwptr]:=t;
  1225. include(next_avail,t);
  1226. end;
  1227. t:=byte(c);
  1228. u:=128;
  1229. inc(i);
  1230. end;
  1231. inc(minilzw_encode[0]);
  1232. minilzw_encode[length(minilzw_encode)]:=char(t);
  1233. end;
  1234. end;
  1235. function minilzw_decode(const s:string):string;
  1236. var oldc,newc,c:char;
  1237. i,j:byte;
  1238. data:array[128..255] of char;
  1239. previous:array[128..255] of byte;
  1240. lzwptr:byte;
  1241. t:string;
  1242. begin
  1243. minilzw_decode:='';
  1244. fillchar(data,sizeof(data),#0);
  1245. fillchar(previous,sizeof(previous),#0);
  1246. if s<>'' then
  1247. begin
  1248. lzwptr:=127;
  1249. oldc:=s[1];
  1250. c:=oldc;
  1251. i:=2;
  1252. minilzw_decode:=oldc;
  1253. while i<=length(s) do
  1254. begin
  1255. newc:=s[i];
  1256. if byte(newc)>lzwptr then
  1257. begin
  1258. t:=c;
  1259. c:=oldc;
  1260. end
  1261. else
  1262. begin
  1263. c:=newc;
  1264. t:='';
  1265. end;
  1266. while c>=#128 do
  1267. begin
  1268. inc(t[0]);
  1269. t[length(t)]:=data[byte(c)];
  1270. byte(c):=previous[byte(c)];
  1271. end;
  1272. inc(minilzw_decode[0]);
  1273. minilzw_decode[length(minilzw_decode)]:=c;
  1274. for j:=length(t) downto 1 do
  1275. begin
  1276. inc(minilzw_decode[0]);
  1277. minilzw_decode[length(minilzw_decode)]:=t[j];
  1278. end;
  1279. if lzwptr=255 then
  1280. lzwptr:=127
  1281. else
  1282. begin
  1283. inc(lzwptr);
  1284. previous[lzwptr]:=byte(oldc);
  1285. data[lzwptr]:=c;
  1286. end;
  1287. oldc:=newc;
  1288. inc(i);
  1289. end;
  1290. end;
  1291. end;
  1292. procedure defaulterror(i:longint);
  1293. begin
  1294. writeln('Internal error ',i);
  1295. runerror(255);
  1296. end;
  1297. Function Nextafter(x,y:double):double;
  1298. // Returns the double precision number closest to x in
  1299. // the direction toward y.
  1300. // Initial direct translation by Soeren Haastrup from
  1301. // www.netlib.org/fdlibm/s_nextafter.c according to
  1302. // ====================================================
  1303. // Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
  1304. // Developed at SunSoft, a Sun Microsystems, Inc. business.
  1305. // Permission to use, copy, modify, and distribute this
  1306. // software is freely granted, provided that this notice
  1307. // is preserved.
  1308. // ====================================================
  1309. // and with all signaling policies preserved as is.
  1310. type
  1311. {$if defined(ENDIAN_LITTLE) and not defined(FPC_DOUBLE_HILO_SWAPPED)}
  1312. twoword=record
  1313. lo,hi:longword; // Little Endian split of a double.
  1314. end;
  1315. {$else}
  1316. twoword=record
  1317. hi,lo:longword; // Big Endian split of a double.
  1318. end;
  1319. {$endif}
  1320. var
  1321. hx,hy,ix,iy:longint;
  1322. lx,ly:longword;
  1323. Begin
  1324. hx:=twoword(x).hi; // high and low words of x and y
  1325. lx:=twoword(x).lo;
  1326. hy:=twoword(y).hi;
  1327. ly:=twoword(y).lo;
  1328. ix:=hx and $7fffffff; // absolute values
  1329. iy:=hy and $7fffffff;
  1330. // Case x=NAN or y=NAN
  1331. if ( (ix>=$7ff00000) and ((longword(ix-$7ff00000) or lx) <> 0) )
  1332. or ( (iy>=$7ff00000) and ((longword(iy-$7ff00000) OR ly) <> 0) )
  1333. then exit(x+y);
  1334. // Case x=y
  1335. if x=y then exit(x); // (implies Nextafter(0,-0) is 0 and not -0...)
  1336. // Case x=0
  1337. if (longword(ix) or lx)=0
  1338. then begin
  1339. twoword(x).hi:=hy and $80000000; // return +-minimalSubnormal
  1340. twoword(x).lo:=1;
  1341. y:=x*x; // set underflow flag (ignored in FPC as default)
  1342. if y=x
  1343. then exit(y)
  1344. else exit(x);
  1345. end;
  1346. // all other cases
  1347. if hx>=0 // x>0
  1348. then begin
  1349. if (hx>hy) or ( (hx=hy) and (lx>ly) ) // x>y , return x-ulp
  1350. then begin
  1351. if (lx=0) then hx:=hx-1;
  1352. lx:=lx-1;
  1353. end
  1354. else begin // x<y, return x+ulp
  1355. lx:=lx+1;
  1356. if lx=0 then hx:=hx+1;
  1357. end
  1358. end
  1359. else begin // x<0
  1360. if (hy>=0) or (hx>=hy) or ( (hx=hy) and (lx>ly)) // x<y, return x-ulp
  1361. then begin
  1362. if (lx=0) then hx:=hx-1;
  1363. lx:=lx-1;
  1364. end
  1365. else begin // x>y , return x+ulp
  1366. lx:=lx+1;
  1367. if lx=0 then hx:=hx+1;
  1368. end
  1369. end;
  1370. // finally check if overflow or underflow just happend
  1371. hy:=hx and $7ff00000;
  1372. if (hy>= $7ff00000) then exit(x+x); // overflow and signal
  1373. if (hy<$0010000) // underflow
  1374. then begin
  1375. y:=x*x; // raise underflow flag
  1376. if y<>x
  1377. then begin
  1378. twoword(y).hi:=hx;
  1379. twoword(y).lo:=lx;
  1380. exit(y);
  1381. end
  1382. end;
  1383. twoword(x).hi:=hx;
  1384. twoword(x).lo:=lx;
  1385. nextafter:=x;
  1386. end;
  1387. initialization
  1388. internalerrorproc:=@defaulterror;
  1389. initupperlower;
  1390. end.