sysutils.pp 12 KB

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