sysutils.pp 12 KB

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