filesys.pas 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093
  1. {
  2. $Id$
  3. Unit to access the file system
  4. All file operations except those on open files (see FileCtrl for that)
  5. Copyright by Marco Schmidt <[email protected]>
  6. This library is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU Library General Public
  8. License as published by the Free Software Foundation; either
  9. version 2 of the License, or (at your option) any later version.
  10. This library is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. Library General Public License for more details.
  14. You should have received a copy of the GNU Library General Public
  15. License along with this library; if not, write to the Free
  16. Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. ****************************************************************************}
  18. unit FileSys;
  19. interface
  20. {$I platform.inc} { Conditional directives :
  21. compiler, operating system }
  22. uses
  23. Common { Error handling }
  24. {$IFDEF PPC_FPC}
  25. , Strings
  26. {$ENDIF}
  27. {$IFDEF OS_DOS}
  28. , DOS { GetFAttr, GetFTime, FindFirst, FindNext, ... }
  29. {$else not OS_DOS}
  30. {$ifdef PPC_FPC}
  31. {$ifdef OS_WINDOWS}
  32. {$define OS_DOS}
  33. , DOS
  34. {$endif OS_WIN32}
  35. {$endif PPC_FPC}
  36. {$ENDIF}
  37. {$IFDEF OS_LINUX}
  38. , linux
  39. {$ENDIF}
  40. ;
  41. const
  42. { Maximum length of a file name (must be <= 255, for we use
  43. standard Pascal strings) }
  44. MaxNameLength = {$IFDEF PPC_BP}
  45. 79;
  46. {$ELSE}
  47. 255;
  48. {$ENDIF}
  49. { Character to separate directories in a path }
  50. PathSeparator = {$IFDEF OS_Linux}
  51. '/';
  52. {$ELSE}
  53. '\';
  54. {$ENDIF}
  55. { Defines if a character is inserted into a number string every three
  56. digits;
  57. true : returns "3,555,234"
  58. false : returns "3555234" }
  59. SeparateThousands : Boolean = true;
  60. { Character to be used to separate three digits in FileIntToString }
  61. ThousandsSeparator : Char = ',';
  62. { "CheckName" function return values }
  63. cnUnknown = 0;
  64. cnFile = 1;
  65. cnDirectory = 2;
  66. { File attribute bit masks }
  67. faReadOnly = $0001;
  68. faSystem = $0002;
  69. faHidden = $0004;
  70. faVolumeID = $0008;
  71. faDirectory = $0010;
  72. faArchive = $0020;
  73. faAnyFile = faReadOnly or
  74. faSystem or
  75. faHidden or
  76. faVolumeID or
  77. faDirectory or
  78. faArchive; { = $003f }
  79. { Wildcard characters for use with "ContainsWildcards" }
  80. NumWildcardChars = 2;
  81. WildcardChars : Array[0..NumWildcardChars-1] of Char =
  82. ('*', '?');
  83. type
  84. { file attribute type }
  85. TFileAttr = {$IFDEF PPC_BP}
  86. Word; { DOS: RSHVAD }
  87. {$ELSE}
  88. Longint; { Any other OS }
  89. {$ENDIF}
  90. { Stores date and time in a system-independent way }
  91. TDateTime = packed record
  92. DOW : Byte; { 0=Sunday, 1=Monday, ... }
  93. Day : Byte; { 1..31 }
  94. Month : Byte; { 1..12 }
  95. Year : Word; { 1601..3999 }
  96. IsLeap : Boolean; { is "Year" a leap year ? }
  97. Hour : Byte; { 0..23 }
  98. Minute : Byte; { 0..59 }
  99. Second : Byte; { 0..59 }
  100. Valid : Boolean; { set by "CheckDateTime" }
  101. end;
  102. { Stores file size & offset values;
  103. may have to be changed for other environments }
  104. TFileInt = Longint; { 32 bit signed, as we have no unsigned 32 bit type }
  105. { directory / file name }
  106. TFileName = String[MaxNameLength];
  107. { record to describe a file or directory entry;
  108. used in combination with a file search }
  109. TFileDescriptor = packed record
  110. { fields available for all platforms }
  111. Attr : TFileAttr;
  112. IsDirectory : Boolean;
  113. LastModification : TDateTime;
  114. Name : TFileName;
  115. Size : TFileInt;
  116. { platform-specific fields }
  117. {$IFDEF OS_LINUX}
  118. Created : TDateTime;
  119. LastAccessed : TDateTime;
  120. {$ENDIF OS_LINUX}
  121. end;
  122. { Search record declaration for FPC for DOS (we're not using the DOS unit
  123. that provides SearchRec) }
  124. {$IFDEF PPC_FPC}
  125. {$IFDEF OS_DOS}
  126. type
  127. TDOSSearchRec = packed record
  128. Fill: Array[1..21] of Byte;
  129. Attr: Byte;
  130. Time: Longint;
  131. Reserved: Word; { requires the DOS extender (DJ GNU-C) }
  132. Size: Longint;
  133. Name: String[15]; { the same size as declared by (DJ GNU C) }
  134. end;
  135. {$ENDIF OS_DOS}
  136. {$ENDIF PPC_FPC}
  137. { File search record to be used with
  138. StartSearch, ContinueSearch and TerminateSearch }
  139. TFileSearch = packed record
  140. { Input fields for all platforms }
  141. Specs : TFileName;
  142. { OS-specific input fields }
  143. {$IFDEF OS_DOS}
  144. Attr : TFileAttr;
  145. {$ENDIF}
  146. { Output fields for all platforms }
  147. FD : TFileDescriptor;
  148. Success : Boolean;
  149. { OS-specific output fields }
  150. {$IFDEF OS_Linux}
  151. GL : PGlob;
  152. {$ELSE OS_Linux}
  153. SR : DOS.SearchRec;
  154. {$ENDIF OS_Linux}
  155. end;
  156. procedure CheckDateTime(var DT: TDateTime);
  157. function CheckName(AName: TFileName): Byte;
  158. function ContainsWildcards(AName: TFileName): Boolean;
  159. procedure ContinueSearch(var FS: TFileSearch);
  160. procedure CreateDir(AName: TFileName);
  161. function DateToString(const DT: TDateTime): String;
  162. procedure DeleteDir(AName: TFileName);
  163. procedure DeleteFile(AName: TFileName);
  164. function EqualNames(Name1, Name2: TFileName): Boolean;
  165. function Exists(AName: TFileName): Boolean;
  166. function ExpandName(AName: TFileName): TFileName;
  167. function FileAttrToString(AFileAttr: TFileAttr): String;
  168. function FileIntToString(FI: TFileInt): String;
  169. function GetCurrentDir: TFileName;
  170. procedure GetFAttr(AName: TFileName; var Attr: TFileAttr);
  171. procedure GetFTime(AName: TFileName; var DT: TDateTime);
  172. function IsValidName(AName: TFileName) : Boolean;
  173. procedure RenameDir(OldName, NewName: TFileName);
  174. procedure RenameFile(OldName, NewName: TFileName);
  175. procedure SetCurrentDir(AName: TFileName);
  176. procedure SetFAttr(AName: TFileName; AFileAttr: TFileAttr);
  177. procedure SetFTime(AName: TFileName; DT: TDateTime);
  178. procedure SplitName(AName: TFileName; var Path, RawName, Extension: TFileName);
  179. procedure StartSearch(var FS: TFileSearch);
  180. procedure TerminateSearch(var FS: TFileSearch);
  181. function TimeToString(DT: TDateTime): String;
  182. implementation
  183. { Structure of the implementation section
  184. ---------------------------------------
  185. - proc. & functions that do not appear in the interface section and
  186. are the same for all platforms
  187. - proc. & functions that do appear in the interface section and
  188. are the same for all platforms
  189. - proc. & functions that do not appear in the interface section and
  190. are DOS-specific
  191. - proc. & functions that do appear in the interface section and
  192. are not the same for all platforms
  193. }
  194. { procedures and functions that do not appear in the interface section and
  195. are the same for all platforms }
  196. function weekday(y,m,d : longint) : longint;
  197. { Calculates th day of the week. Florian provided this.
  198. returns -1 on error }
  199. var
  200. century_offset : integer;
  201. temp : longint;
  202. _is_leap_year : boolean;
  203. const
  204. month_table : array[1..12] of longint = (1,4,4,0,2,5,0,3,6,1,4,6);
  205. function is_leap_year(y : longint) : boolean;
  206. begin
  207. if (y mod 100)=0 then
  208. is_leap_year:=((y mod 400)=0)
  209. else
  210. is_leap_year:=(y mod 4)=0;
  211. end;
  212. { Beginning of weekday }
  213. begin
  214. if (m<1) or (m>12) then
  215. begin
  216. weekday:=-1;
  217. exit;
  218. end;
  219. case y of
  220. 1700..1799 : century_offset:=4;
  221. 1800..1899 : century_offset:=2;
  222. 1900..1999 : century_offset:=0;
  223. 2000..2099 : century_offset:=-1;
  224. else
  225. begin
  226. if (y>=2100) then
  227. begin
  228. end;
  229. weekday:=-1;
  230. exit;
  231. end;
  232. end;
  233. _is_leap_year:=is_leap_year(y);
  234. y:=y mod 100;
  235. temp:=(y div 12)+(y mod 12)+((y mod 12) div 4);
  236. temp:=temp mod 7;
  237. temp:=(temp+month_table[m]+d) mod 7;
  238. { do some corrections for special years }
  239. { other century ? }
  240. inc(temp,century_offset);
  241. { leap year correction }
  242. if _is_leap_year and (m<3) then
  243. dec(temp);
  244. { now is sonday 1, but should be for example 0 }
  245. dec(temp);
  246. { the result could be less than zero }
  247. while temp<0 do
  248. inc(temp,7);
  249. weekday:=temp mod 7;
  250. end;
  251. { Returns Longint value as String }
  252. function LongToStr(L: Longint): String;
  253. var
  254. S: String[20];
  255. begin
  256. System.Str(L, S);
  257. LongToStr := S;
  258. end;
  259. { Returns Longint value as String, adding a leading '0' character if value
  260. is >= 0 and <= 9 (LZ = leading zero) }
  261. function LongToStrLZ(L: Longint): String;
  262. var
  263. Z: String[1];
  264. begin
  265. if (L >= 0) and (L <= 9)
  266. then Z := '0'
  267. else Z := '';
  268. LongToStrLZ := Z + LongToStr(L);
  269. end;
  270. { Procedures and functions that do appear in the interface section and are
  271. the same for all platforms }
  272. { Checks if date and time in "dt" is valid; also determines the day of the
  273. week }
  274. procedure CheckDateTime(var DT: TDateTime);
  275. const
  276. MonthLength : array[1..12] of Byte =
  277. (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
  278. begin
  279. DT.Valid := false;
  280. { check data that is within a fixed range }
  281. with DT do
  282. if (Hour < 0) or (Hour > 23) or
  283. (Minute < 0) or (Minute > 59) or
  284. (Second < 0) or (Second > 59) or
  285. (Month < 1) or (Month > 12) or
  286. (Day < 1) or
  287. (Year < 1600) or (Year > 3999)
  288. then exit;
  289. { determine if year is leap year }
  290. DT.IsLeap := ((dt.Year mod 4) = 0) and
  291. (not (((dt.Year mod 100) = 0) and
  292. ((dt.Year mod 400) <> 0)));
  293. { check if day is within limits }
  294. if ( DT.IsLeap and (dt.Month = 2) and (dt.Day > 29)) or
  295. ((not dt.IsLeap) and (dt.Day > MonthLength[dt.Month]))
  296. then exit;
  297. { date seems to be alright, compute day of the week
  298. (formula taken from DDJ 06/95 [#231], p.11) }
  299. if weekday (dt.year,dt.month,dt.day)<0 then
  300. dt.dow:=0
  301. else
  302. dt.dow:=weekday(dt.year,dt.month,dt.day);
  303. { Removed - caused segfault in linux. Michael.
  304. dt.DOW := (((( 3 * (dt.Year) - ( 7 * ((dt.Year) +
  305. ((dt.Month)+9) div 12)) div 4 +
  306. (23 * (dt.Month)) div 9 + (dt.Day) + 2 +
  307. (((dt.Year) - Ord ((dt.Month) < 3)) div 100 + 1)
  308. * 3 div 4 - 16 ) + 1 ) mod 7));
  309. }
  310. dt.Valid := true;
  311. end;
  312. { Returns if AName contains at least one of the characters from global
  313. constant WildcardChars }
  314. function ContainsWildcards(AName: TFileName): Boolean;
  315. var
  316. I, J: Longint;
  317. begin
  318. ContainsWildcards := false;
  319. if (Length(AName) = 0)
  320. then exit;
  321. { compare each character in AName with each character in WildCards }
  322. for I := 1 to Length (AName) do
  323. for J := 0 to NumWildcardChars-1 do
  324. if (AName[I] = WildcardChars[J])
  325. then begin
  326. ContainsWildcards := true;
  327. exit;
  328. end;
  329. end;
  330. { Returns date part of TDateTime as String : "Tue 29 Jul 1997" }
  331. function DateToString(const DT: TDateTime): String;
  332. const
  333. DOWNames : array[0..6] of String[3] =
  334. ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat');
  335. MonthNames : array[1..12] of String[3] =
  336. ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
  337. 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec');
  338. begin
  339. if DT.Valid
  340. then DateToString := DOWNames [dt.DOW] + ' ' +
  341. LongToStrLZ (dt.Day) + ' ' +
  342. MonthNames [dt.Month] + ' ' +
  343. LongToStr (dt.Year)
  344. else DateToString := '';
  345. end;
  346. { Returns if two names are considered equal for the file system }
  347. function EqualNames(Name1, Name2: TFileName): Boolean;
  348. {$IFDEF OS_DOS}
  349. var
  350. I: Byte;
  351. begin
  352. { case-insensitive comparision of strings }
  353. EqualNames := false;
  354. if (Length(Name1) <> Length(Name2)) or (Length(Name1) = 0)
  355. then exit;
  356. for I := 1 to Length(Name1) do
  357. if (Upcase(Name1[I]) <> Upcase(Name2[I]))
  358. then exit;
  359. EqualNames := true;
  360. end;
  361. {$ELSE}
  362. begin
  363. { case-sensitive comparision of strings }
  364. EqualNames := (Name1 = Name2);
  365. end;
  366. {$ENDIF}
  367. { Returns if name "AName" is in use (as file or directory) }
  368. function Exists(AName: TFileName): Boolean;
  369. begin
  370. Exists := (CheckName (AName) <> cnUnknown);
  371. end;
  372. { Splits AName into its path, raw name and extension; example:
  373. "c:\pp\fv\archive.zip" will be split into path "c:\pp\fv\",
  374. raw name "archive" and extension "zip" }
  375. procedure SplitName(AName: TFileName; var Path, RawName, Extension: TFileName);
  376. var
  377. HasDot, HasSeparator: Boolean;
  378. I, NameLength, DotOffset, SeparatorOffset: Longint;
  379. begin
  380. NameLength := Length(AName);
  381. Path := '';
  382. RawName := '';
  383. Extension := '';
  384. { search for last separator in name }
  385. SeparatorOffset := -1;
  386. HasSeparator := false;
  387. I := NameLength;
  388. while (I > 0) and (not HasSeparator) do begin
  389. if (AName[i] = PathSeparator)
  390. then begin
  391. HasSeparator := true;
  392. SeparatorOffset := I;
  393. end;
  394. Dec(I);
  395. end;
  396. if HasSeparator
  397. then begin
  398. Path := System.Copy(AName, 1, SeparatorOffset);
  399. SeparatorOffset := SeparatorOffset + 1;
  400. end
  401. else SeparatorOffset := 1;
  402. I := SeparatorOffset;
  403. { search for last dot in name (not in path /
  404. think of 'dir/files.old/filename') }
  405. HasDot := false;
  406. while (I <= NameLength) do begin
  407. if (AName[I] = '.')
  408. then begin
  409. HasDot := true;
  410. DotOffset := I;
  411. end;
  412. Inc(I);
  413. end;
  414. if HasDot
  415. then begin
  416. RawName := System.Copy (AName,
  417. SeparatorOffset,
  418. DotOffset-SeparatorOffset);
  419. Extension := System.Copy (AName,
  420. DotOffset + 1,
  421. NameLength - DotOffset);
  422. end
  423. else begin
  424. { no extension }
  425. RawName := System.Copy (AName,
  426. SeparatorOffset,
  427. NameLength - SeparatorOffset);
  428. end;
  429. end;
  430. { Returns time part of "DT" as "23:04:38" }
  431. function TimeToString(DT: TDateTime): String;
  432. begin
  433. if DT.Valid
  434. then TimeToString := LongToStrLZ(DT.Hour) + ':' +
  435. LongToStrLZ(DT.Minute) + ':' +
  436. LongToStrLZ(DT.Second)
  437. else TimeToString := '';
  438. end;
  439. {$IFDEF OS_DOS} { procedures & functions for the DOS platform }
  440. { Functions and procedures not declared in the interface section }
  441. { Returns date part of dt in DOS format, as unsigned 16 bit integer }
  442. procedure GetDOSDate(DT: TDateTime; var W: Word);
  443. begin
  444. W := (DT.Day and $1f) or
  445. ((DT.Month and $f) shl 5) or
  446. (((DT.Year - 1980) and $7f) shl 9);
  447. end;
  448. { Returns time part of DT in DOS format, as unsigned 16 bit integer }
  449. procedure GetDOSTime(DT: TDateTime; var W: Word);
  450. begin
  451. W := ((DT.Second shr 1) and $1f) or
  452. ((DT.Minute and $3f) shl 5) or
  453. ((DT.Hour and $1f) shl 11);
  454. end;
  455. { Returns date and time as 32 bit integer value (DOS time format) }
  456. procedure GetDOSDateTime(DT : TDateTime; var L: Longint);
  457. var
  458. W: Word;
  459. begin
  460. GetDOSTime(DT, W);
  461. L := W;
  462. GetDOSDate(DT, W);
  463. L := L + (W * 65536); { shifting by 16 doesn't work everywhere ... }
  464. end;
  465. { Sets date part of DT to W }
  466. procedure SetDOSDate(W: Word; var DT: TDateTime);
  467. begin
  468. DT.Day := W and $1f;
  469. DT.Month := (W shr 5) and $f;
  470. DT.Year := 1980 + (W shr 9) and $7f;
  471. end;
  472. { Sets time part of DT to W }
  473. procedure SetDOSTime(W: Word; var DT: TDateTime);
  474. begin
  475. DT.Second := (W and $1f) shl 1;
  476. DT.Minute := (W shr 5) and $3f;
  477. DT.Hour := (W shr 11) and $1f;
  478. end;
  479. { Sets DT to data from L }
  480. procedure SetDOSDateTime(L: Longint; var DT: TDateTime);
  481. begin
  482. SetDOSTime(L mod 65536, DT);
  483. SetDOSDate(L div 65536, DT);
  484. end;
  485. { Converts DOS.SearchRec to TFileDesciptor }
  486. procedure SearchRecToFileDescriptor ( SR: DOS.SearchRec;
  487. var FD: TFileDescriptor);
  488. begin
  489. FD.Name := SR.Name;
  490. FD.Attr := SR.Attr;
  491. FD.Size := SR.Size;
  492. FD.IsDirectory := ((SR.Attr and faDirectory) <> 0);
  493. SetDOSDateTime(SR.Time, FD.LastModification);
  494. CheckDateTime(FD.LastModification);
  495. end;
  496. {$ENDIF} { OS_DOS }
  497. {$IFDEF OS_LINUX}
  498. { Functions and procedures not decalred in interface section,
  499. Linux operating system }
  500. Procedure EpochToDateTime (Epoch : Longint; var DT : TDateTime);
  501. { Returns a Checked datetime, starting from a Unix epoch-style time }
  502. var y,m,d,h,mi,s : integer; { needed because of call by var }
  503. begin
  504. Linux.EpochToLocal(Epoch,Y,M,D,h,mi,s);
  505. DT.Year :=y;
  506. DT.Month :=m;
  507. DT.Day :=d;
  508. DT.Hour :=h;
  509. DT.Minute :=mi;
  510. DT.Second :=s;
  511. CheckDateTime (DT);
  512. end;
  513. Procedure StatToFileDescriptor (Info : Stat; Var Fd : TFileDescriptor);
  514. {Starting from a stat record, returns a TFileDescriptor record.
  515. Name is not filled in !}
  516. begin
  517. Fd.Attr:=Info.Mode;
  518. Fd.IsDirectory:=S_ISDIR(Info.mode);
  519. EpochToDateTime(Info.Mtime,Fd.LastModification);
  520. EpochToDateTime(Info.Atime,Fd.LastAccessed);
  521. EpochToDateTime(Info.Ctime,Fd.Created);
  522. Fd.Size:=Info.size;
  523. end;
  524. {$ENDIF} {OS_LINUX}
  525. { Functions and procedures declared in the interface section }
  526. { Returns type of name as cnXXXX constant (unknown, file, directory) }
  527. function CheckName(AName: TFileName): Byte;
  528. var
  529. FS: TFileSearch;
  530. begin
  531. FS.Specs := AName;
  532. {$IFDEF OS_DOS}
  533. FS.Attr := faAnyFile;
  534. {$ENDIF}
  535. StartSearch(fs);
  536. if FS.Success
  537. then begin
  538. if FS.FD.IsDirectory
  539. then CheckName := cnDirectory
  540. else CheckName := cnFile;
  541. end
  542. else CheckName := cnUnknown;
  543. TerminateSearch(FS);
  544. end;
  545. { Continues a file search started by StartSearch }
  546. procedure ContinueSearch(var FS: TFileSearch);
  547. {$IFDEF OS_Linux}
  548. Var g : PGLob;
  549. info : stat;
  550. begin
  551. if Not FS.Success then exit;
  552. FS.Success:=False;
  553. if FS.GL=nil then exit; { Paranoia setting }
  554. g:=FS.GL;
  555. FS.GL:=FS.GL^.NEXT;
  556. strdispose(g^.name);
  557. dispose (g);
  558. If FS.GL=Nil then exit;
  559. linux.fstat(strpas(FS.GL^.Name),info);
  560. if linuxerror<>0 then
  561. begin
  562. StatToFileDescriptor (info,FS.FD);
  563. FS.FD.Name:=strpas(FS.GL^.Name);
  564. FS.Success:=True;
  565. end;
  566. end;
  567. {$ELSE OS_Linux}
  568. begin
  569. if fs.Success
  570. then begin
  571. DOS.FindNext(FS.SR);
  572. FS.Success := (DOS.DOSError = 0);
  573. if FS.Success
  574. then SearchRecToFileDescriptor(fs.sr, fs.fd);
  575. end;
  576. end;
  577. {$ENDIF OS_Linux}
  578. { Create a new subdirectory AName }
  579. procedure CreateDir(AName : TFileName);
  580. begin
  581. {$I-}
  582. System.MkDir(AName);
  583. {$I+}
  584. ErrorCode := System.IOResult;
  585. end;
  586. { Deletes the directory AName }
  587. procedure DeleteDir(AName : TFileName);
  588. begin
  589. {$I-}
  590. System.RmDir(AName);
  591. {$I+}
  592. ErrorCode := System.IOResult;
  593. end;
  594. { Deletes the file AName }
  595. procedure DeleteFile(AName: TFileName);
  596. var
  597. F: file;
  598. begin
  599. Assign(F, AName);
  600. {$I-}
  601. System.Erase(F);
  602. {$I+}
  603. ErrorCode := System.IOResult;
  604. end;
  605. { Returns the full version of AName }
  606. function ExpandName(AName : TFileName): TFileName;
  607. begin
  608. {$IFDEF OS_LINUX}
  609. ExpandName := Linux.FExpand(AName);
  610. {$ELSE}
  611. ExpandName := DOS.FExpand(AName);
  612. {$ENDIF}
  613. end;
  614. { Returns a string version of AFileAttr; OS-dependent }
  615. function FileAttrToString(AFileAttr: TFileAttr): String;
  616. {$IFDEF OS_DOS}
  617. { Volume Label and Directory are not regarded }
  618. const
  619. NumChars = 4;
  620. AttrChars: String[NumChars] = 'RSHA';
  621. AttrMasks: Array[0..NumChars-1] of Word = (1, 2, 4, 32);
  622. var
  623. I: Word;
  624. S: String[NumChars];
  625. begin
  626. s[0] := Chr(NumChars);
  627. for I := 1 to NumChars do begin
  628. if ((AFileAttr and AttrMasks[i-1]) = 0)
  629. then S[I] := '.'
  630. else S[I] := AttrChars[i];
  631. end;
  632. FileAttrToString := S;
  633. end;
  634. {$ELSE OS_DOS}
  635. {$IFDEF OS_LINUX}
  636. var temp : string[9];
  637. i : longint;
  638. const
  639. full = 'rwxrwxrwx';
  640. begin
  641. temp:='---------';
  642. for i:=0 to 8 do
  643. if (AFileAttr and (1 shl i))=(1 shl I) then temp[9-i]:=full[9-i];
  644. FileAttrToString := Temp;
  645. end;
  646. {$ELSE OS_LINUX}
  647. begin
  648. FileAttrToString:='';
  649. end;
  650. {$ENDIF OS_LINUX}
  651. {$ENDIF OS_DOS}
  652. { Returns a string version of the file integer value fi }
  653. function FileIntToString(fi: TFileInt): String;
  654. var
  655. S: String[14]; { maximum is "-2,147,483,648" }
  656. I: Integer; { must be signed ! }
  657. begin
  658. Str(fi, S);
  659. if SeparateThousands
  660. then begin
  661. I := System.Length(S) - 2;
  662. while (I > 1) and (not (I = 2) and (s[1] = '-')) do begin
  663. System.Insert (ThousandsSeparator, S, I);
  664. Dec(I, 3);
  665. end;
  666. end;
  667. FileIntToString := S;
  668. end;
  669. { Returns the currently set directory }
  670. function GetCurrentDir: TFileName;
  671. {$IFDEF PPC_BP}
  672. var
  673. I: Byte;
  674. R: DOS.Registers;
  675. S: TFileName;
  676. begin
  677. { to get a full name, we have to get the drive letter ourselves }
  678. { get current drive letter first }
  679. R.AH := $19;
  680. DOS.MsDos(R);
  681. S[1] := Chr(Ord('A') + R.AL);
  682. S[2] := ':';
  683. S[3] := '\';
  684. { get current directory }
  685. R.AH := $47;
  686. R.DL := $00;
  687. R.DS := Seg(S[4]);
  688. R.SI := Ofs(S[4]);
  689. DOS.MsDos (r);
  690. if ((R.Flags and FCarry) <> 0)
  691. then begin
  692. { error }
  693. end;
  694. { determine length of current directory }
  695. I := 4;
  696. while (S[I] <> #0) and (I < MaxNameLength) do
  697. Inc(I);
  698. S[0] := Chr(I - 1);
  699. GetCurrentDir := S;
  700. end;
  701. {$ELSE}
  702. var
  703. S: TFileName;
  704. begin
  705. System.GetDir(0, S);
  706. GetCurrentDir := S;
  707. end;
  708. {$ENDIF}
  709. { Gets attribute of AName }
  710. procedure GetFAttr(AName: TFileName; var Attr: TFileAttr);
  711. {$IFDEF OS_DOS}
  712. var
  713. F: file;
  714. W: word;
  715. begin
  716. Assign(F, AName);
  717. {$I-}
  718. DOS.GetFAttr(F, W);
  719. Attr:=W;
  720. {$I+}
  721. ErrorCode := DOS.DOSError;
  722. end;
  723. {$ELSE}
  724. {$IFDEF OS_LINUX}
  725. var
  726. info : stat;
  727. begin
  728. Linux.FStat (AName,Info);
  729. ErrorCode:=LinuxError;
  730. if ErrorCode<>0 then exit;
  731. Attr:=Info.Mode;
  732. end;
  733. {$ELSE}
  734. begin
  735. end;
  736. {$ENDIF}
  737. {$ENDIF}
  738. { Gets date and time of last modification of AName }
  739. procedure GetFTime(AName: TFileName; var DT: TDateTime);
  740. {$IFDEF OS_DOS}
  741. var
  742. F: file;
  743. L: Longint;
  744. begin
  745. DT.Valid := false;
  746. { open file }
  747. Assign(F, AName);
  748. {$I-}
  749. Reset(F);
  750. {$I+}
  751. ErrorCode := System.IOResult;
  752. if (ErrorCode <> errOK)
  753. then exit;
  754. { get date/time of last modification in DOS format }
  755. {$I-}
  756. DOS.GetFTime(F, L);
  757. {$I+}
  758. ErrorCode := DOS.DOSError;
  759. if (ErrorCode <> errOK)
  760. then exit;
  761. { close file }
  762. {$I-}
  763. Close(F);
  764. {$I+}
  765. ErrorCode := System.IOResult;
  766. { convert date/time L to TDateTime format }
  767. GetDOSDateTime(DT, L);
  768. CheckDateTime(DT);
  769. end;
  770. {$ELSE}
  771. {$IFDEF OS_LINUX}
  772. var info : Stat;
  773. begin
  774. Linux.FStat (AName,Info);
  775. ErrorCode:=LinuxError;
  776. if ErrorCode<>0 then exit;
  777. EpochToDateTime (info.mtime,DT);
  778. end;
  779. {$ELSE}
  780. begin
  781. end;
  782. {$ENDIF}
  783. {$ENDIF}
  784. { Returns if AName is a valid file name (not if it actually exists) }
  785. function IsValidName(AName: TFileName): Boolean;
  786. {$IFDEF OS_DOS}
  787. { isn't ready yet }
  788. { Returns if a name (without a path) is valid }
  789. function ValidName(S: TFileName): Boolean;
  790. var
  791. I: Byte;
  792. begin
  793. ValidName := false;
  794. if (Length(S) > 12)
  795. then exit;
  796. I := Pos('.', S);
  797. ValidName := true;
  798. end;
  799. const
  800. InvalidChars: String[2] = '*?';
  801. var
  802. I, J: Longint;
  803. P, R, E: TFileName;
  804. begin
  805. IsValidName := false;
  806. { check for invalid characters }
  807. for I := 1 to Length(AName) do
  808. for J := 1 to Length(InvalidChars) do
  809. if (AName[I] = InvalidChars[J])
  810. then exit;
  811. SplitName(AName, P, R, E);
  812. if (Length(R) > 0) or (Length(E) > 0)
  813. then begin
  814. if (not ValidName(R + E))
  815. then exit;
  816. end;
  817. IsValidName := true;
  818. end;
  819. {$ELSE}
  820. {$IFDEF OS_LINUX}
  821. begin
  822. IsVAlidName:=((pos('?',AName)=0) and (pos('*',AName)=0))
  823. end;
  824. {$ELSE}
  825. begin
  826. IsValidName:=True;
  827. end;
  828. {$ENDIF}
  829. {$ENDIF}
  830. { Renames directory from OldName to NewName }
  831. procedure RenameDir(OldName, NewName : TFileName);
  832. begin
  833. { for DOS, renaming files and directories should be the same ... }
  834. RenameFile(OldName, NewName);
  835. end;
  836. { Renames file from OldName to NewName }
  837. procedure RenameFile(OldName, NewName : TFileName);
  838. var
  839. F: file;
  840. begin
  841. Assign(F, OldName);
  842. {$I-}
  843. System.Rename(F, NewName);
  844. {$I+}
  845. ErrorCode := IOResult;
  846. end;
  847. { Sets current directory to AName }
  848. procedure SetCurrentDir(AName : TFileName);
  849. begin
  850. {$I-}
  851. System.ChDir(AName);
  852. {$I+}
  853. ErrorCode := IOResult;
  854. end;
  855. { Sets attribute of file AName to AFileAttr }
  856. procedure SetFAttr(AName: TFileName; AFileAttr: TFileAttr);
  857. {$IFDEF OS_DOS}
  858. var
  859. F: file;
  860. begin
  861. Assign(F, AName);
  862. {$I-}
  863. DOS.SetFAttr(F, AFileAttr);
  864. {$I+}
  865. ErrorCode := DOS.DOSError;
  866. end;
  867. {$ELSE}
  868. {$IFDEF OS_LINUX}
  869. begin
  870. Linux.Chmod (Aname,AFileAttr);
  871. ErrorCode:=LinuxError;
  872. end;
  873. {$ELSE}
  874. begin
  875. end;
  876. {$ENDIF}
  877. {$ENDIF}
  878. { Sets date and time of last modification of file AName to dt }
  879. procedure SetFTime(AName: TFileName; DT: TDateTime);
  880. {$IFDEF OS_DOS}
  881. var
  882. F: file;
  883. L: Longint;
  884. begin
  885. GetDOSDateTime(DT, L);
  886. Assign(f, AName);
  887. {$I-}
  888. DOS.SetFTime(F, L);
  889. {$I+}
  890. ErrorCode := DOS.DOSError;
  891. end;
  892. {$ELSE}
  893. {$IFDEF OS_LINUX}
  894. var
  895. utim : utimebuf;
  896. begin
  897. utim.actime:=LocalToEpoch(DT.Year,DT.Month,DT.Day,DT.Hour,DT.Minute,DT.second);
  898. utim.modtime:=utim.actime;
  899. utime (AName,utim);
  900. ErrorCode:=linuxerror
  901. end;
  902. {$ELSE}
  903. begin
  904. end;
  905. {$ENDIF}
  906. {$ENDIF}
  907. { Starts a file search, using input data from fs }
  908. procedure StartSearch(var FS: TFileSearch);
  909. {$IFDEF OS_Linux}
  910. var
  911. info : stat;
  912. begin
  913. FS.Success:=False;
  914. FS.GL:=Linux.Glob(FS.Specs);
  915. if FS.GL=nil then exit;
  916. linux.fstat(strpas(FS.GL^.Name),info);
  917. if linuxerror=0 then
  918. begin
  919. StatToFileDescriptor (info,FS.FD);
  920. FS.FD.Name:=strpas(FS.GL^.Name);
  921. FS.Success:=True;
  922. end;
  923. end;
  924. {$ELSE OS_Linux}
  925. { this version works for every platform/os/bits combination that has a
  926. working DOS unit : BP/FPC/Virtual Pascal }
  927. begin
  928. DOS.FindFirst(fs.Specs, fs.Attr, fs.sr);
  929. fs.Success := (DOS.DOSError = 0);
  930. if fs.Success
  931. then SearchRecToFileDescriptor(FS.SR, FS.FD);
  932. end;
  933. {$ENDIF OS_Linux}
  934. { Terminates a file search }
  935. procedure TerminateSearch (var FS: TFileSearch);
  936. begin
  937. {$IFDEF OS_LINUX}
  938. GlobFree (FS.GL);
  939. {$ELSE}
  940. {$IFNDEF PPC_BP}
  941. DOS.FindClose(fs.sr);
  942. {$ENDIF}
  943. {$ENDIF}
  944. end;
  945. { Unit initialization }
  946. begin
  947. { Empty, though we could retrieve the thousands separator and
  948. date/time formats here (in case the OS supports that) }
  949. end.
  950. {
  951. $Log$
  952. Revision 1.1 2000-01-06 01:20:31 peter
  953. * moved out of packages/ back to topdir
  954. Revision 1.1 1999/12/23 19:36:47 peter
  955. * place unitfiles in target dirs
  956. Revision 1.1 1999/11/24 23:36:37 peter
  957. * moved to packages dir
  958. Revision 1.4 1999/05/17 13:55:18 pierre
  959. * FPC win32 also need dos unit
  960. Revision 1.3 1999/04/13 09:25:47 daniel
  961. * Reverted a terrible mistake
  962. Revision 1.1 1998/12/04 12:48:24 peter
  963. * moved some dirs
  964. Revision 1.5 1998/10/26 11:22:50 peter
  965. * updates
  966. ? 0.1 marco Initial implementation
  967. ? Several fixes ...
  968. 08/29/1997 0.4 marco Some platform adjustments
  969. 09/16/1997 0.4.1 marco Added "EqualNames"
  970. 09/17/1997 0.5 michael Implemented linux part.
  971. 09/20/1997 0.5.1 marco Added LastAccessed/Created to Linux part of
  972. file descriptor
  973. 04/15/1998 0.5.2 michael Updated linux part.
  974. }