sysutils.pp 26 KB

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