cutils.pas 44 KB

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