wutils.pas 31 KB

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