sysutils.pp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952
  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) : LongInt;
  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: LongInt) : 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: LongInt) : 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): Longint;
  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 FileExists (const FileName : RawByteString) : Boolean;
  313. var
  314. tmpLock: BPTR;
  315. tmpFIB : PFileInfoBlock;
  316. SystemFileName: RawByteString;
  317. begin
  318. result:=false;
  319. SystemFileName := PathConv(ToSingleByteFileSystemEncodedFileName(FileName));
  320. tmpLock := Lock(PChar(SystemFileName), SHARED_LOCK);
  321. if (tmpLock <> 0) then begin
  322. new(tmpFIB);
  323. if (Examine(tmpLock,tmpFIB) <> 0) and (tmpFIB^.fib_DirEntryType <= 0) then
  324. result:=true;
  325. Unlock(tmpLock);
  326. dispose(tmpFIB);
  327. end;
  328. end;
  329. Function InternalFindFirst (Const Path : RawByteString; Attr : Longint; out Rslt : TAbstractSearchRec; var Name: RawByteString) : Longint;
  330. var
  331. tmpStr: RawByteString;
  332. Anchor: PAnchorPath;
  333. tmpDateTime: TDateTime;
  334. validDate: boolean;
  335. begin
  336. result:=-1; { We emulate Linux/Unix behaviour, and return -1 on errors. }
  337. tmpStr:=PathConv(ToSingleByteFileSystemEncodedFileName(Path));
  338. { $1e = faHidden or faSysFile or faVolumeID or faDirectory }
  339. Rslt.ExcludeAttr := (not Attr) and ($1e);
  340. Rslt.FindHandle := nil;
  341. new(Anchor);
  342. FillChar(Anchor^,sizeof(TAnchorPath),#0);
  343. Rslt.FindHandle := Anchor;
  344. if MatchFirst(pchar(tmpStr),Anchor)<>0 then
  345. begin
  346. InternalFindClose(Rslt.FindHandle);
  347. exit;
  348. end;
  349. with Anchor^.ap_Info do begin
  350. Name := fib_FileName;
  351. SetCodePage(Name,DefaultFileSystemCodePage,false);
  352. Rslt.Size := fib_Size;
  353. Rslt.Time := DateTimeToFileDate(AmigaFileDateToDateTime(fib_Date,validDate));
  354. if not validDate then
  355. begin
  356. InternalFindClose(Rslt.FindHandle);
  357. exit;
  358. end;
  359. { "128" is Windows "NORMALFILE" attribute. Some buggy code depend on this... :( (KB) }
  360. Rslt.Attr := 128;
  361. if fib_DirEntryType > 0 then Rslt.Attr:=Rslt.Attr or faDirectory;
  362. if ((fib_Protection and FIBF_READ) <> 0) and
  363. ((fib_Protection and FIBF_WRITE) = 0) then Rslt.Attr:=Rslt.Attr or faReadOnly;
  364. result:=0; { Return zero if everything went OK }
  365. end;
  366. end;
  367. Function InternalFindNext (var Rslt : TAbstractSearchRec; var Name : RawByteString) : Longint;
  368. var
  369. Anchor: PAnchorPath;
  370. validDate: boolean;
  371. begin
  372. result:=-1;
  373. Anchor:=PAnchorPath(Rslt.FindHandle);
  374. if not assigned(Anchor) then exit;
  375. if MatchNext(Anchor) <> 0 then exit;
  376. with Anchor^.ap_Info do begin
  377. Name := fib_FileName;
  378. SetCodePage(Name,DefaultFileSystemCodePage,false);
  379. Rslt.Size := fib_Size;
  380. Rslt.Time := DateTimeToFileDate(AmigaFileDateToDateTime(fib_Date,validDate));
  381. if not validDate then exit;
  382. { "128" is Windows "NORMALFILE" attribute. Some buggy code depend on this... :( (KB) }
  383. Rslt.Attr := 128;
  384. if fib_DirEntryType > 0 then Rslt.Attr:=Rslt.Attr or faDirectory;
  385. if ((fib_Protection and FIBF_READ) <> 0) and
  386. ((fib_Protection and FIBF_WRITE) = 0) then Rslt.Attr:=Rslt.Attr or faReadOnly;
  387. result:=0; { Return zero if everything went OK }
  388. end;
  389. end;
  390. Procedure InternalFindClose(var Handle: Pointer);
  391. var
  392. Anchor: PAnchorPath absolute Handle;
  393. begin
  394. if not assigned(Anchor) then
  395. exit;
  396. MatchEnd(Anchor);
  397. Dispose(Anchor);
  398. Handle:=nil;
  399. end;
  400. (****** end of non portable routines ******)
  401. Function FileGetAttr (Const FileName : RawByteString) : Longint;
  402. var
  403. F: file;
  404. attr: word;
  405. begin
  406. Assign(F,FileName);
  407. dos.GetFAttr(F,attr);
  408. if DosError <> 0 then
  409. FileGetAttr := -1
  410. else
  411. FileGetAttr := Attr;
  412. end;
  413. Function FileSetAttr (Const Filename : RawByteString; Attr: longint) : Longint;
  414. var
  415. F: file;
  416. begin
  417. Assign(F, FileName);
  418. Dos.SetFAttr(F, Attr and $ffff);
  419. FileSetAttr := DosError;
  420. end;
  421. {****************************************************************************
  422. Disk Functions
  423. ****************************************************************************}
  424. {
  425. The Diskfree and Disksize functions need a file on the specified drive, since this
  426. is required for the statfs system call.
  427. These filenames are set in drivestr[0..26], and have been preset to :
  428. 0 - ':' (default drive - hence current dir is ok.)
  429. 1 - 'DF0:' (floppy drive 1 - should be adapted to local system )
  430. 2 - 'DF1:' (floppy drive 2 - should be adapted to local system )
  431. 3 - 'SYS:' (C: equivalent of dos is the SYS: partition)
  432. 4..26 (can be set by you're own applications)
  433. ! Use AddDisk() to Add new drives !
  434. They both return -1 when a failure occurs.
  435. }
  436. var
  437. DeviceList: array[0..26] of string[20];
  438. NumDevices: Integer = 0;
  439. const
  440. IllegalDevices: array[0..12] of string =(
  441. 'PED:',
  442. 'PRJ:',
  443. 'PIPE:', // Pipes
  444. 'XPIPE:', // Extented Pipe
  445. 'CON:', // Console
  446. 'RAW:', // RAW: Console
  447. 'KCON:', // KingCON Console
  448. 'KRAW:', // KingCON RAW
  449. 'SER:', // serial Ports
  450. 'SER0:',
  451. 'SER1:',
  452. 'PAR:', // Parallel Porty
  453. 'PRT:'); // Printer
  454. function IsIllegalDevice(DeviceName: string): Boolean;
  455. var
  456. i: Integer;
  457. Str: AnsiString;
  458. begin
  459. IsIllegalDevice := False;
  460. Str := UpperCase(DeviceName);
  461. for i := Low(IllegalDevices) to High(IllegalDevices) do
  462. begin
  463. if Str = IllegalDevices[i] then
  464. begin
  465. IsIllegalDevice := True;
  466. Exit;
  467. end;
  468. end;
  469. end;
  470. function DeviceByIdx(Idx: Integer): string;
  471. begin
  472. DeviceByIdx := '';
  473. if (Idx < 0) or (Idx >= NumDevices) then
  474. Exit;
  475. DeviceByIdx := DeviceList[Idx];
  476. end;
  477. function AddDisk(const Path: string): Integer;
  478. begin
  479. // if hit border, restart at 4
  480. if NumDevices > 26 then
  481. NumDevices := 4;
  482. // set the device
  483. DeviceList[NumDevices] := Copy(Path, 1, 20);
  484. // return the Index increment for next run
  485. AddDisk := NumDevices;
  486. Inc(NumDevices);
  487. end;
  488. function RefreshDeviceList: Integer;
  489. var
  490. List: PDosList;
  491. Temp: PChar;
  492. Str: string;
  493. begin
  494. NumDevices := 0;
  495. AddDisk(':'); // Index 0
  496. AddDisk('DF0:'); // Index 1
  497. AddDisk('DF1:'); // Index 2
  498. AddDisk('SYS:'); // Index 3
  499. // Lock the List
  500. List := LockDosList(LDF_DEVICES or LDF_READ);
  501. // Inspect the List
  502. repeat
  503. List := NextDosEntry(List, LDF_DEVICES);
  504. if List <> nil then
  505. begin
  506. Temp := BSTR2STRING(List^.dol_Name);
  507. Str := strpas(Temp) + ':';
  508. if not IsIllegalDevice(str) then
  509. AddDisk(Str);
  510. end;
  511. until List = nil;
  512. UnLockDosList(LDF_DEVICES or LDF_READ);
  513. RefreshDeviceList := NumDevices;
  514. end;
  515. // New easier DiskSize()
  516. //
  517. function DiskSize(Drive: AnsiString): Int64;
  518. var
  519. DirLock: BPTR;
  520. Inf: TInfoData;
  521. MyProc: PProcess;
  522. OldWinPtr: Pointer;
  523. begin
  524. DiskSize := -1;
  525. //
  526. MyProc := PProcess(FindTask(Nil));
  527. OldWinPtr := MyProc^.pr_WindowPtr;
  528. MyProc^.pr_WindowPtr := Pointer(-1);
  529. //
  530. DirLock := Lock(PChar(Drive), SHARED_LOCK);
  531. if DirLock <> 0 then
  532. begin
  533. if Info(DirLock, @Inf) <> 0 then
  534. DiskSize := Int64(Inf.id_NumBlocks) * Inf.id_BytesPerBlock;
  535. UnLock(DirLock);
  536. end;
  537. if OldWinPtr <> Pointer(-1) then
  538. MyProc^.pr_WindowPtr := OldWinPtr;
  539. end;
  540. function DiskSize(Drive: Byte): Int64;
  541. begin
  542. DiskSize := -1;
  543. if (Drive < 0) or (Drive >= NumDevices) then
  544. Exit;
  545. DiskSize := DiskSize(DeviceList[Drive]);
  546. end;
  547. // New easier DiskFree()
  548. //
  549. function DiskFree(Drive: AnsiString): Int64;
  550. var
  551. DirLock: BPTR;
  552. Inf: TInfoData;
  553. MyProc: PProcess;
  554. OldWinPtr: Pointer;
  555. begin
  556. DiskFree := -1;
  557. //
  558. MyProc := PProcess(FindTask(Nil));
  559. OldWinPtr := MyProc^.pr_WindowPtr;
  560. MyProc^.pr_WindowPtr := Pointer(-1);
  561. //
  562. DirLock := Lock(PChar(Drive), SHARED_LOCK);
  563. if DirLock <> 0 then
  564. begin
  565. if Info(DirLock, @Inf) <> 0 then
  566. DiskFree := Int64(Inf.id_NumBlocks - Inf.id_NumBlocksUsed) * Inf.id_BytesPerBlock;
  567. UnLock(DirLock);
  568. end;
  569. if OldWinPtr <> Pointer(-1) then
  570. MyProc^.pr_WindowPtr := OldWinPtr;
  571. end;
  572. function DiskFree(Drive: Byte): Int64;
  573. begin
  574. DiskFree := -1;
  575. if (Drive < 0) or (Drive >= NumDevices) then
  576. Exit;
  577. DiskFree := DiskFree(DeviceList[Drive]);
  578. end;
  579. function DirectoryExists(const Directory: RawByteString): Boolean;
  580. var
  581. tmpLock: BPTR;
  582. FIB : PFileInfoBlock;
  583. SystemDirName: RawByteString;
  584. begin
  585. result:=false;
  586. if (Directory='') or (InOutRes<>0) then exit;
  587. SystemDirName:=PathConv(ToSingleByteFileSystemEncodedFileName(Directory));
  588. tmpLock:=Lock(PChar(SystemDirName),SHARED_LOCK);
  589. if tmpLock=0 then exit;
  590. FIB:=nil; new(FIB);
  591. if (Examine(tmpLock,FIB) <> 0) and (FIB^.fib_DirEntryType>0) then
  592. result:=True;
  593. if tmpLock<>0 then Unlock(tmpLock);
  594. if assigned(FIB) then dispose(FIB);
  595. end;
  596. {****************************************************************************
  597. Locale Functions
  598. ****************************************************************************}
  599. Procedure GetLocalTime(var SystemTime: TSystemTime);
  600. var
  601. dayOfWeek: word;
  602. Sec100: Word;
  603. begin
  604. dos.GetTime(SystemTime.Hour, SystemTime.Minute, SystemTime.Second, Sec100);
  605. SystemTime.Millisecond := Sec100 * 10;
  606. dos.GetDate(SystemTime.Year, SystemTime.Month, SystemTime.Day, DayOfWeek);
  607. end;
  608. Procedure InitAnsi;
  609. Var
  610. i : longint;
  611. begin
  612. { Fill table entries 0 to 127 }
  613. for i := 0 to 96 do
  614. UpperCaseTable[i] := chr(i);
  615. for i := 97 to 122 do
  616. UpperCaseTable[i] := chr(i - 32);
  617. for i := 123 to 191 do
  618. UpperCaseTable[i] := chr(i);
  619. Move (CPISO88591UCT,UpperCaseTable[192],SizeOf(CPISO88591UCT));
  620. for i := 0 to 64 do
  621. LowerCaseTable[i] := chr(i);
  622. for i := 65 to 90 do
  623. LowerCaseTable[i] := chr(i + 32);
  624. for i := 91 to 191 do
  625. LowerCaseTable[i] := chr(i);
  626. Move (CPISO88591LCT,UpperCaseTable[192],SizeOf(CPISO88591UCT));
  627. end;
  628. Procedure InitInternational;
  629. begin
  630. InitInternationalGeneric;
  631. InitAnsi;
  632. end;
  633. function SysErrorMessage(ErrorCode: Integer): String;
  634. begin
  635. Result:=Format(SUnknownErrorCode,[ErrorCode]);
  636. end;
  637. function GetLastOSError: Integer;
  638. begin
  639. result:=-1;
  640. end;
  641. {****************************************************************************
  642. OS utility functions
  643. ****************************************************************************}
  644. var
  645. StrOfPaths: String;
  646. function SystemTags(const command: PChar; const tags: array of PtrUInt): LongInt;
  647. begin
  648. SystemTags:=SystemTagList(command,@tags);
  649. end;
  650. function GetPathString: String;
  651. var
  652. f : text;
  653. s : string;
  654. begin
  655. s := '';
  656. result := '';
  657. { Alternatively, this could use PIPE: handler on systems which
  658. have this by default (not the case on classic Amiga), but then
  659. the child process should be started async, which for a simple
  660. Path command probably isn't worth the trouble. (KB) }
  661. assign(f,'T:'+HexStr(FindTask(nil))+'_path.tmp');
  662. rewrite(f);
  663. { This is a pretty ugly stunt, combining Pascal and Amiga system
  664. functions, but works... }
  665. SystemTags('C:Path',[SYS_Input, 0, SYS_Output, TextRec(f).Handle, TAG_END]);
  666. close(f);
  667. reset(f);
  668. { skip the first line, garbage }
  669. if not eof(f) then readln(f,s);
  670. while not eof(f) do begin
  671. readln(f,s);
  672. if result = '' then
  673. result := s
  674. else
  675. result := result + ';' + s;
  676. end;
  677. close(f);
  678. erase(f);
  679. end;
  680. Function GetEnvironmentVariable(Const EnvVar : String) : String;
  681. begin
  682. if UpCase(envvar) = 'PATH' then begin
  683. if StrOfpaths = '' then StrOfPaths := GetPathString;
  684. Result:=StrOfPaths;
  685. end else
  686. Result:=Dos.Getenv(shortstring(EnvVar));
  687. end;
  688. Function GetEnvironmentVariableCount : Integer;
  689. begin
  690. // Result:=FPCCountEnvVar(EnvP);
  691. Result:=Dos.envCount;
  692. end;
  693. Function GetEnvironmentString(Index : Integer) : {$ifdef FPC_RTL_UNICODE}UnicodeString{$else}AnsiString{$endif};
  694. begin
  695. // Result:=FPCGetEnvStrFromP(Envp,Index);
  696. Result:=Dos.EnvStr(Index);
  697. end;
  698. function ExecuteProcess (const Path: RawByteString; const ComLine: RawByteString;Flags:TExecuteFlags=[]):
  699. integer;
  700. var
  701. tmpPath,
  702. convPath: RawByteString;
  703. CommandLine: AnsiString;
  704. tmpLock: BPTR;
  705. E: EOSError;
  706. begin
  707. DosError:= 0;
  708. convPath:=PathConv(ToSingleByteFileSystemEncodedFileName(Path));
  709. tmpPath:=convPath+' '+ToSingleByteFileSystemEncodedFileName(ComLine);
  710. { Here we must first check if the command we wish to execute }
  711. { actually exists, because this is NOT handled by the }
  712. { _SystemTagList call (program will abort!!) }
  713. { Try to open with shared lock }
  714. tmpLock:=Lock(PChar(convPath),SHARED_LOCK);
  715. if tmpLock<>0 then
  716. begin
  717. { File exists - therefore unlock it }
  718. Unlock(tmpLock);
  719. result:=SystemTagList(PChar(tmpPath),nil);
  720. { on return of -1 the shell could not be executed }
  721. { probably because there was not enough memory }
  722. if result = -1 then
  723. DosError:=8;
  724. end
  725. else
  726. DosError:=3;
  727. if DosError <> 0 then begin
  728. if ComLine = '' then
  729. CommandLine := Path
  730. else
  731. CommandLine := Path + ' ' + ComLine;
  732. E := EOSError.CreateFmt (SExecuteProcessFailed, [CommandLine, DosError]);
  733. E.ErrorCode := DosError;
  734. raise E;
  735. end;
  736. end;
  737. function ExecuteProcess (const Path: RawByteString;
  738. const ComLine: array of RawByteString;Flags:TExecuteFlags=[]): integer;
  739. var
  740. CommandLine: RawByteString;
  741. I: integer;
  742. begin
  743. Commandline := '';
  744. for I := 0 to High (ComLine) do
  745. if Pos (' ', ComLine [I]) <> 0 then
  746. CommandLine := CommandLine + ' ' + '"' + ToSingleByteFileSystemEncodedFileName(ComLine [I]) + '"'
  747. else
  748. CommandLine := CommandLine + ' ' + ToSingleByteFileSystemEncodedFileName(Comline [I]);
  749. ExecuteProcess := ExecuteProcess (Path, CommandLine);
  750. end;
  751. procedure Sleep(Milliseconds: cardinal);
  752. begin
  753. // Amiga dos.library Delay() has precision of 1/50 seconds
  754. DOSDelay(Milliseconds div 20);
  755. end;
  756. function GetTempDir(Global: Boolean): string;
  757. begin
  758. if Assigned(OnGetTempDir) then
  759. Result := OnGetTempDir(Global)
  760. else
  761. begin
  762. Result := GetEnvironmentVariable('TEMP');
  763. if Result = '' Then
  764. Result:=GetEnvironmentVariable('TMP');
  765. if Result = '' then
  766. Result := 'T:'; // fallback.
  767. end;
  768. if Result <> '' then
  769. Result := IncludeTrailingPathDelimiter(Result);
  770. end;
  771. {****************************************************************************
  772. Initialization code
  773. ****************************************************************************}
  774. Initialization
  775. InitExceptions;
  776. InitInternational; { Initialize internationalization settings }
  777. OnBeep:=Nil; { No SysBeep() on Amiga, for now. Figure out if we want
  778. to use intuition.library/DisplayBeep() for this (KB) }
  779. StrOfPaths:='';
  780. RefreshDeviceList;
  781. Finalization
  782. DoneExceptions;
  783. end.