f3903e2e461edd2d9066a2302e05b6c0f6287e2e
[supertux.git] / src / squirrel / sqstdlib / sqstdio.cpp
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 _UNICODE
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, long offset, int origin)
30 {
31         int 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,offset,realorigin);
39 }
40
41 long 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) { 
76                         sqstd_fclose(_handle);
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         int Flush() {
88                 return sqstd_fflush(_handle);
89         }
90         long Tell() {
91                 return sqstd_ftell(_handle);
92         }
93         SQInteger Len() {
94                 int prevpos=Tell();
95                 Seek(0,SQ_SEEK_END);
96                 int size=Tell();
97                 Seek(prevpos,SQ_SEEK_SET);
98                 return size;
99         }
100         SQInteger Seek(long offset, int 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 int _file__typeof(HSQUIRRELVM v)
112 {
113         sq_pushstring(v,_SC("file"),-1);
114         return 1;
115 }
116
117 static int _file_releasehook(SQUserPointer p, int size)
118 {
119         (void) size;
120         SQFile *self = (SQFile*)p;
121         delete self;
122         return 1;
123 }
124
125 static int _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         }
147         sq_setreleasehook(v,1,_file_releasehook);
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         int top = sq_gettop(v);
164         sq_pushregistrytable(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) )) {
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, int idx, SQFILE *file)
186 {
187         SQFile *fileobj = NULL;
188         if(SQ_SUCCEEDED(sq_getinstanceup(v,idx,(SQUserPointer*)&fileobj,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 static SQInteger _io_file_lexfeedASCII(SQUserPointer file)
197 {
198         int ret;
199         char c;
200         if( ( ret=sqstd_fread(&c,sizeof(c),1,(FILE *)file )>0) )
201                 return c;
202         return 0;
203 }
204
205 static SQInteger _io_file_lexfeedWCHAR(SQUserPointer file)
206 {
207         int ret;
208         wchar_t c;
209         if( ( ret=sqstd_fread(&c,sizeof(c),1,(FILE *)file )>0) )
210                 return (SQChar)c;
211         return 0;
212 }
213
214 int file_read(SQUserPointer file,SQUserPointer buf,int size)
215 {
216         int ret;
217         if( ( ret = sqstd_fread(buf,1,size,(SQFILE)file ))!=0 )return ret;
218         return -1;
219 }
220
221 int file_write(SQUserPointer file,SQUserPointer p,int size)
222 {
223         return sqstd_fwrite(p,1,size,(SQFILE)file);
224 }
225
226 SQRESULT sqstd_loadfile(HSQUIRRELVM v,const SQChar *filename,SQBool printerror)
227 {
228         SQFILE file = sqstd_fopen(filename,_SC("rb"));
229         int ret;
230         unsigned short uc;
231         SQLEXREADFUNC func = _io_file_lexfeedASCII;
232         if(file && (ret=sqstd_fread(&uc,1,2,file))){
233                 if(ret!=2) {
234                         sqstd_fclose(file);
235                         return sq_throwerror(v,_SC("io error"));
236                 }
237                 if(uc==SQ_BYTECODE_STREAM_TAG) { //BYTECODE
238                         sqstd_fseek(file,0,SQ_SEEK_SET);
239                         if(SQ_SUCCEEDED(sq_readclosure(v,file_read,file))) {
240                                 sqstd_fclose(file);
241                                 return SQ_OK;
242                         }
243                 }
244                 else { //SCRIPT
245                         if(uc==0xFEFF)
246                                 func = _io_file_lexfeedWCHAR;
247                         else
248                                 sqstd_fseek(file,0,SQ_SEEK_SET);
249
250                         if(SQ_SUCCEEDED(sq_compile(v,func,file,filename,printerror))){
251                                 sqstd_fclose(file);
252                                 return SQ_OK;
253                         }
254                 }
255                 sqstd_fclose(file);
256                 return SQ_ERROR;
257         }
258         return sq_throwerror(v,_SC("cannot open the file"));
259 }
260
261 SQRESULT sqstd_dofile(HSQUIRRELVM v,const SQChar *filename,SQBool retval,SQBool printerror)
262 {
263         if(SQ_SUCCEEDED(sqstd_loadfile(v,filename,printerror))) {
264                 sq_push(v,-2);
265                 //int ntop = sq_gettop(v);
266                 if(SQ_SUCCEEDED(sq_call(v,1,retval))) {
267                         sq_remove(v,retval?-2:-1); //removes the closure
268                         return 1;
269                 }
270                 sq_pop(v,1); //removes the closure
271         }
272         return SQ_ERROR;
273 }
274
275 SQRESULT sqstd_writeclosuretofile(HSQUIRRELVM v,const SQChar *filename)
276 {
277         SQFILE file = sqstd_fopen(filename,_SC("wb+"));
278         if(!file) return sq_throwerror(v,_SC("cannot open the file"));
279         if(SQ_SUCCEEDED(sq_writeclosure(v,file_write,file))) {
280                 sqstd_fclose(file);
281                 return SQ_OK;
282         }
283         sqstd_fclose(file);
284         return SQ_ERROR; //forward the error
285 }
286
287 int _g_io_loadfile(HSQUIRRELVM v)
288 {
289         const SQChar *filename;
290         SQBool printerror = SQFalse;
291         sq_getstring(v,2,&filename);
292         if(sq_gettop(v) >= 3) {
293                 sq_getbool(v,3,&printerror);
294         }
295         if(SQ_SUCCEEDED(sqstd_loadfile(v,filename,printerror)))
296                 return 1;
297         return SQ_ERROR; //propagates the error
298 }
299
300 int _g_io_dofile(HSQUIRRELVM v)
301 {
302         const SQChar *filename;
303         SQBool printerror = SQFalse;
304         sq_getstring(v,2,&filename);
305         if(sq_gettop(v) >= 3) {
306                 sq_getbool(v,3,&printerror);
307         }
308         sq_push(v,1); //repush the this
309         if(SQ_SUCCEEDED(sqstd_dofile(v,filename,SQTrue,printerror)))
310                 return 1;
311         return SQ_ERROR; //propagates the error
312 }
313
314 #define _DECL_GLOBALIO_FUNC(name,nparams,typecheck) {_SC(#name),_g_io_##name,nparams,typecheck}
315 static SQRegFunction iolib_funcs[]={
316         _DECL_GLOBALIO_FUNC(loadfile,-2,_SC(".sb")),
317         _DECL_GLOBALIO_FUNC(dofile,-2,_SC(".sb")),
318         {0,0,0,0}
319 };
320
321 SQRESULT sqstd_register_iolib(HSQUIRRELVM v)
322 {
323         int top = sq_gettop(v);
324         //create delegate
325         declare_stream(v,_SC("file"),SQSTD_FILE_TYPE_TAG,_SC("std_file"),_file_methods,iolib_funcs);
326         sq_pushstring(v,_SC("stdout"),-1);
327         sqstd_createfile(v,stdout,0);
328         sq_createslot(v,-3);
329         sq_pushstring(v,_SC("stdin"),-1);
330         sqstd_createfile(v,stdin,0);
331         sq_createslot(v,-3);
332         sq_pushstring(v,_SC("stderr"),-1);
333         sqstd_createfile(v,stderr,0);
334         sq_createslot(v,-3);
335         sq_settop(v,top);
336         return SQ_OK;
337 }