cutils.pas 41 KB

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