sysfile.inc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2005 by Free Pascal development team
  4. Low level file functions
  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. { Enable this for file handling debug }
  12. {DEFINE ASYS_FPC_FILEDEBUG}
  13. {*****************************************************************************
  14. File-handling Support Functions
  15. *****************************************************************************}
  16. type
  17. { AmigaOS does not automatically close opened files on exit back to }
  18. { the operating system, therefore as a precuation we close all files }
  19. { manually on exit. }
  20. PFileList = ^TFileList;
  21. TFileList = record { no packed, must be correctly aligned }
  22. handle : LongInt; { Handle to file }
  23. next : PFileList; { Next file in list }
  24. buffered : boolean; { used buffered I/O? }
  25. end;
  26. var
  27. ASYS_fileList: PFileList; public name 'ASYS_FILELIST'; { List pointer to opened files }
  28. { Function to be called at program shutdown, to close all opened files }
  29. procedure CloseList(l: PFileList);
  30. var
  31. tmpNext : PFileList;
  32. tmpHandle : LongInt;
  33. begin
  34. if l=nil then exit;
  35. { First, close all tracked files }
  36. tmpNext:=l^.next;
  37. while tmpNext<>nil do begin
  38. tmpHandle:=tmpNext^.handle;
  39. if (tmpHandle<>StdInputHandle) and (tmpHandle<>StdOutputHandle)
  40. and (tmpHandle<>StdErrorHandle) then begin
  41. dosClose(tmpHandle);
  42. end;
  43. tmpNext:=tmpNext^.next;
  44. end;
  45. { Next, erase the linked list }
  46. while l<>nil do begin
  47. tmpNext:=l;
  48. l:=l^.next;
  49. dispose(tmpNext);
  50. end;
  51. end;
  52. { Function to be called to add a file to the opened file list }
  53. procedure AddToList(var l: PFileList; h: LongInt); alias: 'ADDTOLIST'; [public];
  54. var
  55. p : PFileList;
  56. inList: Boolean;
  57. begin
  58. inList:=False;
  59. if l<>nil then begin
  60. { if there is a valid filelist, search for the value }
  61. { in the list to avoid double additions }
  62. p:=l;
  63. while (p^.next<>nil) and (not inList) do
  64. if p^.next^.handle=h then inList:=True
  65. else p:=p^.next;
  66. p:=nil;
  67. end else begin
  68. { if the list is not yet allocated, allocate it. }
  69. New(l);
  70. l^.next:=nil;
  71. end;
  72. if not inList then begin
  73. New(p);
  74. p^.handle:=h;
  75. p^.buffered:=False;
  76. p^.next:=l^.next;
  77. l^.next:=p;
  78. end
  79. {$IFDEF ASYS_FPC_FILEDEBUG}
  80. else
  81. RawDoFmt('FPC_FILE_DEBUG: Error! Trying add filehandle a filehandle twice: $%lx !'+#10,@h,pointer(1),nil);
  82. {$ENDIF}
  83. ;
  84. end;
  85. { Function to be called to remove a file from the list }
  86. function RemoveFromList(var l: PFileList; h: LongInt): boolean; alias: 'REMOVEFROMLIST'; [public];
  87. var
  88. p : PFileList;
  89. inList : Boolean;
  90. tmpList: PFileList;
  91. begin
  92. inList:=False;
  93. if l=nil then begin
  94. RemoveFromList:=inList;
  95. exit;
  96. end;
  97. p:=l;
  98. while (p^.next<>nil) and (not inList) do
  99. if p^.next^.handle=h then inList:=True
  100. else p:=p^.next;
  101. if inList then begin
  102. tmpList:=p^.next^.next;
  103. dispose(p^.next);
  104. p^.next:=tmpList;
  105. end
  106. {$IFDEF ASYS_FPC_FILEDEBUG}
  107. else
  108. RawDoFmt('FPC_FILE_DEBUG: Error! Trying to remove not existing filehandle: $%lx !'+#10,@h,pointer(1),nil);
  109. {$ENDIF}
  110. ;
  111. RemoveFromList:=inList;
  112. end;
  113. { Function to check if file is in the list }
  114. function CheckInList(var l: PFileList; h: LongInt): pointer; alias: 'CHECKINLIST'; [public];
  115. var
  116. p : PFileList;
  117. inList : Pointer;
  118. begin
  119. inList:=nil;
  120. if l=nil then begin
  121. CheckInList:=inList;
  122. exit;
  123. end;
  124. p:=l;
  125. while (p^.next<>nil) and (inList=nil) do
  126. if p^.next^.handle=h then inList:=p^.next
  127. else p:=p^.next;
  128. {$IFDEF ASYS_FPC_FILEDEBUG}
  129. if inList=nil then
  130. RawDoFmt('FPC_FILE_DEBUG: Warning! Check for not existing filehandle: $%lx !'+#10,@h,pointer(1),nil);
  131. {$ENDIF}
  132. CheckInList:=inList;
  133. end;
  134. {****************************************************************************
  135. Low level File Routines
  136. All these functions can set InOutRes on errors
  137. ****************************************************************************}
  138. { close a file from the handle value }
  139. procedure do_close(handle : longint);
  140. begin
  141. if RemoveFromList(ASYS_fileList,handle) then begin
  142. { Do _NOT_ check CTRL_C on Close, because it will conflict
  143. with System_Exit! }
  144. if not dosClose(handle) then
  145. dosError2InOut(IoErr);
  146. end;
  147. end;
  148. procedure do_erase(p : pchar; pchangeable: boolean);
  149. var
  150. tmpStr: array[0..255] of Char;
  151. begin
  152. tmpStr:=PathConv(strpas(p))+#0;
  153. checkCTRLC;
  154. if not dosDeleteFile(@tmpStr) then
  155. dosError2InOut(IoErr);
  156. end;
  157. procedure do_rename(p1,p2 : pchar; p1changeable, p2changeable: boolean);
  158. { quite stack-effective code, huh? :) damn path conversions... (KB) }
  159. var
  160. tmpStr1: array[0..255] of Char;
  161. tmpStr2: array[0..255] of Char;
  162. begin
  163. tmpStr1:=PathConv(strpas(p1))+#0;
  164. tmpStr2:=PathConv(strpas(p2))+#0;
  165. checkCTRLC;
  166. if not (dosRename(@tmpStr1,@tmpStr2) <> 0) then
  167. dosError2InOut(IoErr);
  168. end;
  169. function do_write(h: longint; addr: pointer; len: longint) : longint;
  170. var dosResult: LongInt;
  171. begin
  172. checkCTRLC;
  173. do_write:=0;
  174. if (len<=0) or (h=0) or (h=-1) then exit;
  175. {$IFDEF ASYS_FPC_FILEDEBUG}
  176. if not ((h=StdOutputHandle) or (h=StdInputHandle) or
  177. (h=StdErrorHandle)) then CheckInList(ASYS_fileList,h);
  178. {$ENDIF}
  179. dosResult:=dosWrite(h,addr,len);
  180. if dosResult<0 then begin
  181. dosError2InOut(IoErr);
  182. end else begin
  183. do_write:=dosResult;
  184. end;
  185. end;
  186. function do_read(h: longint; addr: pointer; len: longint) : longint;
  187. var dosResult: LongInt;
  188. begin
  189. checkCTRLC;
  190. do_read:=0;
  191. if (len<=0) or (h=0) or (h=-1) then exit;
  192. {$IFDEF ASYS_FPC_FILEDEBUG}
  193. if not ((h=StdOutputHandle) or (h=StdInputHandle) or
  194. (h=StdErrorHandle)) then CheckInList(ASYS_fileList,h);
  195. {$ENDIF}
  196. dosResult:=dosRead(h,addr,len);
  197. if dosResult<0 then begin
  198. dosError2InOut(IoErr);
  199. end else begin
  200. do_read:=dosResult;
  201. end
  202. end;
  203. function do_filepos(handle: longint) : longint;
  204. var dosResult: LongInt;
  205. begin
  206. checkCTRLC;
  207. do_filepos:=-1;
  208. if CheckInList(ASYS_fileList,handle)<>nil then begin
  209. { Seeking zero from OFFSET_CURRENT to find out where we are }
  210. dosResult:=dosSeek(handle,0,OFFSET_CURRENT);
  211. if dosResult<0 then begin
  212. dosError2InOut(IoErr);
  213. end else begin
  214. do_filepos:=dosResult;
  215. end;
  216. end;
  217. end;
  218. procedure do_seek(handle, pos: longint);
  219. begin
  220. checkCTRLC;
  221. if CheckInList(ASYS_fileList,handle)<>nil then begin
  222. { Seeking from OFFSET_BEGINNING }
  223. if dosSeek(handle,pos,OFFSET_BEGINNING)<0 then
  224. dosError2InOut(IoErr);
  225. end;
  226. end;
  227. function do_seekend(handle: longint):longint;
  228. var dosResult: LongInt;
  229. begin
  230. checkCTRLC;
  231. do_seekend:=-1;
  232. if CheckInList(ASYS_fileList,handle)<>nil then begin
  233. { Seeking to OFFSET_END }
  234. dosResult:=dosSeek(handle,0,OFFSET_END);
  235. if dosResult<0 then begin
  236. dosError2InOut(IoErr);
  237. end else begin
  238. do_seekend:=dosSeek(handle,0,OFFSET_CURRENT);
  239. end;
  240. end;
  241. end;
  242. {$DEFINE ASYS_FILESIZE_NO_DOUBLE_SEEK}
  243. { I changed the double-Seek filesize method which we
  244. were using for 10+ years to the new ExamineFH() method.
  245. It should be available AmigaOS 2.0+, and much faster.
  246. (I actually measured several magnitudes of improvement,
  247. especially on large files.)
  248. It should be safe since there are several libc implementations
  249. using the same method on all Amiga flavors, but if anyone has
  250. a problem with it, disable this define to revert to the old
  251. method and report the issue. (KB) }
  252. function do_filesize(handle : longint) : longint;
  253. var
  254. {$IFDEF ASYS_FILESIZE_NO_DOUBLE_SEEK}
  255. fib: PFileInfoBlock;
  256. {$ENDIF}
  257. currfilepos: longint;
  258. begin
  259. checkCTRLC;
  260. do_filesize:=-1;
  261. if CheckInList(ASYS_fileList,handle)<>nil then begin
  262. {$IFDEF ASYS_FILESIZE_NO_DOUBLE_SEEK}
  263. fib:=AllocDosObject(DOS_FIB,nil);
  264. if fib <> nil then begin
  265. if ExamineFH(BPTR(handle), fib) then
  266. do_filesize:=fib^.fib_Size;
  267. FreeDosObject(DOS_FIB,fib);
  268. end;
  269. {$ELSE}
  270. currfilepos:=do_filepos(handle);
  271. do_filesize:=do_seekend(handle);
  272. do_seek(handle,currfilepos);
  273. {$ENDIF}
  274. end;
  275. end;
  276. { truncate at a given position }
  277. procedure do_truncate(handle, pos: longint);
  278. begin
  279. checkCTRLC;
  280. if CheckInList(ASYS_fileList,handle)<>nil then begin
  281. { Seeking from OFFSET_BEGINNING }
  282. if SetFileSize(handle,pos,OFFSET_BEGINNING)<0 then
  283. dosError2InOut(IoErr);
  284. end;
  285. end;
  286. procedure do_open(var f;p:pchar;flags:longint; pchangeable: boolean);
  287. {
  288. filerec and textrec have both handle and mode as the first items so
  289. they could use the same routine for opening/creating.
  290. when (flags and $10) the file will be append
  291. when (flags and $100) the file will be truncate/rewritten
  292. when (flags and $1000) there is no check for close (needed for textfiles)
  293. }
  294. var
  295. handle : LongInt;
  296. openflags: LongInt;
  297. tmpStr : array[0..255] of Char;
  298. begin
  299. tmpStr:=PathConv(strpas(p))+#0;
  300. { close first if opened }
  301. if ((flags and $10000)=0) then begin
  302. case filerec(f).mode of
  303. fminput,fmoutput,fminout : Do_Close(filerec(f).handle);
  304. fmclosed : ;
  305. else begin
  306. inoutres:=102; {not assigned}
  307. exit;
  308. end;
  309. end;
  310. end;
  311. { reset file handle }
  312. filerec(f).handle:=UnusedHandle;
  313. { convert filemode to filerec modes }
  314. { READ/WRITE on existing file }
  315. { RESET/APPEND }
  316. openflags:=MODE_OLDFILE;
  317. case (flags and 3) of
  318. 0 : filerec(f).mode:=fminput;
  319. 1 : filerec(f).mode:=fmoutput;
  320. 2 : filerec(f).mode:=fminout;
  321. end;
  322. { rewrite (create a new file) }
  323. if (flags and $1000)<>0 then openflags:=MODE_NEWFILE;
  324. { empty name is special }
  325. if p[0]=#0 then begin
  326. case filerec(f).mode of
  327. fminput :
  328. filerec(f).handle:=StdInputHandle;
  329. fmappend,
  330. fmoutput : begin
  331. filerec(f).handle:=StdOutputHandle;
  332. filerec(f).mode:=fmoutput; {fool fmappend}
  333. end;
  334. end;
  335. exit;
  336. end;
  337. handle:=Open(@tmpStr,openflags);
  338. if handle=0 then begin
  339. begin
  340. dosError2InOut(IoErr);
  341. FileRec(f).mode:=fmclosed;
  342. end
  343. end else begin
  344. AddToList(ASYS_fileList,handle);
  345. filerec(f).handle:=handle;
  346. end;
  347. { append mode }
  348. if ((Flags and $100)<>0) and
  349. (FileRec(F).Handle<>UnusedHandle) then begin
  350. do_seekend(filerec(f).handle);
  351. filerec(f).mode:=fmoutput; {fool fmappend}
  352. end;
  353. end;
  354. function do_isdevice(handle: longint): boolean;
  355. begin
  356. if (handle=StdOutputHandle) or (handle=StdInputHandle) or
  357. (handle=StdErrorHandle) then
  358. do_isdevice:=True
  359. else
  360. do_isdevice:=False;
  361. end;