cutils.pas 45 KB

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