wutils.pas 31 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283
  1. {
  2. This file is part of the Free Pascal Integrated Development Environment
  3. Copyright (c) 1998 by Berczi Gabor
  4. See the file COPYING.FPC, included in this distribution,
  5. for details about the copyright.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  9. **********************************************************************}
  10. unit WUtils;
  11. interface
  12. uses
  13. {$ifdef Windows}
  14. windows,
  15. {$endif Windows}
  16. {$ifdef netwlibc}
  17. libc,
  18. {$else}
  19. {$ifdef netware}
  20. nwserv,
  21. {$endif}
  22. {$endif}
  23. {$ifdef Unix}
  24. baseunix,
  25. unix,
  26. {$endif Unix}
  27. Dos,Objects;
  28. const
  29. kbCtrlGrayPlus = $9000;
  30. kbCtrlGrayMinus = $8e00;
  31. kbCtrlGrayMul = $9600;
  32. TempFirstChar = {$ifndef Unix}'~'{$else}'_'{$endif};
  33. TempExt = '.tmp';
  34. TempNameLen = 8;
  35. EOL : String[2] = {$ifdef Unix}#10;{$else}#13#10;{$endif}
  36. type
  37. PByteArray = ^TByteArray;
  38. TByteArray = array[0..MaxBytes] of byte;
  39. PNoDisposeCollection = ^TNoDisposeCollection;
  40. TNoDisposeCollection = object(TCollection)
  41. procedure FreeItem(Item: Pointer); virtual;
  42. end;
  43. PUnsortedStringCollection = ^TUnsortedStringCollection;
  44. TUnsortedStringCollection = object(TCollection)
  45. constructor CreateFrom(ALines: PUnsortedStringCollection);
  46. procedure Assign(ALines: PUnsortedStringCollection);
  47. function At(Index: Sw_Integer): PString;
  48. procedure FreeItem(Item: Pointer); virtual;
  49. function GetItem(var S: TStream): Pointer; virtual;
  50. procedure PutItem(var S: TStream; Item: Pointer); virtual;
  51. procedure InsertStr(const S: string);
  52. end;
  53. PNulStream = ^TNulStream;
  54. TNulStream = object(TStream)
  55. constructor Init;
  56. function GetPos: Longint; virtual;
  57. function GetSize: Longint; virtual;
  58. procedure Read(var Buf; Count: longint); virtual;
  59. procedure Seek(Pos: Longint); virtual;
  60. procedure Write(var Buf; Count: longint); virtual;
  61. end;
  62. PSubStream = ^TSubStream;
  63. TSubStream = object(TStream)
  64. constructor Init(AStream: PStream; AStartPos, ASize: longint);
  65. function GetPos: Longint; virtual;
  66. function GetSize: Longint; virtual;
  67. procedure Read(var Buf; Count: longint); virtual;
  68. procedure Seek(Pos: Longint); virtual;
  69. procedure Write(var Buf; Count: longint); virtual;
  70. private
  71. StartPos: longint;
  72. S : PStream;
  73. end;
  74. PFastBufStream = ^TFastBufStream;
  75. TFastBufStream = object(TBufStream)
  76. constructor Init (FileName: FNameStr; Mode, Size: Word);
  77. procedure Seek(Pos: Longint); virtual;
  78. procedure Readline(var s:string;var linecomplete,hasCR : boolean);
  79. private
  80. BasePos: longint;
  81. end;
  82. PTextCollection = ^TTextCollection;
  83. TTextCollection = object(TStringCollection)
  84. function LookUp(const S: string; var Idx: sw_integer): string;
  85. function Compare(Key1, Key2: Pointer): sw_Integer; virtual;
  86. end;
  87. PIntCollection = ^TIntCollection;
  88. TIntCollection = object(TSortedCollection)
  89. function Compare(Key1, Key2: Pointer): sw_Integer; virtual;
  90. procedure FreeItem(Item: Pointer); virtual;
  91. procedure Add(Item: ptrint);
  92. function Contains(Item: ptrint): boolean;
  93. function AtInt(Index: sw_integer): ptrint;
  94. end;
  95. procedure ReadlnFromStream(Stream: PStream; var s:string;var linecomplete,hasCR : boolean);
  96. function eofstream(s: pstream): boolean;
  97. procedure ReadlnFromFile(var f : file; var S:string;
  98. var linecomplete,hasCR : boolean;
  99. BreakOnSpacesOnly : boolean);
  100. function Min(A,B: longint): longint;
  101. function Max(A,B: longint): longint;
  102. function CharStr(C: char; Count: integer): string;
  103. function UpcaseStr(const S: string): string;
  104. function LowCase(C: char): char;
  105. function LowcaseStr(S: string): string;
  106. function RExpand(const S: string; MinLen: byte): string;
  107. function LExpand(const S: string; MinLen: byte): string;
  108. function LTrim(const S: string): string;
  109. function RTrim(const S: string): string;
  110. function Trim(const S: string): string;
  111. function IntToStr(L: longint): string;
  112. function IntToStrL(L: longint; MinLen: sw_integer): string;
  113. function IntToStrZ(L: longint; MinLen: sw_integer): string;
  114. function StrToInt(const S: string): longint;
  115. function StrToCard(const S: string): cardinal;
  116. function FloatToStr(D: Double; Decimals: byte): string;
  117. function FloatToStrL(D: Double; Decimals: byte; MinLen: byte): string;
  118. function GetStr(P: PString): string;
  119. function GetPChar(P: PChar): string;
  120. function BoolToStr(B: boolean; const TrueS, FalseS: string): string;
  121. function LExtendString(S: string; MinLen: byte): string;
  122. function DirOf(const S: string): string;
  123. function ExtOf(const S: string): string;
  124. function NameOf(const S: string): string;
  125. function NameAndExtOf(const S: string): string;
  126. function DirAndNameOf(const S: string): string;
  127. { return Dos GetFTime value or -1 if the file does not exist }
  128. function GetFileTime(const FileName: string): longint;
  129. { copied from compiler global unit }
  130. function GetShortName(const n:string):string;
  131. function GetLongName(const n:string):string;
  132. function TrimEndSlash(const Path: string): string;
  133. function CompleteDir(const Path: string): string;
  134. function GetCurDir: string;
  135. function OptimizePath(Path: string; MaxLen: integer): string;
  136. function CompareText(S1, S2: string): integer;
  137. function ExistsDir(const DirName: string): boolean;
  138. function ExistsFile(const FileName: string): boolean;
  139. function SizeOfFile(const FileName: string): longint;
  140. function DeleteFile(const FileName: string): integer;
  141. function CopyFile(const SrcFileName, DestFileName: string): boolean;
  142. function GenTempFileName: string;
  143. function FormatPath(Path: string): string;
  144. function CompletePath(const Base, InComplete: string): string;
  145. function CompleteURL(const Base, URLRef: string): string;
  146. function EatIO: integer;
  147. function Now: longint;
  148. function FormatDateTimeL(L: longint; const Format: string): string;
  149. function FormatDateTime(const D: DateTime; const Format: string): string;
  150. function MemToStr(var B; Count: byte): string;
  151. procedure StrToMem(S: string; var B);
  152. const LastStrToIntResult : integer = 0;
  153. LastHexToIntResult : integer = 0;
  154. LastStrToCardResult : integer = 0;
  155. LastHexToCardResult : integer = 0;
  156. DirSep : char = {$ifdef Unix}'/'{$else}'\'{$endif};
  157. UseOldBufStreamMethod : boolean = false;
  158. procedure RegisterWUtils;
  159. Procedure DebugMessage(AFileName, AText : string; ALine, APos : sw_word); // calls DebugMessage
  160. Procedure WUtilsDebugMessage(AFileName, AText : string; ALine, APos : string; nrLine, nrPos : sw_word);
  161. type
  162. TDebugMessage = procedure(AFileName, AText : string; ALine, APos : String; nrLine, nrPos : sw_word);
  163. Const
  164. DebugMessageS : TDebugMessage = @WUtilsDebugMessage;
  165. implementation
  166. uses
  167. {$IFDEF OS2}
  168. DosCalls,
  169. {$ENDIF OS2}
  170. Strings;
  171. {$ifndef NOOBJREG}
  172. const
  173. SpaceStr = ' '+
  174. ' '+
  175. ' '+
  176. ' ' ;
  177. RUnsortedStringCollection: TStreamRec = (
  178. ObjType: 22500;
  179. VmtLink: Ofs(TypeOf(TUnsortedStringCollection)^);
  180. Load: @TUnsortedStringCollection.Load;
  181. Store: @TUnsortedStringCollection.Store
  182. );
  183. {$endif}
  184. function eofstream(s: pstream): boolean;
  185. begin
  186. eofstream:=(s^.getpos>=s^.getsize);
  187. end;
  188. procedure ReadlnFromStream(Stream: PStream; var S:string;var linecomplete,hasCR : boolean);
  189. var
  190. c : char;
  191. i,pos : longint;
  192. begin
  193. linecomplete:=false;
  194. c:=#0;
  195. i:=0;
  196. { this created problems for lines longer than 255 characters
  197. now those lines are cutted into pieces without warning PM }
  198. { changed implicit 255 to High(S), so it will be automatically extended
  199. when longstrings eventually become default - Gabor }
  200. while (not eofstream(stream)) and (c<>#10) and (i<High(S)) do
  201. begin
  202. stream^.read(c,sizeof(c));
  203. if c<>#10 then
  204. begin
  205. inc(i);
  206. s[i]:=c;
  207. end;
  208. end;
  209. { if there was a CR LF then remove the CR Dos newline style }
  210. if (i>0) and (s[i]=#13) then
  211. begin
  212. dec(i);
  213. end;
  214. if (c=#13) and (not eofstream(stream)) then
  215. stream^.read(c,sizeof(c));
  216. if (i=High(S)) and not eofstream(stream) then
  217. begin
  218. pos:=stream^.getpos;
  219. stream^.read(c,sizeof(c));
  220. if (c=#13) and not eofstream(stream) then
  221. stream^.read(c,sizeof(c));
  222. if c<>#10 then
  223. stream^.seek(pos);
  224. end;
  225. if (c=#10) or eofstream(stream) then
  226. linecomplete:=true;
  227. if (c=#10) then
  228. hasCR:=true;
  229. s[0]:=chr(i);
  230. end;
  231. procedure ReadlnFromFile(var f : file; var S:string;
  232. var linecomplete,hasCR : boolean;
  233. BreakOnSpacesOnly : boolean);
  234. var
  235. c : char;
  236. i,pos,
  237. lastspacepos,LastSpaceFilePos : longint;
  238. {$ifdef DEBUG}
  239. filename: string;
  240. {$endif DEBUG}
  241. begin
  242. LastSpacePos:=0;
  243. linecomplete:=false;
  244. c:=#0;
  245. i:=0;
  246. { this created problems for lines longer than 255 characters
  247. now those lines are cutted into pieces without warning PM }
  248. { changed implicit 255 to High(S), so it will be automatically extended
  249. when longstrings eventually become default - Gabor }
  250. while (not eof(f)) and (c<>#10) and (i<High(S)) do
  251. begin
  252. system.blockread(f,c,sizeof(c));
  253. if c<>#10 then
  254. begin
  255. inc(i);
  256. s[i]:=c;
  257. end;
  258. if BreakOnSpacesOnly and (c=' ') then
  259. begin
  260. LastSpacePos:=i;
  261. LastSpaceFilePos:=system.filepos(f);
  262. end;
  263. end;
  264. { if there was a CR LF then remove the CR Dos newline style }
  265. if (i>0) and (s[i]=#13) then
  266. begin
  267. dec(i);
  268. end;
  269. if (c=#13) and (not eof(f)) then
  270. system.blockread(f,c,sizeof(c));
  271. if (i=High(S)) and not eof(f) then
  272. begin
  273. pos:=system.filepos(f);
  274. system.blockread(f,c,sizeof(c));
  275. if (c=#13) and not eof(f) then
  276. system.blockread(f,c,sizeof(c));
  277. if c<>#10 then
  278. system.seek(f,pos);
  279. if (c<>' ') and (c<>#10) and BreakOnSpacesOnly and
  280. (LastSpacePos>1) then
  281. begin
  282. {$ifdef DEBUG}
  283. s[0]:=chr(i);
  284. filename:=strpas(@(filerec(f).Name));
  285. DebugMessage(filename,'s='+s,1,1);
  286. {$endif DEBUG}
  287. i:=LastSpacePos;
  288. {$ifdef DEBUG}
  289. s[0]:=chr(i);
  290. DebugMessage(filename,'reduced to '+s,1,1);
  291. {$endif DEBUG}
  292. system.seek(f,LastSpaceFilePos);
  293. end;
  294. end;
  295. if (c=#10) or eof(f) then
  296. linecomplete:=true;
  297. if (c=#10) then
  298. hasCR:=true;
  299. s[0]:=chr(i);
  300. end;
  301. function MemToStr(var B; Count: byte): string;
  302. var S: string;
  303. begin
  304. S[0]:=chr(Count);
  305. if Count>0 then Move(B,S[1],Count);
  306. MemToStr:=S;
  307. end;
  308. procedure StrToMem(S: string; var B);
  309. begin
  310. if length(S)>0 then Move(S[1],B,length(S));
  311. end;
  312. function Max(A,B: longint): longint;
  313. begin
  314. if A>B then Max:=A else Max:=B;
  315. end;
  316. function Min(A,B: longint): longint;
  317. begin
  318. if A<B then Min:=A else Min:=B;
  319. end;
  320. function CharStr(C: char; Count: integer): string;
  321. begin
  322. if Count<=0 then
  323. begin
  324. CharStr:='';
  325. exit;
  326. end
  327. else if Count>255 then
  328. Count:=255;
  329. CharStr[0]:=chr(Count);
  330. FillChar(CharStr[1],Count,C);
  331. end;
  332. function UpcaseStr(const S: string): string;
  333. var
  334. I: Longint;
  335. begin
  336. for I:=1 to length(S) do
  337. if S[I] in ['a'..'z'] then
  338. UpCaseStr[I]:=chr(ord(S[I])-32)
  339. else
  340. UpCaseStr[I]:=S[I];
  341. UpcaseStr[0]:=S[0];
  342. end;
  343. function RExpand(const S: string; MinLen: byte): string;
  344. begin
  345. if length(S)<MinLen then
  346. RExpand:=S+CharStr(' ',MinLen-length(S))
  347. else
  348. RExpand:=S;
  349. end;
  350. function LExpand(const S: string; MinLen: byte): string;
  351. begin
  352. if length(S)<MinLen then
  353. LExpand:=CharStr(' ',MinLen-length(S))+S
  354. else
  355. LExpand:=S;
  356. end;
  357. function LTrim(const S: string): string;
  358. var
  359. i : longint;
  360. begin
  361. i:=1;
  362. while (i<length(s)) and (s[i]=' ') do
  363. inc(i);
  364. LTrim:=Copy(s,i,High(S));
  365. end;
  366. function RTrim(const S: string): string;
  367. var
  368. i : longint;
  369. begin
  370. i:=length(s);
  371. while (i>0) and (s[i]=' ') do
  372. dec(i);
  373. RTrim:=Copy(s,1,i);
  374. end;
  375. function Trim(const S: string): string;
  376. var
  377. i,j : longint;
  378. begin
  379. i:=1;
  380. while (i<length(s)) and (s[i]=' ') do
  381. inc(i);
  382. j:=length(s);
  383. while (j>0) and (s[j]=' ') do
  384. dec(j);
  385. Trim:=Copy(S,i,j-i+1);
  386. end;
  387. function IntToStr(L: longint): string;
  388. var S: string;
  389. begin
  390. Str(L,S);
  391. IntToStr:=S;
  392. end;
  393. function IntToStrL(L: longint; MinLen: sw_integer): string;
  394. begin
  395. IntToStrL:=LExpand(IntToStr(L),MinLen);
  396. end;
  397. function IntToStrZ(L: longint; MinLen: sw_integer): string;
  398. var S: string;
  399. begin
  400. S:=IntToStr(L);
  401. if length(S)<MinLen then
  402. S:=CharStr('0',MinLen-length(S))+S;
  403. IntToStrZ:=S;
  404. end;
  405. function StrToInt(const S: string): longint;
  406. var L: longint;
  407. C: integer;
  408. begin
  409. Val(S,L,C); if C<>0 then L:=-1;
  410. LastStrToIntResult:=C;
  411. StrToInt:=L;
  412. end;
  413. function StrToCard(const S: string): cardinal;
  414. var L: cardinal;
  415. C: integer;
  416. begin
  417. Val(S,L,C); if C<>0 then L:=$ffffffff;
  418. LastStrToCardResult:=C;
  419. StrToCard:=L;
  420. end;
  421. function FloatToStr(D: Double; Decimals: byte): string;
  422. var S: string;
  423. L: byte;
  424. begin
  425. Str(D:0:Decimals,S);
  426. if length(S)>0 then
  427. while (S[1]=' ') do Delete(S,1,1);
  428. FloatToStr:=S;
  429. end;
  430. function FloatToStrL(D: Double; Decimals: byte; MinLen: byte): string;
  431. begin
  432. FloatToStrL:=LExtendString(FloatToStr(D,Decimals),MinLen);
  433. end;
  434. function LExtendString(S: string; MinLen: byte): string;
  435. begin
  436. LExtendString:=copy(SpaceStr,1,MinLen-length(S))+S;
  437. end;
  438. function GetStr(P: PString): string;
  439. begin
  440. if P=nil then GetStr:='' else GetStr:=P^;
  441. end;
  442. function GetPChar(P: PChar): string;
  443. begin
  444. if P=nil then GetPChar:='' else GetPChar:=StrPas(P);
  445. end;
  446. function DirOf(const S: string): string;
  447. var D: DirStr; E: ExtStr; N: NameStr;
  448. begin
  449. FSplit(S,D,N,E);
  450. if (D<>'') and (D[Length(D)]<>DirSep) then
  451. DirOf:=D+DirSep
  452. else
  453. DirOf:=D;
  454. end;
  455. function ExtOf(const S: string): string;
  456. var D: DirStr; E: ExtStr; N: NameStr;
  457. begin
  458. FSplit(S,D,N,E);
  459. ExtOf:=E;
  460. end;
  461. function NameOf(const S: string): string;
  462. var D: DirStr; E: ExtStr; N: NameStr;
  463. begin
  464. FSplit(S,D,N,E);
  465. NameOf:=N;
  466. end;
  467. function NameAndExtOf(const S: string): string;
  468. var D: DirStr; E: ExtStr; N: NameStr;
  469. begin
  470. FSplit(S,D,N,E);
  471. NameAndExtOf:=N+E;
  472. end;
  473. function DirAndNameOf(const S: string): string;
  474. var D: DirStr; E: ExtStr; N: NameStr;
  475. begin
  476. FSplit(S,D,N,E);
  477. DirAndNameOf:=D+N;
  478. end;
  479. { return Dos GetFTime value or -1 if the file does not exist }
  480. function GetFileTime(const FileName: string): longint;
  481. var T: longint;
  482. f: file;
  483. FM: integer;
  484. begin
  485. if FileName='' then
  486. T:=-1
  487. else
  488. begin
  489. FM:=FileMode; FileMode:=0;
  490. EatIO; Dos.DosError:=0;
  491. Assign(f,FileName);
  492. {$I-}
  493. Reset(f);
  494. if InOutRes=0 then
  495. begin
  496. GetFTime(f,T);
  497. Close(f);
  498. end;
  499. {$I+}
  500. if (EatIO<>0) or (Dos.DosError<>0) then T:=-1;
  501. FileMode:=FM;
  502. end;
  503. GetFileTime:=T;
  504. end;
  505. function GetShortName(const n:string):string;
  506. {$ifdef Windows}
  507. var
  508. hs,hs2 : string;
  509. i : longint;
  510. {$endif}
  511. {$ifdef go32v2}
  512. var
  513. hs : string;
  514. {$endif}
  515. begin
  516. GetShortName:=n;
  517. {$ifdef Windows}
  518. hs:=n+#0;
  519. i:=Windows.GetShortPathName(@hs[1],@hs2[1],high(hs2));
  520. if (i>0) and (i<=high(hs2)) then
  521. begin
  522. hs2[0]:=chr(strlen(@hs2[1]));
  523. GetShortName:=hs2;
  524. end;
  525. {$endif}
  526. {$ifdef go32v2}
  527. hs:=n;
  528. if Dos.GetShortName(hs) then
  529. GetShortName:=hs;
  530. {$endif}
  531. end;
  532. function GetLongName(const n:string):string;
  533. {$ifdef Windows}
  534. var
  535. hs : string;
  536. hs2 : Array [0..255] of char;
  537. i : longint;
  538. j : pchar;
  539. {$endif}
  540. {$ifdef go32v2}
  541. var
  542. hs : string;
  543. {$endif}
  544. begin
  545. GetLongName:=n;
  546. {$ifdef Windows}
  547. hs:=n+#0;
  548. i:=Windows.GetFullPathName(@hs[1],256,hs2,j);
  549. if (i>0) and (i<=high(hs)) then
  550. begin
  551. hs:=strpas(hs2);
  552. GetLongName:=hs;
  553. end;
  554. {$endif}
  555. {$ifdef go32v2}
  556. hs:=n;
  557. if Dos.GetLongName(hs) then
  558. GetLongName:=hs;
  559. {$endif}
  560. end;
  561. function EatIO: integer;
  562. begin
  563. EatIO:=IOResult;
  564. end;
  565. function LowCase(C: char): char;
  566. begin
  567. if ('A'<=C) and (C<='Z') then C:=chr(ord(C)+32);
  568. LowCase:=C;
  569. end;
  570. function LowcaseStr(S: string): string;
  571. var I: Longint;
  572. begin
  573. for I:=1 to length(S) do
  574. S[I]:=Lowcase(S[I]);
  575. LowcaseStr:=S;
  576. end;
  577. function BoolToStr(B: boolean; const TrueS, FalseS: string): string;
  578. begin
  579. if B then BoolToStr:=TrueS else BoolToStr:=FalseS;
  580. end;
  581. procedure TNoDisposeCollection.FreeItem(Item: Pointer);
  582. begin
  583. { don't do anything here }
  584. end;
  585. constructor TUnsortedStringCollection.CreateFrom(ALines: PUnsortedStringCollection);
  586. begin
  587. if Assigned(ALines)=false then Fail;
  588. inherited Init(ALines^.Count,ALines^.Count div 10);
  589. Assign(ALines);
  590. end;
  591. procedure TUnsortedStringCollection.Assign(ALines: PUnsortedStringCollection);
  592. procedure AddIt(P: PString);
  593. begin
  594. Insert(NewStr(GetStr(P)));
  595. end;
  596. begin
  597. FreeAll;
  598. if Assigned(ALines) then
  599. ALines^.ForEach(@AddIt);
  600. end;
  601. procedure TUnsortedStringCollection.InsertStr(const S: string);
  602. begin
  603. Insert(NewStr(S));
  604. end;
  605. function TUnsortedStringCollection.At(Index: Sw_Integer): PString;
  606. begin
  607. At:=inherited At(Index);
  608. end;
  609. procedure TUnsortedStringCollection.FreeItem(Item: Pointer);
  610. begin
  611. if Item<>nil then DisposeStr(Item);
  612. end;
  613. function TUnsortedStringCollection.GetItem(var S: TStream): Pointer;
  614. begin
  615. GetItem:=S.ReadStr;
  616. end;
  617. procedure TUnsortedStringCollection.PutItem(var S: TStream; Item: Pointer);
  618. begin
  619. S.WriteStr(Item);
  620. end;
  621. function TIntCollection.Contains(Item: ptrint): boolean;
  622. var Index: sw_integer;
  623. begin
  624. Contains:=Search(pointer(Item),Index);
  625. end;
  626. function TIntCollection.AtInt(Index: sw_integer): ptrint;
  627. begin
  628. AtInt:=longint(At(Index));
  629. end;
  630. procedure TIntCollection.Add(Item: ptrint);
  631. begin
  632. Insert(pointer(Item));
  633. end;
  634. function TIntCollection.Compare(Key1, Key2: Pointer): sw_Integer;
  635. var K1: longint absolute Key1;
  636. K2: longint absolute Key2;
  637. R: integer;
  638. begin
  639. if K1<K2 then R:=-1 else
  640. if K1>K2 then R:= 1 else
  641. R:=0;
  642. Compare:=R;
  643. end;
  644. procedure TIntCollection.FreeItem(Item: Pointer);
  645. begin
  646. { do nothing here }
  647. end;
  648. constructor TNulStream.Init;
  649. begin
  650. inherited Init;
  651. Position:=0;
  652. end;
  653. function TNulStream.GetPos: Longint;
  654. begin
  655. GetPos:=Position;
  656. end;
  657. function TNulStream.GetSize: Longint;
  658. begin
  659. GetSize:=Position;
  660. end;
  661. procedure TNulStream.Read(var Buf; Count: longint);
  662. begin
  663. Error(stReadError,0);
  664. end;
  665. procedure TNulStream.Seek(Pos: Longint);
  666. begin
  667. if Pos<=Position then
  668. Position:=Pos;
  669. end;
  670. procedure TNulStream.Write(var Buf; Count: longint);
  671. begin
  672. Inc(Position,Count);
  673. end;
  674. constructor TSubStream.Init(AStream: PStream; AStartPos, ASize: longint);
  675. begin
  676. inherited Init;
  677. if Assigned(AStream)=false then Fail;
  678. S:=AStream; StartPos:=AStartPos; StreamSize:=ASize;
  679. Seek(0);
  680. end;
  681. function TSubStream.GetPos: Longint;
  682. var Pos: longint;
  683. begin
  684. Pos:=S^.GetPos; Dec(Pos,StartPos);
  685. GetPos:=Pos;
  686. end;
  687. function TSubStream.GetSize: Longint;
  688. begin
  689. GetSize:=StreamSize;
  690. end;
  691. procedure TSubStream.Read(var Buf; Count: longint);
  692. var Pos: longint;
  693. RCount: longint;
  694. begin
  695. Pos:=GetPos;
  696. if Pos+Count>StreamSize then RCount:=StreamSize-Pos else RCount:=Count;
  697. S^.Read(Buf,RCount);
  698. if RCount<Count then
  699. Error(stReadError,0);
  700. end;
  701. procedure TSubStream.Seek(Pos: Longint);
  702. var RPos: longint;
  703. begin
  704. if (Pos<=StreamSize) then RPos:=Pos else RPos:=StreamSize;
  705. S^.Seek(StartPos+RPos);
  706. end;
  707. procedure TSubStream.Write(var Buf; Count: longint);
  708. begin
  709. S^.Write(Buf,Count);
  710. end;
  711. constructor TFastBufStream.Init (FileName: FNameStr; Mode, Size: Word);
  712. begin
  713. Inherited Init(FileName,Mode,Size);
  714. BasePos:=0;
  715. end;
  716. procedure TFastBufStream.Seek(Pos: Longint);
  717. var RelOfs: longint;
  718. begin
  719. RelOfs:=Pos-BasePos;
  720. if (RelOfs<0) or (RelOfs>=BufEnd) or (BufEnd=0) then
  721. begin
  722. inherited Seek(Pos);
  723. BasePos:=Pos-BufPtr;
  724. end
  725. else
  726. begin
  727. BufPtr:=RelOfs;
  728. Position:=Pos;
  729. end;
  730. end;
  731. procedure TFastBufStream.Readline(var s:string;var linecomplete,hasCR : boolean);
  732. var
  733. c : char;
  734. i,pos,StartPos : longint;
  735. charsInS : boolean;
  736. begin
  737. linecomplete:=false;
  738. c:=#0;
  739. i:=0;
  740. { this created problems for lines longer than 255 characters
  741. now those lines are cutted into pieces without warning PM }
  742. { changed implicit 255 to High(S), so it will be automatically extended
  743. when longstrings eventually become default - Gabor }
  744. if (bufend-bufptr>=High(S)) and (getpos+High(S)<getsize) then
  745. begin
  746. StartPos:=GetPos;
  747. //read(S[1],High(S));
  748. system.move(buffer^[bufptr],S[1],High(S));
  749. charsInS:=true;
  750. end
  751. else
  752. CharsInS:=false;
  753. while (CharsInS or not (getpos>=getsize)) and
  754. (c<>#10) and (i<High(S)) do
  755. begin
  756. if CharsInS then
  757. c:=s[i+1]
  758. else
  759. read(c,sizeof(c));
  760. if c<>#10 then
  761. begin
  762. inc(i);
  763. if not CharsInS then
  764. s[i]:=c;
  765. end;
  766. end;
  767. if CharsInS then
  768. begin
  769. if c=#10 then
  770. Seek(StartPos+i+1)
  771. else
  772. Seek(StartPos+i);
  773. end;
  774. { if there was a CR LF then remove the CR Dos newline style }
  775. if (i>0) and (s[i]=#13) then
  776. begin
  777. dec(i);
  778. end;
  779. if (c=#13) and (not (getpos>=getsize)) then
  780. begin
  781. read(c,sizeof(c));
  782. end;
  783. if (i=High(S)) and not (getpos>=getsize) then
  784. begin
  785. pos:=getpos;
  786. read(c,sizeof(c));
  787. if (c=#13) and not (getpos>=getsize) then
  788. read(c,sizeof(c));
  789. if c<>#10 then
  790. seek(pos);
  791. end;
  792. if (c=#10) or (getpos>=getsize) then
  793. linecomplete:=true;
  794. if (c=#10) then
  795. hasCR:=true;
  796. s[0]:=chr(i);
  797. end;
  798. function TTextCollection.Compare(Key1, Key2: Pointer): Sw_Integer;
  799. var K1: PString absolute Key1;
  800. K2: PString absolute Key2;
  801. R: Sw_integer;
  802. S1,S2: string;
  803. begin
  804. S1:=UpCaseStr(K1^);
  805. S2:=UpCaseStr(K2^);
  806. if S1<S2 then R:=-1 else
  807. if S1>S2 then R:=1 else
  808. R:=0;
  809. Compare:=R;
  810. end;
  811. function TTextCollection.LookUp(const S: string; var Idx: sw_integer): string;
  812. var OLI,ORI,Left,Right,Mid: integer;
  813. {LeftP,RightP,}MidP: PString;
  814. {LeftS,}MidS{,RightS}: string;
  815. FoundS: string;
  816. UpS : string;
  817. begin
  818. Idx:=-1; FoundS:='';
  819. Left:=0; Right:=Count-1;
  820. UpS:=UpCaseStr(S);
  821. while Left<=Right do
  822. begin
  823. OLI:=Left; ORI:=Right;
  824. Mid:=Left+(Right-Left) div 2;
  825. MidP:=At(Mid);
  826. MidS:=UpCaseStr(MidP^);
  827. if copy(MidS,1,length(UpS))=UpS then
  828. begin
  829. Idx:=Mid; FoundS:=GetStr(MidP);
  830. { exit immediately if exact match PM }
  831. If Length(MidS)=Length(UpS) then
  832. break;
  833. end;
  834. if UpS<MidS then
  835. Right:=Mid
  836. else
  837. Left:=Mid;
  838. if (OLI=Left) and (ORI=Right) then
  839. begin
  840. if (Left<Right) then
  841. Left:=Right
  842. else
  843. Break;
  844. end;
  845. end;
  846. LookUp:=FoundS;
  847. end;
  848. function TrimEndSlash(const Path: string): string;
  849. var S: string;
  850. begin
  851. S:=Path;
  852. if (length(S)>0) and (S<>DirSep) and (copy(S,length(S),1)=DirSep) and
  853. (S[length(S)-1]<>':') then
  854. S:=copy(S,1,length(S)-1);
  855. TrimEndSlash:=S;
  856. end;
  857. function CompareText(S1, S2: string): integer;
  858. var R: integer;
  859. begin
  860. S1:=UpcaseStr(S1); S2:=UpcaseStr(S2);
  861. if S1<S2 then R:=-1 else
  862. if S1>S2 then R:= 1 else
  863. R:=0;
  864. CompareText:=R;
  865. end;
  866. function FormatPath(Path: string): string;
  867. var P: sw_integer;
  868. SC: char;
  869. begin
  870. if ord(DirSep)=ord('/') then
  871. SC:='\'
  872. else
  873. SC:='/';
  874. repeat
  875. P:=Pos(SC,Path);
  876. if P>0 then Path[P]:=DirSep;
  877. until P=0;
  878. FormatPath:=Path;
  879. end;
  880. function CompletePath(const Base, InComplete: string): string;
  881. var Drv,BDrv: string[40]; D,BD: DirStr; N,BN: NameStr; E,BE: ExtStr;
  882. P: sw_integer;
  883. Complete: string;
  884. begin
  885. Complete:=FormatPath(InComplete);
  886. FSplit(FormatPath(InComplete),D,N,E);
  887. P:=Pos(':',D); if P=0 then Drv:='' else begin Drv:=copy(D,1,P); Delete(D,1,P); end;
  888. FSplit(FormatPath(Base),BD,BN,BE);
  889. P:=Pos(':',BD); if P=0 then BDrv:='' else begin BDrv:=copy(BD,1,P); Delete(BD,1,P); end;
  890. if copy(D,1,1)<>DirSep then
  891. Complete:=BD+D+N+E;
  892. if Drv='' then
  893. Complete:=BDrv+Complete;
  894. Complete:=FExpand(Complete);
  895. CompletePath:=Complete;
  896. end;
  897. function CompleteURL(const Base, URLRef: string): string;
  898. var P: integer;
  899. Drive: string[20];
  900. IsComplete: boolean;
  901. S: string;
  902. Ref: string;
  903. Bookmark: string;
  904. begin
  905. IsComplete:=false; Ref:=URLRef;
  906. P:=Pos(':',Ref);
  907. if P=0 then Drive:='' else Drive:=UpcaseStr(copy(Ref,1,P-1));
  908. if Drive<>'' then
  909. if (Drive='MAILTO') or (Drive='FTP') or (Drive='HTTP') or
  910. (Drive='GOPHER') or (Drive='FILE') then
  911. IsComplete:=true;
  912. if IsComplete then S:=Ref else
  913. begin
  914. P:=Pos('#',Ref);
  915. if P=0 then
  916. Bookmark:=''
  917. else
  918. begin
  919. Bookmark:=copy(Ref,P+1,length(Ref));
  920. Ref:=copy(Ref,1,P-1);
  921. end;
  922. S:=CompletePath(Base,Ref);
  923. if Bookmark<>'' then
  924. S:=S+'#'+Bookmark;
  925. end;
  926. CompleteURL:=S;
  927. end;
  928. function OptimizePath(Path: string; MaxLen: integer): string;
  929. var i : integer;
  930. BackSlashs : array[1..20] of integer;
  931. BSCount : integer;
  932. Jobbra : boolean;
  933. Jobb, Bal : byte;
  934. Hiba : boolean;
  935. begin
  936. if length(Path)>MaxLen then
  937. begin
  938. BSCount:=0; Jobbra:=true;
  939. for i:=1 to length(Path) do if Path[i]=DirSep then
  940. begin
  941. Inc(BSCount);
  942. BackSlashs[BSCount]:=i;
  943. end;
  944. i:=BSCount div 2;
  945. Hiba:=false;
  946. Bal:=i; Jobb:=i+1;
  947. case i of 0 : ;
  948. 1 : Path:=copy(Path, 1, BackSlashs[1])+'..'+
  949. copy(Path, BackSlashs[2], length(Path));
  950. else begin
  951. while (BackSlashs[Bal]+(length(Path)-BackSlashs[Jobb]) >=
  952. MaxLen) and not Hiba do
  953. begin
  954. if Jobbra then begin
  955. if Jobb<BSCount then inc(Jobb)
  956. else Hiba:=true;
  957. Jobbra:=false;
  958. end
  959. else begin
  960. if Bal>1 then dec(Bal)
  961. else Hiba:=true;
  962. Jobbra:=true;
  963. end;
  964. end;
  965. Path:=copy(Path, 1, BackSlashs[Bal])+'..'+
  966. copy(Path, BackSlashs[Jobb], length(Path));
  967. end;
  968. end;
  969. end;
  970. if length(Path)>MaxLen then
  971. begin
  972. i:=Pos('\..\',Path);
  973. if i>0 then Path:=copy(Path,1,i-1)+'..'+copy(Path,i+length('\..\'),length(Path));
  974. end;
  975. OptimizePath:=Path;
  976. end;
  977. function Now: longint;
  978. var D: DateTime;
  979. W: word;
  980. L: longint;
  981. begin
  982. FillChar(D,sizeof(D),0);
  983. GetDate(D.Year,D.Month,D.Day,W);
  984. GetTime(D.Hour,D.Min,D.Sec,W);
  985. PackTime(D,L);
  986. Now:=L;
  987. end;
  988. function FormatDateTimeL(L: longint; const Format: string): string;
  989. var D: DateTime;
  990. begin
  991. UnpackTime(L,D);
  992. FormatDateTimeL:=FormatDateTime(D,Format);
  993. end;
  994. function FormatDateTime(const D: DateTime; const Format: string): string;
  995. var I: sw_integer;
  996. CurCharStart: sw_integer;
  997. CurChar: char;
  998. CurCharCount: integer;
  999. DateS: string;
  1000. C: char;
  1001. procedure FlushChars;
  1002. var S: string;
  1003. I: sw_integer;
  1004. begin
  1005. S:='';
  1006. for I:=1 to CurCharCount do
  1007. S:=S+CurChar;
  1008. case CurChar of
  1009. 'y' : S:=IntToStrL(D.Year,length(S));
  1010. 'm' : S:=IntToStrZ(D.Month,length(S));
  1011. 'd' : S:=IntToStrZ(D.Day,length(S));
  1012. 'h' : S:=IntToStrZ(D.Hour,length(S));
  1013. 'n' : S:=IntToStrZ(D.Min,length(S));
  1014. 's' : S:=IntToStrZ(D.Sec,length(S));
  1015. end;
  1016. DateS:=DateS+S;
  1017. end;
  1018. begin
  1019. DateS:='';
  1020. CurCharStart:=-1; CurCharCount:=0; CurChar:=#0;
  1021. for I:=1 to length(Format) do
  1022. begin
  1023. C:=Format[I];
  1024. if (C<>CurChar) or (CurCharStart=-1) then
  1025. begin
  1026. if CurCharStart<>-1 then FlushChars;
  1027. CurCharCount:=1; CurCharStart:=I;
  1028. end
  1029. else
  1030. Inc(CurCharCount);
  1031. CurChar:=C;
  1032. end;
  1033. FlushChars;
  1034. FormatDateTime:=DateS;
  1035. end;
  1036. function DeleteFile(const FileName: string): integer;
  1037. var f: file;
  1038. begin
  1039. {$I-}
  1040. Assign(f,FileName);
  1041. Erase(f);
  1042. DeleteFile:=EatIO;
  1043. {$I+}
  1044. end;
  1045. function ExistsFile(const FileName: string): boolean;
  1046. var
  1047. Dir : SearchRec;
  1048. begin
  1049. Dos.FindFirst(FileName,Archive+ReadOnly,Dir);
  1050. ExistsFile:=(Dos.DosError=0);
  1051. Dos.FindClose(Dir);
  1052. end;
  1053. { returns zero for empty and non existant files }
  1054. function SizeOfFile(const FileName: string): longint;
  1055. var
  1056. Dir : SearchRec;
  1057. begin
  1058. Dos.FindFirst(FileName,Archive+ReadOnly,Dir);
  1059. if (Dos.DosError=0) then
  1060. SizeOfFile:=Dir.Size
  1061. else
  1062. SizeOfFile:=0;
  1063. Dos.FindClose(Dir);
  1064. end;
  1065. function ExistsDir(const DirName: string): boolean;
  1066. var
  1067. Dir : SearchRec;
  1068. begin
  1069. Dos.FindFirst(TrimEndSlash(DirName),anyfile,Dir);
  1070. { if a file is found it is also reported
  1071. at least for some Dos version
  1072. so we need to check the attributes PM }
  1073. ExistsDir:=(Dos.DosError=0) and ((Dir.attr and Directory) <> 0);
  1074. Dos.FindClose(Dir);
  1075. end;
  1076. function CompleteDir(const Path: string): string;
  1077. begin
  1078. { keep c: untouched PM }
  1079. if (Path<>'') and (Path[Length(Path)]<>DirSep) and
  1080. (Path[Length(Path)]<>':') then
  1081. CompleteDir:=Path+DirSep
  1082. else
  1083. CompleteDir:=Path;
  1084. end;
  1085. function GetCurDir: string;
  1086. var S: string;
  1087. begin
  1088. GetDir(0,S);
  1089. if copy(S,length(S),1)<>DirSep then S:=S+DirSep;
  1090. GetCurDir:=S;
  1091. end;
  1092. function GenTempFileName: string;
  1093. var Dir: string;
  1094. Name: string;
  1095. I: integer;
  1096. OK: boolean;
  1097. Path: string;
  1098. begin
  1099. Dir:=GetEnv('TEMP');
  1100. if Dir='' then Dir:=GetEnv('TMP');
  1101. if (Dir<>'') then if not ExistsDir(Dir) then Dir:='';
  1102. if Dir='' then Dir:=GetCurDir;
  1103. repeat
  1104. Name:=TempFirstChar;
  1105. for I:=2 to TempNameLen do
  1106. Name:=Name+chr(ord('a')+random(ord('z')-ord('a')+1));
  1107. Name:=Name+TempExt;
  1108. Path:=CompleteDir(Dir)+Name;
  1109. OK:=not ExistsFile(Path);
  1110. until OK;
  1111. GenTempFileName:=Path;
  1112. end;
  1113. function CopyFile(const SrcFileName, DestFileName: string): boolean;
  1114. var SrcF,DestF: PBufStream;
  1115. OK: boolean;
  1116. begin
  1117. SrcF:=nil; DestF:=nil;
  1118. New(SrcF, Init(SrcFileName,stOpenRead,4096));
  1119. OK:=Assigned(SrcF) and (SrcF^.Status=stOK);
  1120. if OK then
  1121. begin
  1122. New(DestF, Init(DestFileName,stCreate,1024));
  1123. OK:=Assigned(DestF) and (DestF^.Status=stOK);
  1124. end;
  1125. if OK then DestF^.CopyFrom(SrcF^,SrcF^.GetSize);
  1126. if Assigned(DestF) then Dispose(DestF, Done);
  1127. if Assigned(SrcF) then Dispose(SrcF, Done);
  1128. CopyFile:=OK;
  1129. end;
  1130. procedure RegisterWUtils;
  1131. begin
  1132. {$ifndef NOOBJREG}
  1133. RegisterType(RUnsortedStringCollection);
  1134. {$endif}
  1135. end;
  1136. Procedure DebugMessage(AFileName, AText : string; ALine, APos : sw_word); // calls DebugMessage
  1137. begin
  1138. DebugMessageS(Afilename,AText,'','',aline,apos);
  1139. end;
  1140. Procedure WUtilsDebugMessage(AFileName, AText : string; ALine, APos : string;nrLine, nrPos : sw_word);
  1141. begin
  1142. writeln(stderr,AFileName,' (',ALine,',',APos,') ',AText);
  1143. flush(stderr);
  1144. end;
  1145. BEGIN
  1146. Randomize;
  1147. END.