@@ -40,6 +40,7 @@ impl LuaFile {
4040 let file = std:: fs:: OpenOptions :: new ( )
4141 . write ( true )
4242 . append ( true )
43+ . create ( true )
4344 . open ( path) ?;
4445 Ok ( LuaFile {
4546 inner : FileInner :: Write ( BufWriter :: new ( file) ) ,
@@ -50,11 +51,24 @@ impl LuaFile {
5051 let file = std:: fs:: OpenOptions :: new ( )
5152 . read ( true )
5253 . write ( true )
54+ . create ( true )
5355 . open ( path) ?;
5456 Ok ( LuaFile {
5557 inner : FileInner :: ReadWrite ( file) ,
5658 } )
5759 }
60+
61+ /// Create from existing File (for tmpfile)
62+ pub fn from_file ( file : File ) -> Self {
63+ LuaFile {
64+ inner : FileInner :: ReadWrite ( file) ,
65+ }
66+ }
67+
68+ /// Check if file is closed
69+ pub fn is_closed ( & self ) -> bool {
70+ matches ! ( self . inner, FileInner :: Closed )
71+ }
5872
5973 /// Read operations
6074 pub fn read_line ( & mut self ) -> io:: Result < Option < String > > {
@@ -220,15 +234,31 @@ fn file_read(vm: &mut LuaVM) -> LuaResult<MultiValue> {
220234 let mut data_ref = data. borrow_mut ( ) ;
221235 if let Some ( lua_file) = data_ref. downcast_mut :: < LuaFile > ( ) {
222236 // Get format (default "*l") - register 2 is first argument after self
223- let format_str = if let Some ( fmt) = get_arg ( vm, 2 ) {
224- if let Some ( s) = vm. get_string ( & fmt) {
225- s. as_str ( ) . to_string ( )
226- } else {
227- "*l" . to_string ( )
237+ let format_arg = get_arg ( vm, 2 ) ;
238+
239+ // Check if format is a number (byte count)
240+ if let Some ( ref fmt) = format_arg {
241+ if let Some ( n) = fmt. as_integer ( ) {
242+ // Read n bytes
243+ match lua_file. read_bytes ( n as usize ) {
244+ Ok ( bytes) => {
245+ if bytes. is_empty ( ) {
246+ return Ok ( MultiValue :: single ( LuaValue :: nil ( ) ) ) ;
247+ }
248+ let s = String :: from_utf8_lossy ( & bytes) ;
249+ return Ok ( MultiValue :: single ( vm. create_string ( & s) ) ) ;
250+ }
251+ Err ( e) => {
252+ return Err ( vm. error ( format ! ( "read error: {}" , e) ) ) ;
253+ }
254+ }
228255 }
229- } else {
230- "*l" . to_string ( )
231- } ;
256+ }
257+
258+ // Otherwise treat as format string
259+ let format_str = format_arg
260+ . and_then ( |v| vm. get_string ( & v) . map ( |s| s. as_str ( ) . to_string ( ) ) )
261+ . unwrap_or_else ( || "*l" . to_string ( ) ) ;
232262 let format = format_str. as_str ( ) ;
233263
234264 let result = match format {
@@ -241,13 +271,34 @@ fn file_read(vm: &mut LuaVM) -> LuaResult<MultiValue> {
241271 Ok ( content) => vm. create_string ( & content) ,
242272 Err ( e) => return Err ( vm. error ( format ! ( "read error: {}" , e) ) ) ,
243273 } ,
274+ "*n" => {
275+ // Read a number
276+ match lua_file. read_line ( ) {
277+ Ok ( Some ( line) ) => {
278+ let trimmed = line. trim ( ) ;
279+ if let Ok ( n) = trimmed. parse :: < i64 > ( ) {
280+ LuaValue :: integer ( n)
281+ } else if let Ok ( n) = trimmed. parse :: < f64 > ( ) {
282+ LuaValue :: float ( n)
283+ } else {
284+ LuaValue :: nil ( )
285+ }
286+ }
287+ Ok ( None ) => LuaValue :: nil ( ) ,
288+ Err ( e) => return Err ( vm. error ( format ! ( "read error: {}" , e) ) ) ,
289+ }
290+ }
244291 _ => {
245- // Try to parse as number (byte count)
292+ // Try to parse as number (byte count) from string like "10"
246293 if let Ok ( n) = format. parse :: < usize > ( ) {
247294 match lua_file. read_bytes ( n) {
248295 Ok ( bytes) => {
249- let s = String :: from_utf8_lossy ( & bytes) ;
250- vm. create_string ( & s)
296+ if bytes. is_empty ( ) {
297+ LuaValue :: nil ( )
298+ } else {
299+ let s = String :: from_utf8_lossy ( & bytes) ;
300+ vm. create_string ( & s)
301+ }
251302 }
252303 Err ( e) => {
253304 return Err ( vm. error ( format ! ( "read error: {}" , e) ) ) ;
0 commit comments