sqstdio.cpp

00001 /* see copyright notice in squirrel.h */
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 //basic API
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; //failed
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 //File
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 //bindings
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); //removes the registry
00167     sq_pushroottable(v); // push the this
00168     sq_pushuserpointer(v,file); //file
00169     if(own){
00170       sq_pushinteger(v,1); //true
00171     }
00172     else{
00173       sq_pushnull(v); //false
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,        /* 0000 to 0111 : 1 byte (plain ASCII) */
00214     0,0,0,0,                /* 1000 to 1011 : not valid */
00215     2,2,                    /* 1100, 1101 : 2 bytes */
00216     3,                      /* 1110 : 3 bytes */
00217     4                       /* 1111 :4 bytes */
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       //"invalid UTF-8 stream";
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       //probably an empty file
00285       us = 0;
00286     }
00287     if(us == SQ_BYTECODE_STREAM_TAG) { //BYTECODE
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 { //SCRIPT
00295       switch(us)
00296       {
00297         //gotta swap the next 2 lines on BIG endian machines
00298         case 0xFFFE: func = _io_file_lexfeed_UCS2_BE; break;//UTF-16 little endian;
00299         case 0xFEFF: func = _io_file_lexfeed_UCS2_LE; break;//UTF-16 big endian;
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;//UTF-8 ;
00311         default: sqstd_fseek(file,0,SQ_SEEK_SET); break; // ascii
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); //removes the closure
00331       return 1;
00332     }
00333     sq_pop(v,1); //removes the closure
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; //forward the 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; //propagates the 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; //propagates the 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); //repush the this
00381   if(SQ_SUCCEEDED(sqstd_dofile(v,filename,SQTrue,printerror)))
00382     return 1;
00383   return SQ_ERROR; //propagates the 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   //create delegate
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 }

Generated on Mon Dec 14 20:59:56 2009 for OpenTTD by  doxygen 1.5.6