sysfile.inc 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2020 by Free Pascal development team
  4. Low level file functions for the 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. {****************************************************************************
  12. Low level File Routines
  13. All these functions can set InOutRes on errors
  14. ****************************************************************************}
  15. { close a file from the handle value }
  16. procedure do_close(handle : longint);
  17. begin
  18. Error2InOutRes(io_close(handle));
  19. end;
  20. { delete a file, given its name }
  21. procedure do_erase(p : pchar; pchangeable: boolean);
  22. begin
  23. Error2InOutRes(io_delet(p));
  24. end;
  25. procedure do_rename(p1,p2 : pchar; p1changeable, p2changeable: boolean);
  26. var
  27. chanId: longint;
  28. res: longint;
  29. begin
  30. { To rename a QL file, it must exist and be opened. For WIN/FLP this
  31. means open mode 0 (Q_OPEN) but for RAM this can be any of Q_OPEN,
  32. Q_OPEN_NEW or Q_OPEN_OVER. }
  33. { Does the file exist? }
  34. chanId := io_open(p1, Q_OPEN_IN);
  35. if chanId < 0 then
  36. begin
  37. InOutRes:=2; { File not found. }
  38. exit;
  39. end;
  40. { Close and reopen in correct mode. }
  41. io_close(chanId);
  42. chanId := io_open(p1, Q_OPEN);
  43. if chanId < 0 then
  44. begin
  45. Error2InOutRes(chanId);
  46. exit;
  47. end;
  48. { Now, finally, we can rename. }
  49. res := fs_rename(chanId,p2);
  50. { Close the file. Never errors out. }
  51. io_close(chanId);
  52. if res < 0 then
  53. Error2InOutRes(res);
  54. end;
  55. function do_write(h: longint; addr: pointer; len: longint) : longint;
  56. var
  57. res: longint;
  58. begin
  59. do_write:=0;
  60. res:=io_sstrg(h, -1, addr, len);
  61. if res < 0 then
  62. Error2InOutRes(res)
  63. else
  64. do_write:=res;
  65. end;
  66. function do_read(h: longint; addr: pointer; len: longint) : longint;
  67. var
  68. res: longint;
  69. begin
  70. do_read := 0;
  71. res := io_fline(h, -1, addr, len);
  72. if res = ERR_EF then
  73. res := 0;
  74. if res < 0 then
  75. Error2InOutRes(res)
  76. else
  77. do_read := res;
  78. end;
  79. function do_filepos(handle: longint): longint;
  80. var
  81. res: longint;
  82. pos: longint;
  83. begin
  84. do_filepos := 0;
  85. pos := 0;
  86. res := fs_posre(handle, pos);
  87. if res = ERR_EF then
  88. res := 0;
  89. if (res < 0) then
  90. Error2InOutRes(res)
  91. else
  92. do_filepos := pos;
  93. end;
  94. procedure do_seek(handle, pos: longint);
  95. var
  96. res: longint;
  97. begin
  98. res := fs_posab(handle, pos);
  99. if res = ERR_EF then
  100. res := 0;
  101. if (res < 0) then
  102. Error2InOutRes(res);
  103. end;
  104. { The maximum length of a QL file is 2^31 - 64 bytes ($7FFFFFC0)
  105. so the maximum offset is that, minus 1. ($7fffffBF) }
  106. const
  107. MAX_QL_FILE_LENGTH = $7FFFFFBF;
  108. function do_seekend(handle: longint): longint;
  109. var
  110. res: longint;
  111. pos: longint;
  112. begin
  113. do_seekend:=-1;
  114. pos:=MAX_QL_FILE_LENGTH;
  115. res:=fs_posab(handle, pos);
  116. if res = ERR_EF then
  117. res := 0;
  118. if res < 0 then
  119. Error2InOutRes(res)
  120. else
  121. do_seekend := pos;
  122. end;
  123. function do_filesize(handle: longint): longint;
  124. var
  125. res: longint;
  126. header: array [0..$39] of byte;
  127. begin
  128. do_filesize := 0;
  129. res := fs_headr(handle, @header, $40);
  130. if res < 0 then
  131. Error2InOutRes(res)
  132. else
  133. do_filesize := plongint(@header[0])^;
  134. end;
  135. { truncate at a given position }
  136. procedure do_truncate(handle, pos: longint);
  137. begin
  138. do_seek(handle, pos);
  139. fs_truncate(handle);
  140. end;
  141. procedure do_open(var f;p:pchar;flags:longint; pchangeable: boolean);
  142. {
  143. filerec and textrec have both handle and mode as the first items so
  144. they could use the same routine for opening/creating.
  145. when (flags and $100) the file will be append
  146. when (flags and $1000) the file will be truncate/rewritten
  147. when (flags and $10000) there is no check for close (needed for textfiles)
  148. }
  149. var
  150. res: longint;
  151. openMode: longint;
  152. begin
  153. openMode:=Q_OPEN;
  154. { close first if opened }
  155. if ((flags and $10000)=0) then
  156. begin
  157. case filerec(f).mode of
  158. fmInput, fmOutput, fmInout:
  159. do_close(filerec(f).handle);
  160. fmClosed: ;
  161. else
  162. begin
  163. InOutRes:=102; {not assigned}
  164. exit;
  165. end;
  166. end;
  167. end;
  168. { reset file handle }
  169. filerec(f).handle:=UnusedHandle;
  170. { convert filemode to filerec modes }
  171. case (flags and 3) of
  172. 0 : filerec(f).mode:=fmInput;
  173. 1 : filerec(f).mode:=fmOutput;
  174. 2 : filerec(f).mode:=fmInout;
  175. end;
  176. { empty name is special }
  177. if p[0]=#0 then begin
  178. case filerec(f).mode of
  179. fminput :
  180. filerec(f).handle:=StdInputHandle;
  181. fmappend,
  182. fmoutput : begin
  183. filerec(f).handle:=StdOutputHandle;
  184. filerec(f).mode:=fmOutput; {fool fmappend}
  185. end;
  186. end;
  187. exit;
  188. end;
  189. { rewrite (create a new file) }
  190. if (flags and $1000)<>0 then openMode:=Q_OPEN_OVER;
  191. res:=io_open(p,openMode);
  192. if res < 0 then
  193. begin
  194. Error2InOutRes(res);
  195. filerec(f).mode:=fmClosed;
  196. exit;
  197. end
  198. else
  199. filerec(f).handle:=res;
  200. { append mode }
  201. if ((Flags and $100)<>0) and
  202. (FileRec(F).Handle<>UnusedHandle) then begin
  203. do_seekend(filerec(f).handle);
  204. filerec(f).mode:=fmOutput; {fool fmappend}
  205. end;
  206. end;
  207. function do_isdevice(handle: thandle): boolean;
  208. begin
  209. { FIXME: See if this can be implemented properly on the QL. }
  210. { Prefer to return true here as a default answer, as it is less harmful
  211. than false. This basically determines if the file handle is a "device",
  212. for example the console. Returning true here causes a flush before a
  213. read on the file handle which is preferred for consoleio, and a few
  214. other minor behavioral changes, for example shorter stacktraces.
  215. Returning false will cause weird behavior and unprinted lines when
  216. read() and write() is mixed during consoleio. }
  217. do_isdevice:=true;
  218. end;