2
0

cutils.pas 44 KB

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