cutils.pas 43 KB

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