2
0

cutils.pas 40 KB

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