sqstdio.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695
  1. /* see copyright notice in squirrel.h */
  2. #include <new>
  3. #include <stdio.h>
  4. #include <string.h>
  5. #include <squirrel.h>
  6. #include <sqstdio.h>
  7. #include <sqstdfile.h>
  8. #include "sqstdstream.h"
  9. #if 0
  10. #ifndef _WIN32
  11. #include <unistd.h>
  12. #include <fcntl.h>
  13. #endif // _WIN32
  14. #endif // 0
  15. //only to make the SQFile vtable be generated here
  16. void SQFile::DummyPinVtable(){}
  17. //#define SQSTD_FILE_TYPE_TAG (SQSTD_STREAM_TYPE_TAG | 0x00000001)
  18. const SQChar SQSTD_FILE_TYPE_TAG[] = _SC("std_stream_file");
  19. const SQChar SQSTD_FILE_CLASS_TYPE_TAG[] = _SC("std_file");
  20. //basic API
  21. SQFILE sqstd_fopen(const SQChar *filename ,const SQChar *mode)
  22. {
  23. return (SQFILE)scfopen(filename,mode);
  24. }
  25. SQInteger sqstd_fread(void* buffer, SQInteger size, SQInteger count, SQFILE file)
  26. {
  27. return (SQInteger)fread(buffer,size,count,(FILE *)file);
  28. }
  29. SQChar *sqstd_fgets(SQChar* buffer, SQInteger count, SQFILE file)
  30. {
  31. return (SQChar*)fgets(buffer,count,(FILE *)file);
  32. }
  33. SQInteger sqstd_fwrite(const SQUserPointer buffer, SQInteger size, SQInteger count, SQFILE file)
  34. {
  35. return (SQInteger)fwrite(buffer,size,count,(FILE *)file);
  36. }
  37. SQInteger sqstd_fseek(SQFILE file, SQInteger offset, SQInteger origin)
  38. {
  39. SQInteger realorigin;
  40. switch(origin) {
  41. case SQ_SEEK_CUR: realorigin = SEEK_CUR; break;
  42. case SQ_SEEK_END: realorigin = SEEK_END; break;
  43. case SQ_SEEK_SET: realorigin = SEEK_SET; break;
  44. default: return -1; //failed
  45. }
  46. return fseek((FILE *)file,(long)offset,(int)realorigin);
  47. }
  48. SQInteger sqstd_ftell(SQFILE file)
  49. {
  50. return ftell((FILE *)file);
  51. }
  52. SQInteger sqstd_fflush(SQFILE file)
  53. {
  54. return fflush((FILE *)file);
  55. }
  56. SQInteger sqstd_fclose(SQFILE file)
  57. {
  58. return fclose((FILE *)file);
  59. }
  60. SQInteger sqstd_feof(SQFILE file)
  61. {
  62. return feof((FILE *)file);
  63. }
  64. struct SQPopen : public SQFile {
  65. SQPopen():SQFile() {}
  66. SQPopen(SQFILE file, bool owns):SQFile(file, owns) {}
  67. bool Open(const SQChar *filename ,const SQChar *mode) {
  68. Close();
  69. if( (_handle = popen(filename,mode)) ) {
  70. _owns = true;
  71. return true;
  72. }
  73. return false;
  74. }
  75. int PClose() {
  76. int result = 0;
  77. if(_handle && _owns) {
  78. result = pclose((FILE*)_handle);
  79. _handle = NULL;
  80. _owns = false;
  81. }
  82. return result;
  83. }
  84. void Close() {
  85. PClose();
  86. }
  87. void DummyPinVtable();
  88. };
  89. //only to make the SQPopen vtable be generated here
  90. void SQPopen::DummyPinVtable(){}
  91. static SQRESULT _popen__typeof(HSQUIRRELVM v)
  92. {
  93. sq_pushstring(v,_SC("popen"),-1);
  94. return 1;
  95. }
  96. static SQRESULT _popen_releasehook(SQUserPointer p, SQInteger /*size*/, void */*ep*/)
  97. {
  98. SQPopen *self = (SQPopen*)p;
  99. self->~SQPopen(); //on osx it doesn't seem to work
  100. sq_free(self,sizeof(SQFile));
  101. return 1;
  102. }
  103. static SQRESULT _popen_constructor(HSQUIRRELVM v)
  104. {
  105. const SQChar *filename,*mode;
  106. bool owns = true;
  107. SQPopen *f;
  108. SQFILE newf;
  109. if(sq_gettype(v,2) == OT_STRING && sq_gettype(v,3) == OT_STRING) {
  110. sq_getstring(v, 2, &filename);
  111. sq_getstring(v, 3, &mode);
  112. newf = popen(filename, mode);
  113. if(!newf) return sq_throwerror(v, _SC("cannot open file"));
  114. } else {
  115. return sq_throwerror(v,_SC("wrong parameter"));
  116. }
  117. f = new (sq_malloc(sizeof(SQPopen)))SQPopen(newf,owns);
  118. if(SQ_FAILED(sq_setinstanceup(v,1,f))) {
  119. f->~SQPopen();
  120. sq_free(f,sizeof(SQPopen));
  121. return sq_throwerror(v, _SC("cannot create popen"));
  122. }
  123. sq_setreleasehook(v,1,_popen_releasehook);
  124. return 0;
  125. }
  126. static SQRESULT _popen_close(HSQUIRRELVM v)
  127. {
  128. SQPopen *self = NULL;
  129. if(SQ_SUCCEEDED(sq_getinstanceup(v,1,(SQUserPointer*)&self,(SQUserPointer)SQSTD_FILE_TYPE_TAG))
  130. && self != NULL)
  131. {
  132. sq_pushinteger(v, self->PClose());
  133. return 1;
  134. }
  135. return 0;
  136. }
  137. #define _DECL_FILE_FUNC(name,nparams,typecheck) {_SC(#name),_popen_##name,nparams,typecheck,false}
  138. static const SQRegFunction _popen_methods[] = {
  139. _DECL_FILE_FUNC(constructor,3,_SC("x")),
  140. _DECL_FILE_FUNC(_typeof,1,_SC("x")),
  141. _DECL_FILE_FUNC(close,1,_SC("x")),
  142. {NULL,(SQFUNCTION)0,0,NULL,false}
  143. };
  144. #undef _DECL_FILE_FUNC
  145. static SQRESULT _file__typeof(HSQUIRRELVM v)
  146. {
  147. sq_pushstring(v,_SC("file"),-1);
  148. return 1;
  149. }
  150. static SQRESULT _file_releasehook(SQUserPointer p, SQInteger /*size*/, void */*ep*/)
  151. {
  152. SQFile *self = (SQFile*)p;
  153. self->~SQFile();
  154. sq_free(self,sizeof(SQFile));
  155. return 1;
  156. }
  157. static SQRESULT _file_constructor(HSQUIRRELVM v)
  158. {
  159. const SQChar *filename,*mode;
  160. bool owns = true;
  161. SQFile *f;
  162. SQFILE newf;
  163. if(sq_gettype(v,2) == OT_STRING && sq_gettype(v,3) == OT_STRING) {
  164. sq_getstring(v, 2, &filename);
  165. sq_getstring(v, 3, &mode);
  166. newf = sqstd_fopen(filename, mode);
  167. if(!newf) return sq_throwerror(v, _SC("cannot open file"));
  168. } else if(sq_gettype(v,2) == OT_USERPOINTER) {
  169. owns = !(sq_gettype(v,3) == OT_NULL);
  170. sq_getuserpointer(v,2,&newf);
  171. } else {
  172. return sq_throwerror(v,_SC("wrong parameter"));
  173. }
  174. f = new (sq_malloc(sizeof(SQFile)))SQFile(newf,owns);
  175. if(SQ_FAILED(sq_setinstanceup(v,1,f))) {
  176. f->~SQFile();
  177. sq_free(f,sizeof(SQFile));
  178. return sq_throwerror(v, _SC("cannot create blob with negative size"));
  179. }
  180. sq_setreleasehook(v,1,_file_releasehook);
  181. return 0;
  182. }
  183. static SQRESULT _file_close(HSQUIRRELVM v)
  184. {
  185. SQFile *self = NULL;
  186. if(SQ_SUCCEEDED(sq_getinstanceup(v,1,(SQUserPointer*)&self,(SQUserPointer)SQSTD_FILE_TYPE_TAG))
  187. && self != NULL)
  188. {
  189. self->Close();
  190. }
  191. return 0;
  192. }
  193. #if 0
  194. static SQRESULT _file_nonblock(HSQUIRRELVM v)
  195. {
  196. SQFile *self = NULL;
  197. #ifdef _WIN32
  198. return sq_throwerror(v, _SC("nonblock not supported on win32"));
  199. #else
  200. if(SQ_SUCCEEDED(sq_getinstanceup(v,1,(SQUserPointer*)&self,(SQUserPointer)SQSTD_FILE_TYPE_TAG))
  201. && self != NULL)
  202. {
  203. SQFILE handle = self->GetHandle();
  204. if(handle)
  205. {
  206. int fd = fileno((FILE*)handle);
  207. if(fd > STDERR_FILENO)
  208. {
  209. int flags = fcntl(fd, F_GETFL, 0);
  210. if(sq_gettop(v) > 1)
  211. {
  212. //set nonblocking
  213. SQBool isNonBlocking;
  214. sq_getbool(v, 2, &isNonBlocking);
  215. if (flags >= 0) {
  216. int rc = fcntl(fd, F_SETFL,
  217. isNonBlocking ? flags | O_NONBLOCK
  218. : flags ^ O_NONBLOCK);
  219. sq_pushbool(v, rc == 0);
  220. }
  221. else return 0;
  222. }
  223. else
  224. {
  225. sq_pushbool(v, flags & O_NONBLOCK);
  226. }
  227. return 1;
  228. }
  229. }
  230. }
  231. return 0;
  232. #endif // _WIN32
  233. }
  234. #endif // 0
  235. //bindings
  236. #define _DECL_FILE_FUNC(name,nparams,typecheck) {_SC(#name),_file_##name,nparams,typecheck,false}
  237. static const SQRegFunction _file_methods[] = {
  238. _DECL_FILE_FUNC(constructor,3,_SC("x")), //TODO if we change "x" to "xss" it stops working
  239. _DECL_FILE_FUNC(_typeof,1,_SC("x")),
  240. _DECL_FILE_FUNC(close,1,_SC("x")),
  241. //_DECL_FILE_FUNC(nonblock,-1,_SC("xb")),
  242. {NULL,(SQFUNCTION)0,0,NULL,false}
  243. };
  244. SQRESULT sqstd_createfile(HSQUIRRELVM v, SQFILE file,SQBool own)
  245. {
  246. SQInteger top = sq_gettop(v);
  247. sq_pushregistrytable(v);
  248. sq_pushstring(v,_SC("std_file"),-1);
  249. if(SQ_SUCCEEDED(sq_get(v,-2))) {
  250. sq_remove(v,-2); //removes the registry
  251. sq_pushroottable(v); // push the this
  252. sq_pushuserpointer(v,file); //file
  253. if(own){
  254. sq_pushinteger(v,1); //true
  255. }
  256. else{
  257. sq_pushnull(v); //false
  258. }
  259. if(SQ_SUCCEEDED( sq_call(v,3,SQTrue,SQFalse) )) {
  260. sq_remove(v,-2);
  261. return SQ_OK;
  262. }
  263. }
  264. sq_settop(v,top);
  265. return SQ_ERROR;
  266. }
  267. SQRESULT sqstd_getfile(HSQUIRRELVM v, SQInteger idx, SQFILE *file)
  268. {
  269. SQFile *fileobj = NULL;
  270. if(SQ_SUCCEEDED(sq_getinstanceup(v,idx,(SQUserPointer*)&fileobj,(SQUserPointer)SQSTD_FILE_TYPE_TAG))) {
  271. *file = fileobj->GetHandle();
  272. return SQ_OK;
  273. }
  274. return sq_throwerror(v,_SC("not a file"));
  275. }
  276. #define IO_BUFFER_SIZE 2048
  277. struct IOBuffer {
  278. unsigned char buffer[IO_BUFFER_SIZE];
  279. SQInteger size;
  280. SQInteger ptr;
  281. SQFILE file;
  282. };
  283. static SQInteger _read_byte(IOBuffer *iobuffer)
  284. {
  285. if(iobuffer->ptr < iobuffer->size) {
  286. SQInteger ret = iobuffer->buffer[iobuffer->ptr];
  287. iobuffer->ptr++;
  288. return ret;
  289. }
  290. else {
  291. if( (iobuffer->size = sqstd_fread(iobuffer->buffer,1,IO_BUFFER_SIZE,iobuffer->file )) > 0 )
  292. {
  293. SQInteger ret = iobuffer->buffer[0];
  294. iobuffer->ptr = 1;
  295. return ret;
  296. }
  297. }
  298. return 0;
  299. }
  300. static SQInteger _read_two_bytes(IOBuffer *iobuffer)
  301. {
  302. if(iobuffer->ptr < iobuffer->size) {
  303. if(iobuffer->size < 2) return 0;
  304. SQInteger ret = *((const wchar_t*)&iobuffer->buffer[iobuffer->ptr]);
  305. iobuffer->ptr += 2;
  306. return ret;
  307. }
  308. else {
  309. if( (iobuffer->size = sqstd_fread(iobuffer->buffer,1,IO_BUFFER_SIZE,iobuffer->file )) > 0 )
  310. {
  311. if(iobuffer->size < 2) return 0;
  312. SQInteger ret = *((const wchar_t*)&iobuffer->buffer[0]);
  313. iobuffer->ptr = 2;
  314. return ret;
  315. }
  316. }
  317. return 0;
  318. }
  319. static SQInteger _io_file_lexfeed_PLAIN(SQUserPointer iobuf)
  320. {
  321. IOBuffer *iobuffer = (IOBuffer *)iobuf;
  322. return _read_byte(iobuffer);
  323. }
  324. #ifdef SQUNICODE
  325. static SQInteger _io_file_lexfeed_UTF8(SQUserPointer iobuf)
  326. {
  327. IOBuffer *iobuffer = (IOBuffer *)iobuf;
  328. #define READ(iobuf) \
  329. if((inchar = (unsigned char)_read_byte(iobuf)) == 0) \
  330. return 0;
  331. static const SQInteger utf8_lengths[16] =
  332. {
  333. 1,1,1,1,1,1,1,1, /* 0000 to 0111 : 1 byte (plain ASCII) */
  334. 0,0,0,0, /* 1000 to 1011 : not valid */
  335. 2,2, /* 1100, 1101 : 2 bytes */
  336. 3, /* 1110 : 3 bytes */
  337. 4 /* 1111 :4 bytes */
  338. };
  339. static const unsigned char byte_masks[5] = {0,0,0x1f,0x0f,0x07};
  340. unsigned char inchar;
  341. SQInteger c = 0;
  342. READ(iobuffer);
  343. c = inchar;
  344. //
  345. if(c >= 0x80) {
  346. SQInteger tmp;
  347. SQInteger codelen = utf8_lengths[c>>4];
  348. if(codelen == 0)
  349. return 0;
  350. //"invalid UTF-8 stream";
  351. tmp = c&byte_masks[codelen];
  352. for(SQInteger n = 0; n < codelen-1; n++) {
  353. tmp<<=6;
  354. READ(iobuffer);
  355. tmp |= inchar & 0x3F;
  356. }
  357. c = tmp;
  358. }
  359. return c;
  360. }
  361. #endif
  362. static SQInteger _io_file_lexfeed_UCS2_LE(SQUserPointer iobuf)
  363. {
  364. SQInteger ret;
  365. IOBuffer *iobuffer = (IOBuffer *)iobuf;
  366. if( (ret = _read_two_bytes(iobuffer)) > 0 )
  367. return ret;
  368. return 0;
  369. }
  370. static SQInteger _io_file_lexfeed_UCS2_BE(SQUserPointer iobuf)
  371. {
  372. SQInteger c;
  373. IOBuffer *iobuffer = (IOBuffer *)iobuf;
  374. if( (c = _read_two_bytes(iobuffer)) > 0 ) {
  375. c = ((c>>8)&0x00FF)| ((c<<8)&0xFF00);
  376. return c;
  377. }
  378. return 0;
  379. }
  380. static SQInteger file_read(SQUserPointer file,SQUserPointer buf,SQInteger size)
  381. {
  382. SQInteger ret;
  383. if( ( ret = sqstd_fread(buf,1,size,(SQFILE)file ))!=0 )return ret;
  384. return -1;
  385. }
  386. static SQInteger file_write(SQUserPointer file,SQUserPointer p,SQInteger size)
  387. {
  388. return sqstd_fwrite(p,1,size,(SQFILE)file);
  389. }
  390. SQRESULT sqstd_loadfile(HSQUIRRELVM v,const SQChar *filename,SQBool printerror,SQBool show_warnings)
  391. {
  392. SQFILE file = sqstd_fopen(filename,_SC("rb"));
  393. SQInteger ret;
  394. unsigned short us;
  395. unsigned char uc;
  396. SQLEXREADFUNC func = _io_file_lexfeed_PLAIN;
  397. if(file){
  398. ret = sqstd_fread(&us,1,2,file);
  399. if(ret != 2) {
  400. //probably an empty file
  401. us = 0;
  402. }
  403. if(us == SQ_BYTECODE_STREAM_TAG) { //BYTECODE
  404. sqstd_fseek(file,0,SQ_SEEK_SET);
  405. if(SQ_SUCCEEDED(sq_readclosure(v,file_read,file))) {
  406. sqstd_fclose(file);
  407. return SQ_OK;
  408. }
  409. }
  410. else { //SCRIPT
  411. switch(us)
  412. {
  413. //gotta swap the next 2 lines on BIG endian machines
  414. case 0xFFFE: func = _io_file_lexfeed_UCS2_BE; break;//UTF-16 little endian;
  415. case 0xFEFF: func = _io_file_lexfeed_UCS2_LE; break;//UTF-16 big endian;
  416. case 0xBBEF:
  417. if(sqstd_fread(&uc,1,sizeof(uc),file) == 0) {
  418. sqstd_fclose(file);
  419. return sq_throwerror(v,_SC("io error"));
  420. }
  421. if(uc != 0xBF) {
  422. sqstd_fclose(file);
  423. return sq_throwerror(v,_SC("Unrecognozed ecoding"));
  424. }
  425. #ifdef SQUNICODE
  426. func = _io_file_lexfeed_UTF8;
  427. #else
  428. func = _io_file_lexfeed_PLAIN;
  429. #endif
  430. break;//UTF-8 ;
  431. default: sqstd_fseek(file,0,SQ_SEEK_SET); break; // ascii
  432. }
  433. IOBuffer buffer;
  434. buffer.ptr = 0;
  435. buffer.size = 0;
  436. buffer.file = file;
  437. if(SQ_SUCCEEDED(sq_compile(v,func,&buffer,filename,printerror,show_warnings,
  438. SQ_MAX_INCLUDE_FILES))){
  439. sqstd_fclose(file);
  440. return SQ_OK;
  441. }
  442. }
  443. sqstd_fclose(file);
  444. return SQ_ERROR;
  445. }
  446. return sq_throwerror(v,_SC("cannot open the file"));
  447. }
  448. SQRESULT sqstd_dofile(HSQUIRRELVM v,const SQChar *filename,SQBool retval,SQBool printerror,SQBool show_warnings)
  449. {
  450. if(SQ_SUCCEEDED(sqstd_loadfile(v,filename,printerror,show_warnings))) {
  451. sq_push(v,-2);
  452. if(SQ_SUCCEEDED(sq_call(v,1,retval,SQTrue))) {
  453. sq_remove(v,retval?-2:-1); //removes the closure
  454. return 1;
  455. }
  456. sq_pop(v,1); //removes the closure
  457. }
  458. return SQ_ERROR;
  459. }
  460. SQRESULT sqstd_writeclosuretofile(HSQUIRRELVM v,const SQChar *filename)
  461. {
  462. SQFILE file = sqstd_fopen(filename,_SC("wb+"));
  463. if(!file) return sq_throwerror(v,_SC("cannot open the file"));
  464. if(SQ_SUCCEEDED(sq_writeclosure(v,file_write,file))) {
  465. sqstd_fclose(file);
  466. return SQ_OK;
  467. }
  468. sqstd_fclose(file);
  469. return SQ_ERROR; //forward the error
  470. }
  471. SQRESULT sqstd_writeclosuretofile_as_source(HSQUIRRELVM v,const SQChar *filename)
  472. {
  473. SQFILE file = sqstd_fopen(filename,_SC("wb+"));
  474. if(!file) return sq_throwerror(v,_SC("cannot open the file"));
  475. if(SQ_SUCCEEDED(sq_writeclosure_as_source(v,file_write,file))) {
  476. sqstd_fclose(file);
  477. return SQ_OK;
  478. }
  479. sqstd_fclose(file);
  480. return SQ_ERROR; //forward the error
  481. }
  482. SQInteger _g_io_loadfile(HSQUIRRELVM v)
  483. {
  484. SQ_FUNC_VARS(v);
  485. SQ_GET_STRING(v, 2, filename);
  486. SQ_OPT_BOOL(v, 3, printerror, SQFalse);
  487. SQ_OPT_BOOL(v, 4, show_warnings, SQTrue);
  488. if(SQ_SUCCEEDED(sqstd_loadfile(v,filename,printerror,show_warnings)))
  489. return 1;
  490. return SQ_ERROR; //propagates the error
  491. }
  492. SQInteger _g_io_writeclosuretofile(HSQUIRRELVM v)
  493. {
  494. const SQChar *filename;
  495. sq_getstring(v,2,&filename);
  496. if(SQ_SUCCEEDED(sqstd_writeclosuretofile(v,filename)))
  497. return 1;
  498. return SQ_ERROR; //propagates the error
  499. }
  500. #include "sqstdblobimpl.h"
  501. SQInteger blob_write(SQUserPointer file,SQUserPointer p,SQInteger size);
  502. SQInteger _g_io_dumpclosure(HSQUIRRELVM v)
  503. {
  504. SQBlob b(0,8192);
  505. if(SQ_SUCCEEDED(sq_writeclosure(v,blob_write,&b))) {
  506. sq_pushstring(v, (const SQChar*)b.GetBuf(), b.Len());
  507. return 1;
  508. }
  509. return SQ_ERROR; //forward the error
  510. }
  511. SQInteger blob_read(SQUserPointer file,SQUserPointer p,SQInteger size);
  512. SQInteger _g_io_loadstring(HSQUIRRELVM v)
  513. {
  514. if(sq_gettype(v, 2) != OT_STRING) return sq_throwerror(v, _SC("string expected as parameter"));
  515. SQInteger rc, size = sq_getsize(v, 2);
  516. const SQChar *dump;
  517. sq_getstring(v, 2, &dump);
  518. unsigned short tag = *((unsigned short*)dump);
  519. if(tag == SQ_BYTECODE_STREAM_TAG){
  520. SQBlob b(0, size);
  521. b.Write(dump, size);
  522. b.Seek(0, SQ_SEEK_SET);
  523. rc = sq_readclosure(v, blob_read, &b);
  524. }
  525. else
  526. {
  527. rc = sq_compilebuffer(v, dump, size, _SC("loadstring"), SQFalse, SQFalse, SQ_MAX_INCLUDE_FILES);
  528. }
  529. return rc < 0 ? rc : 1;
  530. }
  531. //used by sq_slave_vm
  532. SQInteger _g_io_dostring(HSQUIRRELVM v)
  533. {
  534. SQ_FUNC_VARS(v);
  535. SQInteger rc = _g_io_loadstring(v);
  536. if(rc < 0) return rc;
  537. SQ_OPT_BOOL(v, 3, retval, SQFalse);
  538. sq_push(v,1); //this environment
  539. if(SQ_SUCCEEDED(sq_call(v,1,retval,SQTrue))) {
  540. sq_remove(v,retval?-2:-1); //removes the closure
  541. return 1;
  542. }
  543. sq_pop(v,1); //removes the closure
  544. return SQ_ERROR; //forward the error
  545. }
  546. SQInteger _g_io_dofile(HSQUIRRELVM v)
  547. {
  548. SQ_FUNC_VARS(v);
  549. SQ_GET_STRING(v, 2, filename);
  550. SQ_OPT_BOOL(v, 3, printerror, SQFalse);
  551. SQ_OPT_BOOL(v, 4, show_warnings, SQTrue);
  552. sq_push(v,1); //repush the this
  553. if(SQ_SUCCEEDED(sqstd_dofile(v,filename,SQTrue,printerror,show_warnings)))
  554. return 1;
  555. return SQ_ERROR; //propagates the error
  556. }
  557. SQInteger _g_io_existsfile(HSQUIRRELVM v)
  558. {
  559. SQ_FUNC_VARS_NO_TOP(v);
  560. SQ_GET_STRING(v, 2, filename);
  561. SQFile fs;
  562. sq_pushbool(v, fs.Open(filename, "rb"));
  563. return 1;
  564. }
  565. SQInteger _g_io_readfile(HSQUIRRELVM v)
  566. {
  567. SQ_FUNC_VARS_NO_TOP(v);
  568. SQ_GET_STRING(v, 2, filename);
  569. SQFile fs;
  570. if(fs.Open(filename, "rb"))
  571. {
  572. SQInteger size,res;
  573. SQChar *data;
  574. size = fs.Len();
  575. data = sq_getscratchstr(v,size);
  576. res = fs.Read(data,size);
  577. if(res != size)
  578. {
  579. sq_delscratchstr(v, data);
  580. if(res <= 0)
  581. return sq_throwerror(v,_SC("no data left to read"));
  582. return sq_throwerror(v,_SC("could not read whole file"));
  583. }
  584. sq_pushscratchstr(v);
  585. return 1;
  586. }
  587. return sq_throwerror(v,_SC("could not open file %s"), filename);
  588. }
  589. SQInteger _g_io_writefile(HSQUIRRELVM v)
  590. {
  591. SQ_FUNC_VARS_NO_TOP(v);
  592. SQ_GET_STRING(v, 2, filename);
  593. SQ_GET_STRING(v, 3, data);
  594. SQFile fs;
  595. if(fs.Open(filename, "wb"))
  596. {
  597. SQInteger res = fs.Write(data, data_size);
  598. if(res != data_size)
  599. return sq_throwerror(v,_SC("could not write to file"));
  600. return 0;
  601. }
  602. return sq_throwerror(v,_SC("could not open file %s"), filename);
  603. }
  604. #define _DECL_GLOBALIO_FUNC(name,nparams,typecheck) {_SC(#name),_g_io_##name,nparams,typecheck,false}
  605. static const SQRegFunction iolib_funcs[]={
  606. _DECL_GLOBALIO_FUNC(loadfile,-2,_SC(".sbb")),
  607. _DECL_GLOBALIO_FUNC(dofile,-2,_SC(".sbb")),
  608. _DECL_GLOBALIO_FUNC(writeclosuretofile,3,_SC(".sc")),
  609. _DECL_GLOBALIO_FUNC(dostring,-2,_SC(".sb")),
  610. _DECL_GLOBALIO_FUNC(loadstring,2,_SC(".s")),
  611. _DECL_GLOBALIO_FUNC(dumpclosure,3,_SC(".sc")),
  612. _DECL_GLOBALIO_FUNC(existsfile,2,_SC(".s")),
  613. _DECL_GLOBALIO_FUNC(readfile,2,_SC(".s")),
  614. _DECL_GLOBALIO_FUNC(writefile,3,_SC(".ss")),
  615. {NULL,(SQFUNCTION)0,0,NULL,false}
  616. };
  617. SQRESULT sqstd_register_iolib(HSQUIRRELVM v)
  618. {
  619. //create delegate
  620. declare_stream(v,_SC("popen"),(SQUserPointer)SQSTD_FILE_TYPE_TAG,SQSTD_FILE_CLASS_TYPE_TAG,_popen_methods,iolib_funcs);
  621. declare_stream(v,_SC("file"),(SQUserPointer)SQSTD_FILE_TYPE_TAG,SQSTD_FILE_CLASS_TYPE_TAG,_file_methods,iolib_funcs);
  622. sq_pushstring(v,_SC("stdout"),-1);
  623. sqstd_createfile(v,stdout,SQFalse);
  624. sq_newslot(v,-3,SQFalse);
  625. sq_pushstring(v,_SC("stdin"),-1);
  626. sqstd_createfile(v,stdin,SQFalse);
  627. sq_newslot(v,-3,SQFalse);
  628. sq_pushstring(v,_SC("stderr"),-1);
  629. sqstd_createfile(v,stderr,SQFalse);
  630. sq_newslot(v,-3,SQFalse);
  631. return SQ_OK;
  632. }