cutils.pas 45 KB

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