wutils.pas 32 KB

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