sysutils.pp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919
  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. RefreshDeviceList := NumDevices;
  499. end;
  500. // New easier DiskSize()
  501. //
  502. function DiskSize(Drive: AnsiString): Int64;
  503. var
  504. DirLock: LongInt;
  505. Inf: TInfoData;
  506. MyProc: PProcess;
  507. OldWinPtr: Pointer;
  508. begin
  509. DiskSize := -1;
  510. //
  511. MyProc := PProcess(FindTask(Nil));
  512. OldWinPtr := MyProc^.pr_WindowPtr;
  513. MyProc^.pr_WindowPtr := Pointer(-1);
  514. //
  515. DirLock := Lock(PChar(Drive), SHARED_LOCK);
  516. if DirLock <> 0 then
  517. begin
  518. if Info(DirLock, @Inf) <> 0 then
  519. DiskSize := Int64(Inf.id_NumBlocks) * Inf.id_BytesPerBlock;
  520. UnLock(DirLock);
  521. end;
  522. if OldWinPtr <> Pointer(-1) then
  523. MyProc^.pr_WindowPtr := OldWinPtr;
  524. end;
  525. function DiskSize(Drive: Byte): Int64;
  526. begin
  527. DiskSize := -1;
  528. if (Drive < 0) or (Drive >= NumDevices) then
  529. Exit;
  530. DiskSize := DiskSize(DeviceList[Drive]);
  531. end;
  532. // New easier DiskFree()
  533. //
  534. function DiskFree(Drive: AnsiString): Int64;
  535. var
  536. DirLock: LongInt;
  537. Inf: TInfoData;
  538. MyProc: PProcess;
  539. OldWinPtr: Pointer;
  540. begin
  541. DiskFree := -1;
  542. //
  543. MyProc := PProcess(FindTask(Nil));
  544. OldWinPtr := MyProc^.pr_WindowPtr;
  545. MyProc^.pr_WindowPtr := Pointer(-1);
  546. //
  547. DirLock := Lock(PChar(Drive), SHARED_LOCK);
  548. if DirLock <> 0 then
  549. begin
  550. if Info(DirLock, @Inf) <> 0 then
  551. DiskFree := Int64(Inf.id_NumBlocks - Inf.id_NumBlocksUsed) * Inf.id_BytesPerBlock;
  552. UnLock(DirLock);
  553. end;
  554. if OldWinPtr <> Pointer(-1) then
  555. MyProc^.pr_WindowPtr := OldWinPtr;
  556. end;
  557. function DiskFree(Drive: Byte): Int64;
  558. begin
  559. DiskFree := -1;
  560. if (Drive < 0) or (Drive >= NumDevices) then
  561. Exit;
  562. DiskFree := DiskSize(DeviceList[Drive]);
  563. end;
  564. function DirectoryExists(const Directory: RawByteString): Boolean;
  565. var
  566. tmpLock: LongInt;
  567. FIB : PFileInfoBlock;
  568. SystemDirName: RawByteString;
  569. begin
  570. result:=false;
  571. if (Directory='') or (InOutRes<>0) then exit;
  572. SystemDirName:=PathConv(ToSingleByteFileSystemEncodedFileName(Directory));
  573. tmpLock:=Lock(PChar(SystemDirName),SHARED_LOCK);
  574. if tmpLock=0 then exit;
  575. FIB:=nil; new(FIB);
  576. if (Examine(tmpLock,FIB) <> 0) and (FIB^.fib_DirEntryType>0) then
  577. result:=True;
  578. if tmpLock<>0 then Unlock(tmpLock);
  579. if assigned(FIB) then dispose(FIB);
  580. end;
  581. {****************************************************************************
  582. Locale Functions
  583. ****************************************************************************}
  584. Procedure GetLocalTime(var SystemTime: TSystemTime);
  585. var
  586. dayOfWeek: word;
  587. Sec100: Word;
  588. begin
  589. dos.GetTime(SystemTime.Hour, SystemTime.Minute, SystemTime.Second, Sec100);
  590. SystemTime.Millisecond := Sec100 * 10;
  591. dos.GetDate(SystemTime.Year, SystemTime.Month, SystemTime.Day, DayOfWeek);
  592. end;
  593. Procedure InitAnsi;
  594. Var
  595. i : longint;
  596. begin
  597. { Fill table entries 0 to 127 }
  598. for i := 0 to 96 do
  599. UpperCaseTable[i] := chr(i);
  600. for i := 97 to 122 do
  601. UpperCaseTable[i] := chr(i - 32);
  602. for i := 123 to 191 do
  603. UpperCaseTable[i] := chr(i);
  604. Move (CPISO88591UCT,UpperCaseTable[192],SizeOf(CPISO88591UCT));
  605. for i := 0 to 64 do
  606. LowerCaseTable[i] := chr(i);
  607. for i := 65 to 90 do
  608. LowerCaseTable[i] := chr(i + 32);
  609. for i := 91 to 191 do
  610. LowerCaseTable[i] := chr(i);
  611. Move (CPISO88591LCT,UpperCaseTable[192],SizeOf(CPISO88591UCT));
  612. end;
  613. Procedure InitInternational;
  614. begin
  615. InitInternationalGeneric;
  616. InitAnsi;
  617. end;
  618. function SysErrorMessage(ErrorCode: Integer): String;
  619. begin
  620. { Result:=StrError(ErrorCode);}
  621. end;
  622. function GetLastOSError: Integer;
  623. begin
  624. result:=-1;
  625. end;
  626. {****************************************************************************
  627. OS utility functions
  628. ****************************************************************************}
  629. var
  630. StrOfPaths: String;
  631. function SystemTags(const command: PChar; const tags: array of DWord): LongInt;
  632. begin
  633. SystemTags:=SystemTagList(command,@tags);
  634. end;
  635. function GetPathString: String;
  636. var
  637. f : text;
  638. s : string;
  639. begin
  640. s := '';
  641. result := '';
  642. { Alternatively, this could use PIPE: handler on systems which
  643. have this by default (not the case on classic Amiga), but then
  644. the child process should be started async, which for a simple
  645. Path command probably isn't worth the trouble. (KB) }
  646. assign(f,'T:'+HexStr(FindTask(nil))+'_path.tmp');
  647. rewrite(f);
  648. { This is a pretty ugly stunt, combining Pascal and Amiga system
  649. functions, but works... }
  650. SystemTags('C:Path',[SYS_Input, 0, SYS_Output, TextRec(f).Handle, TAG_END]);
  651. close(f);
  652. reset(f);
  653. { skip the first line, garbage }
  654. if not eof(f) then readln(f,s);
  655. while not eof(f) do begin
  656. readln(f,s);
  657. if result = '' then
  658. result := s
  659. else
  660. result := result + ';' + s;
  661. end;
  662. close(f);
  663. erase(f);
  664. end;
  665. Function GetEnvironmentVariable(Const EnvVar : String) : String;
  666. begin
  667. if UpCase(envvar) = 'PATH' then begin
  668. if StrOfpaths = '' then StrOfPaths := GetPathString;
  669. Result:=StrOfPaths;
  670. end else
  671. Result:=Dos.Getenv(shortstring(EnvVar));
  672. end;
  673. Function GetEnvironmentVariableCount : Integer;
  674. begin
  675. // Result:=FPCCountEnvVar(EnvP);
  676. Result:=Dos.envCount;
  677. end;
  678. Function GetEnvironmentString(Index : Integer) : {$ifdef FPC_RTL_UNICODE}UnicodeString{$else}AnsiString{$endif};
  679. begin
  680. // Result:=FPCGetEnvStrFromP(Envp,Index);
  681. Result:=Dos.EnvStr(Index);
  682. end;
  683. function ExecuteProcess (const Path: AnsiString; const ComLine: AnsiString;Flags:TExecuteFlags=[]):
  684. integer;
  685. var
  686. tmpPath: AnsiString;
  687. convPath: AnsiString;
  688. CommandLine: AnsiString;
  689. tmpLock: longint;
  690. E: EOSError;
  691. begin
  692. DosError:= 0;
  693. convPath:=PathConv(Path);
  694. tmpPath:=convPath+' '+ComLine;
  695. { Here we must first check if the command we wish to execute }
  696. { actually exists, because this is NOT handled by the }
  697. { _SystemTagList call (program will abort!!) }
  698. { Try to open with shared lock }
  699. tmpLock:=Lock(PChar(convPath),SHARED_LOCK);
  700. if tmpLock<>0 then
  701. begin
  702. { File exists - therefore unlock it }
  703. Unlock(tmpLock);
  704. result:=SystemTagList(PChar(tmpPath),nil);
  705. { on return of -1 the shell could not be executed }
  706. { probably because there was not enough memory }
  707. if result = -1 then
  708. DosError:=8;
  709. end
  710. else
  711. DosError:=3;
  712. if DosError <> 0 then begin
  713. if ComLine = '' then
  714. CommandLine := Path
  715. else
  716. CommandLine := Path + ' ' + ComLine;
  717. E := EOSError.CreateFmt (SExecuteProcessFailed, [CommandLine, DosError]);
  718. E.ErrorCode := DosError;
  719. raise E;
  720. end;
  721. end;
  722. function ExecuteProcess (const Path: AnsiString;
  723. const ComLine: array of AnsiString;Flags:TExecuteFlags=[]): integer;
  724. var
  725. CommandLine: AnsiString;
  726. I: integer;
  727. begin
  728. Commandline := '';
  729. for I := 0 to High (ComLine) do
  730. if Pos (' ', ComLine [I]) <> 0 then
  731. CommandLine := CommandLine + ' ' + '"' + ComLine [I] + '"'
  732. else
  733. CommandLine := CommandLine + ' ' + Comline [I];
  734. ExecuteProcess := ExecuteProcess (Path, CommandLine);
  735. end;
  736. procedure Sleep(Milliseconds: cardinal);
  737. begin
  738. // Amiga dos.library Delay() has precision of 1/50 seconds
  739. Delay(Milliseconds div 20);
  740. end;
  741. {****************************************************************************
  742. Initialization code
  743. ****************************************************************************}
  744. Initialization
  745. InitExceptions;
  746. InitInternational; { Initialize internationalization settings }
  747. OnBeep:=Nil; { No SysBeep() on Amiga, for now. Figure out if we want
  748. to use intuition.library/DisplayBeep() for this (KB) }
  749. StrOfPaths:='';
  750. RefreshDeviceList;
  751. Finalization
  752. DoneExceptions;
  753. end.