sysutils.pp 25 KB

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