wutils.pas 30 KB

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