cutils.pas 42 KB

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