5d02f55acba16c6293d4b5be7a3af0a6c8e877f6
[supertux.git] / src / squirrel / sqstdlib / sqstdio.cpp
1 /* see copyright notice in squirrel.h */\r
2 #include <new>\r
3 #include <stdio.h>\r
4 #include <squirrel.h>\r
5 #include <sqstdio.h>\r
6 #include "sqstdstream.h"\r
7 \r
8 #define SQSTD_FILE_TYPE_TAG (SQSTD_STREAM_TYPE_TAG | 0x00000001)\r
9 //basic API\r
10 SQFILE sqstd_fopen(const SQChar *filename ,const SQChar *mode)\r
11 {\r
12 #ifndef _UNICODE\r
13         return (SQFILE)fopen(filename,mode);\r
14 #else\r
15         return (SQFILE)_wfopen(filename,mode);\r
16 #endif\r
17 }\r
18 \r
19 SQInteger sqstd_fread(void* buffer, SQInteger size, SQInteger count, SQFILE file)\r
20 {\r
21         return (SQInteger)fread(buffer,size,count,(FILE *)file);\r
22 }\r
23 \r
24 SQInteger sqstd_fwrite(const SQUserPointer buffer, SQInteger size, SQInteger count, SQFILE file)\r
25 {\r
26         return (SQInteger)fwrite(buffer,size,count,(FILE *)file);\r
27 }\r
28 \r
29 SQInteger sqstd_fseek(SQFILE file, long offset, int origin)\r
30 {\r
31         int realorigin;\r
32         switch(origin) {\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
37         }\r
38         return fseek((FILE *)file,offset,realorigin);\r
39 }\r
40 \r
41 long sqstd_ftell(SQFILE file)\r
42 {\r
43         return ftell((FILE *)file);\r
44 }\r
45 \r
46 SQInteger sqstd_fflush(SQFILE file)\r
47 {\r
48         return fflush((FILE *)file);\r
49 }\r
50 \r
51 SQInteger sqstd_fclose(SQFILE file)\r
52 {\r
53         return fclose((FILE *)file);\r
54 }\r
55 \r
56 SQInteger sqstd_feof(SQFILE file)\r
57 {\r
58         return feof((FILE *)file);\r
59 }\r
60 \r
61 //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         ~SQFile() { Close(); }\r
66         bool Open(const SQChar *filename ,const SQChar *mode) {\r
67                 Close();\r
68                 if(_handle = sqstd_fopen(filename,mode)) {\r
69                         _owns = true;\r
70                         return true;\r
71                 }\r
72                 return false;\r
73         }\r
74         void Close() {\r
75                 if(_handle && _owns) { \r
76                         sqstd_fclose(_handle);\r
77                         _handle = NULL;\r
78                         _owns = false;\r
79                 }\r
80         }\r
81         SQInteger Read(void *buffer,SQInteger size) {\r
82                 return sqstd_fread(buffer,1,size,_handle);\r
83         }\r
84         SQInteger Write(void *buffer,SQInteger size) {\r
85                 return sqstd_fwrite(buffer,1,size,_handle);\r
86         }\r
87         int Flush() {\r
88                 return sqstd_fflush(_handle);\r
89         }\r
90         long Tell() {\r
91                 return sqstd_ftell(_handle);\r
92         }\r
93         SQInteger Len() {\r
94                 int prevpos=Tell();\r
95                 Seek(0,SQ_SEEK_END);\r
96                 int size=Tell();\r
97                 Seek(prevpos,SQ_SEEK_SET);\r
98                 return size;\r
99         }\r
100         SQInteger Seek(long offset, int origin) {\r
101                 return sqstd_fseek(_handle,offset,origin);\r
102         }\r
103         bool IsValid() { return _handle?true:false; }\r
104         bool EOS() { return Tell()==Len()?true:false;}\r
105         SQFILE GetHandle() {return _handle;}\r
106 private:\r
107         SQFILE _handle;\r
108         bool _owns;\r
109 };\r
110 \r
111 static int _file__typeof(HSQUIRRELVM v)\r
112 {\r
113         sq_pushstring(v,_SC("file"),-1);\r
114         return 1;\r
115 }\r
116 \r
117 static int _file_releasehook(SQUserPointer p, int size)\r
118 {\r
119         SQFile *self = (SQFile*)p;\r
120         delete self;\r
121         return 1;\r
122 }\r
123 \r
124 static int _file_constructor(HSQUIRRELVM v)\r
125 {\r
126         const SQChar *filename,*mode;\r
127         bool owns = true;\r
128         SQFile *f;\r
129         SQFILE newf;\r
130         if(sq_gettype(v,2) == OT_STRING && sq_gettype(v,3) == OT_STRING) {\r
131                 sq_getstring(v, 2, &filename);\r
132                 sq_getstring(v, 3, &mode);\r
133                 newf = sqstd_fopen(filename, mode);\r
134                 if(!newf) return sq_throwerror(v, _SC("cannot open file"));\r
135         } else if(sq_gettype(v,2) == OT_USERPOINTER) {\r
136                 owns = !(sq_gettype(v,3) == OT_NULL);\r
137                 sq_getuserpointer(v,2,&newf);\r
138         } else {\r
139                 return sq_throwerror(v,_SC("wrong parameter"));\r
140         }\r
141         f = new SQFile(newf,owns);\r
142         if(SQ_FAILED(sq_setinstanceup(v,1,f))) {\r
143                 delete f;\r
144                 return sq_throwerror(v, _SC("cannot create blob with negative size"));\r
145         }\r
146         sq_setreleasehook(v,1,_file_releasehook);\r
147         return 0;\r
148 }\r
149 \r
150 //bindings\r
151 #define _DECL_FILE_FUNC(name,nparams,typecheck) {_SC(#name),_file_##name,nparams,typecheck}\r
152 static SQRegFunction _file_methods[] = {\r
153         _DECL_FILE_FUNC(constructor,3,_SC("x")),\r
154         _DECL_FILE_FUNC(_typeof,1,_SC("x")),\r
155         {0,0,0,0},\r
156 };\r
157 \r
158 \r
159 \r
160 SQRESULT sqstd_createfile(HSQUIRRELVM v, SQFILE file,SQBool own)\r
161 {\r
162         int top = sq_gettop(v);\r
163         sq_pushregistrytable(v);\r
164         sq_pushstring(v,_SC("std_file"),-1);\r
165         if(SQ_SUCCEEDED(sq_get(v,-2))) {\r
166                 sq_remove(v,-2); //removes the registry\r
167                 sq_pushroottable(v); // push the this\r
168                 sq_pushuserpointer(v,file); //file\r
169                 if(own){\r
170                         sq_pushinteger(v,1); //true\r
171                 }\r
172                 else{\r
173                         sq_pushnull(v); //false\r
174                 }\r
175                 if(SQ_SUCCEEDED( sq_call(v,3,SQTrue) )) {\r
176                         sq_remove(v,-2);\r
177                         return SQ_OK;\r
178                 }\r
179         }\r
180         sq_settop(v,top);\r
181         return SQ_OK;\r
182 }\r
183 \r
184 SQRESULT sqstd_getfile(HSQUIRRELVM v, int idx, SQFILE *file)\r
185 {\r
186         SQFile *fileobj = NULL;\r
187         if(SQ_SUCCEEDED(sq_getinstanceup(v,idx,(SQUserPointer*)&fileobj,SQSTD_FILE_TYPE_TAG))) {\r
188                 *file = fileobj->GetHandle();\r
189                 return SQ_OK;\r
190         }\r
191         return sq_throwerror(v,_SC("not a file"));\r
192 }\r
193 \r
194 \r
195 static SQInteger _io_file_lexfeedASCII(SQUserPointer file)\r
196 {\r
197         int ret;\r
198         char c;\r
199         if( ( ret=sqstd_fread(&c,sizeof(c),1,(FILE *)file )>0) )\r
200                 return c;\r
201         return 0;\r
202 }\r
203 \r
204 static SQInteger _io_file_lexfeedWCHAR(SQUserPointer file)\r
205 {\r
206         int ret;\r
207         wchar_t c;\r
208         if( ( ret=sqstd_fread(&c,sizeof(c),1,(FILE *)file )>0) )\r
209                 return (SQChar)c;\r
210         return 0;\r
211 }\r
212 \r
213 int file_read(SQUserPointer file,SQUserPointer buf,int size)\r
214 {\r
215         int ret;\r
216         if( ( ret = sqstd_fread(buf,1,size,(SQFILE)file ))!=0 )return ret;\r
217         return -1;\r
218 }\r
219 \r
220 int file_write(SQUserPointer file,SQUserPointer p,int size)\r
221 {\r
222         return sqstd_fwrite(p,1,size,(SQFILE)file);\r
223 }\r
224 \r
225 SQRESULT sqstd_loadfile(HSQUIRRELVM v,const SQChar *filename,SQBool printerror)\r
226 {\r
227         SQFILE file = sqstd_fopen(filename,_SC("rb"));\r
228         int ret;\r
229         unsigned short uc;\r
230         SQLEXREADFUNC func = _io_file_lexfeedASCII;\r
231         if(file && (ret=sqstd_fread(&uc,1,2,file))){\r
232                 if(ret!=2) {\r
233                         sqstd_fclose(file);\r
234                         return sq_throwerror(v,_SC("io error"));\r
235                 }\r
236                 if(uc==SQ_BYTECODE_STREAM_TAG) { //BYTECODE\r
237                         sqstd_fseek(file,0,SQ_SEEK_SET);\r
238                         if(SQ_SUCCEEDED(sq_readclosure(v,file_read,file))) {\r
239                                 sqstd_fclose(file);\r
240                                 return SQ_OK;\r
241                         }\r
242                 }\r
243                 else { //SCRIPT\r
244                         if(uc==0xFEFF)\r
245                                 func = _io_file_lexfeedWCHAR;\r
246                         else\r
247                                 sqstd_fseek(file,0,SQ_SEEK_SET);\r
248 \r
249                         if(SQ_SUCCEEDED(sq_compile(v,func,file,filename,printerror))){\r
250                                 sqstd_fclose(file);\r
251                                 return SQ_OK;\r
252                         }\r
253                 }\r
254                 sqstd_fclose(file);\r
255                 return SQ_ERROR;\r
256         }\r
257         return sq_throwerror(v,_SC("cannot open the file"));\r
258 }\r
259 \r
260 SQRESULT sqstd_dofile(HSQUIRRELVM v,const SQChar *filename,SQBool retval,SQBool printerror)\r
261 {\r
262         if(SQ_SUCCEEDED(sqstd_loadfile(v,filename,printerror))) {\r
263                 sq_push(v,-2);\r
264                 int ntop = sq_gettop(v);\r
265                 if(SQ_SUCCEEDED(sq_call(v,1,retval))) {\r
266                         sq_remove(v,retval?-2:-1); //removes the closure\r
267                         return 1;\r
268                 }\r
269                 sq_pop(v,1); //removes the closure\r
270         }\r
271         return SQ_ERROR;\r
272 }\r
273 \r
274 SQRESULT sqstd_writeclosuretofile(HSQUIRRELVM v,const SQChar *filename)\r
275 {\r
276         SQFILE file = sqstd_fopen(filename,_SC("wb+"));\r
277         if(!file) return sq_throwerror(v,_SC("cannot open the file"));\r
278         if(SQ_SUCCEEDED(sq_writeclosure(v,file_write,file))) {\r
279                 sqstd_fclose(file);\r
280                 return SQ_OK;\r
281         }\r
282         sqstd_fclose(file);\r
283         return SQ_ERROR; //forward the error\r
284 }\r
285 \r
286 int _g_io_loadfile(HSQUIRRELVM v)\r
287 {\r
288         const SQChar *filename;\r
289         SQBool printerror = SQFalse;\r
290         sq_getstring(v,2,&filename);\r
291         if(sq_gettop(v) >= 3) {\r
292                 sq_getbool(v,3,&printerror);\r
293         }\r
294         if(SQ_SUCCEEDED(sqstd_loadfile(v,filename,printerror)))\r
295                 return 1;\r
296         return SQ_ERROR; //propagates the error\r
297 }\r
298 \r
299 int _g_io_dofile(HSQUIRRELVM v)\r
300 {\r
301         const SQChar *filename;\r
302         SQBool printerror = SQFalse;\r
303         sq_getstring(v,2,&filename);\r
304         if(sq_gettop(v) >= 3) {\r
305                 sq_getbool(v,3,&printerror);\r
306         }\r
307         sq_push(v,1); //repush the this\r
308         if(SQ_SUCCEEDED(sqstd_dofile(v,filename,SQTrue,printerror)))\r
309                 return 1;\r
310         return SQ_ERROR; //propagates the error\r
311 }\r
312 \r
313 #define _DECL_GLOBALIO_FUNC(name,nparams,typecheck) {_SC(#name),_g_io_##name,nparams,typecheck}\r
314 static SQRegFunction iolib_funcs[]={\r
315         _DECL_GLOBALIO_FUNC(loadfile,-2,_SC(".sb")),\r
316         _DECL_GLOBALIO_FUNC(dofile,-2,_SC(".sb")),\r
317         {0,0}\r
318 };\r
319 \r
320 SQRESULT sqstd_register_iolib(HSQUIRRELVM v)\r
321 {\r
322         int top = sq_gettop(v);\r
323         //create delegate\r
324         declare_stream(v,_SC("file"),SQSTD_FILE_TYPE_TAG,_SC("std_file"),_file_methods,iolib_funcs);\r
325         sq_pushstring(v,_SC("stdout"),-1);\r
326         sqstd_createfile(v,stdout,0);\r
327         sq_createslot(v,-3);\r
328         sq_pushstring(v,_SC("stdin"),-1);\r
329         sqstd_createfile(v,stdin,0);\r
330         sq_createslot(v,-3);\r
331         sq_pushstring(v,_SC("stderr"),-1);\r
332         sqstd_createfile(v,stderr,0);\r
333         sq_createslot(v,-3);\r
334         sq_settop(v,top);\r
335         return SQ_OK;\r
336 }\r