sysfile.inc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2001 by Free Pascal development team
  4. Low leve 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. { Keep Track of open files }
  12. const
  13. max_files = 50;
  14. var
  15. openfiles : array [0..max_files-1] of boolean;
  16. {$ifdef SYSTEMDEBUG}
  17. opennames : array [0..max_files-1] of pchar;
  18. const
  19. free_closed_names : boolean = true;
  20. verbose_files : boolean = true;
  21. { we cannot allocate memory using SysGetMem, as we use tinyheap code,
  22. but tinyheap.inc source in inserted later, so we need a forward declaration }
  23. function SysTinyFreeMemSize(Addr: Pointer; Size: Ptruint): ptruint; forward;
  24. function SysTinyGetMem(Size: ptruint): pointer; forward;
  25. {$endif SYSTEMDEBUG}
  26. {****************************************************************************
  27. Low level File Routines
  28. ****************************************************************************}
  29. procedure do_close(handle : thandle);
  30. var
  31. regs : Registers;
  32. begin
  33. if Handle<=4 then
  34. exit;
  35. regs.BX:=handle;
  36. if handle<max_files then
  37. begin
  38. {$ifdef SYSTEMDEBUG}
  39. if not openfiles[handle] then
  40. Writeln(stderr,'Trying to close file h=',handle,' marked as closed');
  41. if assigned(opennames[handle]) and free_closed_names then
  42. begin
  43. if verbose_files then
  44. Writeln(stderr,'file ',opennames[handle],' closed');
  45. systinyfreememsize(opennames[handle],strlen(opennames[handle])+1);
  46. opennames[handle]:=nil;
  47. end;
  48. {$endif SYSTEMDEBUG}
  49. openfiles[handle]:=false;
  50. end;
  51. regs.AX:=$3e00;
  52. MsDos(regs);
  53. if (regs.Flags and fCarry) <> 0 then
  54. begin
  55. GetInOutRes(regs.AX);
  56. {$ifdef SYSTEMDEBUG}
  57. if verbose_files then
  58. Writeln(stderr,'file close failed AX= ',regs.AX);
  59. {$endif SYSTEMDEBUG}
  60. end;
  61. end;
  62. procedure do_erase(p : pchar; pchangeable: boolean);
  63. var
  64. regs : Registers;
  65. oldp : pchar;
  66. begin
  67. oldp:=p;
  68. DoDirSeparators(p,pchangeable);
  69. regs.DX:=Ofs(p^);
  70. regs.DS:=Seg(p^);
  71. {$ifndef RTLLITE}
  72. if LFNSupport then
  73. regs.AX:=$7141
  74. else
  75. {$endif ndef RTLLITE}
  76. regs.AX:=$4100;
  77. regs.SI:=0;
  78. regs.CX:=0;
  79. MsDos(regs);
  80. if (regs.Flags and fCarry) <> 0 then
  81. GetInOutRes(regs.AX);
  82. if p<>oldp then
  83. freemem(p);
  84. end;
  85. procedure do_rename(p1,p2 : pchar; p1changeable, p2changeable: boolean);
  86. var
  87. regs : Registers;
  88. oldp1, oldp2 : pchar;
  89. begin
  90. oldp1:=p1;
  91. oldp2:=p2;
  92. DoDirSeparators(p1,p1changeable);
  93. DoDirSeparators(p2,p2changeable);
  94. regs.DS:=Seg(p1^);
  95. regs.DX:=Ofs(p1^);
  96. regs.ES:=Seg(p2^);
  97. regs.DI:=Ofs(p2^);
  98. {$ifndef RTLLITE}
  99. if LFNSupport then
  100. regs.AX:=$7156
  101. else
  102. {$endif ndef RTLLITE}
  103. regs.AX:=$5600;
  104. regs.CX:=$ff; { attribute problem here ! }
  105. MsDos(regs);
  106. if (regs.Flags and fCarry) <> 0 then
  107. GetInOutRes(regs.AX);
  108. if p1<>oldp1 then
  109. freemem(p1);
  110. if p2<>oldp2 then
  111. freemem(p2);
  112. end;
  113. function do_write(h:thandle;addr:pointer;len : longint) : longint;
  114. var
  115. regs: Registers;
  116. begin
  117. regs.AH := $40;
  118. regs.BX := h;
  119. regs.CX := len;
  120. regs.DS := Seg(addr^);
  121. regs.DX := Ofs(addr^);
  122. MsDos(regs);
  123. if (regs.Flags and fCarry) <> 0 then
  124. begin
  125. GetInOutRes(regs.AX);
  126. exit(0);
  127. end;
  128. do_write := regs.AX;
  129. end;
  130. function do_read(h:thandle;addr:pointer;len : longint) : longint;
  131. var
  132. regs: Registers;
  133. begin
  134. regs.AH := $3F;
  135. regs.BX := h;
  136. regs.CX := len;
  137. regs.DS := Seg(addr^);
  138. regs.DX := Ofs(addr^);
  139. MsDos(regs);
  140. if (regs.Flags and fCarry) <> 0 then
  141. begin
  142. GetInOutRes(regs.AX);
  143. exit(0);
  144. end;
  145. do_read := regs.AX;
  146. end;
  147. function do_filepos(handle : thandle) : longint;
  148. var
  149. regs : Registers;
  150. begin
  151. regs.BX:=handle;
  152. regs.CX:=0;
  153. regs.DX:=0;
  154. regs.AX:=$4201;
  155. MsDos(regs);
  156. if (regs.Flags and fCarry) <> 0 then
  157. Begin
  158. GetInOutRes(regs.AX);
  159. do_filepos:=0;
  160. end
  161. else
  162. do_filepos:=(longint(regs.DX) shl 16) + regs.AX;
  163. end;
  164. procedure do_seek(handle:thandle;pos : longint);
  165. var
  166. regs : Registers;
  167. begin
  168. regs.BX:=handle;
  169. regs.CX:=pos shr 16;
  170. regs.DX:=pos and $ffff;
  171. regs.AX:=$4200;
  172. MsDos(regs);
  173. if (regs.Flags and fCarry) <> 0 then
  174. GetInOutRes(regs.AX);
  175. end;
  176. function do_seekend(handle:thandle):longint;
  177. var
  178. regs : Registers;
  179. begin
  180. regs.BX:=handle;
  181. regs.CX:=0;
  182. regs.DX:=0;
  183. regs.AX:=$4202;
  184. MsDos(regs);
  185. if (regs.Flags and fCarry) <> 0 then
  186. Begin
  187. GetInOutRes(regs.AX);
  188. do_seekend:=0;
  189. end
  190. else
  191. do_seekend:=(longint(regs.DX) shl 16) + regs.AX;
  192. end;
  193. function do_filesize(handle : thandle) : longint;
  194. var
  195. aktfilepos : longint;
  196. begin
  197. aktfilepos:=do_filepos(handle);
  198. do_filesize:=do_seekend(handle);
  199. do_seek(handle,aktfilepos);
  200. end;
  201. { truncate at a given position }
  202. procedure do_truncate (handle:thandle;pos:longint);
  203. var
  204. regs : Registers;
  205. begin
  206. do_seek(handle,pos);
  207. regs.CX:=0;
  208. regs.BX:=handle;
  209. regs.AX:=$4000;
  210. MsDos(regs);
  211. if (regs.Flags and fCarry) <> 0 then
  212. GetInOutRes(regs.AX);
  213. end;
  214. const
  215. FileHandleCount : word = 20;
  216. function Increase_file_handle_count : boolean;
  217. var
  218. regs : Registers;
  219. begin
  220. Inc(FileHandleCount,10);
  221. regs.BX:=FileHandleCount;
  222. regs.AX:=$6700;
  223. MsDos(regs);
  224. if (regs.Flags and fCarry) <> 0 then
  225. begin
  226. Increase_file_handle_count:=false;
  227. Dec (FileHandleCount, 10);
  228. end
  229. else
  230. Increase_file_handle_count:=true;
  231. end;
  232. procedure do_open(var f;p:pchar;flags:longint; pchangeable: boolean);
  233. {
  234. filerec and textrec have both handle and mode as the first items so
  235. they could use the same routine for opening/creating.
  236. when (flags and $100) the file will be append
  237. when (flags and $1000) the file will be truncate/rewritten
  238. when (flags and $10000) there is no check for close (needed for textfiles)
  239. }
  240. var
  241. regs : Registers;
  242. action : word;
  243. oldp : pchar;
  244. begin
  245. {$ifdef SYSTEMDEBUG}
  246. if verbose_files then
  247. Writeln(stderr,'do_open for file "',p,'" called');
  248. {$endif SYSTEMDEBUG}
  249. { close first if opened }
  250. if ((flags and $10000)=0) then
  251. begin
  252. case filerec(f).mode of
  253. fminput,fmoutput,fminout : Do_Close(filerec(f).handle);
  254. fmclosed : ;
  255. else
  256. begin
  257. inoutres:=102; {not assigned}
  258. exit;
  259. end;
  260. end;
  261. end;
  262. { reset file handle }
  263. filerec(f).handle:=UnusedHandle;
  264. action:=$1;
  265. { convert filemode to filerec modes }
  266. case (flags and 3) of
  267. 0 : filerec(f).mode:=fminput;
  268. 1 : filerec(f).mode:=fmoutput;
  269. 2 : filerec(f).mode:=fminout;
  270. end;
  271. if (flags and $1000)<>0 then
  272. action:=$12; {create file function}
  273. { empty name is special }
  274. if p[0]=#0 then
  275. begin
  276. case FileRec(f).mode of
  277. fminput :
  278. FileRec(f).Handle:=StdInputHandle;
  279. fminout, { this is set by rewrite }
  280. fmoutput :
  281. FileRec(f).Handle:=StdOutputHandle;
  282. fmappend :
  283. begin
  284. FileRec(f).Handle:=StdOutputHandle;
  285. FileRec(f).mode:=fmoutput; {fool fmappend}
  286. end;
  287. end;
  288. exit;
  289. end;
  290. oldp:=p;
  291. DoDirSeparators(p,pchangeable);
  292. {$ifndef RTLLITE}
  293. if LFNSupport then
  294. begin
  295. regs.AX := $716c; { Use LFN Open/Create API }
  296. regs.DX := action; { action if file does/doesn't exist }
  297. regs.SI := Ofs(p^);
  298. regs.BX := $2000 + (flags and $ff); { file open mode }
  299. end
  300. else
  301. {$endif RTLLITE}
  302. begin
  303. if (action and $00f0) <> 0 then
  304. regs.AX := $3c00 { Map to Create/Replace API }
  305. else
  306. regs.AX := $3d00 + (flags and $ff); { Map to Open_Existing API }
  307. regs.DX := Ofs(p^);
  308. end;
  309. regs.DS := Seg(p^);
  310. regs.CX := $20; { file attributes }
  311. MsDos(regs);
  312. {$ifndef RTLLITE}
  313. if (regs.Flags and fCarry) <> 0 then
  314. if regs.AX=4 then
  315. if Increase_file_handle_count then
  316. begin
  317. { Try again }
  318. if LFNSupport then
  319. begin
  320. regs.AX := $716c; {Use LFN Open/Create API}
  321. regs.DX := action; {action if file does/doesn't exist}
  322. regs.SI := Ofs(p^);
  323. regs.BX := $2000 + (flags and $ff); {file open mode}
  324. end
  325. else
  326. begin
  327. if (action and $00f0) <> 0 then
  328. regs.AX := $3c00 {Map to Create/Replace API}
  329. else
  330. regs.AX := $3d00 + (flags and $ff); {Map to Open API}
  331. regs.DX := Ofs(p^);
  332. end;
  333. regs.DS := Seg(p^);
  334. regs.CX := $20; {file attributes}
  335. MsDos(regs);
  336. end;
  337. {$endif RTLLITE}
  338. if (regs.Flags and fCarry) <> 0 then
  339. begin
  340. FileRec(f).mode:=fmclosed;
  341. GetInOutRes(regs.AX);
  342. if oldp<>p then
  343. freemem(p);
  344. {$ifdef SYSTEMDEBUG}
  345. if verbose_files then
  346. Writeln(stderr,'MSDOS INT open for file "',p,'" failed err=',regs.AX);
  347. {$endif SYSTEMDEBUG}
  348. exit;
  349. end
  350. else
  351. begin
  352. filerec(f).handle:=regs.AX;
  353. {$ifndef RTLLITE}
  354. { for systems that have more then 20 by default ! }
  355. if regs.AX>FileHandleCount then
  356. FileHandleCount:=regs.AX;
  357. {$endif RTLLITE}
  358. end;
  359. {$ifdef SYSTEMDEBUG}
  360. if verbose_files then
  361. Writeln(stderr,'MSDOS INT open for file "',p,'" returned ',regs.AX);
  362. {$endif SYSTEMDEBUG}
  363. if regs.AX<max_files then
  364. begin
  365. {$ifdef SYSTEMDEBUG}
  366. if openfiles[regs.AX] and
  367. assigned(opennames[regs.AX]) then
  368. begin
  369. Writeln(stderr,'file ',opennames[regs.AX],'(',regs.AX,') not closed but handle reused!');
  370. systinyfreememsize(opennames[regs.AX],strlen(opennames[regs.AX])+1);
  371. end;
  372. {$endif SYSTEMDEBUG}
  373. openfiles[regs.AX]:=true;
  374. {$ifdef SYSTEMDEBUG}
  375. opennames[regs.AX] := systinygetmem(strlen(p)+1);
  376. move(p^,opennames[regs.AX]^,strlen(p)+1);
  377. if verbose_files then
  378. Writeln(stderr,'file ',opennames[regs.AX],' opened');
  379. {$endif SYSTEMDEBUG}
  380. end;
  381. { append mode }
  382. if ((flags and $100) <> 0) and
  383. (FileRec (F).Handle <> UnusedHandle) then
  384. begin
  385. do_seekend(filerec(f).handle);
  386. filerec(f).mode:=fmoutput; {fool fmappend}
  387. end;
  388. if oldp<>p then
  389. freemem(p);
  390. end;
  391. function do_isdevice(handle:THandle):boolean;
  392. var
  393. regs: Registers;
  394. begin
  395. regs.AX := $4400;
  396. regs.BX := handle;
  397. MsDos(regs);
  398. do_isdevice := (regs.DL and $80) <> 0;
  399. if (regs.Flags and fCarry) <> 0 then
  400. GetInOutRes(regs.AX);
  401. end;