sysutils.pp 24 KB

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