/* ************************************************************************ */ /* */ /* Neko Standard Library */ /* Copyright (c)2005 Motion-Twin */ /* */ /* This library is free software; you can redistribute it and/or */ /* modify it under the terms of the GNU Lesser General Public */ /* License as published by the Free Software Foundation; either */ /* version 2.1 of the License, or (at your option) any later version. */ /* */ /* This library 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. See the GNU */ /* Lesser General Public License or the LICENSE file for more details. */ /* */ /* ************************************************************************ */ #include #include #ifdef NEKO_WINDOWS # include #endif /**

File

The file api can be used for different kind of file I/O.

**/ typedef struct { value name; FILE *io; } fio; #define val_file(o) ((fio*)val_data(o)) DEFINE_KIND(k_file); static void file_error( const char *msg, fio *f ) { value a = alloc_array(2); val_array_ptr(a)[0] = alloc_string(msg); val_array_ptr(a)[1] = alloc_string(val_string(f->name)); val_throw(a); } /** file_open : f:string -> r:string -> 'file Call the C function [fopen] with the file path and access rights. Return the opened file or throw an exception if the file couldn't be open. **/ static value file_open( value name, value r ) { fio *f; val_check(name,string); val_check(r,string); f = (fio*)alloc(sizeof(fio)); f->name = alloc_string(val_string(name)); f->io = fopen(val_string(name),val_string(r)); if( f->io == NULL ) file_error("file_open",f); return alloc_abstract(k_file,f); } /** file_close : 'file -> void Close an file. Any other operations on this file will fail **/ static value file_close( value o ) { fio *f; val_check_kind(o,k_file); f = val_file(o); fclose(f->io); val_kind(o) = NULL; return val_true; } /** file_name : 'file -> string Return the name of the file which was opened **/ static value file_name( value o ) { val_check_kind(o,k_file); return alloc_string(val_string(val_file(o)->name)); } /** file_write : 'file -> s:string -> p:int -> l:int -> int Write up to [l] chars of string [s] starting at position [p]. Returns the number of chars written which is >= 0. **/ static value file_write( value o, value s, value pp, value n ) { int p, len; fio *f; val_check_kind(o,k_file); val_check(s,string); val_check(pp,int); val_check(n,int); f = val_file(o); p = val_int(pp); len = val_int(n); if( p < 0 || len < 0 || p > val_strlen(s) || p + len > val_strlen(s) ) neko_error(); while( len > 0 ) { int d; POSIX_LABEL(file_write_again); d = (int)fwrite(val_string(s)+p,1,len,f->io); if( d <= 0 ) { HANDLE_FINTR(f->io,file_write_again); file_error("file_write",f); } p += d; len -= d; } return n; } /** file_read : 'file -> s:string -> p:int -> l:int -> int Read up to [l] chars into the string [s] starting at position [p]. Returns the number of chars readed which is > 0 (or 0 if l == 0). **/ static value file_read( value o, value s, value pp, value n ) { fio *f; int p; int len; val_check_kind(o,k_file); val_check(s,string); val_check(pp,int); val_check(n,int); f = val_file(o); p = val_int(pp); len = val_int(n); if( p < 0 || len < 0 || p > val_strlen(s) || p + len > val_strlen(s) ) neko_error(); while( len > 0 ) { int d; POSIX_LABEL(file_read_again); d = (int)fread((char*)val_string(s)+p,1,len,f->io); if( d <= 0 ) { int size = val_int(n) - len; HANDLE_FINTR(f->io,file_read_again); if( size == 0 ) file_error("file_read",f); return alloc_int(size); } p += d; len -= d; } return n; } /** file_write_char : 'file -> c:int -> void Write the char [c]. Error if [c] outside of the range 0..255 **/ static value file_write_char( value o, value c ) { unsigned char cc; fio *f; val_check(c,int); val_check_kind(o,k_file); if( val_int(c) < 0 || val_int(c) > 255 ) neko_error(); cc = (char)val_int(c); f = val_file(o); POSIX_LABEL(write_char_again); if( fwrite(&cc,1,1,f->io) != 1 ) { HANDLE_FINTR(f->io,write_char_again); file_error("file_write_char",f); } return val_true; } /** file_read_char : 'file -> int Read a char from the file. Exception on error **/ static value file_read_char( value o ) { unsigned char cc; fio *f; val_check_kind(o,k_file); f = val_file(o); POSIX_LABEL(read_char_again); if( fread(&cc,1,1,f->io) != 1 ) { HANDLE_FINTR(f->io,read_char_again); file_error("file_read_char",f); } return alloc_int(cc); } /** file_seek : 'file -> pos:int -> mode:int -> void Use [fseek] to move the file pointer. **/ static value file_seek( value o, value pos, value kind ) { fio *f; val_check_kind(o,k_file); val_check(pos,int); val_check(kind,int); f = val_file(o); if( fseek(f->io,val_int(pos),val_int(kind)) != 0 ) file_error("file_seek",f); return val_true; } /** file_tell : 'file -> int Return the current position in the file **/ static value file_tell( value o ) { int p; fio *f; val_check_kind(o,k_file); f = val_file(o); p = ftell(f->io); if( p == -1 ) file_error("file_tell",f); return alloc_int(p); } /** file_eof : 'file -> bool Tell if we have reached the end of the file **/ static value file_eof( value o ) { val_check_kind(o,k_file); return alloc_bool( feof(val_file(o)->io) ); } /** file_flush : 'file -> void Flush the file buffer **/ static value file_flush( value o ) { fio *f; val_check_kind(o,k_file); f = val_file(o); if( fflush( f->io ) != 0 ) file_error("file_flush",f); return val_true; } /** file_contents : f:string -> string Read the content of the file [f] and return it. **/ static value file_contents( value name ) { value s; fio f; int len; int p; val_check(name,string); f.name = name; f.io = fopen(val_string(name),"rb"); if( f.io == NULL ) file_error("file_contents",&f); fseek(f.io,0,SEEK_END); len = ftell(f.io); fseek(f.io,0,SEEK_SET); s = alloc_empty_string(len); p = 0; while( len > 0 ) { int d; POSIX_LABEL(file_contents); d = (int)fread((char*)val_string(s)+p,1,len,f.io); if( d <= 0 ) { HANDLE_FINTR(f.io,file_contents); fclose(f.io); file_error("file_contents",&f); } p += d; len -= d; } fclose(f.io); return s; } #define MAKE_STDIO(k) \ static value file_##k() { \ fio *f; \ f = (fio*)alloc(sizeof(fio)); \ f->name = alloc_string(#k); \ f->io = k; \ return alloc_abstract(k_file,f); \ } \ DEFINE_PRIM(file_##k,0); /** file_stdin : void -> 'file The standard input **/ MAKE_STDIO(stdin); /** file_stdout : void -> 'file The standard output **/ MAKE_STDIO(stdout); /** file_stderr : void -> 'file The standard error output **/ MAKE_STDIO(stderr); DEFINE_PRIM(file_open,2); DEFINE_PRIM(file_close,1); DEFINE_PRIM(file_name,1); DEFINE_PRIM(file_write,4); DEFINE_PRIM(file_read,4); DEFINE_PRIM(file_write_char,2); DEFINE_PRIM(file_read_char,1); DEFINE_PRIM(file_seek,3); DEFINE_PRIM(file_tell,1); DEFINE_PRIM(file_eof,1); DEFINE_PRIM(file_flush,1); DEFINE_PRIM(file_contents,1); /* ************************************************************************ */