Code::Blocks  SVN r11506
sqstdio.cpp
Go to the documentation of this file.
1 /* see copyright notice in squirrel.h */
2 #include <new>
3 #include <stdio.h>
4 #include <squirrel.h>
5 #include <sqstdio.h>
6 #include "sqstdstream.h"
7 
8 #define SQSTD_FILE_TYPE_TAG (SQSTD_STREAM_TYPE_TAG | 0x00000001)
9 //basic API
10 SQFILE sqstd_fopen(const SQChar *filename ,const SQChar *mode)
11 {
12 #ifndef SQUNICODE
13  return (SQFILE)fopen(filename,mode);
14 #else
15  return (SQFILE)_wfopen(filename,mode);
16 #endif
17 }
18 
19 SQInteger sqstd_fread(void* buffer, SQInteger size, SQInteger count, SQFILE file)
20 {
21  return (SQInteger)fread(buffer,size,count,(FILE *)file);
22 }
23 
24 SQInteger sqstd_fwrite(const SQUserPointer buffer, SQInteger size, SQInteger count, SQFILE file)
25 {
26  return (SQInteger)fwrite(buffer,size,count,(FILE *)file);
27 }
28 
29 SQInteger sqstd_fseek(SQFILE file, SQInteger offset, SQInteger origin)
30 {
31  SQInteger realorigin;
32  switch(origin) {
33  case SQ_SEEK_CUR: realorigin = SEEK_CUR; break;
34  case SQ_SEEK_END: realorigin = SEEK_END; break;
35  case SQ_SEEK_SET: realorigin = SEEK_SET; break;
36  default: return -1; //failed
37  }
38  return fseek((FILE *)file,(long)offset,(int)realorigin);
39 }
40 
41 SQInteger sqstd_ftell(SQFILE file)
42 {
43  return ftell((FILE *)file);
44 }
45 
46 SQInteger sqstd_fflush(SQFILE file)
47 {
48  return fflush((FILE *)file);
49 }
50 
51 SQInteger sqstd_fclose(SQFILE file)
52 {
53  return fclose((FILE *)file);
54 }
55 
56 SQInteger sqstd_feof(SQFILE file)
57 {
58  return feof((FILE *)file);
59 }
60 
61 //File
62 struct SQFile : public SQStream {
63  SQFile() { _handle = NULL; _owns = false;}
64  SQFile(SQFILE file, bool owns) { _handle = file; _owns = owns;}
65  virtual ~SQFile() { Close(); }
66  bool Open(const SQChar *filename ,const SQChar *mode) {
67  Close();
68  if( (_handle = sqstd_fopen(filename,mode)) ) {
69  _owns = true;
70  return true;
71  }
72  return false;
73  }
74  void Close() {
75  if(_handle && _owns) {
77  _handle = NULL;
78  _owns = false;
79  }
80  }
81  SQInteger Read(void *buffer,SQInteger size) {
82  return sqstd_fread(buffer,1,size,_handle);
83  }
84  SQInteger Write(void *buffer,SQInteger size) {
85  return sqstd_fwrite(buffer,1,size,_handle);
86  }
87  SQInteger Flush() {
88  return sqstd_fflush(_handle);
89  }
90  SQInteger Tell() {
91  return sqstd_ftell(_handle);
92  }
93  SQInteger Len() {
94  SQInteger prevpos=Tell();
95  Seek(0,SQ_SEEK_END);
96  SQInteger size=Tell();
97  Seek(prevpos,SQ_SEEK_SET);
98  return size;
99  }
100  SQInteger Seek(SQInteger offset, SQInteger origin) {
101  return sqstd_fseek(_handle,offset,origin);
102  }
103  bool IsValid() { return _handle?true:false; }
104  bool EOS() { return Tell()==Len()?true:false;}
105  SQFILE GetHandle() {return _handle;}
106 private:
107  SQFILE _handle;
108  bool _owns;
109 };
110 
111 static SQInteger _file__typeof(HSQUIRRELVM v)
112 {
113  sq_pushstring(v,_SC("file"),-1);
114  return 1;
115 }
116 
117 // C::B patch: Make the compiler happy by commenting unused variables
118 static SQInteger _file_releasehook(SQUserPointer p, SQInteger /*size*/)
119 {
120  SQFile *self = (SQFile*)p;
121  delete self;
122  return 1;
123 }
124 
125 static SQInteger _file_constructor(HSQUIRRELVM v)
126 {
127  const SQChar *filename,*mode;
128  bool owns = true;
129  SQFile *f;
130  SQFILE newf;
131  if(sq_gettype(v,2) == OT_STRING && sq_gettype(v,3) == OT_STRING) {
132  sq_getstring(v, 2, &filename);
133  sq_getstring(v, 3, &mode);
134  newf = sqstd_fopen(filename, mode);
135  if(!newf) return sq_throwerror(v, _SC("cannot open file"));
136  } else if(sq_gettype(v,2) == OT_USERPOINTER) {
137  owns = !(sq_gettype(v,3) == OT_NULL);
138  sq_getuserpointer(v,2,&newf);
139  } else {
140  return sq_throwerror(v,_SC("wrong parameter"));
141  }
142  f = new SQFile(newf,owns);
143  if(SQ_FAILED(sq_setinstanceup(v,1,f))) {
144  delete f;
145  return sq_throwerror(v, _SC("cannot create blob with negative size"));
146  }
148  return 0;
149 }
150 
151 //bindings
152 #define _DECL_FILE_FUNC(name,nparams,typecheck) {_SC(#name),_file_##name,nparams,typecheck}
153 static SQRegFunction _file_methods[] = {
154  _DECL_FILE_FUNC(constructor,3,_SC("x")),
155  _DECL_FILE_FUNC(_typeof,1,_SC("x")),
156  {0,0,0,0},
157 };
158 
159 
160 
161 SQRESULT sqstd_createfile(HSQUIRRELVM v, SQFILE file,SQBool own)
162 {
163  SQInteger top = sq_gettop(v);
165  sq_pushstring(v,_SC("std_file"),-1);
166  if(SQ_SUCCEEDED(sq_get(v,-2))) {
167  sq_remove(v,-2); //removes the registry
168  sq_pushroottable(v); // push the this
169  sq_pushuserpointer(v,file); //file
170  if(own){
171  sq_pushinteger(v,1); //true
172  }
173  else{
174  sq_pushnull(v); //false
175  }
176  if(SQ_SUCCEEDED( sq_call(v,3,SQTrue,SQFalse) )) {
177  sq_remove(v,-2);
178  return SQ_OK;
179  }
180  }
181  sq_settop(v,top);
182  return SQ_OK;
183 }
184 
185 SQRESULT sqstd_getfile(HSQUIRRELVM v, SQInteger idx, SQFILE *file)
186 {
187  SQFile *fileobj = NULL;
188  if(SQ_SUCCEEDED(sq_getinstanceup(v,idx,(SQUserPointer*)&fileobj,(SQUserPointer)SQSTD_FILE_TYPE_TAG))) {
189  *file = fileobj->GetHandle();
190  return SQ_OK;
191  }
192  return sq_throwerror(v,_SC("not a file"));
193 }
194 
195 
196 
197 static SQInteger _io_file_lexfeed_ASCII(SQUserPointer file)
198 {
199  SQInteger ret;
200  char c;
201  if( ( ret=sqstd_fread(&c,sizeof(c),1,(FILE *)file )>0) )
202  return c;
203  return 0;
204 }
205 
206 static SQInteger _io_file_lexfeed_UTF8(SQUserPointer file)
207 {
208 #define READ() \
209  if(sqstd_fread(&inchar,sizeof(inchar),1,(FILE *)file) != 1) \
210  return 0;
211 
212  static const SQInteger utf8_lengths[16] =
213  {
214  1,1,1,1,1,1,1,1, /* 0000 to 0111 : 1 byte (plain ASCII) */
215  0,0,0,0, /* 1000 to 1011 : not valid */
216  2,2, /* 1100, 1101 : 2 bytes */
217  3, /* 1110 : 3 bytes */
218  4 /* 1111 :4 bytes */
219  };
220  static unsigned char byte_masks[5] = {0,0,0x1f,0x0f,0x07};
221  unsigned char inchar;
222  SQInteger c = 0;
223  READ();
224  c = inchar;
225  //
226  if(c >= 0x80) {
227  SQInteger tmp;
228  SQInteger codelen = utf8_lengths[c>>4];
229  if(codelen == 0)
230  return 0;
231  //"invalid UTF-8 stream";
232  tmp = c&byte_masks[codelen];
233  for(SQInteger n = 0; n < codelen-1; n++) {
234  tmp<<=6;
235  READ();
236  tmp |= inchar & 0x3F;
237  }
238  c = tmp;
239  }
240  return c;
241 }
242 
243 static SQInteger _io_file_lexfeed_UCS2_LE(SQUserPointer file)
244 {
245  SQInteger ret;
246  wchar_t c;
247  if( ( ret=sqstd_fread(&c,sizeof(c),1,(FILE *)file )>0) )
248  return (SQChar)c;
249  return 0;
250 }
251 
252 static SQInteger _io_file_lexfeed_UCS2_BE(SQUserPointer file)
253 {
254  SQInteger ret;
255  unsigned short c;
256  if( ( ret=sqstd_fread(&c,sizeof(c),1,(FILE *)file )>0) ) {
257  c = ((c>>8)&0x00FF)| ((c<<8)&0xFF00);
258  return (SQChar)c;
259  }
260  return 0;
261 }
262 
263 SQInteger file_read(SQUserPointer file,SQUserPointer buf,SQInteger size)
264 {
265  SQInteger ret;
266  if( ( ret = sqstd_fread(buf,1,size,(SQFILE)file ))!=0 )return ret;
267  return -1;
268 }
269 
270 SQInteger file_write(SQUserPointer file,SQUserPointer p,SQInteger size)
271 {
272  return sqstd_fwrite(p,1,size,(SQFILE)file);
273 }
274 
275 SQRESULT sqstd_loadfile(HSQUIRRELVM v,const SQChar *filename,SQBool printerror)
276 {
277  SQFILE file = sqstd_fopen(filename,_SC("rb"));
278  SQInteger ret;
279  unsigned short us;
280  unsigned char uc;
281  SQLEXREADFUNC func = _io_file_lexfeed_ASCII;
282  if(file){
283  ret = sqstd_fread(&us,1,2,file);
284  if(ret != 2) {
285  //probably an empty file
286  us = 0;
287  }
288  if(us == SQ_BYTECODE_STREAM_TAG) { //BYTECODE
289  sqstd_fseek(file,0,SQ_SEEK_SET);
290  if(SQ_SUCCEEDED(sq_readclosure(v,file_read,file))) {
291  sqstd_fclose(file);
292  return SQ_OK;
293  }
294  }
295  else { //SCRIPT
296  switch(us)
297  {
298  //gotta swap the next 2 lines on BIG endian machines
299  case 0xFFFE: func = _io_file_lexfeed_UCS2_BE; break;//UTF-16 little endian;
300  case 0xFEFF: func = _io_file_lexfeed_UCS2_LE; break;//UTF-16 big endian;
301  case 0xBBEF:
302  if(sqstd_fread(&uc,1,sizeof(uc),file) == 0) {
303  sqstd_fclose(file);
304  return sq_throwerror(v,_SC("io error"));
305  }
306  if(uc != 0xBF) {
307  sqstd_fclose(file);
308  return sq_throwerror(v,_SC("Unrecognozed ecoding"));
309  }
310  func = _io_file_lexfeed_UTF8;
311  break;//UTF-8 ;
312  default: sqstd_fseek(file,0,SQ_SEEK_SET); break; // ascii
313  }
314 
315  if(SQ_SUCCEEDED(sq_compile(v,func,file,filename,printerror))){
316  sqstd_fclose(file);
317  return SQ_OK;
318  }
319  }
320  sqstd_fclose(file);
321  return SQ_ERROR;
322  }
323  return sq_throwerror(v,_SC("cannot open the file"));
324 }
325 
326 SQRESULT sqstd_dofile(HSQUIRRELVM v,const SQChar *filename,SQBool retval,SQBool printerror)
327 {
328  if(SQ_SUCCEEDED(sqstd_loadfile(v,filename,printerror))) {
329  sq_push(v,-2);
330  if(SQ_SUCCEEDED(sq_call(v,1,retval,SQTrue))) {
331  sq_remove(v,retval?-2:-1); //removes the closure
332  return 1;
333  }
334  sq_pop(v,1); //removes the closure
335  }
336  return SQ_ERROR;
337 }
338 
339 SQRESULT sqstd_writeclosuretofile(HSQUIRRELVM v,const SQChar *filename)
340 {
341  SQFILE file = sqstd_fopen(filename,_SC("wb+"));
342  if(!file) return sq_throwerror(v,_SC("cannot open the file"));
343  if(SQ_SUCCEEDED(sq_writeclosure(v,file_write,file))) {
344  sqstd_fclose(file);
345  return SQ_OK;
346  }
347  sqstd_fclose(file);
348  return SQ_ERROR; //forward the error
349 }
350 
351 SQInteger _g_io_loadfile(HSQUIRRELVM v)
352 {
353  const SQChar *filename;
354  SQBool printerror = SQFalse;
355  sq_getstring(v,2,&filename);
356  if(sq_gettop(v) >= 3) {
357  sq_getbool(v,3,&printerror);
358  }
359  if(SQ_SUCCEEDED(sqstd_loadfile(v,filename,printerror)))
360  return 1;
361  return SQ_ERROR; //propagates the error
362 }
363 
364 SQInteger _g_io_writeclosuretofile(HSQUIRRELVM v)
365 {
366  const SQChar *filename;
367  sq_getstring(v,2,&filename);
368  if(SQ_SUCCEEDED(sqstd_writeclosuretofile(v,filename)))
369  return 1;
370  return SQ_ERROR; //propagates the error
371 }
372 
373 SQInteger _g_io_dofile(HSQUIRRELVM v)
374 {
375  const SQChar *filename;
376  SQBool printerror = SQFalse;
377  sq_getstring(v,2,&filename);
378  if(sq_gettop(v) >= 3) {
379  sq_getbool(v,3,&printerror);
380  }
381  sq_push(v,1); //repush the this
382  if(SQ_SUCCEEDED(sqstd_dofile(v,filename,SQTrue,printerror)))
383  return 1;
384  return SQ_ERROR; //propagates the error
385 }
386 
387 #define _DECL_GLOBALIO_FUNC(name,nparams,typecheck) {_SC(#name),_g_io_##name,nparams,typecheck}
388 static SQRegFunction iolib_funcs[]={
389  _DECL_GLOBALIO_FUNC(loadfile,-2,_SC(".sb")),
390  _DECL_GLOBALIO_FUNC(dofile,-2,_SC(".sb")),
391  _DECL_GLOBALIO_FUNC(writeclosuretofile,3,_SC(".sc")),
392  {0,0}
393 };
394 
395 SQRESULT sqstd_register_iolib(HSQUIRRELVM v)
396 {
397  SQInteger top = sq_gettop(v);
398  //create delegate
399  declare_stream(v,_SC("file"),(SQUserPointer)SQSTD_FILE_TYPE_TAG,_SC("std_file"),_file_methods,iolib_funcs);
400  sq_pushstring(v,_SC("stdout"),-1);
401  sqstd_createfile(v,stdout,SQFalse);
402  sq_createslot(v,-3);
403  sq_pushstring(v,_SC("stdin"),-1);
404  sqstd_createfile(v,stdin,SQFalse);
405  sq_createslot(v,-3);
406  sq_pushstring(v,_SC("stderr"),-1);
407  sqstd_createfile(v,stderr,SQFalse);
408  sq_createslot(v,-3);
409  sq_settop(v,top);
410  return SQ_OK;
411 }
#define SQSTD_FILE_TYPE_TAG
Definition: sqstdio.cpp:8
SQRESULT sq_get(HSQUIRRELVM v, SQInteger idx)
Definition: sqapi.cpp:840
SQRESULT sq_getinstanceup(HSQUIRRELVM v, SQInteger idx, SQUserPointer *p, SQUserPointer typetag)
Definition: sqapi.cpp:647
SQInteger Seek(SQInteger offset, SQInteger origin)
Definition: sqstdio.cpp:100
SQInteger sqstd_fflush(SQFILE file)
Definition: sqstdio.cpp:46
SQInteger _g_io_writeclosuretofile(HSQUIRRELVM v)
Definition: sqstdio.cpp:364
void sq_pop(HSQUIRRELVM v, SQInteger nelemstopop)
Definition: sqapi.cpp:678
SQInteger Len()
Definition: sqstdio.cpp:93
SQInteger sqstd_ftell(SQFILE file)
Definition: sqstdio.cpp:41
SQInteger sqstd_fread(void *buffer, SQInteger size, SQInteger count, SQFILE file)
Definition: sqstdio.cpp:19
SQInteger sqstd_fseek(SQFILE file, SQInteger offset, SQInteger origin)
Definition: sqstdio.cpp:29
SQRESULT sq_throwerror(HSQUIRRELVM v, const SQChar *err)
Definition: sqapi.cpp:918
static SQRegFunction iolib_funcs[]
Definition: sqstdio.cpp:388
SQInteger Tell()
Definition: sqstdio.cpp:90
void sq_pushnull(HSQUIRRELVM v)
Definition: sqapi.cpp:190
SQInteger _g_io_loadfile(HSQUIRRELVM v)
Definition: sqstdio.cpp:351
SQFILE GetHandle()
Definition: sqstdio.cpp:105
void sq_pushroottable(HSQUIRRELVM v)
Definition: sqapi.cpp:437
void sq_pushregistrytable(HSQUIRRELVM v)
Definition: sqapi.cpp:442
SQInteger sqstd_feof(SQFILE file)
Definition: sqstdio.cpp:56
SQFILE _handle
Definition: sqstdio.cpp:107
SQRESULT sq_writeclosure(HSQUIRRELVM v, SQWRITEFUNC w, SQUserPointer up)
Definition: sqapi.cpp:1017
#define _DECL_FILE_FUNC(name, nparams, typecheck)
Definition: sqstdio.cpp:152
SQRESULT sqstd_createfile(HSQUIRRELVM v, SQFILE file, SQBool own)
Definition: sqstdio.cpp:161
static SQInteger _io_file_lexfeed_UTF8(SQUserPointer file)
Definition: sqstdio.cpp:206
SQInteger sq_gettop(HSQUIRRELVM v)
Definition: sqapi.cpp:664
void sq_pushinteger(HSQUIRRELVM v, SQInteger n)
Definition: sqapi.cpp:202
SQRESULT sq_call(HSQUIRRELVM v, SQInteger params, SQBool retval, SQBool raiseerror)
Definition: sqapi.cpp:954
void sq_push(HSQUIRRELVM v, SQInteger idx)
Definition: sqapi.cpp:484
SQInteger _g_io_dofile(HSQUIRRELVM v)
Definition: sqstdio.cpp:373
void Close()
Definition: sqstdio.cpp:74
SQRESULT sqstd_getfile(HSQUIRRELVM v, SQInteger idx, SQFILE *file)
Definition: sqstdio.cpp:185
bool EOS()
Definition: sqstdio.cpp:104
SQRESULT sqstd_writeclosuretofile(HSQUIRRELVM v, const SQChar *filename)
Definition: sqstdio.cpp:339
static SQInteger _io_file_lexfeed_UCS2_LE(SQUserPointer file)
Definition: sqstdio.cpp:243
void sq_settop(HSQUIRRELVM v, SQInteger newtop)
Definition: sqapi.cpp:669
SQRESULT sq_compile(HSQUIRRELVM v, SQLEXREADFUNC read, SQUserPointer p, const SQChar *sourcename, SQBool raiseerror)
Definition: sqapi.cpp:117
SQInteger sqstd_fwrite(const SQUserPointer buffer, SQInteger size, SQInteger count, SQFILE file)
Definition: sqstdio.cpp:24
static SQInteger _file__typeof(HSQUIRRELVM v)
Definition: sqstdio.cpp:111
static SQInteger _file_releasehook(SQUserPointer p, SQInteger)
Definition: sqstdio.cpp:118
void sq_remove(HSQUIRRELVM v, SQInteger idx)
Definition: sqapi.cpp:691
SQInteger Read(void *buffer, SQInteger size)
Definition: sqstdio.cpp:81
void sq_pushstring(HSQUIRRELVM v, const SQChar *s, SQInteger len)
Definition: sqapi.cpp:195
SQRESULT sq_setinstanceup(HSQUIRRELVM v, SQInteger idx, SQUserPointer p)
Definition: sqapi.cpp:629
bool _owns
Definition: sqstdio.cpp:108
SQObjectType sq_gettype(HSQUIRRELVM v, SQInteger idx)
Definition: sqapi.cpp:489
SQInteger sqstd_fclose(SQFILE file)
Definition: sqstdio.cpp:51
static SQRegFunction _file_methods[]
Definition: sqstdio.cpp:153
SQRESULT sq_getstring(HSQUIRRELVM v, SQInteger idx, const SQChar **c)
Definition: sqapi.cpp:539
SQRESULT sqstd_register_iolib(HSQUIRRELVM v)
Definition: sqstdio.cpp:395
SQRESULT declare_stream(HSQUIRRELVM v, const SQChar *name, SQUserPointer typetag, const SQChar *reg_name, SQRegFunction *methods, SQRegFunction *globals)
SQRESULT sq_readclosure(HSQUIRRELVM v, SQREADFUNC r, SQUserPointer up)
Definition: sqapi.cpp:1029
SQRESULT sq_getuserpointer(HSQUIRRELVM v, SQInteger idx, SQUserPointer *p)
Definition: sqapi.cpp:621
#define _DECL_GLOBALIO_FUNC(name, nparams, typecheck)
Definition: sqstdio.cpp:387
char SQChar
SQRESULT sq_getbool(HSQUIRRELVM v, SQInteger idx, SQBool *b)
Definition: sqapi.cpp:529
bool IsValid()
Definition: sqstdio.cpp:103
SQRESULT sqstd_dofile(HSQUIRRELVM v, const SQChar *filename, SQBool retval, SQBool printerror)
Definition: sqstdio.cpp:326
SQFile(SQFILE file, bool owns)
Definition: sqstdio.cpp:64
virtual ~SQFile()
Definition: sqstdio.cpp:65
static SQInteger _file_constructor(HSQUIRRELVM v)
Definition: sqstdio.cpp:125
SQInteger file_write(SQUserPointer file, SQUserPointer p, SQInteger size)
Definition: sqstdio.cpp:270
SQInteger Flush()
Definition: sqstdio.cpp:87
SQRESULT sqstd_loadfile(HSQUIRRELVM v, const SQChar *filename, SQBool printerror)
Definition: sqstdio.cpp:275
static SQInteger _io_file_lexfeed_UCS2_BE(SQUserPointer file)
Definition: sqstdio.cpp:252
SQInteger file_read(SQUserPointer file, SQUserPointer buf, SQInteger size)
Definition: sqstdio.cpp:263
void sq_setreleasehook(HSQUIRRELVM v, SQInteger idx, SQRELEASEHOOK hook)
Definition: sqapi.cpp:999
SQFile()
Definition: sqstdio.cpp:63
#define NULL
Definition: prefix.cpp:59
SQInteger Write(void *buffer, SQInteger size)
Definition: sqstdio.cpp:84
static SQInteger _io_file_lexfeed_ASCII(SQUserPointer file)
Definition: sqstdio.cpp:197
void sq_pushuserpointer(HSQUIRRELVM v, SQUserPointer p)
Definition: sqapi.cpp:217
#define READ()
SQFILE sqstd_fopen(const SQChar *filename, const SQChar *mode)
Definition: sqstdio.cpp:10
bool Open(const SQChar *filename, const SQChar *mode)
Definition: sqstdio.cpp:66