sysutils.pp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2004-2013 by Karoly Balogh
  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. See the file COPYING.FPC, included in this distribution,
  8. for details about the copyright.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12. **********************************************************************}
  13. unit sysutils;
  14. interface
  15. {$MODE objfpc}
  16. {$MODESWITCH OUT}
  17. { force ansistrings }
  18. {$H+}
  19. {$DEFINE HAS_SLEEP}
  20. {$DEFINE HAS_OSERROR}
  21. { used OS file system APIs use ansistring }
  22. {$define SYSUTILS_HAS_ANSISTR_FILEUTIL_IMPL}
  23. { OS has an ansistring/single byte environment variable API }
  24. {$define SYSUTILS_HAS_ANSISTR_ENVVAR_IMPL}
  25. { Include platform independent interface part }
  26. {$i sysutilh.inc}
  27. { Platform dependent calls }
  28. Procedure AddDisk(const path:string);
  29. implementation
  30. uses dos,sysconst;
  31. {$DEFINE FPC_FEXPAND_VOLUMES} (* Full paths begin with drive specification *)
  32. {$DEFINE FPC_FEXPAND_DRIVESEP_IS_ROOT}
  33. {$DEFINE FPC_FEXPAND_NO_DEFAULT_PATHS}
  34. { Include platform independent implementation part }
  35. {$i sysutils.inc}
  36. { * Include MorphOS specific includes * }
  37. {$include execd.inc}
  38. {$include execf.inc}
  39. {$include timerd.inc}
  40. {$include doslibd.inc}
  41. {$include doslibf.inc}
  42. {$include utilf.inc}
  43. { * Followings are implemented in the system unit! * }
  44. function PathConv(path: shortstring): shortstring; external name 'PATHCONV';
  45. function PathConv(path: RawByteString): shortstring; external name 'PATHCONVRBS';
  46. procedure AddToList(var l: Pointer; h: LongInt); external name 'ADDTOLIST';
  47. function RemoveFromList(var l: Pointer; h: LongInt): boolean; external name 'REMOVEFROMLIST';
  48. function CheckInList(var l: Pointer; h: LongInt): pointer; external name 'CHECKINLIST';
  49. var
  50. MOS_fileList: Pointer; external name 'AOS_FILELIST';
  51. function dosLock(const name: String;
  52. accessmode: Longint) : LongInt;
  53. var
  54. buffer: array[0..255] of Char;
  55. begin
  56. move(name[1],buffer,length(name));
  57. buffer[length(name)]:=#0;
  58. dosLock:=Lock(buffer,accessmode);
  59. end;
  60. function AmigaFileDateToDateTime(aDate: TDateStamp; out success: boolean): TDateTime;
  61. var
  62. tmpSecs: DWord;
  63. tmpDate: TDateTime;
  64. tmpTime: TDateTime;
  65. clockData: TClockData;
  66. begin
  67. with aDate do
  68. tmpSecs:=(ds_Days * (24 * 60 * 60)) + (ds_Minute * 60) + (ds_Tick div TICKS_PER_SECOND);
  69. Amiga2Date(tmpSecs,@clockData);
  70. {$WARNING TODO: implement msec values, if possible}
  71. with clockData do begin
  72. success:=TryEncodeDate(year,month,mday,tmpDate) and
  73. TryEncodeTime(hour,min,sec,0,tmpTime);
  74. end;
  75. result:=ComposeDateTime(tmpDate,tmpTime);
  76. end;
  77. {****************************************************************************
  78. File Functions
  79. ****************************************************************************}
  80. {$I-}{ Required for correct usage of these routines }
  81. (****** non portable routines ******)
  82. function FileOpen(const FileName: rawbytestring; Mode: Integer): LongInt;
  83. var
  84. SystemFileName: RawByteString;
  85. dosResult: LongInt;
  86. begin
  87. SystemFileName:=PathConv(ToSingleByteFileSystemEncodedFileName(FileName));
  88. {$WARNING FIX ME! To do: FileOpen Access Modes}
  89. dosResult:=Open(PChar(SystemFileName),MODE_OLDFILE);
  90. if dosResult=0 then
  91. dosResult:=-1
  92. else
  93. AddToList(MOS_fileList,dosResult);
  94. FileOpen:=dosResult;
  95. end;
  96. function FileGetDate(Handle: LongInt) : LongInt;
  97. begin
  98. {$WARNING filegetdate call is dummy}
  99. end;
  100. function FileSetDate(Handle, Age: LongInt) : LongInt;
  101. begin
  102. // Impossible under unix from FileHandle !!
  103. FileSetDate:=-1;
  104. end;
  105. function FileCreate(const FileName: RawByteString) : LongInt;
  106. var
  107. SystemFileName: RawByteString;
  108. dosResult: LongInt;
  109. begin
  110. SystemFileName:=PathConv(ToSingleByteFileSystemEncodedFileName(FileName));
  111. dosResult:=Open(PChar(FileName),MODE_NEWFILE);
  112. if dosResult=0 then
  113. dosResult:=-1
  114. else
  115. AddToList(MOS_fileList,dosResult);
  116. FileCreate:=dosResult;
  117. end;
  118. function FileCreate(const FileName: RawByteString; Rights: integer): LongInt;
  119. begin
  120. {$WARNING FIX ME! To do: FileCreate Access Modes}
  121. FileCreate:=FileCreate(FileName);
  122. end;
  123. function FileCreate(const FileName: RawByteString; ShareMode: integer; Rights : Integer): LongInt;
  124. begin
  125. {$WARNING FIX ME! To do: FileCreate Access Modes}
  126. FileCreate:=FileCreate(FileName);
  127. end;
  128. function FileRead(Handle: LongInt; Out Buffer; Count: LongInt): LongInt;
  129. begin
  130. FileRead:=-1;
  131. if (Count<=0) or (Handle<=0) then exit;
  132. FileRead:=dosRead(Handle,@Buffer,Count);
  133. end;
  134. function FileWrite(Handle: LongInt; const Buffer; Count: LongInt): LongInt;
  135. begin
  136. FileWrite:=-1;
  137. if (Count<=0) or (Handle<=0) then exit;
  138. FileWrite:=dosWrite(Handle,@Buffer,Count);
  139. end;
  140. function FileSeek(Handle, FOffset, Origin: LongInt) : LongInt;
  141. var
  142. seekMode: LongInt;
  143. begin
  144. FileSeek:=-1;
  145. if (Handle<=0) then exit;
  146. case Origin of
  147. fsFromBeginning: seekMode:=OFFSET_BEGINNING;
  148. fsFromCurrent : seekMode:=OFFSET_CURRENT;
  149. fsFromEnd : seekMode:=OFFSET_END;
  150. end;
  151. FileSeek:=dosSeek(Handle, FOffset, seekMode);
  152. end;
  153. function FileSeek(Handle: LongInt; FOffset: Int64; Origin: Longint): Int64;
  154. begin
  155. {$WARNING Need to add 64bit call }
  156. FileSeek:=FileSeek(Handle,LongInt(FOffset),LongInt(Origin));
  157. end;
  158. procedure FileClose(Handle: LongInt);
  159. begin
  160. if (Handle<=0) then exit;
  161. dosClose(Handle);
  162. RemoveFromList(MOS_fileList,Handle);
  163. end;
  164. function FileTruncate(Handle: longint; Size: Int64): Boolean;
  165. var
  166. dosResult: LongInt;
  167. begin
  168. FileTruncate:=False;
  169. if Size > high (longint) then exit;
  170. {$WARNING Possible support for 64-bit FS to be checked!}
  171. if (Handle<=0) then exit;
  172. dosResult:=SetFileSize(Handle, Size, OFFSET_BEGINNING);
  173. if (dosResult<0) then exit;
  174. FileTruncate:=True;
  175. end;
  176. function DeleteFile(const FileName: RawByteString) : Boolean;
  177. var
  178. SystemFileName: RawByteString;
  179. begin
  180. SystemFileName:=PathConv(ToSingleByteFileSystemEncodedFileName(FileName));
  181. DeleteFile:=dosDeleteFile(PChar(SystemFileName));
  182. end;
  183. function RenameFile(const OldName, NewName: string): Boolean;
  184. var
  185. OldSystemFileName, NewSystemFileName: RawByteString;
  186. begin
  187. OldSystemFileName:=PathConv(ToSingleByteFileSystemEncodedFileName(OldName));
  188. NewSystemFileName:=PathConv(ToSingleByteFileSystemEncodedFileName(NewName));
  189. RenameFile:=dosRename(PChar(OldSystemFileName), PChar(NewSystemFileName));
  190. end;
  191. (****** end of non portable routines ******)
  192. function FileAge (const FileName : RawByteString): Longint;
  193. var
  194. tmpName: RawByteString;
  195. tmpLock: Longint;
  196. tmpFIB : PFileInfoBlock;
  197. tmpDateTime: TDateTime;
  198. validFile: boolean;
  199. begin
  200. validFile:=false;
  201. tmpName := PathConv(ToSingleByteFileSystemEncodedFileName(FileName));
  202. tmpLock := dosLock(tmpName, SHARED_LOCK);
  203. if (tmpLock <> 0) then begin
  204. new(tmpFIB);
  205. if Examine(tmpLock,tmpFIB) then begin
  206. tmpDateTime:=AmigaFileDateToDateTime(tmpFIB^.fib_Date,validFile);
  207. end;
  208. Unlock(tmpLock);
  209. dispose(tmpFIB);
  210. end;
  211. if validFile then
  212. result:=DateTimeToFileDate(tmpDateTime)
  213. else
  214. result:=-1;
  215. end;
  216. function FileExists (const FileName : RawByteString) : Boolean;
  217. var
  218. tmpLock: LongInt;
  219. tmpFIB : PFileInfoBlock;
  220. SystemFileName: RawByteString;
  221. begin
  222. result:=false;
  223. SystemFileName:=PathConv(ToSingleByteFileSystemEncodedFileName(FileName));
  224. tmpLock := dosLock(PChar(SystemFileName), SHARED_LOCK);
  225. if (tmpLock <> 0) then begin
  226. new(tmpFIB);
  227. if Examine(tmpLock,tmpFIB) and (tmpFIB^.fib_DirEntryType <= 0) then
  228. result:=true;
  229. Unlock(tmpLock);
  230. dispose(tmpFIB);
  231. end;
  232. end;
  233. Function InternalFindFirst (Const Path : RawByteString; Attr : Longint; out Rslt : TAbstractSearchRec; var Name: RawByteString) : Longint;
  234. var
  235. tmpStr: RawByteString;
  236. Anchor: PAnchorPath;
  237. tmpDateTime: TDateTime;
  238. validDate: boolean;
  239. begin
  240. result:=-1; { We emulate Linux/Unix behaviour, and return -1 on errors. }
  241. tmpStr:=PathConv(ToSingleByteEncodedFileName(path));
  242. { $1e = faHidden or faSysFile or faVolumeID or faDirectory }
  243. Rslt.ExcludeAttr := (not Attr) and ($1e);
  244. Rslt.FindHandle := 0;
  245. new(Anchor);
  246. FillChar(Anchor^,sizeof(TAnchorPath),#0);
  247. if MatchFirst(pchar(tmpStr),Anchor)<>0 then exit;
  248. Rslt.FindHandle := longint(Anchor);
  249. with Anchor^.ap_Info do begin
  250. Name := fib_FileName;
  251. SetCodePage(Name,DefaultFileSystemCodePage,false);
  252. Rslt.Size := fib_Size;
  253. Rslt.Time := DateTimeToFileDate(AmigaFileDateToDateTime(fib_Date,validDate));
  254. if not validDate then exit;
  255. { "128" is Windows "NORMALFILE" attribute. Some buggy code depend on this... :( (KB) }
  256. Rslt.Attr := 128;
  257. if fib_DirEntryType > 0 then Rslt.Attr:=Rslt.Attr or faDirectory;
  258. if ((fib_Protection and FIBF_READ) <> 0) and
  259. ((fib_Protection and FIBF_WRITE) = 0) then Rslt.Attr:=Rslt.Attr or faReadOnly;
  260. result:=0; { Return zero if everything went OK }
  261. end;
  262. end;
  263. Function InternalFindNext (var Rslt : TAbstractSearchRec; var Name : RawByteString) : Longint;
  264. var
  265. Anchor: PAnchorPath;
  266. validDate: boolean;
  267. begin
  268. result:=-1;
  269. Anchor:=PAnchorPath(Rslt.FindHandle);
  270. if not assigned(Anchor) then exit;
  271. if MatchNext(Anchor) <> 0 then exit;
  272. with Anchor^.ap_Info do begin
  273. Name := fib_FileName;
  274. SetCodePage(Name,DefaultFileSystemCodePage,false);
  275. Rslt.Size := fib_Size;
  276. Rslt.Time := DateTimeToFileDate(AmigaFileDateToDateTime(fib_Date,validDate));
  277. if not validDate then exit;
  278. { "128" is Windows "NORMALFILE" attribute. Some buggy code depend on this... :( (KB) }
  279. Rslt.Attr := 128;
  280. if fib_DirEntryType > 0 then Rslt.Attr:=Rslt.Attr or faDirectory;
  281. if ((fib_Protection and FIBF_READ) <> 0) and
  282. ((fib_Protection and FIBF_WRITE) = 0) then Rslt.Attr:=Rslt.Attr or faReadOnly;
  283. result:=0; { Return zero if everything went OK }
  284. end;
  285. end;
  286. Procedure InternalFindClose(var Handle: THandle);
  287. var
  288. Anchor: PAnchorPath;
  289. begin
  290. Anchor:=PAnchorPath(Handle);
  291. if not assigned(Anchor) then exit;
  292. MatchEnd(Anchor);
  293. Dispose(Anchor);
  294. Handle:=THandle(nil);
  295. end;
  296. (****** end of non portable routines ******)
  297. Function FileGetAttr (Const FileName : RawByteString) : Longint;
  298. var
  299. F: file;
  300. attr: word;
  301. begin
  302. Assign(F,FileName);
  303. dos.GetFAttr(F,attr);
  304. if DosError <> 0 then
  305. FileGetAttr := -1
  306. else
  307. FileGetAttr := Attr;
  308. end;
  309. Function FileSetAttr (Const Filename : RawByteString; Attr: longint) : Longint;
  310. var
  311. F: file;
  312. begin
  313. Assign(F, FileName);
  314. Dos.SetFAttr(F, Attr and $ffff);
  315. FileSetAttr := DosError;
  316. end;
  317. {****************************************************************************
  318. Disk Functions
  319. ****************************************************************************}
  320. {
  321. The Diskfree and Disksize functions need a file on the specified drive, since this
  322. is required for the statfs system call.
  323. These filenames are set in drivestr[0..26], and have been preset to :
  324. 0 - '.' (default drive - hence current dir is ok.)
  325. 1 - '/fd0/.' (floppy drive 1 - should be adapted to local system )
  326. 2 - '/fd1/.' (floppy drive 2 - should be adapted to local system )
  327. 3 - '/' (C: equivalent of dos is the root partition)
  328. 4..26 (can be set by you're own applications)
  329. ! Use AddDisk() to Add new drives !
  330. They both return -1 when a failure occurs.
  331. }
  332. Const
  333. FixDriveStr : array[0..3] of pchar=(
  334. '.',
  335. '/fd0/.',
  336. '/fd1/.',
  337. '/.'
  338. );
  339. var
  340. Drives : byte;
  341. DriveStr : array[4..26] of pchar;
  342. Procedure AddDisk(const path:string);
  343. begin
  344. if not (DriveStr[Drives]=nil) then
  345. FreeMem(DriveStr[Drives],StrLen(DriveStr[Drives])+1);
  346. GetMem(DriveStr[Drives],length(Path)+1);
  347. StrPCopy(DriveStr[Drives],path);
  348. inc(Drives);
  349. if Drives>26 then
  350. Drives:=4;
  351. end;
  352. Function DiskFree(Drive: Byte): int64;
  353. Begin
  354. DiskFree := dos.diskFree(Drive);
  355. End;
  356. Function DiskSize(Drive: Byte): int64;
  357. Begin
  358. DiskSize := dos.DiskSize(Drive);
  359. End;
  360. function DirectoryExists(const Directory: RawBytetring): Boolean;
  361. var
  362. tmpStr : String;
  363. tmpLock: LongInt;
  364. FIB : PFileInfoBlock;
  365. SystemFileName: RawByteString;
  366. begin
  367. result:=false;
  368. if (Directory='') or (InOutRes<>0) then exit;
  369. SystemFileName:=PathConv(ToSingleByteFileSystemEncodedFileName(FileName));
  370. tmpLock:=dosLock(PChar(SystemFileName),SHARED_LOCK);
  371. if tmpLock=0 then exit;
  372. FIB:=nil; new(FIB);
  373. if (Examine(tmpLock,FIB)=True) and (FIB^.fib_DirEntryType>0) then
  374. result:=True;
  375. if tmpLock<>0 then Unlock(tmpLock);
  376. if assigned(FIB) then dispose(FIB);
  377. end;
  378. {****************************************************************************
  379. Misc Functions
  380. ****************************************************************************}
  381. procedure SysBeep;
  382. begin
  383. // TODO
  384. end;
  385. {****************************************************************************
  386. Locale Functions
  387. ****************************************************************************}
  388. Procedure GetLocalTime(var SystemTime: TSystemTime);
  389. var
  390. dayOfWeek: word;
  391. begin
  392. dos.GetTime(SystemTime.Hour, SystemTime.Minute, SystemTime.Second,SystemTime.Millisecond);
  393. dos.GetDate(SystemTime.Year, SystemTime.Month, SystemTime.Day, DayOfWeek);
  394. end;
  395. Procedure InitAnsi;
  396. Var
  397. i : longint;
  398. begin
  399. { Fill table entries 0 to 127 }
  400. for i := 0 to 96 do
  401. UpperCaseTable[i] := chr(i);
  402. for i := 97 to 122 do
  403. UpperCaseTable[i] := chr(i - 32);
  404. for i := 123 to 191 do
  405. UpperCaseTable[i] := chr(i);
  406. Move (CPISO88591UCT,UpperCaseTable[192],SizeOf(CPISO88591UCT));
  407. for i := 0 to 64 do
  408. LowerCaseTable[i] := chr(i);
  409. for i := 65 to 90 do
  410. LowerCaseTable[i] := chr(i + 32);
  411. for i := 91 to 191 do
  412. LowerCaseTable[i] := chr(i);
  413. Move (CPISO88591LCT,UpperCaseTable[192],SizeOf(CPISO88591UCT));
  414. end;
  415. Procedure InitInternational;
  416. begin
  417. InitInternationalGeneric;
  418. InitAnsi;
  419. end;
  420. function SysErrorMessage(ErrorCode: Integer): String;
  421. begin
  422. { Result:=StrError(ErrorCode);}
  423. end;
  424. function GetLastOSError: Integer;
  425. begin
  426. result:=-1;
  427. end;
  428. {****************************************************************************
  429. OS utility functions
  430. ****************************************************************************}
  431. Function GetEnvironmentVariable(Const EnvVar : String) : String;
  432. begin
  433. Result:=Dos.Getenv(shortstring(EnvVar));
  434. end;
  435. Function GetEnvironmentVariableCount : Integer;
  436. begin
  437. // Result:=FPCCountEnvVar(EnvP);
  438. Result:=Dos.envCount;
  439. end;
  440. Function GetEnvironmentString(Index : Integer) : {$ifdef FPC_RTL_UNICODE}UnicodeString{$else}AnsiString{$endif};
  441. begin
  442. // Result:=FPCGetEnvStrFromP(Envp,Index);
  443. Result:=Dos.EnvStr(Index);
  444. end;
  445. function ExecuteProcess (const Path: AnsiString; const ComLine: AnsiString;Flags:TExecuteFlags=[]):
  446. integer;
  447. var
  448. CommandLine: AnsiString;
  449. E: EOSError;
  450. begin
  451. Dos.Exec (Path, ComLine);
  452. if DosError <> 0 then begin
  453. if ComLine = '' then
  454. CommandLine := Path
  455. else
  456. CommandLine := Path + ' ' + ComLine;
  457. E := EOSError.CreateFmt (SExecuteProcessFailed, [CommandLine, DosError]);
  458. E.ErrorCode := DosError;
  459. raise E;
  460. end;
  461. end;
  462. function ExecuteProcess (const Path: AnsiString;
  463. const ComLine: array of AnsiString;Flags:TExecuteFlags=[]): integer;
  464. var
  465. CommandLine: AnsiString;
  466. I: integer;
  467. begin
  468. Commandline := '';
  469. for I := 0 to High (ComLine) do
  470. if Pos (' ', ComLine [I]) <> 0 then
  471. CommandLine := CommandLine + ' ' + '"' + ComLine [I] + '"'
  472. else
  473. CommandLine := CommandLine + ' ' + Comline [I];
  474. ExecuteProcess := ExecuteProcess (Path, CommandLine);
  475. end;
  476. procedure Sleep(Milliseconds: cardinal);
  477. begin
  478. // Amiga dos.library Delay() has precision of 1/50 seconds
  479. Delay(Milliseconds div 20);
  480. end;
  481. {****************************************************************************
  482. Initialization code
  483. ****************************************************************************}
  484. Initialization
  485. InitExceptions;
  486. InitInternational; { Initialize internationalization settings }
  487. Finalization
  488. DoneExceptions;
  489. end.