2
0

wutils.pas 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290
  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) then
  453. DirOf:=D+DirSep
  454. else
  455. DirOf:=D;
  456. end;
  457. function ExtOf(const S: string): string;
  458. var D: DirStr; E: ExtStr; N: NameStr;
  459. begin
  460. FSplit(S,D,N,E);
  461. ExtOf:=E;
  462. end;
  463. function NameOf(const S: string): string;
  464. var D: DirStr; E: ExtStr; N: NameStr;
  465. begin
  466. FSplit(S,D,N,E);
  467. NameOf:=N;
  468. end;
  469. function NameAndExtOf(const S: string): string;
  470. var D: DirStr; E: ExtStr; N: NameStr;
  471. begin
  472. FSplit(S,D,N,E);
  473. NameAndExtOf:=N+E;
  474. end;
  475. function DirAndNameOf(const S: string): string;
  476. var D: DirStr; E: ExtStr; N: NameStr;
  477. begin
  478. FSplit(S,D,N,E);
  479. DirAndNameOf:=D+N;
  480. end;
  481. { return Dos GetFTime value or -1 if the file does not exist }
  482. function GetFileTime(const FileName: string): longint;
  483. var T: longint;
  484. f: file;
  485. FM: integer;
  486. begin
  487. if FileName='' then
  488. T:=-1
  489. else
  490. begin
  491. FM:=FileMode; FileMode:=0;
  492. EatIO; Dos.DosError:=0;
  493. Assign(f,FileName);
  494. {$I-}
  495. Reset(f);
  496. if InOutRes=0 then
  497. begin
  498. GetFTime(f,T);
  499. Close(f);
  500. end;
  501. {$I+}
  502. if (EatIO<>0) or (Dos.DosError<>0) then T:=-1;
  503. FileMode:=FM;
  504. end;
  505. GetFileTime:=T;
  506. end;
  507. function GetShortName(const n:string):string;
  508. {$ifdef Windows}
  509. var
  510. hs,hs2 : string;
  511. i : longint;
  512. {$endif}
  513. {$ifdef go32v2}
  514. var
  515. hs : string;
  516. {$endif}
  517. begin
  518. GetShortName:=n;
  519. {$ifdef Windows}
  520. hs:=n+#0;
  521. i:=Windows.GetShortPathName(@hs[1],@hs2[1],high(hs2));
  522. if (i>0) and (i<=high(hs2)) then
  523. begin
  524. hs2[0]:=chr(strlen(@hs2[1]));
  525. GetShortName:=hs2;
  526. end;
  527. {$endif}
  528. {$ifdef go32v2}
  529. hs:=n;
  530. if Dos.GetShortName(hs) then
  531. GetShortName:=hs;
  532. {$endif}
  533. end;
  534. function GetLongName(const n:string):string;
  535. {$ifdef Windows}
  536. var
  537. hs : string;
  538. hs2 : Array [0..255] of char;
  539. i : longint;
  540. j : pchar;
  541. {$endif}
  542. {$ifdef go32v2}
  543. var
  544. hs : string;
  545. {$endif}
  546. begin
  547. GetLongName:=n;
  548. {$ifdef Windows}
  549. hs:=n+#0;
  550. i:=Windows.GetFullPathName(@hs[1],256,hs2,j);
  551. if (i>0) and (i<=high(hs)) then
  552. begin
  553. hs:=strpas(hs2);
  554. GetLongName:=hs;
  555. end;
  556. {$endif}
  557. {$ifdef go32v2}
  558. hs:=n;
  559. if Dos.GetLongName(hs) then
  560. GetLongName:=hs;
  561. {$endif}
  562. end;
  563. function EatIO: integer;
  564. begin
  565. EatIO:=IOResult;
  566. end;
  567. function LowCase(C: char): char;
  568. begin
  569. if ('A'<=C) and (C<='Z') then C:=chr(ord(C)+32);
  570. LowCase:=C;
  571. end;
  572. function LowcaseStr(S: string): string;
  573. var I: Longint;
  574. begin
  575. for I:=1 to length(S) do
  576. S[I]:=Lowcase(S[I]);
  577. LowcaseStr:=S;
  578. end;
  579. function BoolToStr(B: boolean; const TrueS, FalseS: string): string;
  580. begin
  581. if B then BoolToStr:=TrueS else BoolToStr:=FalseS;
  582. end;
  583. procedure TNoDisposeCollection.FreeItem(Item: Pointer);
  584. begin
  585. { don't do anything here }
  586. end;
  587. constructor TUnsortedStringCollection.CreateFrom(ALines: PUnsortedStringCollection);
  588. begin
  589. if Assigned(ALines)=false then Fail;
  590. inherited Init(ALines^.Count,ALines^.Count div 10);
  591. Assign(ALines);
  592. end;
  593. procedure TUnsortedStringCollection.Assign(ALines: PUnsortedStringCollection);
  594. procedure AddIt(P: PString);
  595. begin
  596. Insert(NewStr(GetStr(P)));
  597. end;
  598. begin
  599. FreeAll;
  600. if Assigned(ALines) then
  601. ALines^.ForEach(@AddIt);
  602. end;
  603. procedure TUnsortedStringCollection.InsertStr(const S: string);
  604. begin
  605. Insert(NewStr(S));
  606. end;
  607. function TUnsortedStringCollection.At(Index: Sw_Integer): PString;
  608. begin
  609. At:=inherited At(Index);
  610. end;
  611. procedure TUnsortedStringCollection.FreeItem(Item: Pointer);
  612. begin
  613. if Item<>nil then DisposeStr(Item);
  614. end;
  615. function TUnsortedStringCollection.GetItem(var S: TStream): Pointer;
  616. begin
  617. GetItem:=S.ReadStr;
  618. end;
  619. procedure TUnsortedStringCollection.PutItem(var S: TStream; Item: Pointer);
  620. begin
  621. S.WriteStr(Item);
  622. end;
  623. function TIntCollection.Contains(Item: ptrint): boolean;
  624. var Index: sw_integer;
  625. begin
  626. Contains:=Search(pointer(Item),Index);
  627. end;
  628. function TIntCollection.AtInt(Index: sw_integer): ptrint;
  629. begin
  630. AtInt:=longint(At(Index));
  631. end;
  632. procedure TIntCollection.Add(Item: ptrint);
  633. begin
  634. Insert(pointer(Item));
  635. end;
  636. function TIntCollection.Compare(Key1, Key2: Pointer): sw_Integer;
  637. var K1: longint absolute Key1;
  638. K2: longint absolute Key2;
  639. R: integer;
  640. begin
  641. if K1<K2 then R:=-1 else
  642. if K1>K2 then R:= 1 else
  643. R:=0;
  644. Compare:=R;
  645. end;
  646. procedure TIntCollection.FreeItem(Item: Pointer);
  647. begin
  648. { do nothing here }
  649. end;
  650. constructor TNulStream.Init;
  651. begin
  652. inherited Init;
  653. Position:=0;
  654. end;
  655. function TNulStream.GetPos: Longint;
  656. begin
  657. GetPos:=Position;
  658. end;
  659. function TNulStream.GetSize: Longint;
  660. begin
  661. GetSize:=Position;
  662. end;
  663. procedure TNulStream.Read(var Buf; Count: longint);
  664. begin
  665. Error(stReadError,0);
  666. end;
  667. procedure TNulStream.Seek(Pos: Longint);
  668. begin
  669. if Pos<=Position then
  670. Position:=Pos;
  671. end;
  672. procedure TNulStream.Write(var Buf; Count: longint);
  673. begin
  674. Inc(Position,Count);
  675. end;
  676. constructor TSubStream.Init(AStream: PStream; AStartPos, ASize: longint);
  677. begin
  678. inherited Init;
  679. if Assigned(AStream)=false then Fail;
  680. S:=AStream; StartPos:=AStartPos; StreamSize:=ASize;
  681. Seek(0);
  682. end;
  683. function TSubStream.GetPos: Longint;
  684. var Pos: longint;
  685. begin
  686. Pos:=S^.GetPos; Dec(Pos,StartPos);
  687. GetPos:=Pos;
  688. end;
  689. function TSubStream.GetSize: Longint;
  690. begin
  691. GetSize:=StreamSize;
  692. end;
  693. procedure TSubStream.Read(var Buf; Count: longint);
  694. var Pos: longint;
  695. RCount: longint;
  696. begin
  697. Pos:=GetPos;
  698. if Pos+Count>StreamSize then RCount:=StreamSize-Pos else RCount:=Count;
  699. S^.Read(Buf,RCount);
  700. if RCount<Count then
  701. Error(stReadError,0);
  702. end;
  703. procedure TSubStream.Seek(Pos: Longint);
  704. var RPos: longint;
  705. begin
  706. if (Pos<=StreamSize) then RPos:=Pos else RPos:=StreamSize;
  707. S^.Seek(StartPos+RPos);
  708. end;
  709. procedure TSubStream.Write(var Buf; Count: longint);
  710. begin
  711. S^.Write(Buf,Count);
  712. end;
  713. constructor TFastBufStream.Init (FileName: FNameStr; Mode, Size: Word);
  714. begin
  715. Inherited Init(FileName,Mode,Size);
  716. BasePos:=0;
  717. end;
  718. procedure TFastBufStream.Seek(Pos: Longint);
  719. var RelOfs: longint;
  720. begin
  721. RelOfs:=Pos-BasePos;
  722. if (RelOfs<0) or (RelOfs>=BufEnd) or (BufEnd=0) then
  723. begin
  724. inherited Seek(Pos);
  725. BasePos:=Pos-BufPtr;
  726. end
  727. else
  728. begin
  729. BufPtr:=RelOfs;
  730. Position:=Pos;
  731. end;
  732. end;
  733. procedure TFastBufStream.Readline(var s:string;var linecomplete,hasCR : boolean);
  734. var
  735. c : char;
  736. i,pos,StartPos : longint;
  737. charsInS : boolean;
  738. begin
  739. linecomplete:=false;
  740. c:=#0;
  741. i:=0;
  742. { this created problems for lines longer than 255 characters
  743. now those lines are cutted into pieces without warning PM }
  744. { changed implicit 255 to High(S), so it will be automatically extended
  745. when longstrings eventually become default - Gabor }
  746. if (bufend-bufptr>=High(S)) and (getpos+High(S)<getsize) then
  747. begin
  748. StartPos:=GetPos;
  749. //read(S[1],High(S));
  750. system.move(buffer^[bufptr],S[1],High(S));
  751. charsInS:=true;
  752. end
  753. else
  754. CharsInS:=false;
  755. while (CharsInS or not (getpos>=getsize)) and
  756. (c<>#10) and (i<High(S)) do
  757. begin
  758. if CharsInS then
  759. c:=s[i+1]
  760. else
  761. read(c,sizeof(c));
  762. if c<>#10 then
  763. begin
  764. inc(i);
  765. if not CharsInS then
  766. s[i]:=c;
  767. end;
  768. end;
  769. if CharsInS then
  770. begin
  771. if c=#10 then
  772. Seek(StartPos+i+1)
  773. else
  774. Seek(StartPos+i);
  775. end;
  776. { if there was a CR LF then remove the CR Dos newline style }
  777. if (i>0) and (s[i]=#13) then
  778. begin
  779. dec(i);
  780. end;
  781. if (c=#13) and (not (getpos>=getsize)) then
  782. begin
  783. read(c,sizeof(c));
  784. end;
  785. if (i=High(S)) and not (getpos>=getsize) then
  786. begin
  787. pos:=getpos;
  788. read(c,sizeof(c));
  789. if (c=#13) and not (getpos>=getsize) then
  790. read(c,sizeof(c));
  791. if c<>#10 then
  792. seek(pos);
  793. end;
  794. if (c=#10) or (getpos>=getsize) then
  795. linecomplete:=true;
  796. if (c=#10) then
  797. hasCR:=true;
  798. s[0]:=chr(i);
  799. end;
  800. function TTextCollection.Compare(Key1, Key2: Pointer): Sw_Integer;
  801. var K1: PString absolute Key1;
  802. K2: PString absolute Key2;
  803. R: Sw_integer;
  804. S1,S2: string;
  805. begin
  806. S1:=UpCaseStr(K1^);
  807. S2:=UpCaseStr(K2^);
  808. if S1<S2 then R:=-1 else
  809. if S1>S2 then R:=1 else
  810. R:=0;
  811. Compare:=R;
  812. end;
  813. function TTextCollection.LookUp(const S: string; var Idx: sw_integer): string;
  814. var OLI,ORI,Left,Right,Mid: integer;
  815. {LeftP,RightP,}MidP: PString;
  816. {LeftS,}MidS{,RightS}: string;
  817. FoundS: string;
  818. UpS : string;
  819. begin
  820. Idx:=-1; FoundS:='';
  821. Left:=0; Right:=Count-1;
  822. UpS:=UpCaseStr(S);
  823. while Left<=Right do
  824. begin
  825. OLI:=Left; ORI:=Right;
  826. Mid:=Left+(Right-Left) div 2;
  827. MidP:=At(Mid);
  828. MidS:=UpCaseStr(MidP^);
  829. if copy(MidS,1,length(UpS))=UpS then
  830. begin
  831. Idx:=Mid; FoundS:=GetStr(MidP);
  832. { exit immediately if exact match PM }
  833. If Length(MidS)=Length(UpS) then
  834. break;
  835. end;
  836. if UpS<MidS then
  837. Right:=Mid
  838. else
  839. Left:=Mid;
  840. if (OLI=Left) and (ORI=Right) then
  841. begin
  842. if (Left<Right) then
  843. Left:=Right
  844. else
  845. Break;
  846. end;
  847. end;
  848. LookUp:=FoundS;
  849. end;
  850. function TrimEndSlash(const Path: string): string;
  851. var S: string;
  852. begin
  853. S:=Path;
  854. if (length(S)>0) and (S<>DirSep) and (copy(S,length(S),1)=DirSep) and
  855. (S[length(S)-1]<>':') then
  856. S:=copy(S,1,length(S)-1);
  857. TrimEndSlash:=S;
  858. end;
  859. function CompareText(S1, S2: string): integer;
  860. var R: integer;
  861. begin
  862. S1:=UpcaseStr(S1); S2:=UpcaseStr(S2);
  863. if S1<S2 then R:=-1 else
  864. if S1>S2 then R:= 1 else
  865. R:=0;
  866. CompareText:=R;
  867. end;
  868. function FormatPath(Path: string): string;
  869. var P: sw_integer;
  870. SC: char;
  871. begin
  872. if ord(DirSep)=ord('/') then
  873. SC:='\'
  874. else
  875. SC:='/';
  876. repeat
  877. P:=Pos(SC,Path);
  878. if P>0 then Path[P]:=DirSep;
  879. until P=0;
  880. FormatPath:=Path;
  881. end;
  882. function CompletePath(const Base, InComplete: string): string;
  883. var Drv,BDrv: string[40]; D,BD: DirStr; N,BN: NameStr; E,BE: ExtStr;
  884. P: sw_integer;
  885. Complete: string;
  886. begin
  887. Complete:=FormatPath(InComplete);
  888. FSplit(FormatPath(InComplete),D,N,E);
  889. P:=Pos(':',D); if P=0 then Drv:='' else begin Drv:=copy(D,1,P); Delete(D,1,P); end;
  890. FSplit(FormatPath(Base),BD,BN,BE);
  891. P:=Pos(':',BD); if P=0 then BDrv:='' else begin BDrv:=copy(BD,1,P); Delete(BD,1,P); end;
  892. if copy(D,1,1)<>DirSep then
  893. Complete:=BD+D+N+E;
  894. if Drv='' then
  895. Complete:=BDrv+Complete;
  896. Complete:=FExpand(Complete);
  897. CompletePath:=Complete;
  898. end;
  899. function CompleteURL(const Base, URLRef: string): string;
  900. var P: integer;
  901. Drive: string[20];
  902. IsComplete: boolean;
  903. S: string;
  904. Ref: string;
  905. Bookmark: string;
  906. begin
  907. IsComplete:=false; Ref:=URLRef;
  908. P:=Pos(':',Ref);
  909. if P=0 then Drive:='' else Drive:=UpcaseStr(copy(Ref,1,P-1));
  910. if Drive<>'' then
  911. if (Drive='MAILTO') or (Drive='FTP') or (Drive='HTTP') or
  912. (Drive='GOPHER') or (Drive='FILE') then
  913. IsComplete:=true;
  914. if IsComplete then S:=Ref else
  915. begin
  916. P:=Pos('#',Ref);
  917. if P=0 then
  918. Bookmark:=''
  919. else
  920. begin
  921. Bookmark:=copy(Ref,P+1,length(Ref));
  922. Ref:=copy(Ref,1,P-1);
  923. end;
  924. S:=CompletePath(Base,Ref);
  925. if Bookmark<>'' then
  926. S:=S+'#'+Bookmark;
  927. end;
  928. CompleteURL:=S;
  929. end;
  930. function OptimizePath(Path: string; MaxLen: integer): string;
  931. var i : integer;
  932. BackSlashs : array[1..20] of integer;
  933. BSCount : integer;
  934. Jobbra : boolean;
  935. Jobb, Bal : byte;
  936. Hiba : boolean;
  937. begin
  938. if length(Path)>MaxLen then
  939. begin
  940. BSCount:=0; Jobbra:=true;
  941. for i:=1 to length(Path) do if Path[i]=DirSep then
  942. begin
  943. Inc(BSCount);
  944. BackSlashs[BSCount]:=i;
  945. end;
  946. i:=BSCount div 2;
  947. Hiba:=false;
  948. Bal:=i; Jobb:=i+1;
  949. case i of 0 : ;
  950. 1 : Path:=copy(Path, 1, BackSlashs[1])+'..'+
  951. copy(Path, BackSlashs[2], length(Path));
  952. else begin
  953. while (BackSlashs[Bal]+(length(Path)-BackSlashs[Jobb]) >=
  954. MaxLen) and not Hiba do
  955. begin
  956. if Jobbra then begin
  957. if Jobb<BSCount then inc(Jobb)
  958. else Hiba:=true;
  959. Jobbra:=false;
  960. end
  961. else begin
  962. if Bal>1 then dec(Bal)
  963. else Hiba:=true;
  964. Jobbra:=true;
  965. end;
  966. end;
  967. Path:=copy(Path, 1, BackSlashs[Bal])+'..'+
  968. copy(Path, BackSlashs[Jobb], length(Path));
  969. end;
  970. end;
  971. end;
  972. if length(Path)>MaxLen then
  973. begin
  974. i:=Pos('\..\',Path);
  975. if i>0 then Path:=copy(Path,1,i-1)+'..'+copy(Path,i+length('\..\'),length(Path));
  976. end;
  977. OptimizePath:=Path;
  978. end;
  979. function Now: longint;
  980. var D: DateTime;
  981. W: word;
  982. L: longint;
  983. begin
  984. FillChar(D,sizeof(D),0);
  985. GetDate(D.Year,D.Month,D.Day,W);
  986. GetTime(D.Hour,D.Min,D.Sec,W);
  987. PackTime(D,L);
  988. Now:=L;
  989. end;
  990. function FormatDateTimeL(L: longint; const Format: string): string;
  991. var D: DateTime;
  992. begin
  993. UnpackTime(L,D);
  994. FormatDateTimeL:=FormatDateTime(D,Format);
  995. end;
  996. function FormatDateTime(const D: DateTime; const Format: string): string;
  997. var I: sw_integer;
  998. CurCharStart: sw_integer;
  999. CurChar: char;
  1000. CurCharCount: integer;
  1001. DateS: string;
  1002. C: char;
  1003. procedure FlushChars;
  1004. var S: string;
  1005. I: sw_integer;
  1006. begin
  1007. S:='';
  1008. for I:=1 to CurCharCount do
  1009. S:=S+CurChar;
  1010. case CurChar of
  1011. 'y' : S:=IntToStrL(D.Year,length(S));
  1012. 'm' : S:=IntToStrZ(D.Month,length(S));
  1013. 'd' : S:=IntToStrZ(D.Day,length(S));
  1014. 'h' : S:=IntToStrZ(D.Hour,length(S));
  1015. 'n' : S:=IntToStrZ(D.Min,length(S));
  1016. 's' : S:=IntToStrZ(D.Sec,length(S));
  1017. end;
  1018. DateS:=DateS+S;
  1019. end;
  1020. begin
  1021. DateS:='';
  1022. CurCharStart:=-1; CurCharCount:=0; CurChar:=#0;
  1023. for I:=1 to length(Format) do
  1024. begin
  1025. C:=Format[I];
  1026. if (C<>CurChar) or (CurCharStart=-1) then
  1027. begin
  1028. if CurCharStart<>-1 then FlushChars;
  1029. CurCharCount:=1; CurCharStart:=I;
  1030. end
  1031. else
  1032. Inc(CurCharCount);
  1033. CurChar:=C;
  1034. end;
  1035. FlushChars;
  1036. FormatDateTime:=DateS;
  1037. end;
  1038. function DeleteFile(const FileName: string): integer;
  1039. var f: file;
  1040. begin
  1041. {$I-}
  1042. Assign(f,FileName);
  1043. Erase(f);
  1044. DeleteFile:=EatIO;
  1045. {$I+}
  1046. end;
  1047. function ExistsFile(const FileName: string): boolean;
  1048. var
  1049. Dir : SearchRec;
  1050. begin
  1051. Dos.FindFirst(FileName,Archive+ReadOnly,Dir);
  1052. ExistsFile:=(Dos.DosError=0);
  1053. Dos.FindClose(Dir);
  1054. end;
  1055. { returns zero for empty and non existant files }
  1056. function SizeOfFile(const FileName: string): longint;
  1057. var
  1058. Dir : SearchRec;
  1059. begin
  1060. Dos.FindFirst(FileName,Archive+ReadOnly,Dir);
  1061. if (Dos.DosError=0) then
  1062. SizeOfFile:=Dir.Size
  1063. else
  1064. SizeOfFile:=0;
  1065. Dos.FindClose(Dir);
  1066. end;
  1067. function ExistsDir(const DirName: string): boolean;
  1068. var
  1069. Dir : SearchRec;
  1070. begin
  1071. Dos.FindFirst(TrimEndSlash(DirName),anyfile,Dir);
  1072. { if a file is found it is also reported
  1073. at least for some Dos version
  1074. so we need to check the attributes PM }
  1075. ExistsDir:=(Dos.DosError=0) and ((Dir.attr and Directory) <> 0);
  1076. Dos.FindClose(Dir);
  1077. end;
  1078. function CompleteDir(const Path: string): string;
  1079. begin
  1080. { keep c: untouched PM }
  1081. if (Path<>'') and (Path[Length(Path)]<>DirSep) and
  1082. (Path[Length(Path)]<>':') then
  1083. CompleteDir:=Path+DirSep
  1084. else
  1085. CompleteDir:=Path;
  1086. end;
  1087. function GetCurDir: string;
  1088. var S: string;
  1089. begin
  1090. GetDir(0,S);
  1091. if copy(S,length(S),1)<>DirSep then S:=S+DirSep;
  1092. GetCurDir:=S;
  1093. end;
  1094. function GenTempFileName: string;
  1095. var Dir: string;
  1096. Name: string;
  1097. I: integer;
  1098. OK: boolean;
  1099. Path: string;
  1100. begin
  1101. Dir:=GetEnv('TEMP');
  1102. if Dir='' then Dir:=GetEnv('TMP');
  1103. {$if defined(morphos) or defined(amiga)}
  1104. if Dir='' then Dir:='T:';
  1105. {$endif}
  1106. if (Dir<>'') then if not ExistsDir(Dir) then Dir:='';
  1107. if Dir='' then Dir:=GetCurDir;
  1108. repeat
  1109. Name:=TempFirstChar;
  1110. for I:=2 to TempNameLen do
  1111. Name:=Name+chr(ord('a')+random(ord('z')-ord('a')+1));
  1112. Name:=Name+TempExt;
  1113. Path:=CompleteDir(Dir)+Name;
  1114. OK:=not ExistsFile(Path);
  1115. until OK;
  1116. GenTempFileName:=Path;
  1117. end;
  1118. function CopyFile(const SrcFileName, DestFileName: string): boolean;
  1119. var SrcF,DestF: PBufStream;
  1120. OK: boolean;
  1121. begin
  1122. SrcF:=nil; DestF:=nil;
  1123. New(SrcF, Init(SrcFileName,stOpenRead,4096));
  1124. OK:=Assigned(SrcF) and (SrcF^.Status=stOK);
  1125. if OK then
  1126. begin
  1127. New(DestF, Init(DestFileName,stCreate,1024));
  1128. OK:=Assigned(DestF) and (DestF^.Status=stOK);
  1129. end;
  1130. if OK then DestF^.CopyFrom(SrcF^,SrcF^.GetSize);
  1131. if Assigned(DestF) then Dispose(DestF, Done);
  1132. if Assigned(SrcF) then Dispose(SrcF, Done);
  1133. CopyFile:=OK;
  1134. end;
  1135. procedure RegisterWUtils;
  1136. begin
  1137. {$ifndef NOOBJREG}
  1138. RegisterType(RUnsortedStringCollection);
  1139. {$endif}
  1140. end;
  1141. Procedure DebugMessage(AFileName, AText : string; ALine, APos : sw_word); // calls DebugMessage
  1142. begin
  1143. DebugMessageS(Afilename,AText,'','',aline,apos);
  1144. end;
  1145. Procedure WUtilsDebugMessage(AFileName, AText : string; ALine, APos : string;nrLine, nrPos : sw_word);
  1146. begin
  1147. writeln(stderr,AFileName,' (',ALine,',',APos,') ',AText);
  1148. flush(stderr);
  1149. end;
  1150. BEGIN
  1151. Randomize;
  1152. END.