sysutils.pp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2021 by Free Pascal development team
  4. Sysutils unit for Sinclair QL
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. unit sysutils;
  12. interface
  13. {$MODE objfpc}
  14. {$MODESWITCH OUT}
  15. { force ansistrings }
  16. {$H+}
  17. {$modeswitch typehelpers}
  18. {$modeswitch advancedrecords}
  19. {$DEFINE OS_FILESETDATEBYNAME}
  20. {$DEFINE HAS_SLEEP}
  21. {$DEFINE HAS_OSERROR}
  22. {OS has only 1 byte version for ExecuteProcess}
  23. {$define executeprocuni}
  24. { used OS file system APIs use ansistring }
  25. {$define SYSUTILS_HAS_ANSISTR_FILEUTIL_IMPL}
  26. { OS has an ansistring/single byte environment variable API }
  27. {$define SYSUTILS_HAS_ANSISTR_ENVVAR_IMPL}
  28. { Include platform independent interface part }
  29. {$i sysutilh.inc}
  30. { Platform dependent calls }
  31. implementation
  32. uses
  33. sysconst;
  34. {$DEFINE FPC_FEXPAND_UNC} (* UNC paths are supported *)
  35. {$DEFINE FPC_FEXPAND_DRIVES} (* Full paths begin with drive specification *)
  36. { Include platform independent implementation part }
  37. {$i sysutils.inc}
  38. {$i qdosh.inc}
  39. {$i qdosfuncs.inc}
  40. {$i smsfuncs.inc}
  41. {****************************************************************************
  42. File Functions
  43. ****************************************************************************}
  44. {$I-}{ Required for correct usage of these routines }
  45. (****** non portable routines ******)
  46. function FileOpen(const FileName: rawbytestring; Mode: Integer): THandle;
  47. var
  48. QLMode: Integer;
  49. begin
  50. FileOpen:=-1;
  51. case Mode of
  52. fmOpenRead: QLMode := Q_OPEN_IN;
  53. fmOpenWrite: QLMode := Q_OPEN_OVER;
  54. fmOpenReadWrite: QLMode := Q_OPEN;
  55. end;
  56. FileOpen := io_open(pchar(Filename), QLMode);
  57. if FileOpen < 0 then
  58. FileOpen:=-1;
  59. end;
  60. function FileGetDate(Handle: THandle) : Int64;
  61. begin
  62. result:=-1;
  63. end;
  64. function FileSetDate(Handle: THandle; Age: Int64) : LongInt;
  65. begin
  66. result:=0;
  67. end;
  68. function FileSetDate(const FileName: RawByteString; Age: Int64) : LongInt;
  69. var
  70. f: THandle;
  71. begin
  72. result:=-1;
  73. f:=FileOpen(FileName,fmOpenReadWrite);
  74. if f < 0 then
  75. exit;
  76. result:=FileSetDate(f,Age);
  77. FileClose(f);
  78. end;
  79. function FileCreate(const FileName: RawByteString) : THandle;
  80. begin
  81. DeleteFile(FileName);
  82. FileCreate := io_open(pchar(FileName), Q_OPEN_NEW);
  83. if FileCreate < 0 then
  84. FileCreate:=-1;
  85. end;
  86. function FileCreate(const FileName: RawByteString; Rights: integer): THandle;
  87. begin
  88. { Rights don't exist on the QL, so we simply map this to FileCreate() }
  89. FileCreate:=FileCreate(FileName);
  90. end;
  91. function FileCreate(const FileName: RawByteString; ShareMode: integer; Rights : integer): THandle;
  92. begin
  93. { Rights and ShareMode don't exist on the QL so we simply map this to FileCreate() }
  94. FileCreate:=FileCreate(FileName);
  95. end;
  96. function FileRead(Handle: THandle; out Buffer; Count: LongInt): LongInt;
  97. begin
  98. if (Count<=0) then
  99. exit;
  100. { io_fstrg handles EOF }
  101. FileRead := io_fstrg(Handle, -1, @Buffer, Count);
  102. if FileRead < 0 then
  103. FileRead:=-1;
  104. end;
  105. function FileWrite(Handle: THandle; const Buffer; Count: LongInt): LongInt;
  106. begin
  107. FileWrite:=-1;
  108. if (Count<=0) then
  109. exit;
  110. FileWrite:= io_sstrg(Handle, -1, @Buffer, Count);
  111. if FileWrite < 0 then
  112. FileWrite:=-1;
  113. end;
  114. function FileSeek(Handle: THandle; FOffset, Origin: LongInt) : LongInt;
  115. var
  116. dosResult: longint;
  117. seekEOF: longint;
  118. begin
  119. FileSeek := -1;
  120. case Origin of
  121. fsFromBeginning: dosResult := fs_posab(Handle, FOffset);
  122. fsFromCurrent: dosResult := fs_posre(Handle, FOffset);
  123. fsFromEnd:
  124. begin
  125. seekEOF := $7FFFFFBF;
  126. dosResult := fs_posab(Handle, seekEOF);
  127. fOffset := -FOffset;
  128. dosResult := fs_posre(Handle, FOffset);
  129. end;
  130. end;
  131. { We might need to handle Errors in dosResult, but
  132. EOF is permitted as a non-error in QDOS/SMSQ. }
  133. if dosResult = ERR_EF then
  134. dosResult := 0;
  135. if dosResult <> 0 then
  136. begin
  137. FileSeek := -1;
  138. exit;
  139. end;
  140. { However, BEWARE! FS_POSAB/FS_POSRE use FOFFSET as a VAR parameter.
  141. the new file position is returned in FOFFSET. }
  142. { Did we change FOffset? }
  143. FileSeek := FOffset;
  144. end;
  145. function FileSeek(Handle: THandle; FOffset: Int64; Origin: Longint): Int64;
  146. var
  147. longOffset: longint;
  148. begin
  149. longOffset := longint(FOffset);
  150. FileSeek:=FileSeek(Handle, longOffset, Origin);
  151. flush(output);
  152. end;
  153. procedure FileClose(Handle: THandle);
  154. begin
  155. io_close(Handle);
  156. end;
  157. function FileTruncate(Handle: THandle; Size: Int64): Boolean;
  158. begin
  159. FileTruncate := False;
  160. if FileSeek(Handle, LongInt(Size), fsFromBeginning) = -1 then
  161. exit;
  162. if fs_truncate(Handle) = 0 then
  163. FileTruncate := True;
  164. end;
  165. function DeleteFile(const FileName: RawByteString) : Boolean;
  166. begin
  167. DeleteFile:=false;
  168. if io_delet(pchar(Filename)) < 0 then
  169. exit;
  170. DeleteFile := True;
  171. end;
  172. function RenameFile(const OldName, NewName: RawByteString): Boolean;
  173. var
  174. Handle: THandle;
  175. QLerr: longint;
  176. begin
  177. RenameFile:=false;
  178. Handle := FileOpen(OldName, fmOpenReadWrite);
  179. if Handle = -1 then
  180. exit;
  181. QLerr := fs_rename(Handle, pchar(NewName));
  182. FileClose(Handle);
  183. if QLerr >= 0 then
  184. RenameFile := true;
  185. end;
  186. (****** end of non portable routines ******)
  187. function FileAge (const FileName : RawByteString): Int64;
  188. var
  189. f: THandle;
  190. begin
  191. FileAge:=-1;
  192. f:=FileOpen(FileName,fmOpenRead);
  193. if f < 0 then
  194. exit;
  195. FileAge:=FileGetDate(f);
  196. FileClose(f);
  197. end;
  198. function FileGetSymLinkTarget(const FileName: RawByteString; out SymLinkRec: TRawbyteSymLinkRec): Boolean;
  199. begin
  200. Result := False;
  201. end;
  202. function FileExists (const FileName : RawByteString; FollowLink : Boolean) : Boolean;
  203. var
  204. Attr: longint;
  205. begin
  206. FileExists:=false;
  207. Attr:=FileGetAttr(FileName);
  208. if Attr < 0 then
  209. exit;
  210. result:=(Attr and (faVolumeID or faDirectory)) = 0;
  211. end;
  212. type
  213. PInternalFindData = ^TInternalFindData;
  214. TInternalFindData = record
  215. dummy: pointer;
  216. end;
  217. Function InternalFindFirst (Const Path : RawByteString; Attr : Longint; out Rslt : TAbstractSearchRec; var Name: RawByteString) : Longint;
  218. var
  219. dosResult: longint;
  220. IFD: PInternalFindData;
  221. begin
  222. result:=-1; { We emulate Linux/Unix behaviour, and return -1 on errors. }
  223. new(IFD);
  224. IFD^.dummy:=nil;
  225. Rslt.FindHandle:=nil;
  226. dosResult:=-1; { add findfirst here }
  227. if dosResult < 0 then
  228. begin
  229. InternalFindClose(IFD);
  230. exit;
  231. end;
  232. Rslt.FindHandle:=IFD;
  233. Name:='';
  234. SetCodePage(Name,DefaultFileSystemCodePage,false);
  235. Rslt.Time:=0;
  236. Rslt.Size:=0;
  237. { "128" is Windows "NORMALFILE" attribute. Some buggy code depend on this... :( (KB) }
  238. Rslt.Attr := 128 or 0;
  239. result:=0;
  240. end;
  241. Function InternalFindNext (var Rslt : TAbstractSearchRec; var Name : RawByteString) : Longint;
  242. var
  243. dosResult: longint;
  244. IFD: PInternalFindData;
  245. begin
  246. result:=-1;
  247. IFD:=PInternalFindData(Rslt.FindHandle);
  248. if not assigned(IFD) then
  249. exit;
  250. dosResult:=-1;
  251. if dosResult < 0 then
  252. exit;
  253. Name:='';
  254. SetCodePage(Name,DefaultFileSystemCodePage,false);
  255. Rslt.Time:=0;
  256. Rslt.Size:=0;
  257. { "128" is Windows "NORMALFILE" attribute. Some buggy code depend on this... :( (KB) }
  258. Rslt.Attr := 128 or 0;
  259. result:=0;
  260. end;
  261. Procedure InternalFindClose(var Handle: Pointer);
  262. var
  263. IFD: PInternalFindData;
  264. begin
  265. IFD:=PInternalFindData(Handle);
  266. if not assigned(IFD) then
  267. exit;
  268. dispose(IFD);
  269. end;
  270. (****** end of non portable routines ******)
  271. Function FileGetAttr (Const FileName : RawByteString) : Longint;
  272. begin
  273. FileGetAttr:=0;
  274. end;
  275. Function FileSetAttr (Const Filename : RawByteString; Attr: longint) : Longint;
  276. begin
  277. FileSetAttr:=-1;
  278. if FileSetAttr < -1 then
  279. FileSetAttr:=-1
  280. else
  281. FileSetAttr:=0;
  282. end;
  283. {****************************************************************************
  284. Disk Functions
  285. ****************************************************************************}
  286. function DiskSize(Drive: Byte): Int64;
  287. var
  288. dosResult: longint;
  289. begin
  290. DiskSize := -1;
  291. dosResult:=-1;
  292. if dosResult < 0 then
  293. exit;
  294. DiskSize:=0;
  295. end;
  296. function DiskFree(Drive: Byte): Int64;
  297. var
  298. dosResult: longint;
  299. begin
  300. DiskFree := -1;
  301. dosResult:=-1;
  302. if dosResult < 0 then
  303. exit;
  304. DiskFree:=0;
  305. end;
  306. function DirectoryExists(const Directory: RawByteString; FollowLink : Boolean): Boolean;
  307. var
  308. Attr: longint;
  309. begin
  310. DirectoryExists:=false;
  311. Attr:=FileGetAttr(Directory);
  312. if Attr < 0 then
  313. exit;
  314. result:=(Attr and faDirectory) <> 0;
  315. end;
  316. {****************************************************************************
  317. Locale Functions
  318. ****************************************************************************}
  319. Procedure GetLocalTime(var SystemTime: TSystemTime);
  320. begin
  321. DateTimeToSystemTime(FileDateToDateTime(0),SystemTime);
  322. end;
  323. Procedure InitAnsi;
  324. Var
  325. i : longint;
  326. begin
  327. { Fill table entries 0 to 127 }
  328. for i := 0 to 96 do
  329. UpperCaseTable[i] := chr(i);
  330. for i := 97 to 122 do
  331. UpperCaseTable[i] := chr(i - 32);
  332. for i := 123 to 191 do
  333. UpperCaseTable[i] := chr(i);
  334. Move (CPISO88591UCT,UpperCaseTable[192],SizeOf(CPISO88591UCT));
  335. for i := 0 to 64 do
  336. LowerCaseTable[i] := chr(i);
  337. for i := 65 to 90 do
  338. LowerCaseTable[i] := chr(i + 32);
  339. for i := 91 to 191 do
  340. LowerCaseTable[i] := chr(i);
  341. Move (CPISO88591LCT,UpperCaseTable[192],SizeOf(CPISO88591UCT));
  342. end;
  343. Procedure InitInternational;
  344. begin
  345. InitInternationalGeneric;
  346. InitAnsi;
  347. end;
  348. function SysErrorMessage(ErrorCode: Integer): String;
  349. begin
  350. Result:=Format(SUnknownErrorCode,[ErrorCode]);
  351. end;
  352. function GetLastOSError: Integer;
  353. begin
  354. result:=-1;
  355. end;
  356. {****************************************************************************
  357. OS utility functions
  358. ****************************************************************************}
  359. function GetPathString: String;
  360. begin
  361. {writeln('Unimplemented GetPathString');}
  362. result := '';
  363. end;
  364. Function GetEnvironmentVariable(Const EnvVar : String) : String;
  365. begin
  366. {writeln('Unimplemented GetEnvironmentVariable');}
  367. result:='';
  368. end;
  369. Function GetEnvironmentVariableCount : Integer;
  370. begin
  371. {writeln('Unimplemented GetEnvironmentVariableCount');}
  372. result:=0;
  373. end;
  374. Function GetEnvironmentString(Index : Integer) : {$ifdef FPC_RTL_UNICODE}UnicodeString{$else}AnsiString{$endif};
  375. begin
  376. {writeln('Unimplemented GetEnvironmentString');}
  377. result:='';
  378. end;
  379. function ExecuteProcess (const Path: RawByteString; const ComLine: RawByteString;Flags:TExecuteFlags=[]):
  380. integer;
  381. var
  382. tmpPath: RawByteString;
  383. pcmdline: ShortString;
  384. CommandLine: RawByteString;
  385. E: EOSError;
  386. begin
  387. tmpPath:=ToSingleByteFileSystemEncodedFileName(Path);
  388. pcmdline:=ToSingleByteFileSystemEncodedFileName(ComLine);
  389. result:=-1; { execute here }
  390. if result < 0 then begin
  391. if ComLine = '' then
  392. CommandLine := Path
  393. else
  394. CommandLine := Path + ' ' + ComLine;
  395. E := EOSError.CreateFmt (SExecuteProcessFailed, [CommandLine, result]);
  396. E.ErrorCode := result;
  397. raise E;
  398. end;
  399. end;
  400. function ExecuteProcess (const Path: RawByteString;
  401. const ComLine: array of RawByteString;Flags:TExecuteFlags=[]): integer;
  402. var
  403. CommandLine: RawByteString;
  404. I: integer;
  405. begin
  406. Commandline := '';
  407. for I := 0 to High (ComLine) do
  408. if Pos (' ', ComLine [I]) <> 0 then
  409. CommandLine := CommandLine + ' ' + '"' + ToSingleByteFileSystemEncodedFileName(ComLine [I]) + '"'
  410. else
  411. CommandLine := CommandLine + ' ' + ToSingleByteFileSystemEncodedFileName(Comline [I]);
  412. ExecuteProcess := ExecuteProcess (Path, CommandLine);
  413. end;
  414. procedure Sleep(Milliseconds: cardinal);
  415. begin
  416. {writeln('Unimplemented sleep');}
  417. end;
  418. {****************************************************************************
  419. Initialization code
  420. ****************************************************************************}
  421. Initialization
  422. InitExceptions;
  423. InitInternational; { Initialize internationalization settings }
  424. OnBeep:=Nil; { No SysBeep() on the QL for now. }
  425. Finalization
  426. FreeTerminateProcs;
  427. DoneExceptions;
  428. end.