00001
00002 #include <stdio.h>
00003 #include <squirrel.h>
00004 #include <new>
00005 #include <sqstdio.h>
00006 #include "sqstdstream.h"
00007
00008 #define SQSTD_FILE_TYPE_TAG (SQSTD_STREAM_TYPE_TAG | 0x00000001)
00009
00010 SQFILE sqstd_fopen(const SQChar *filename ,const SQChar *mode)
00011 {
00012 #ifndef SQUNICODE
00013 return (SQFILE)fopen(filename,mode);
00014 #else
00015 return (SQFILE)_wfopen(filename,mode);
00016 #endif
00017 }
00018
00019 SQInteger sqstd_fread(void* buffer, SQInteger size, SQInteger count, SQFILE file)
00020 {
00021 return (SQInteger)fread(buffer,size,count,(FILE *)file);
00022 }
00023
00024 SQInteger sqstd_fwrite(const SQUserPointer buffer, SQInteger size, SQInteger count, SQFILE file)
00025 {
00026 return (SQInteger)fwrite(buffer,size,count,(FILE *)file);
00027 }
00028
00029 SQInteger sqstd_fseek(SQFILE file, SQInteger offset, SQInteger origin)
00030 {
00031 SQInteger realorigin;
00032 switch(origin) {
00033 case SQ_SEEK_CUR: realorigin = SEEK_CUR; break;
00034 case SQ_SEEK_END: realorigin = SEEK_END; break;
00035 case SQ_SEEK_SET: realorigin = SEEK_SET; break;
00036 default: return -1;
00037 }
00038 return fseek((FILE *)file,(long)offset,(int)realorigin);
00039 }
00040
00041 SQInteger sqstd_ftell(SQFILE file)
00042 {
00043 return ftell((FILE *)file);
00044 }
00045
00046 SQInteger sqstd_fflush(SQFILE file)
00047 {
00048 return fflush((FILE *)file);
00049 }
00050
00051 SQInteger sqstd_fclose(SQFILE file)
00052 {
00053 return fclose((FILE *)file);
00054 }
00055
00056 SQInteger sqstd_feof(SQFILE file)
00057 {
00058 return feof((FILE *)file);
00059 }
00060
00061
00062 struct SQFile : public SQStream {
00063 SQFile() { _handle = NULL; _owns = false;}
00064 SQFile(SQFILE file, bool owns) { _handle = file; _owns = owns;}
00065 virtual ~SQFile() { Close(); }
00066 bool Open(const SQChar *filename ,const SQChar *mode) {
00067 Close();
00068 if( (_handle = sqstd_fopen(filename,mode)) ) {
00069 _owns = true;
00070 return true;
00071 }
00072 return false;
00073 }
00074 void Close() {
00075 if(_handle && _owns) {
00076 sqstd_fclose(_handle);
00077 _handle = NULL;
00078 _owns = false;
00079 }
00080 }
00081 SQInteger Read(void *buffer,SQInteger size) {
00082 return sqstd_fread(buffer,1,size,_handle);
00083 }
00084 SQInteger Write(void *buffer,SQInteger size) {
00085 return sqstd_fwrite(buffer,1,size,_handle);
00086 }
00087 SQInteger Flush() {
00088 return sqstd_fflush(_handle);
00089 }
00090 SQInteger Tell() {
00091 return sqstd_ftell(_handle);
00092 }
00093 SQInteger Len() {
00094 SQInteger prevpos=Tell();
00095 Seek(0,SQ_SEEK_END);
00096 SQInteger size=Tell();
00097 Seek(prevpos,SQ_SEEK_SET);
00098 return size;
00099 }
00100 SQInteger Seek(SQInteger offset, SQInteger origin) {
00101 return sqstd_fseek(_handle,offset,origin);
00102 }
00103 bool IsValid() { return _handle?true:false; }
00104 bool EOS() { return Tell()==Len()?true:false;}
00105 SQFILE GetHandle() {return _handle;}
00106 private:
00107 SQFILE _handle;
00108 bool _owns;
00109 };
00110
00111 static SQInteger _file__typeof(HSQUIRRELVM v)
00112 {
00113 sq_pushstring(v,_SC("file"),-1);
00114 return 1;
00115 }
00116
00117 static SQInteger _file_releasehook(SQUserPointer p, SQInteger size)
00118 {
00119 SQFile *self = (SQFile*)p;
00120 delete self;
00121 return 1;
00122 }
00123
00124 static SQInteger _file_constructor(HSQUIRRELVM v)
00125 {
00126 const SQChar *filename,*mode;
00127 bool owns = true;
00128 SQFile *f;
00129 SQFILE newf;
00130 if(sq_gettype(v,2) == OT_STRING && sq_gettype(v,3) == OT_STRING) {
00131 sq_getstring(v, 2, &filename);
00132 sq_getstring(v, 3, &mode);
00133 newf = sqstd_fopen(filename, mode);
00134 if(!newf) return sq_throwerror(v, _SC("cannot open file"));
00135 } else if(sq_gettype(v,2) == OT_USERPOINTER) {
00136 owns = !(sq_gettype(v,3) == OT_NULL);
00137 sq_getuserpointer(v,2,&newf);
00138 } else {
00139 return sq_throwerror(v,_SC("wrong parameter"));
00140 }
00141 f = new SQFile(newf,owns);
00142 if(SQ_FAILED(sq_setinstanceup(v,1,f))) {
00143 delete f;
00144 return sq_throwerror(v, _SC("cannot create blob with negative size"));
00145 }
00146 sq_setreleasehook(v,1,_file_releasehook);
00147 return 0;
00148 }
00149
00150
00151 #define _DECL_FILE_FUNC(name,nparams,typecheck) {_SC(#name),_file_##name,nparams,typecheck}
00152 static SQRegFunction _file_methods[] = {
00153 _DECL_FILE_FUNC(constructor,3,_SC("x")),
00154 _DECL_FILE_FUNC(_typeof,1,_SC("x")),
00155 {0,0,0,0},
00156 };
00157
00158
00159
00160 SQRESULT sqstd_createfile(HSQUIRRELVM v, SQFILE file,SQBool own)
00161 {
00162 SQInteger top = sq_gettop(v);
00163 sq_pushregistrytable(v);
00164 sq_pushstring(v,_SC("std_file"),-1);
00165 if(SQ_SUCCEEDED(sq_get(v,-2))) {
00166 sq_remove(v,-2);
00167 sq_pushroottable(v);
00168 sq_pushuserpointer(v,file);
00169 if(own){
00170 sq_pushinteger(v,1);
00171 }
00172 else{
00173 sq_pushnull(v);
00174 }
00175 if(SQ_SUCCEEDED( sq_call(v,3,SQTrue,SQFalse) )) {
00176 sq_remove(v,-2);
00177 return SQ_OK;
00178 }
00179 }
00180 sq_settop(v,top);
00181 return SQ_OK;
00182 }
00183
00184 SQRESULT sqstd_getfile(HSQUIRRELVM v, SQInteger idx, SQFILE *file)
00185 {
00186 SQFile *fileobj = NULL;
00187 if(SQ_SUCCEEDED(sq_getinstanceup(v,idx,(SQUserPointer*)&fileobj,(SQUserPointer)SQSTD_FILE_TYPE_TAG))) {
00188 *file = fileobj->GetHandle();
00189 return SQ_OK;
00190 }
00191 return sq_throwerror(v,_SC("not a file"));
00192 }
00193
00194
00195
00196 static SQInteger _io_file_lexfeed_ASCII(SQUserPointer file)
00197 {
00198 SQInteger ret;
00199 char c;
00200 if( ( ret=sqstd_fread(&c,sizeof(c),1,(FILE *)file )>0) )
00201 return c;
00202 return 0;
00203 }
00204
00205 static SQInteger _io_file_lexfeed_UTF8(SQUserPointer file)
00206 {
00207 #define READ() \
00208 if(sqstd_fread(&inchar,sizeof(inchar),1,(FILE *)file) != 1) \
00209 return 0;
00210
00211 static const SQInteger utf8_lengths[16] =
00212 {
00213 1,1,1,1,1,1,1,1,
00214 0,0,0,0,
00215 2,2,
00216 3,
00217 4
00218 };
00219 static unsigned char byte_masks[5] = {0,0,0x1f,0x0f,0x07};
00220 unsigned char inchar;
00221 SQInteger c = 0;
00222 READ();
00223 c = inchar;
00224
00225 if(c >= 0x80) {
00226 SQInteger tmp;
00227 SQInteger codelen = utf8_lengths[c>>4];
00228 if(codelen == 0)
00229 return 0;
00230
00231 tmp = c&byte_masks[codelen];
00232 for(SQInteger n = 0; n < codelen-1; n++) {
00233 tmp<<=6;
00234 READ();
00235 tmp |= inchar & 0x3F;
00236 }
00237 c = tmp;
00238 }
00239 return c;
00240 }
00241
00242 static SQInteger _io_file_lexfeed_UCS2_LE(SQUserPointer file)
00243 {
00244 SQInteger ret;
00245 wchar_t c;
00246 if( ( ret=sqstd_fread(&c,sizeof(c),1,(FILE *)file )>0) )
00247 return (SQChar)c;
00248 return 0;
00249 }
00250
00251 static SQInteger _io_file_lexfeed_UCS2_BE(SQUserPointer file)
00252 {
00253 SQInteger ret;
00254 unsigned short c;
00255 if( ( ret=sqstd_fread(&c,sizeof(c),1,(FILE *)file )>0) ) {
00256 c = ((c>>8)&0x00FF)| ((c<<8)&0xFF00);
00257 return (SQChar)c;
00258 }
00259 return 0;
00260 }
00261
00262 SQInteger file_read(SQUserPointer file,SQUserPointer buf,SQInteger size)
00263 {
00264 SQInteger ret;
00265 if( ( ret = sqstd_fread(buf,1,size,(SQFILE)file ))!=0 )return ret;
00266 return -1;
00267 }
00268
00269 SQInteger file_write(SQUserPointer file,SQUserPointer p,SQInteger size)
00270 {
00271 return sqstd_fwrite(p,1,size,(SQFILE)file);
00272 }
00273
00274 SQRESULT sqstd_loadfile(HSQUIRRELVM v,const SQChar *filename,SQBool printerror)
00275 {
00276 SQFILE file = sqstd_fopen(filename,_SC("rb"));
00277 SQInteger ret;
00278 unsigned short us;
00279 unsigned char uc;
00280 SQLEXREADFUNC func = _io_file_lexfeed_ASCII;
00281 if(file){
00282 ret = sqstd_fread(&us,1,2,file);
00283 if(ret != 2) {
00284
00285 us = 0;
00286 }
00287 if(us == SQ_BYTECODE_STREAM_TAG) {
00288 sqstd_fseek(file,0,SQ_SEEK_SET);
00289 if(SQ_SUCCEEDED(sq_readclosure(v,file_read,file))) {
00290 sqstd_fclose(file);
00291 return SQ_OK;
00292 }
00293 }
00294 else {
00295 switch(us)
00296 {
00297
00298 case 0xFFFE: func = _io_file_lexfeed_UCS2_BE; break;
00299 case 0xFEFF: func = _io_file_lexfeed_UCS2_LE; break;
00300 case 0xBBEF:
00301 if(sqstd_fread(&uc,1,sizeof(uc),file) == 0) {
00302 sqstd_fclose(file);
00303 return sq_throwerror(v,_SC("io error"));
00304 }
00305 if(uc != 0xBF) {
00306 sqstd_fclose(file);
00307 return sq_throwerror(v,_SC("Unrecognozed ecoding"));
00308 }
00309 func = _io_file_lexfeed_UTF8;
00310 break;
00311 default: sqstd_fseek(file,0,SQ_SEEK_SET); break;
00312 }
00313
00314 if(SQ_SUCCEEDED(sq_compile(v,func,file,filename,printerror))){
00315 sqstd_fclose(file);
00316 return SQ_OK;
00317 }
00318 }
00319 sqstd_fclose(file);
00320 return SQ_ERROR;
00321 }
00322 return sq_throwerror(v,_SC("cannot open the file"));
00323 }
00324
00325 SQRESULT sqstd_dofile(HSQUIRRELVM v,const SQChar *filename,SQBool retval,SQBool printerror)
00326 {
00327 if(SQ_SUCCEEDED(sqstd_loadfile(v,filename,printerror))) {
00328 sq_push(v,-2);
00329 if(SQ_SUCCEEDED(sq_call(v,1,retval,SQTrue))) {
00330 sq_remove(v,retval?-2:-1);
00331 return 1;
00332 }
00333 sq_pop(v,1);
00334 }
00335 return SQ_ERROR;
00336 }
00337
00338 SQRESULT sqstd_writeclosuretofile(HSQUIRRELVM v,const SQChar *filename)
00339 {
00340 SQFILE file = sqstd_fopen(filename,_SC("wb+"));
00341 if(!file) return sq_throwerror(v,_SC("cannot open the file"));
00342 if(SQ_SUCCEEDED(sq_writeclosure(v,file_write,file))) {
00343 sqstd_fclose(file);
00344 return SQ_OK;
00345 }
00346 sqstd_fclose(file);
00347 return SQ_ERROR;
00348 }
00349
00350 SQInteger _g_io_loadfile(HSQUIRRELVM v)
00351 {
00352 const SQChar *filename;
00353 SQBool printerror = SQFalse;
00354 sq_getstring(v,2,&filename);
00355 if(sq_gettop(v) >= 3) {
00356 sq_getbool(v,3,&printerror);
00357 }
00358 if(SQ_SUCCEEDED(sqstd_loadfile(v,filename,printerror)))
00359 return 1;
00360 return SQ_ERROR;
00361 }
00362
00363 SQInteger _g_io_writeclosuretofile(HSQUIRRELVM v)
00364 {
00365 const SQChar *filename;
00366 sq_getstring(v,2,&filename);
00367 if(SQ_SUCCEEDED(sqstd_writeclosuretofile(v,filename)))
00368 return 1;
00369 return SQ_ERROR;
00370 }
00371
00372 SQInteger _g_io_dofile(HSQUIRRELVM v)
00373 {
00374 const SQChar *filename;
00375 SQBool printerror = SQFalse;
00376 sq_getstring(v,2,&filename);
00377 if(sq_gettop(v) >= 3) {
00378 sq_getbool(v,3,&printerror);
00379 }
00380 sq_push(v,1);
00381 if(SQ_SUCCEEDED(sqstd_dofile(v,filename,SQTrue,printerror)))
00382 return 1;
00383 return SQ_ERROR;
00384 }
00385
00386 #define _DECL_GLOBALIO_FUNC(name,nparams,typecheck) {_SC(#name),_g_io_##name,nparams,typecheck}
00387 static SQRegFunction iolib_funcs[]={
00388 _DECL_GLOBALIO_FUNC(loadfile,-2,_SC(".sb")),
00389 _DECL_GLOBALIO_FUNC(dofile,-2,_SC(".sb")),
00390 _DECL_GLOBALIO_FUNC(writeclosuretofile,3,_SC(".sc")),
00391 {0,0,0,0}
00392 };
00393
00394 SQRESULT sqstd_register_iolib(HSQUIRRELVM v)
00395 {
00396 SQInteger top = sq_gettop(v);
00397
00398 declare_stream(v,_SC("file"),(SQUserPointer)SQSTD_FILE_TYPE_TAG,_SC("std_file"),_file_methods,iolib_funcs);
00399 sq_pushstring(v,_SC("stdout"),-1);
00400 sqstd_createfile(v,stdout,SQFalse);
00401 sq_createslot(v,-3);
00402 sq_pushstring(v,_SC("stdin"),-1);
00403 sqstd_createfile(v,stdin,SQFalse);
00404 sq_createslot(v,-3);
00405 sq_pushstring(v,_SC("stderr"),-1);
00406 sqstd_createfile(v,stderr,SQFalse);
00407 sq_createslot(v,-3);
00408 sq_settop(v,top);
00409 return SQ_OK;
00410 }