sysutils.pp 12 KB

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