wutils.pas 32 KB

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