cutils.pas 44 KB

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