sysutils.pp 24 KB

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