filesys.pas 27 KB

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