cutils.pas 40 KB

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