wutils.pas 31 KB

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