sysutils.pp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2014 by Free Pascal development team
  4. Sysutils unit for AmigaOS & clones
  5. Based on Amiga 1.x version by Carl Eric Codere, and other
  6. parts of the RTL
  7. AmigaOS and MorphOS support by Karoly Balogh
  8. AROS support by Marcus Sackrow
  9. See the file COPYING.FPC, included in this distribution,
  10. for details about the copyright.
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  14. **********************************************************************}
  15. unit sysutils;
  16. interface
  17. {$MODE objfpc}
  18. {$MODESWITCH OUT}
  19. { force ansistrings }
  20. {$H+}
  21. {$DEFINE OS_FILESETDATEBYNAME}
  22. {$DEFINE HAS_SLEEP}
  23. {$DEFINE HAS_OSERROR}
  24. { used OS file system APIs use ansistring }
  25. {$define SYSUTILS_HAS_ANSISTR_FILEUTIL_IMPL}
  26. { OS has an ansistring/single byte environment variable API }
  27. {$define SYSUTILS_HAS_ANSISTR_ENVVAR_IMPL}
  28. { Include platform independent interface part }
  29. {$i sysutilh.inc}
  30. { Platform dependent calls }
  31. function DeviceByIdx(Idx: Integer): string;
  32. function AddDisk(Const Path: string): Integer;
  33. function RefreshDeviceList: Integer;
  34. function DiskSize(Drive: AnsiString): Int64;
  35. function DiskFree(Drive: AnsiString): Int64;
  36. implementation
  37. uses
  38. dos, sysconst;
  39. {$DEFINE FPC_FEXPAND_VOLUMES} (* Full paths begin with drive specification *)
  40. {$DEFINE FPC_FEXPAND_DRIVESEP_IS_ROOT}
  41. {$DEFINE FPC_FEXPAND_NO_DEFAULT_PATHS}
  42. { Include platform independent implementation part }
  43. {$i sysutils.inc}
  44. { * Include sytem specific includes * }
  45. {$include execd.inc}
  46. {$include execf.inc}
  47. {$include timerd.inc}
  48. {$include doslibd.inc}
  49. {$include doslibf.inc}
  50. {$include utilf.inc}
  51. { * Followings are implemented in the system unit! * }
  52. function PathConv(path: shortstring): shortstring; external name 'PATHCONV';
  53. function PathConv(path: RawByteString): RawByteString; external name 'PATHCONVRBS';
  54. procedure AddToList(var l: Pointer; h: LongInt); external name 'ADDTOLIST';
  55. function RemoveFromList(var l: Pointer; h: LongInt): boolean; external name 'REMOVEFROMLIST';
  56. function CheckInList(var l: Pointer; h: LongInt): pointer; external name 'CHECKINLIST';
  57. var
  58. ASYS_FileList: Pointer; external name 'ASYS_FILELIST';
  59. function BADDR(bval: LongInt): Pointer; Inline;
  60. begin
  61. {$if defined(AROS) and (not defined(AROS_FLAVOUR_BINCOMPAT))}
  62. BADDR := Pointer(bval);
  63. {$else}
  64. BADDR:=Pointer(bval Shl 2);
  65. {$endif}
  66. end;
  67. function BSTR2STRING(s : Pointer): PChar; Inline;
  68. begin
  69. {$if defined(AROS) and (not defined(AROS_FLAVOUR_BINCOMPAT))}
  70. BSTR2STRING:=PChar(s);
  71. {$else}
  72. BSTR2STRING:=PChar(BADDR(PtrInt(s)))+1;
  73. {$endif}
  74. end;
  75. function BSTR2STRING(s : LongInt): PChar; Inline;
  76. begin
  77. {$if defined(AROS) and (not defined(AROS_FLAVOUR_BINCOMPAT))}
  78. BSTR2STRING:=PChar(s);
  79. {$else}
  80. BSTR2STRING:=PChar(BADDR(s))+1;
  81. {$endif}
  82. end;
  83. function AmigaFileDateToDateTime(aDate: TDateStamp; out success: boolean): TDateTime;
  84. var
  85. tmpSecs: DWord;
  86. tmpDate: TDateTime;
  87. tmpTime: TDateTime;
  88. clockData: TClockData;
  89. begin
  90. with aDate do
  91. tmpSecs:=(ds_Days * (24 * 60 * 60)) + (ds_Minute * 60) + (ds_Tick div TICKS_PER_SECOND);
  92. Amiga2Date(tmpSecs,@clockData);
  93. {$HINT TODO: implement msec values, if possible}
  94. with clockData do begin
  95. success:=TryEncodeDate(year,month,mday,tmpDate) and
  96. TryEncodeTime(hour,min,sec,0,tmpTime);
  97. end;
  98. result:=ComposeDateTime(tmpDate,tmpTime);
  99. end;
  100. function DateTimeToAmigaDateStamp(dateTime: TDateTime): TDateStamp;
  101. var
  102. tmpSecs: DWord;
  103. clockData: TClockData;
  104. tmpMSec: Word;
  105. begin
  106. {$HINT TODO: implement msec values, if possible}
  107. with clockData do begin
  108. DecodeDate(dateTime,year,month,mday);
  109. DecodeTime(dateTime,hour,min,sec,tmpMSec);
  110. end;
  111. tmpSecs:=Date2Amiga(@clockData);
  112. with result do begin
  113. ds_Days:= tmpSecs div (24 * 60 * 60);
  114. ds_Minute:= (tmpSecs div 60) mod ds_Days;
  115. ds_Tick:= (((tmpSecs mod 60) mod ds_Minute) mod ds_Days) * TICKS_PER_SECOND;
  116. end;
  117. end;
  118. {****************************************************************************
  119. File Functions
  120. ****************************************************************************}
  121. {$I-}{ Required for correct usage of these routines }
  122. (****** non portable routines ******)
  123. function FileOpen(const FileName: rawbytestring; Mode: Integer): LongInt;
  124. var
  125. SystemFileName: RawByteString;
  126. dosResult: LongInt;
  127. begin
  128. SystemFileName:=PathConv(ToSingleByteFileSystemEncodedFileName(FileName));
  129. {$WARNING FIX ME! To do: FileOpen Access Modes}
  130. dosResult:=Open(PChar(SystemFileName),MODE_OLDFILE);
  131. if dosResult=0 then
  132. dosResult:=-1
  133. else
  134. AddToList(ASYS_fileList,dosResult);
  135. FileOpen:=dosResult;
  136. end;
  137. function FileGetDate(Handle: LongInt) : LongInt;
  138. var
  139. tmpFIB : PFileInfoBlock;
  140. tmpDateTime: TDateTime;
  141. validFile: boolean;
  142. begin
  143. validFile:=false;
  144. if (Handle <> 0) then begin
  145. new(tmpFIB);
  146. if ExamineFH(BPTR(Handle),tmpFIB) then begin
  147. tmpDateTime:=AmigaFileDateToDateTime(tmpFIB^.fib_Date,validFile);
  148. end;
  149. dispose(tmpFIB);
  150. end;
  151. if validFile then
  152. result:=DateTimeToFileDate(tmpDateTime)
  153. else
  154. result:=-1;
  155. end;
  156. function FileSetDate(Handle, Age: LongInt) : LongInt;
  157. var
  158. tmpDateStamp: TDateStamp;
  159. tmpName: array[0..255] of char;
  160. begin
  161. result:=0;
  162. if (Handle <> 0) then begin
  163. if NameFromFH(BPTR(Handle), @tmpName, 256) then begin
  164. tmpDateStamp:=DateTimeToAmigaDateStamp(FileDateToDateTime(Age));
  165. if not SetFileDate(@tmpName,@tmpDateStamp) then begin
  166. IoErr(); // dump the error code for now (TODO)
  167. result:=-1;
  168. end;
  169. end;
  170. end;
  171. end;
  172. function FileSetDate(const FileName: RawByteString; Age: LongInt) : LongInt;
  173. var
  174. tmpDateStamp: TDateStamp;
  175. SystemFileName: RawByteString;
  176. begin
  177. result:=0;
  178. SystemFileName:=PathConv(ToSingleByteFileSystemEncodedFileName(FileName));
  179. tmpDateStamp:=DateTimeToAmigaDateStamp(FileDateToDateTime(Age));
  180. if not SetFileDate(PChar(SystemFileName),@tmpDateStamp) then begin
  181. IoErr(); // dump the error code for now (TODO)
  182. result:=-1;
  183. end;
  184. end;
  185. function FileCreate(const FileName: RawByteString) : LongInt;
  186. var
  187. SystemFileName: RawByteString;
  188. dosResult: LongInt;
  189. begin
  190. dosResult:=-1;
  191. { Open file in MODDE_READWRITE, then truncate it by hand rather than
  192. opening it in MODE_NEWFILE, because that returns an exclusive lock
  193. so some operations might fail with it (KB) }
  194. SystemFileName:=PathConv(ToSingleByteFileSystemEncodedFileName(FileName));
  195. dosResult:=Open(PChar(SystemFileName),MODE_READWRITE);
  196. if dosResult = 0 then exit;
  197. if SetFileSize(dosResult, 0, OFFSET_BEGINNING) = 0 then
  198. AddToList(ASYS_fileList,dosResult)
  199. else begin
  200. dosClose(dosResult);
  201. dosResult:=-1;
  202. end;
  203. FileCreate:=dosResult;
  204. end;
  205. function FileCreate(const FileName: RawByteString; Rights: integer): LongInt;
  206. begin
  207. {$WARNING FIX ME! To do: FileCreate Access Modes}
  208. FileCreate:=FileCreate(FileName);
  209. end;
  210. function FileCreate(const FileName: RawByteString; ShareMode: integer; Rights : integer): LongInt;
  211. begin
  212. {$WARNING FIX ME! To do: FileCreate Access Modes}
  213. FileCreate:=FileCreate(FileName);
  214. end;
  215. function FileRead(Handle: LongInt; out Buffer; Count: LongInt): LongInt;
  216. begin
  217. FileRead:=-1;
  218. if (Count<=0) or (Handle=0) or (Handle=-1) then exit;
  219. FileRead:=dosRead(Handle,@Buffer,Count);
  220. end;
  221. function FileWrite(Handle: LongInt; const Buffer; Count: LongInt): LongInt;
  222. begin
  223. FileWrite:=-1;
  224. if (Count<=0) or (Handle=0) or (Handle=-1) then exit;
  225. FileWrite:=dosWrite(Handle,@Buffer,Count);
  226. end;
  227. function FileSeek(Handle, FOffset, Origin: LongInt) : LongInt;
  228. var
  229. seekMode: LongInt;
  230. begin
  231. FileSeek:=-1;
  232. if (Handle=0) or (Handle=-1) then exit;
  233. case Origin of
  234. fsFromBeginning: seekMode:=OFFSET_BEGINNING;
  235. fsFromCurrent : seekMode:=OFFSET_CURRENT;
  236. fsFromEnd : seekMode:=OFFSET_END;
  237. end;
  238. dosSeek(Handle, FOffset, seekMode);
  239. { get the current position when FileSeek ends, which should return
  240. the *NEW* position, while Amiga Seek() returns the old one }
  241. FileSeek:=dosSeek(Handle, 0, OFFSET_CURRENT);
  242. end;
  243. function FileSeek(Handle: LongInt; FOffset: Int64; Origin: Longint): Int64;
  244. begin
  245. {$WARNING Need to add 64bit call }
  246. FileSeek:=FileSeek(Handle,LongInt(FOffset),LongInt(Origin));
  247. end;
  248. procedure FileClose(Handle: LongInt);
  249. begin
  250. if (Handle=0) or (Handle=-1) then exit;
  251. dosClose(Handle);
  252. RemoveFromList(ASYS_fileList,Handle);
  253. end;
  254. function FileTruncate(Handle: THandle; Size: Int64): Boolean;
  255. var
  256. dosResult: LongInt;
  257. begin
  258. FileTruncate:=False;
  259. if Size > high (longint) then exit;
  260. {$WARNING Possible support for 64-bit FS to be checked!}
  261. if (Handle=0) or (Handle=-1) then exit;
  262. dosResult:=SetFileSize(Handle, Size, OFFSET_BEGINNING);
  263. if (dosResult<0) then exit;
  264. FileTruncate:=True;
  265. end;
  266. function DeleteFile(const FileName: RawByteString) : Boolean;
  267. var
  268. SystemFileName: RawByteString;
  269. begin
  270. SystemFileName:=PathConv(ToSingleByteFileSystemEncodedFileName(FileName));
  271. DeleteFile:=dosDeleteFile(PChar(SystemFileName));
  272. end;
  273. function RenameFile(const OldName, NewName: RawByteString): Boolean;
  274. var
  275. OldSystemFileName, NewSystemFileName: RawByteString;
  276. begin
  277. OldSystemFileName:=PathConv(ToSingleByteFileSystemEncodedFileName(OldName));
  278. NewSystemFileName:=PathConv(ToSingleByteFileSystemEncodedFileName(NewName));
  279. RenameFile:=dosRename(PChar(OldSystemFileName), PChar(NewSystemFileName)) <> 0;
  280. end;
  281. (****** end of non portable routines ******)
  282. function FileAge (const FileName : RawByteString): Longint;
  283. var
  284. tmpLock: Longint;
  285. tmpFIB : PFileInfoBlock;
  286. tmpDateTime: TDateTime;
  287. validFile: boolean;
  288. SystemFileName: RawByteString;
  289. begin
  290. validFile:=false;
  291. SystemFileName := PathConv(ToSingleByteFileSystemEncodedFileName(FileName));
  292. tmpLock := Lock(PChar(SystemFileName), SHARED_LOCK);
  293. if (tmpLock <> 0) then begin
  294. new(tmpFIB);
  295. if Examine(tmpLock,tmpFIB) <> 0 then begin
  296. tmpDateTime:=AmigaFileDateToDateTime(tmpFIB^.fib_Date,validFile);
  297. end;
  298. Unlock(tmpLock);
  299. dispose(tmpFIB);
  300. end;
  301. if validFile then
  302. result:=DateTimeToFileDate(tmpDateTime)
  303. else
  304. result:=-1;
  305. end;
  306. function FileExists (const FileName : RawByteString) : Boolean;
  307. var
  308. tmpLock: LongInt;
  309. tmpFIB : PFileInfoBlock;
  310. SystemFileName: RawByteString;
  311. begin
  312. result:=false;
  313. SystemFileName := PathConv(ToSingleByteFileSystemEncodedFileName(FileName));
  314. tmpLock := Lock(PChar(SystemFileName), SHARED_LOCK);
  315. if (tmpLock <> 0) then begin
  316. new(tmpFIB);
  317. if (Examine(tmpLock,tmpFIB) <> 0) and (tmpFIB^.fib_DirEntryType <= 0) then
  318. result:=true;
  319. Unlock(tmpLock);
  320. dispose(tmpFIB);
  321. end;
  322. end;
  323. Function InternalFindFirst (Const Path : RawByteString; Attr : Longint; out Rslt : TAbstractSearchRec; var Name: RawByteString) : Longint;
  324. var
  325. tmpStr: RawByteString;
  326. Anchor: PAnchorPath;
  327. tmpDateTime: TDateTime;
  328. validDate: boolean;
  329. begin
  330. result:=-1; { We emulate Linux/Unix behaviour, and return -1 on errors. }
  331. tmpStr:=PathConv(ToSingleByteFileSystemEncodedFileName(Path));
  332. { $1e = faHidden or faSysFile or faVolumeID or faDirectory }
  333. Rslt.ExcludeAttr := (not Attr) and ($1e);
  334. Rslt.FindHandle := 0;
  335. new(Anchor);
  336. FillChar(Anchor^,sizeof(TAnchorPath),#0);
  337. if MatchFirst(pchar(tmpStr),Anchor)<>0 then exit;
  338. Rslt.FindHandle := longint(Anchor);
  339. with Anchor^.ap_Info do begin
  340. Name := fib_FileName;
  341. SetCodePage(Name,DefaultFileSystemCodePage,false);
  342. Rslt.Size := fib_Size;
  343. Rslt.Time := DateTimeToFileDate(AmigaFileDateToDateTime(fib_Date,validDate));
  344. if not validDate then exit;
  345. { "128" is Windows "NORMALFILE" attribute. Some buggy code depend on this... :( (KB) }
  346. Rslt.Attr := 128;
  347. if fib_DirEntryType > 0 then Rslt.Attr:=Rslt.Attr or faDirectory;
  348. if ((fib_Protection and FIBF_READ) <> 0) and
  349. ((fib_Protection and FIBF_WRITE) = 0) then Rslt.Attr:=Rslt.Attr or faReadOnly;
  350. result:=0; { Return zero if everything went OK }
  351. end;
  352. end;
  353. Function InternalFindNext (var Rslt : TAbstractSearchRec; var Name : RawByteString) : Longint;
  354. var
  355. Anchor: PAnchorPath;
  356. validDate: boolean;
  357. begin
  358. result:=-1;
  359. Anchor:=PAnchorPath(Rslt.FindHandle);
  360. if not assigned(Anchor) then exit;
  361. if MatchNext(Anchor) <> 0 then exit;
  362. with Anchor^.ap_Info do begin
  363. Name := fib_FileName;
  364. SetCodePage(Name,DefaultFileSystemCodePage,false);
  365. Rslt.Size := fib_Size;
  366. Rslt.Time := DateTimeToFileDate(AmigaFileDateToDateTime(fib_Date,validDate));
  367. if not validDate then exit;
  368. { "128" is Windows "NORMALFILE" attribute. Some buggy code depend on this... :( (KB) }
  369. Rslt.Attr := 128;
  370. if fib_DirEntryType > 0 then Rslt.Attr:=Rslt.Attr or faDirectory;
  371. if ((fib_Protection and FIBF_READ) <> 0) and
  372. ((fib_Protection and FIBF_WRITE) = 0) then Rslt.Attr:=Rslt.Attr or faReadOnly;
  373. result:=0; { Return zero if everything went OK }
  374. end;
  375. end;
  376. Procedure InternalFindClose(var Handle: THandle);
  377. var
  378. Anchor: PAnchorPath;
  379. begin
  380. Anchor:=PAnchorPath(Handle);
  381. if not assigned(Anchor) then exit;
  382. MatchEnd(Anchor);
  383. Dispose(Anchor);
  384. Handle:=THandle(nil);
  385. end;
  386. (****** end of non portable routines ******)
  387. Function FileGetAttr (Const FileName : RawByteString) : Longint;
  388. var
  389. F: file;
  390. attr: word;
  391. begin
  392. Assign(F,FileName);
  393. dos.GetFAttr(F,attr);
  394. if DosError <> 0 then
  395. FileGetAttr := -1
  396. else
  397. FileGetAttr := Attr;
  398. end;
  399. Function FileSetAttr (Const Filename : RawByteString; Attr: longint) : Longint;
  400. var
  401. F: file;
  402. begin
  403. Assign(F, FileName);
  404. Dos.SetFAttr(F, Attr and $ffff);
  405. FileSetAttr := DosError;
  406. end;
  407. {****************************************************************************
  408. Disk Functions
  409. ****************************************************************************}
  410. {
  411. The Diskfree and Disksize functions need a file on the specified drive, since this
  412. is required for the statfs system call.
  413. These filenames are set in drivestr[0..26], and have been preset to :
  414. 0 - ':' (default drive - hence current dir is ok.)
  415. 1 - 'DF0:' (floppy drive 1 - should be adapted to local system )
  416. 2 - 'DF1:' (floppy drive 2 - should be adapted to local system )
  417. 3 - 'SYS:' (C: equivalent of dos is the SYS: partition)
  418. 4..26 (can be set by you're own applications)
  419. ! Use AddDisk() to Add new drives !
  420. They both return -1 when a failure occurs.
  421. }
  422. var
  423. DeviceList: array[0..26] of string[20];
  424. NumDevices: Integer = 0;
  425. const
  426. IllegalDevices: array[0..12] of string =(
  427. 'PED:',
  428. 'PRJ:',
  429. 'PIPE:', // Pipes
  430. 'XPIPE:', // Extented Pipe
  431. 'CON:', // Console
  432. 'RAW:', // RAW: Console
  433. 'KCON:', // KingCON Console
  434. 'KRAW:', // KingCON RAW
  435. 'SER:', // serial Ports
  436. 'SER0:',
  437. 'SER1:',
  438. 'PAR:', // Parallel Porty
  439. 'PRT:'); // Printer
  440. function IsIllegalDevice(DeviceName: string): Boolean;
  441. var
  442. i: Integer;
  443. Str: AnsiString;
  444. begin
  445. IsIllegalDevice := False;
  446. Str := UpperCase(DeviceName);
  447. for i := Low(IllegalDevices) to High(IllegalDevices) do
  448. begin
  449. if Str = IllegalDevices[i] then
  450. begin
  451. IsIllegalDevice := True;
  452. Exit;
  453. end;
  454. end;
  455. end;
  456. function DeviceByIdx(Idx: Integer): string;
  457. begin
  458. DeviceByIdx := '';
  459. if (Idx < 0) or (Idx >= NumDevices) then
  460. Exit;
  461. DeviceByIdx := DeviceList[Idx];
  462. end;
  463. function AddDisk(const Path: string): Integer;
  464. begin
  465. // if hit border, restart at 4
  466. if NumDevices > 26 then
  467. NumDevices := 4;
  468. // set the device
  469. DeviceList[NumDevices] := Copy(Path, 1, 20);
  470. // return the Index increment for next run
  471. AddDisk := NumDevices;
  472. Inc(NumDevices);
  473. end;
  474. function RefreshDeviceList: Integer;
  475. var
  476. List: PDosList;
  477. Temp: PChar;
  478. Str: string;
  479. begin
  480. NumDevices := 0;
  481. AddDisk(':'); // Index 0
  482. AddDisk('DF0:'); // Index 1
  483. AddDisk('DF1:'); // Index 2
  484. AddDisk('SYS:'); // Index 3
  485. // Lock the List
  486. List := LockDosList(LDF_DEVICES or LDF_READ);
  487. // Inspect the List
  488. repeat
  489. List := NextDosEntry(List, LDF_DEVICES);
  490. if List <> nil then
  491. begin
  492. Temp := BSTR2STRING(List^.dol_Name);
  493. Str := strpas(Temp) + ':';
  494. if not IsIllegalDevice(str) then
  495. AddDisk(Str);
  496. end;
  497. until List = nil;
  498. UnLockDosList(LDF_DEVICES or LDF_READ);
  499. RefreshDeviceList := NumDevices;
  500. end;
  501. // New easier DiskSize()
  502. //
  503. function DiskSize(Drive: AnsiString): Int64;
  504. var
  505. DirLock: LongInt;
  506. Inf: TInfoData;
  507. MyProc: PProcess;
  508. OldWinPtr: Pointer;
  509. begin
  510. DiskSize := -1;
  511. //
  512. MyProc := PProcess(FindTask(Nil));
  513. OldWinPtr := MyProc^.pr_WindowPtr;
  514. MyProc^.pr_WindowPtr := Pointer(-1);
  515. //
  516. DirLock := Lock(PChar(Drive), SHARED_LOCK);
  517. if DirLock <> 0 then
  518. begin
  519. if Info(DirLock, @Inf) <> 0 then
  520. DiskSize := Int64(Inf.id_NumBlocks) * Inf.id_BytesPerBlock;
  521. UnLock(DirLock);
  522. end;
  523. if OldWinPtr <> Pointer(-1) then
  524. MyProc^.pr_WindowPtr := OldWinPtr;
  525. end;
  526. function DiskSize(Drive: Byte): Int64;
  527. begin
  528. DiskSize := -1;
  529. if (Drive < 0) or (Drive >= NumDevices) then
  530. Exit;
  531. DiskSize := DiskSize(DeviceList[Drive]);
  532. end;
  533. // New easier DiskFree()
  534. //
  535. function DiskFree(Drive: AnsiString): Int64;
  536. var
  537. DirLock: LongInt;
  538. Inf: TInfoData;
  539. MyProc: PProcess;
  540. OldWinPtr: Pointer;
  541. begin
  542. DiskFree := -1;
  543. //
  544. MyProc := PProcess(FindTask(Nil));
  545. OldWinPtr := MyProc^.pr_WindowPtr;
  546. MyProc^.pr_WindowPtr := Pointer(-1);
  547. //
  548. DirLock := Lock(PChar(Drive), SHARED_LOCK);
  549. if DirLock <> 0 then
  550. begin
  551. if Info(DirLock, @Inf) <> 0 then
  552. DiskFree := Int64(Inf.id_NumBlocks - Inf.id_NumBlocksUsed) * Inf.id_BytesPerBlock;
  553. UnLock(DirLock);
  554. end;
  555. if OldWinPtr <> Pointer(-1) then
  556. MyProc^.pr_WindowPtr := OldWinPtr;
  557. end;
  558. function DiskFree(Drive: Byte): Int64;
  559. begin
  560. DiskFree := -1;
  561. if (Drive < 0) or (Drive >= NumDevices) then
  562. Exit;
  563. DiskFree := DiskFree(DeviceList[Drive]);
  564. end;
  565. function DirectoryExists(const Directory: RawByteString): Boolean;
  566. var
  567. tmpLock: LongInt;
  568. FIB : PFileInfoBlock;
  569. SystemDirName: RawByteString;
  570. begin
  571. result:=false;
  572. if (Directory='') or (InOutRes<>0) then exit;
  573. SystemDirName:=PathConv(ToSingleByteFileSystemEncodedFileName(Directory));
  574. tmpLock:=Lock(PChar(SystemDirName),SHARED_LOCK);
  575. if tmpLock=0 then exit;
  576. FIB:=nil; new(FIB);
  577. if (Examine(tmpLock,FIB) <> 0) and (FIB^.fib_DirEntryType>0) then
  578. result:=True;
  579. if tmpLock<>0 then Unlock(tmpLock);
  580. if assigned(FIB) then dispose(FIB);
  581. end;
  582. {****************************************************************************
  583. Locale Functions
  584. ****************************************************************************}
  585. Procedure GetLocalTime(var SystemTime: TSystemTime);
  586. var
  587. dayOfWeek: word;
  588. Sec100: Word;
  589. begin
  590. dos.GetTime(SystemTime.Hour, SystemTime.Minute, SystemTime.Second, Sec100);
  591. SystemTime.Millisecond := Sec100 * 10;
  592. dos.GetDate(SystemTime.Year, SystemTime.Month, SystemTime.Day, DayOfWeek);
  593. end;
  594. Procedure InitAnsi;
  595. Var
  596. i : longint;
  597. begin
  598. { Fill table entries 0 to 127 }
  599. for i := 0 to 96 do
  600. UpperCaseTable[i] := chr(i);
  601. for i := 97 to 122 do
  602. UpperCaseTable[i] := chr(i - 32);
  603. for i := 123 to 191 do
  604. UpperCaseTable[i] := chr(i);
  605. Move (CPISO88591UCT,UpperCaseTable[192],SizeOf(CPISO88591UCT));
  606. for i := 0 to 64 do
  607. LowerCaseTable[i] := chr(i);
  608. for i := 65 to 90 do
  609. LowerCaseTable[i] := chr(i + 32);
  610. for i := 91 to 191 do
  611. LowerCaseTable[i] := chr(i);
  612. Move (CPISO88591LCT,UpperCaseTable[192],SizeOf(CPISO88591UCT));
  613. end;
  614. Procedure InitInternational;
  615. begin
  616. InitInternationalGeneric;
  617. InitAnsi;
  618. end;
  619. function SysErrorMessage(ErrorCode: Integer): String;
  620. begin
  621. { Result:=StrError(ErrorCode);}
  622. end;
  623. function GetLastOSError: Integer;
  624. begin
  625. result:=-1;
  626. end;
  627. {****************************************************************************
  628. OS utility functions
  629. ****************************************************************************}
  630. var
  631. StrOfPaths: String;
  632. function SystemTags(const command: PChar; const tags: array of DWord): LongInt;
  633. begin
  634. SystemTags:=SystemTagList(command,@tags);
  635. end;
  636. function GetPathString: String;
  637. var
  638. f : text;
  639. s : string;
  640. begin
  641. s := '';
  642. result := '';
  643. { Alternatively, this could use PIPE: handler on systems which
  644. have this by default (not the case on classic Amiga), but then
  645. the child process should be started async, which for a simple
  646. Path command probably isn't worth the trouble. (KB) }
  647. assign(f,'T:'+HexStr(FindTask(nil))+'_path.tmp');
  648. rewrite(f);
  649. { This is a pretty ugly stunt, combining Pascal and Amiga system
  650. functions, but works... }
  651. SystemTags('C:Path',[SYS_Input, 0, SYS_Output, TextRec(f).Handle, TAG_END]);
  652. close(f);
  653. reset(f);
  654. { skip the first line, garbage }
  655. if not eof(f) then readln(f,s);
  656. while not eof(f) do begin
  657. readln(f,s);
  658. if result = '' then
  659. result := s
  660. else
  661. result := result + ';' + s;
  662. end;
  663. close(f);
  664. erase(f);
  665. end;
  666. Function GetEnvironmentVariable(Const EnvVar : String) : String;
  667. begin
  668. if UpCase(envvar) = 'PATH' then begin
  669. if StrOfpaths = '' then StrOfPaths := GetPathString;
  670. Result:=StrOfPaths;
  671. end else
  672. Result:=Dos.Getenv(shortstring(EnvVar));
  673. end;
  674. Function GetEnvironmentVariableCount : Integer;
  675. begin
  676. // Result:=FPCCountEnvVar(EnvP);
  677. Result:=Dos.envCount;
  678. end;
  679. Function GetEnvironmentString(Index : Integer) : {$ifdef FPC_RTL_UNICODE}UnicodeString{$else}AnsiString{$endif};
  680. begin
  681. // Result:=FPCGetEnvStrFromP(Envp,Index);
  682. Result:=Dos.EnvStr(Index);
  683. end;
  684. function ExecuteProcess (const Path: AnsiString; const ComLine: AnsiString;Flags:TExecuteFlags=[]):
  685. integer;
  686. var
  687. tmpPath: AnsiString;
  688. convPath: AnsiString;
  689. CommandLine: AnsiString;
  690. tmpLock: longint;
  691. E: EOSError;
  692. begin
  693. DosError:= 0;
  694. convPath:=PathConv(Path);
  695. tmpPath:=convPath+' '+ComLine;
  696. { Here we must first check if the command we wish to execute }
  697. { actually exists, because this is NOT handled by the }
  698. { _SystemTagList call (program will abort!!) }
  699. { Try to open with shared lock }
  700. tmpLock:=Lock(PChar(convPath),SHARED_LOCK);
  701. if tmpLock<>0 then
  702. begin
  703. { File exists - therefore unlock it }
  704. Unlock(tmpLock);
  705. result:=SystemTagList(PChar(tmpPath),nil);
  706. { on return of -1 the shell could not be executed }
  707. { probably because there was not enough memory }
  708. if result = -1 then
  709. DosError:=8;
  710. end
  711. else
  712. DosError:=3;
  713. if DosError <> 0 then begin
  714. if ComLine = '' then
  715. CommandLine := Path
  716. else
  717. CommandLine := Path + ' ' + ComLine;
  718. E := EOSError.CreateFmt (SExecuteProcessFailed, [CommandLine, DosError]);
  719. E.ErrorCode := DosError;
  720. raise E;
  721. end;
  722. end;
  723. function ExecuteProcess (const Path: AnsiString;
  724. const ComLine: array of AnsiString;Flags:TExecuteFlags=[]): integer;
  725. var
  726. CommandLine: AnsiString;
  727. I: integer;
  728. begin
  729. Commandline := '';
  730. for I := 0 to High (ComLine) do
  731. if Pos (' ', ComLine [I]) <> 0 then
  732. CommandLine := CommandLine + ' ' + '"' + ComLine [I] + '"'
  733. else
  734. CommandLine := CommandLine + ' ' + Comline [I];
  735. ExecuteProcess := ExecuteProcess (Path, CommandLine);
  736. end;
  737. procedure Sleep(Milliseconds: cardinal);
  738. begin
  739. // Amiga dos.library Delay() has precision of 1/50 seconds
  740. Delay(Milliseconds div 20);
  741. end;
  742. {****************************************************************************
  743. Initialization code
  744. ****************************************************************************}
  745. Initialization
  746. InitExceptions;
  747. InitInternational; { Initialize internationalization settings }
  748. OnBeep:=Nil; { No SysBeep() on Amiga, for now. Figure out if we want
  749. to use intuition.library/DisplayBeep() for this (KB) }
  750. StrOfPaths:='';
  751. RefreshDeviceList;
  752. Finalization
  753. DoneExceptions;
  754. end.