cutils.pas 34 KB

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