2
0

sysutils.pp 25 KB

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