1 /* see copyright notice in squirrel.h */
\r
4 #include <squirrel.h>
\r
6 #include "sqstdstream.h"
\r
8 #define SQSTD_FILE_TYPE_TAG (SQSTD_STREAM_TYPE_TAG | 0x00000001)
\r
10 SQFILE sqstd_fopen(const SQChar *filename ,const SQChar *mode)
\r
13 return (SQFILE)fopen(filename,mode);
\r
15 return (SQFILE)_wfopen(filename,mode);
\r
19 SQInteger sqstd_fread(void* buffer, SQInteger size, SQInteger count, SQFILE file)
\r
21 return (SQInteger)fread(buffer,size,count,(FILE *)file);
\r
24 SQInteger sqstd_fwrite(const SQUserPointer buffer, SQInteger size, SQInteger count, SQFILE file)
\r
26 return (SQInteger)fwrite(buffer,size,count,(FILE *)file);
\r
29 SQInteger sqstd_fseek(SQFILE file, SQInteger offset, SQInteger origin)
\r
31 SQInteger realorigin;
\r
33 case SQ_SEEK_CUR: realorigin = SEEK_CUR; break;
\r
34 case SQ_SEEK_END: realorigin = SEEK_END; break;
\r
35 case SQ_SEEK_SET: realorigin = SEEK_SET; break;
\r
36 default: return -1; //failed
\r
38 return fseek((FILE *)file,(long)offset,(int)realorigin);
\r
41 SQInteger sqstd_ftell(SQFILE file)
\r
43 return ftell((FILE *)file);
\r
46 SQInteger sqstd_fflush(SQFILE file)
\r
48 return fflush((FILE *)file);
\r
51 SQInteger sqstd_fclose(SQFILE file)
\r
53 return fclose((FILE *)file);
\r
56 SQInteger sqstd_feof(SQFILE file)
\r
58 return feof((FILE *)file);
\r
62 struct SQFile : public SQStream {
\r
63 SQFile() { _handle = NULL; _owns = false;}
\r
64 SQFile(SQFILE file, bool owns) { _handle = file; _owns = owns;}
\r
65 virtual ~SQFile() { Close(); }
\r
66 bool Open(const SQChar *filename ,const SQChar *mode) {
\r
68 if( (_handle = sqstd_fopen(filename,mode)) ) {
\r
75 if(_handle && _owns) {
\r
76 sqstd_fclose(_handle);
\r
81 SQInteger Read(void *buffer,SQInteger size) {
\r
82 return sqstd_fread(buffer,1,size,_handle);
\r
84 SQInteger Write(void *buffer,SQInteger size) {
\r
85 return sqstd_fwrite(buffer,1,size,_handle);
\r
88 return sqstd_fflush(_handle);
\r
91 return sqstd_ftell(_handle);
\r
94 SQInteger prevpos=Tell();
\r
95 Seek(0,SQ_SEEK_END);
\r
96 SQInteger size=Tell();
\r
97 Seek(prevpos,SQ_SEEK_SET);
\r
100 SQInteger Seek(SQInteger offset, SQInteger origin) {
\r
101 return sqstd_fseek(_handle,offset,origin);
\r
103 bool IsValid() { return _handle?true:false; }
\r
104 bool EOS() { return Tell()==Len()?true:false;}
\r
105 SQFILE GetHandle() {return _handle;}
\r
111 static SQInteger _file__typeof(HSQUIRRELVM v)
\r
113 sq_pushstring(v,_SC("file"),-1);
\r
117 static SQInteger _file_releasehook(SQUserPointer p, SQInteger size)
\r
119 SQFile *self = (SQFile*)p;
\r
121 sq_free(self,sizeof(SQFile));
\r
125 static SQInteger _file_constructor(HSQUIRRELVM v)
\r
127 const SQChar *filename,*mode;
\r
131 if(sq_gettype(v,2) == OT_STRING && sq_gettype(v,3) == OT_STRING) {
\r
132 sq_getstring(v, 2, &filename);
\r
133 sq_getstring(v, 3, &mode);
\r
134 newf = sqstd_fopen(filename, mode);
\r
135 if(!newf) return sq_throwerror(v, _SC("cannot open file"));
\r
136 } else if(sq_gettype(v,2) == OT_USERPOINTER) {
\r
137 owns = !(sq_gettype(v,3) == OT_NULL);
\r
138 sq_getuserpointer(v,2,&newf);
\r
140 return sq_throwerror(v,_SC("wrong parameter"));
\r
143 f = new (sq_malloc(sizeof(SQFile)))SQFile(newf,owns);
\r
144 if(SQ_FAILED(sq_setinstanceup(v,1,f))) {
\r
146 sq_free(f,sizeof(SQFile));
\r
147 return sq_throwerror(v, _SC("cannot create blob with negative size"));
\r
149 sq_setreleasehook(v,1,_file_releasehook);
\r
153 static SQInteger _file_close(HSQUIRRELVM v)
\r
155 SQFile *self = NULL;
\r
156 if(SQ_SUCCEEDED(sq_getinstanceup(v,1,(SQUserPointer*)&self,(SQUserPointer)SQSTD_FILE_TYPE_TAG))
\r
165 #define _DECL_FILE_FUNC(name,nparams,typecheck) {_SC(#name),_file_##name,nparams,typecheck}
\r
166 static SQRegFunction _file_methods[] = {
\r
167 _DECL_FILE_FUNC(constructor,3,_SC("x")),
\r
168 _DECL_FILE_FUNC(_typeof,1,_SC("x")),
\r
169 _DECL_FILE_FUNC(close,1,_SC("x")),
\r
175 SQRESULT sqstd_createfile(HSQUIRRELVM v, SQFILE file,SQBool own)
\r
177 SQInteger top = sq_gettop(v);
\r
178 sq_pushregistrytable(v);
\r
179 sq_pushstring(v,_SC("std_file"),-1);
\r
180 if(SQ_SUCCEEDED(sq_get(v,-2))) {
\r
181 sq_remove(v,-2); //removes the registry
\r
182 sq_pushroottable(v); // push the this
\r
183 sq_pushuserpointer(v,file); //file
\r
185 sq_pushinteger(v,1); //true
\r
188 sq_pushnull(v); //false
\r
190 if(SQ_SUCCEEDED( sq_call(v,3,SQTrue,SQFalse) )) {
\r
199 SQRESULT sqstd_getfile(HSQUIRRELVM v, SQInteger idx, SQFILE *file)
\r
201 SQFile *fileobj = NULL;
\r
202 if(SQ_SUCCEEDED(sq_getinstanceup(v,idx,(SQUserPointer*)&fileobj,(SQUserPointer)SQSTD_FILE_TYPE_TAG))) {
\r
203 *file = fileobj->GetHandle();
\r
206 return sq_throwerror(v,_SC("not a file"));
\r
211 static SQInteger _io_file_lexfeed_PLAIN(SQUserPointer file)
\r
215 if( ( ret=sqstd_fread(&c,sizeof(c),1,(FILE *)file )>0) )
\r
221 static SQInteger _io_file_lexfeed_UTF8(SQUserPointer file)
\r
224 if(sqstd_fread(&inchar,sizeof(inchar),1,(FILE *)file) != 1) \
\r
227 static const SQInteger utf8_lengths[16] =
\r
229 1,1,1,1,1,1,1,1, /* 0000 to 0111 : 1 byte (plain ASCII) */
\r
230 0,0,0,0, /* 1000 to 1011 : not valid */
\r
231 2,2, /* 1100, 1101 : 2 bytes */
\r
232 3, /* 1110 : 3 bytes */
\r
233 4 /* 1111 :4 bytes */
\r
235 static unsigned char byte_masks[5] = {0,0,0x1f,0x0f,0x07};
\r
236 unsigned char inchar;
\r
243 SQInteger codelen = utf8_lengths[c>>4];
\r
246 //"invalid UTF-8 stream";
\r
247 tmp = c&byte_masks[codelen];
\r
248 for(SQInteger n = 0; n < codelen-1; n++) {
\r
251 tmp |= inchar & 0x3F;
\r
259 static SQInteger _io_file_lexfeed_UCS2_LE(SQUserPointer file)
\r
263 if( ( ret=sqstd_fread(&c,sizeof(c),1,(FILE *)file )>0) )
\r
268 static SQInteger _io_file_lexfeed_UCS2_BE(SQUserPointer file)
\r
272 if( ( ret=sqstd_fread(&c,sizeof(c),1,(FILE *)file )>0) ) {
\r
273 c = ((c>>8)&0x00FF)| ((c<<8)&0xFF00);
\r
279 SQInteger file_read(SQUserPointer file,SQUserPointer buf,SQInteger size)
\r
282 if( ( ret = sqstd_fread(buf,1,size,(SQFILE)file ))!=0 )return ret;
\r
286 SQInteger file_write(SQUserPointer file,SQUserPointer p,SQInteger size)
\r
288 return sqstd_fwrite(p,1,size,(SQFILE)file);
\r
291 SQRESULT sqstd_loadfile(HSQUIRRELVM v,const SQChar *filename,SQBool printerror)
\r
293 SQFILE file = sqstd_fopen(filename,_SC("rb"));
\r
297 SQLEXREADFUNC func = _io_file_lexfeed_PLAIN;
\r
299 ret = sqstd_fread(&us,1,2,file);
\r
301 //probably an empty file
\r
304 if(us == SQ_BYTECODE_STREAM_TAG) { //BYTECODE
\r
305 sqstd_fseek(file,0,SQ_SEEK_SET);
\r
306 if(SQ_SUCCEEDED(sq_readclosure(v,file_read,file))) {
\r
307 sqstd_fclose(file);
\r
314 //gotta swap the next 2 lines on BIG endian machines
\r
315 case 0xFFFE: func = _io_file_lexfeed_UCS2_BE; break;//UTF-16 little endian;
\r
316 case 0xFEFF: func = _io_file_lexfeed_UCS2_LE; break;//UTF-16 big endian;
\r
318 if(sqstd_fread(&uc,1,sizeof(uc),file) == 0) {
\r
319 sqstd_fclose(file);
\r
320 return sq_throwerror(v,_SC("io error"));
\r
323 sqstd_fclose(file);
\r
324 return sq_throwerror(v,_SC("Unrecognozed ecoding"));
\r
327 func = _io_file_lexfeed_UTF8;
\r
329 func = _io_file_lexfeed_PLAIN;
\r
332 default: sqstd_fseek(file,0,SQ_SEEK_SET); break; // ascii
\r
335 if(SQ_SUCCEEDED(sq_compile(v,func,file,filename,printerror))){
\r
336 sqstd_fclose(file);
\r
340 sqstd_fclose(file);
\r
343 return sq_throwerror(v,_SC("cannot open the file"));
\r
346 SQRESULT sqstd_dofile(HSQUIRRELVM v,const SQChar *filename,SQBool retval,SQBool printerror)
\r
348 if(SQ_SUCCEEDED(sqstd_loadfile(v,filename,printerror))) {
\r
350 if(SQ_SUCCEEDED(sq_call(v,1,retval,SQTrue))) {
\r
351 sq_remove(v,retval?-2:-1); //removes the closure
\r
354 sq_pop(v,1); //removes the closure
\r
359 SQRESULT sqstd_writeclosuretofile(HSQUIRRELVM v,const SQChar *filename)
\r
361 SQFILE file = sqstd_fopen(filename,_SC("wb+"));
\r
362 if(!file) return sq_throwerror(v,_SC("cannot open the file"));
\r
363 if(SQ_SUCCEEDED(sq_writeclosure(v,file_write,file))) {
\r
364 sqstd_fclose(file);
\r
367 sqstd_fclose(file);
\r
368 return SQ_ERROR; //forward the error
\r
371 SQInteger _g_io_loadfile(HSQUIRRELVM v)
\r
373 const SQChar *filename;
\r
374 SQBool printerror = SQFalse;
\r
375 sq_getstring(v,2,&filename);
\r
376 if(sq_gettop(v) >= 3) {
\r
377 sq_getbool(v,3,&printerror);
\r
379 if(SQ_SUCCEEDED(sqstd_loadfile(v,filename,printerror)))
\r
381 return SQ_ERROR; //propagates the error
\r
384 SQInteger _g_io_writeclosuretofile(HSQUIRRELVM v)
\r
386 const SQChar *filename;
\r
387 sq_getstring(v,2,&filename);
\r
388 if(SQ_SUCCEEDED(sqstd_writeclosuretofile(v,filename)))
\r
390 return SQ_ERROR; //propagates the error
\r
393 SQInteger _g_io_dofile(HSQUIRRELVM v)
\r
395 const SQChar *filename;
\r
396 SQBool printerror = SQFalse;
\r
397 sq_getstring(v,2,&filename);
\r
398 if(sq_gettop(v) >= 3) {
\r
399 sq_getbool(v,3,&printerror);
\r
401 sq_push(v,1); //repush the this
\r
402 if(SQ_SUCCEEDED(sqstd_dofile(v,filename,SQTrue,printerror)))
\r
404 return SQ_ERROR; //propagates the error
\r
407 #define _DECL_GLOBALIO_FUNC(name,nparams,typecheck) {_SC(#name),_g_io_##name,nparams,typecheck}
\r
408 static SQRegFunction iolib_funcs[]={
\r
409 _DECL_GLOBALIO_FUNC(loadfile,-2,_SC(".sb")),
\r
410 _DECL_GLOBALIO_FUNC(dofile,-2,_SC(".sb")),
\r
411 _DECL_GLOBALIO_FUNC(writeclosuretofile,3,_SC(".sc")),
\r
415 SQRESULT sqstd_register_iolib(HSQUIRRELVM v)
\r
417 SQInteger top = sq_gettop(v);
\r
419 declare_stream(v,_SC("file"),(SQUserPointer)SQSTD_FILE_TYPE_TAG,_SC("std_file"),_file_methods,iolib_funcs);
\r
420 sq_pushstring(v,_SC("stdout"),-1);
\r
421 sqstd_createfile(v,stdout,SQFalse);
\r
422 sq_newslot(v,-3,SQFalse);
\r
423 sq_pushstring(v,_SC("stdin"),-1);
\r
424 sqstd_createfile(v,stdin,SQFalse);
\r
425 sq_newslot(v,-3,SQFalse);
\r
426 sq_pushstring(v,_SC("stderr"),-1);
\r
427 sqstd_createfile(v,stderr,SQFalse);
\r
428 sq_newslot(v,-3,SQFalse);
\r