2
0

cutils.pas 44 KB

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