123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263 |
- {
- This file is part of the Free Pascal run time library.
- Copyright (c) 2020 by Free Pascal development team
- Low level file functions for the Sinclair QL
- See the file COPYING.FPC, included in this distribution,
- for details about the copyright.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- **********************************************************************}
- {****************************************************************************
- Low level File Routines
- All these functions can set InOutRes on errors
- ****************************************************************************}
- { close a file from the handle value }
- procedure do_close(handle : longint);
- begin
- Error2InOutRes(io_close(handle));
- end;
- { delete a file, given its name }
- procedure do_erase(p : pchar; pchangeable: boolean);
- begin
- Error2InOutRes(io_delet(p));
- end;
- procedure do_rename(p1,p2 : pchar; p1changeable, p2changeable: boolean);
- var
- chanId: longint;
- res: longint;
- begin
- { To rename a QL file, it must exist and be opened. For WIN/FLP this
- means open mode 0 (Q_OPEN) but for RAM this can be any of Q_OPEN,
- Q_OPEN_NEW or Q_OPEN_OVER. }
- { Does the file exist? }
- chanId := io_open(p1, Q_OPEN_IN);
- if chanId < 0 then
- begin
- InOutRes:=2; { File not found. }
- exit;
- end;
- { Close and reopen in correct mode. }
- io_close(chanId);
- chanId := io_open(p1, Q_OPEN);
- if chanId < 0 then
- begin
- Error2InOutRes(chanId);
- exit;
- end;
- { Now, finally, we can rename. }
- res := fs_rename(chanId,p2);
- { Close the file. Never errors out. }
- io_close(chanId);
- if res < 0 then
- Error2InOutRes(res);
- end;
- function do_write(h: longint; addr: pointer; len: longint) : longint;
- var
- res: longint;
- begin
- do_write:=0;
- res:=io_sstrg(h, -1, addr, len);
- if res < 0 then
- Error2InOutRes(res)
- else
- do_write:=res;
- end;
- function do_read(h: longint; addr: pointer; len: longint) : longint;
- var
- res: longint;
- begin
- do_read := 0;
- res := io_fline(h, -1, addr, len);
- if res = ERR_EF then
- res := 0;
- if res < 0 then
- Error2InOutRes(res)
- else
- do_read := res;
- end;
- function do_filepos(handle: longint): longint;
- var
- res: longint;
- pos: longint;
- begin
- do_filepos := 0;
- pos := 0;
- res := fs_posre(handle, pos);
- if res = ERR_EF then
- res := 0;
- if (res < 0) then
- Error2InOutRes(res)
- else
- do_filepos := pos;
- end;
- procedure do_seek(handle, pos: longint);
- var
- res: longint;
- begin
- res := fs_posab(handle, pos);
- if res = ERR_EF then
- res := 0;
- if (res < 0) then
- Error2InOutRes(res);
- end;
- { The maximum length of a QL file is 2^31 - 64 bytes ($7FFFFFC0)
- so the maximum offset is that, minus 1. ($7fffffBF) }
- const
- MAX_QL_FILE_LENGTH = $7FFFFFBF;
- function do_seekend(handle: longint): longint;
- var
- res: longint;
- pos: longint;
- begin
- do_seekend:=-1;
- pos:=MAX_QL_FILE_LENGTH;
- res:=fs_posab(handle, pos);
- if res = ERR_EF then
- res := 0;
- if res < 0 then
- Error2InOutRes(res)
- else
- do_seekend := pos;
- end;
- function do_filesize(handle: longint): longint;
- var
- res: longint;
- header: array [0..$39] of byte;
- begin
- do_filesize := 0;
- res := fs_headr(handle, @header, $40);
- if res < 0 then
- Error2InOutRes(res)
- else
- do_filesize := plongint(@header[0])^;
- end;
- { truncate at a given position }
- procedure do_truncate(handle, pos: longint);
- begin
- do_seek(handle, pos);
- fs_truncate(handle);
- end;
- procedure do_open(var f;p:pchar;flags:longint; pchangeable: boolean);
- {
- filerec and textrec have both handle and mode as the first items so
- they could use the same routine for opening/creating.
- when (flags and $100) the file will be append
- when (flags and $1000) the file will be truncate/rewritten
- when (flags and $10000) there is no check for close (needed for textfiles)
- }
- var
- res: longint;
- openMode: longint;
- begin
- openMode:=Q_OPEN;
- { close first if opened }
- if ((flags and $10000)=0) then
- begin
- case filerec(f).mode of
- fmInput, fmOutput, fmInout:
- do_close(filerec(f).handle);
- fmClosed: ;
- else
- begin
- InOutRes:=102; {not assigned}
- exit;
- end;
- end;
- end;
- { reset file handle }
- filerec(f).handle:=UnusedHandle;
- { convert filemode to filerec modes }
- case (flags and 3) of
- 0 : filerec(f).mode:=fmInput;
- 1 : filerec(f).mode:=fmOutput;
- 2 : filerec(f).mode:=fmInout;
- end;
- { empty name is special }
- if p[0]=#0 then begin
- case filerec(f).mode of
- fminput :
- filerec(f).handle:=StdInputHandle;
- fmappend,
- fmoutput : begin
- filerec(f).handle:=StdOutputHandle;
- filerec(f).mode:=fmOutput; {fool fmappend}
- end;
- end;
- exit;
- end;
- { rewrite (create a new file) }
- if (flags and $1000)<>0 then openMode:=Q_OPEN_OVER;
- res:=io_open(p,openMode);
- if res < 0 then
- begin
- Error2InOutRes(res);
- filerec(f).mode:=fmClosed;
- exit;
- end
- else
- filerec(f).handle:=res;
- { append mode }
- if ((Flags and $100)<>0) and
- (FileRec(F).Handle<>UnusedHandle) then begin
- do_seekend(filerec(f).handle);
- filerec(f).mode:=fmOutput; {fool fmappend}
- end;
- end;
- function do_isdevice(handle: thandle): boolean;
- begin
- { FIXME: See if this can be implemented properly on the QL. }
- { Prefer to return true here as a default answer, as it is less harmful
- than false. This basically determines if the file handle is a "device",
- for example the console. Returning true here causes a flush before a
- read on the file handle which is preferred for consoleio, and a few
- other minor behavioral changes, for example shorter stacktraces.
- Returning false will cause weird behavior and unprinted lines when
- read() and write() is mixed during consoleio. }
- do_isdevice:=true;
- end;
|