sqstdstream.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  1. /* see copyright notice in squirrel.h */
  2. #include <new>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include <squirrel.h>
  7. #include <sqstdio.h>
  8. #include <sqstdblob.h>
  9. #include "sqstdstream.h"
  10. #include "sqstdblobimpl.h"
  11. static const SQChar SQSTD_STREAM_TYPE_TAG[] = _SC("std_stream");
  12. #define SETUP_STREAM(v) \
  13. SQStream *self = NULL; \
  14. if(SQ_FAILED(sq_getinstanceup(v,1,(SQUserPointer*)&self,(SQUserPointer)SQSTD_STREAM_TYPE_TAG))) \
  15. return sq_throwerror(v,_SC("invalid type tag")); \
  16. if(!self || !self->IsValid()) \
  17. return sq_throwerror(v,_SC("the stream is invalid"));
  18. SQInteger _stream_read_line(HSQUIRRELVM v) {
  19. SETUP_STREAM(v);
  20. const SQChar nl = _SC('\n');
  21. const SQChar rc = _SC('\r');
  22. SQInteger size, read_size;
  23. bool new_line_found = false;
  24. //optional expected line size
  25. if(sq_gettop(v) > 1) sq_getinteger(v,2,&size);
  26. else size = 2048;
  27. SQBlob line_buf(0, size);
  28. do {
  29. char *buf = (SQChar*)line_buf.GetBuf();
  30. read_size = self->Gets(buf + line_buf.Len(), size);
  31. if(!read_size) //end of file
  32. {
  33. break;
  34. }
  35. if(buf[read_size-1] == nl) //complete line found
  36. {
  37. //remove '\r' and/or '\n'
  38. if( (read_size > 1) && (buf[read_size-2] == rc))
  39. {
  40. read_size -= 2;
  41. }
  42. else
  43. {
  44. read_size -= 1;
  45. }
  46. line_buf.SetLen(read_size);
  47. new_line_found = true;
  48. break;
  49. }
  50. line_buf.SetLen(read_size);
  51. line_buf.GrowBufOf(size);
  52. } while(read_size > 0);
  53. if(line_buf.Len() > 0) {
  54. sq_pushstring(v, (const SQChar*)line_buf.GetBuf(), line_buf.Len());
  55. }
  56. else if(new_line_found) //empty line
  57. {
  58. sq_pushstring(v, "", 0);
  59. }
  60. else sq_pushnull(v); //end of file
  61. return 1;
  62. }
  63. SQInteger _stream_read_all(HSQUIRRELVM v) {
  64. SETUP_STREAM(v);
  65. SQInteger size = 4096, read_size;
  66. SQBlob line_buf(0, size);
  67. do{
  68. char *buf = (SQChar*)line_buf.GetBuf();
  69. read_size = self->Gets(buf + line_buf.Len(), size);
  70. line_buf.SetLen(line_buf.Len() + read_size);
  71. line_buf.Reserve(size);
  72. } while(read_size > 0);
  73. if(line_buf.Len() > 0) {
  74. sq_pushstring(v, (const SQChar*)line_buf.GetBuf(), line_buf.Len());
  75. }
  76. else sq_pushnull(v); //end of file
  77. return 1;
  78. }
  79. SQInteger _stream_read(HSQUIRRELVM v)
  80. {
  81. SETUP_STREAM(v);
  82. SQChar *data;
  83. SQInteger size,res;
  84. sq_getinteger(v,2,&size);
  85. /* DAD come back here
  86. if(self->GetHandle() != stdin && size > self->Len()) {
  87. size = self->Len();
  88. }
  89. */
  90. data = sq_getscratchpad(v,size);
  91. res = self->Read(data,size);
  92. if(res <= 0)
  93. return sq_throwerror(v,_SC("no data left to read"));
  94. sq_pushstring(v,data,res);
  95. return 1;
  96. }
  97. SQInteger _stream_gets(HSQUIRRELVM v)
  98. {
  99. SETUP_STREAM(v);
  100. SQChar *data;
  101. SQInteger size, read_size;
  102. sq_getinteger(v,2,&size);
  103. /* DAD come back here
  104. if(self->GetHandle() != stdin && size > self->Len()) {
  105. size = self->Len();
  106. }
  107. */
  108. data = sq_getscratchpad(v,size);
  109. read_size = self->Gets(data,size);
  110. if(!read_size)
  111. return sq_throwerror(v,_SC("no data left to read"));
  112. sq_pushstring(v,data,read_size);
  113. return 1;
  114. }
  115. SQInteger _stream_readblob(HSQUIRRELVM v)
  116. {
  117. SETUP_STREAM(v);
  118. SQUserPointer blobp;
  119. SQInteger size,res;
  120. sq_getinteger(v,2,&size);
  121. if(size > self->Len()) {
  122. size = self->Len();
  123. }
  124. blobp = sqstd_createblob(v,size);
  125. res = self->Read(blobp,size);
  126. if(res <= 0)
  127. return sq_throwerror(v,_SC("no data left to read"));
  128. return 1;
  129. }
  130. #define SAFE_READN(ptr,len) { \
  131. if(self->Read(ptr,len) != len) return sq_throwerror(v,_SC("io error")); \
  132. }
  133. SQInteger _stream_readn(HSQUIRRELVM v)
  134. {
  135. SETUP_STREAM(v);
  136. SQInteger format;
  137. sq_getinteger(v, 2, &format);
  138. switch(format) {
  139. case 'l': {
  140. SQInteger i;
  141. SAFE_READN(&i, sizeof(i));
  142. sq_pushinteger(v, i);
  143. }
  144. break;
  145. case 'i': {
  146. SQInt32 i;
  147. SAFE_READN(&i, sizeof(i));
  148. sq_pushinteger(v, i);
  149. }
  150. break;
  151. case 's': {
  152. short s;
  153. SAFE_READN(&s, sizeof(short));
  154. sq_pushinteger(v, s);
  155. }
  156. break;
  157. case 'w': {
  158. unsigned short w;
  159. SAFE_READN(&w, sizeof(unsigned short));
  160. sq_pushinteger(v, w);
  161. }
  162. break;
  163. case 'c': {
  164. char c;
  165. SAFE_READN(&c, sizeof(char));
  166. sq_pushinteger(v, c);
  167. }
  168. break;
  169. case 'b': {
  170. unsigned char c;
  171. SAFE_READN(&c, sizeof(unsigned char));
  172. sq_pushinteger(v, c);
  173. }
  174. break;
  175. case 'f': {
  176. float f;
  177. SAFE_READN(&f, sizeof(float));
  178. sq_pushfloat(v, f);
  179. }
  180. break;
  181. case 'd': {
  182. double d;
  183. SAFE_READN(&d, sizeof(double));
  184. sq_pushfloat(v, (SQFloat)d);
  185. }
  186. break;
  187. default:
  188. return sq_throwerror(v, _SC("invalid format"));
  189. }
  190. return 1;
  191. }
  192. SQInteger _stream_write_str(HSQUIRRELVM v)
  193. {
  194. SQ_FUNC_VARS(v);
  195. SETUP_STREAM(v);
  196. SQ_GET_STRING(v, 2, str);
  197. SQ_OPT_INTEGER(v, 3, start, 0);
  198. if(start < 0 || start > str_size) return sq_throwerror(v, _SC("start position out of range (%d)"), start);
  199. SQ_OPT_INTEGER(v, 4, len, str_size - start);
  200. if(len < 0 || len > (str_size-start)) return sq_throwerror(v, _SC("len value out of range (%d)"), len);
  201. if(self->Write(((SQChar*)str)+start, len) != len)
  202. return sq_throwerror(v,_SC("io error"));
  203. sq_pushinteger(v,len);
  204. return 1;
  205. }
  206. SQInteger _stream_write(HSQUIRRELVM v)
  207. {
  208. const SQChar *str;
  209. SQInteger total_size, size;
  210. SETUP_STREAM(v);
  211. total_size = 0;
  212. for(SQInteger i=2, len=sq_gettop(v); i <= len; ++i){
  213. if(SQ_FAILED(sq_tostring(v,i)))
  214. return sq_throwerror(v,_SC("invalid parameter"));
  215. sq_getstring(v,-1,&str);
  216. size = sq_getsize(v,-1);
  217. if(self->Write((SQChar*)str,size) != size)
  218. return sq_throwerror(v,_SC("io error"));
  219. sq_poptop(v); //remove converted string
  220. total_size += size;
  221. }
  222. sq_pushinteger(v,total_size);
  223. return 1;
  224. }
  225. SQInteger _stream_write_non_null(HSQUIRRELVM v)
  226. {
  227. if(sq_gettype(v, 2) != OT_NULL)
  228. {
  229. return _stream_write(v);
  230. }
  231. return 0;
  232. }
  233. SQInteger _stream_write_fmt(HSQUIRRELVM v)
  234. {
  235. const SQChar *str;
  236. SQInteger size;
  237. SETUP_STREAM(v);
  238. if(SQ_FAILED(sq_tostring(v,2)))
  239. return sq_throwerror(v,_SC("invalid parameter"));
  240. sq_getstring(v,-1,&str);
  241. size = sq_getsize(v,-1);
  242. if(self->Write((SQChar*)str,size) != size)
  243. return sq_throwerror(v,_SC("io error"));
  244. sq_poptop(v); //remove converted string
  245. sq_pushinteger(v,size);
  246. return 1;
  247. }
  248. SQInteger _stream_writeblob(HSQUIRRELVM v)
  249. {
  250. SQUserPointer data;
  251. SQInteger size;
  252. SETUP_STREAM(v);
  253. if(SQ_FAILED(sqstd_getblob(v,2,&data)))
  254. return sq_throwerror(v,_SC("invalid parameter"));
  255. size = sqstd_getblobsize(v,2);
  256. if(self->Write(data,size) != size)
  257. return sq_throwerror(v,_SC("io error"));
  258. sq_pushinteger(v,size);
  259. return 1;
  260. }
  261. SQInteger _stream_writen(HSQUIRRELVM v)
  262. {
  263. SETUP_STREAM(v);
  264. SQInteger format, ti;
  265. SQFloat tf;
  266. sq_getinteger(v, 3, &format);
  267. switch(format) {
  268. case 'l': {
  269. SQInteger i;
  270. sq_getinteger(v, 2, &ti);
  271. i = ti;
  272. self->Write(&i, sizeof(SQInteger));
  273. }
  274. break;
  275. case 'i': {
  276. SQInt32 i;
  277. sq_getinteger(v, 2, &ti);
  278. i = (SQInt32)ti;
  279. self->Write(&i, sizeof(SQInt32));
  280. }
  281. break;
  282. case 's': {
  283. short s;
  284. sq_getinteger(v, 2, &ti);
  285. s = (short)ti;
  286. self->Write(&s, sizeof(short));
  287. }
  288. break;
  289. case 'w': {
  290. unsigned short w;
  291. sq_getinteger(v, 2, &ti);
  292. w = (unsigned short)ti;
  293. self->Write(&w, sizeof(unsigned short));
  294. }
  295. break;
  296. case 'c': {
  297. char c;
  298. sq_getinteger(v, 2, &ti);
  299. c = (char)ti;
  300. self->Write(&c, sizeof(char));
  301. }
  302. break;
  303. case 'b': {
  304. unsigned char b;
  305. sq_getinteger(v, 2, &ti);
  306. b = (unsigned char)ti;
  307. self->Write(&b, sizeof(unsigned char));
  308. }
  309. break;
  310. case 'f': {
  311. float f;
  312. sq_getfloat(v, 2, &tf);
  313. f = (float)tf;
  314. self->Write(&f, sizeof(float));
  315. }
  316. break;
  317. case 'd': {
  318. double d;
  319. sq_getfloat(v, 2, &tf);
  320. d = tf;
  321. self->Write(&d, sizeof(double));
  322. }
  323. break;
  324. default:
  325. return sq_throwerror(v, _SC("invalid format"));
  326. }
  327. return 0;
  328. }
  329. SQInteger _stream_seek(HSQUIRRELVM v)
  330. {
  331. SETUP_STREAM(v);
  332. SQInteger offset, origin = SQ_SEEK_SET;
  333. sq_getinteger(v, 2, &offset);
  334. if(sq_gettop(v) > 2) {
  335. SQInteger t;
  336. sq_getinteger(v, 3, &t);
  337. switch(t) {
  338. case 'b': origin = SQ_SEEK_SET; break;
  339. case 'c': origin = SQ_SEEK_CUR; break;
  340. case 'e': origin = SQ_SEEK_END; break;
  341. default: return sq_throwerror(v,_SC("invalid origin"));
  342. }
  343. }
  344. sq_pushinteger(v, self->Seek(offset, origin));
  345. return 1;
  346. }
  347. SQInteger _stream_tell(HSQUIRRELVM v)
  348. {
  349. SETUP_STREAM(v);
  350. sq_pushinteger(v, self->Tell());
  351. return 1;
  352. }
  353. SQInteger _stream_len(HSQUIRRELVM v)
  354. {
  355. SETUP_STREAM(v);
  356. sq_pushinteger(v, self->Len());
  357. return 1;
  358. }
  359. SQInteger _stream_flush(HSQUIRRELVM v)
  360. {
  361. SETUP_STREAM(v);
  362. if(!self->Flush())
  363. sq_pushinteger(v, 1);
  364. else
  365. sq_pushnull(v);
  366. return 1;
  367. }
  368. SQInteger _stream_eos(HSQUIRRELVM v)
  369. {
  370. SETUP_STREAM(v);
  371. if(self->EOS())
  372. sq_pushinteger(v, 1);
  373. else
  374. sq_pushnull(v);
  375. return 1;
  376. }
  377. SQInteger _stream__cloned(HSQUIRRELVM v)
  378. {
  379. return sq_throwerror(v,_SC("this object cannot be cloned"));
  380. }
  381. #define _DECL_STREAM_FUNC2(name,name2, nparams,typecheck) {_SC(#name2),_stream_##name,nparams,typecheck}
  382. static SQRegFunction _stream_methods[] = {
  383. _DECL_STREAM_FUNC(read_line,-1,_SC("xi")),
  384. _DECL_STREAM_FUNC(read,2,_SC("xn")),
  385. _DECL_STREAM_FUNC(gets,2,_SC("xn")),
  386. _DECL_STREAM_FUNC(readblob,2,_SC("xn")),
  387. _DECL_STREAM_FUNC(readn,2,_SC("xn")),
  388. _DECL_STREAM_FUNC(read_all,1,_SC("x")),
  389. _DECL_STREAM_FUNC(write_str,-2,_SC("xsii")),
  390. _DECL_STREAM_FUNC(write,-2,_SC("x.")),
  391. _DECL_STREAM_FUNC(writeblob,-2,_SC("xx")),
  392. _DECL_STREAM_FUNC(writen,3,_SC("xnn")),
  393. _DECL_STREAM_FUNC(write_non_null,2,_SC("x.")),
  394. _DECL_STREAM_FUNC(seek,-2,_SC("xnn")),
  395. _DECL_STREAM_FUNC(tell,1,_SC("x")),
  396. _DECL_STREAM_FUNC(len,1,_SC("x")),
  397. _DECL_STREAM_FUNC2(len,size,1,_SC("x")),
  398. _DECL_STREAM_FUNC2(len,length,1,_SC("x")),
  399. _DECL_STREAM_FUNC(eos,1,_SC("x")),
  400. _DECL_STREAM_FUNC(flush,1,_SC("x")),
  401. _DECL_STREAM_FUNC(_cloned,0,NULL),
  402. {NULL,(SQFUNCTION)0,0,NULL}
  403. };
  404. void init_streamclass(HSQUIRRELVM v)
  405. {
  406. sq_pushregistrytable(v);
  407. sq_pushstring(v,SQSTD_STREAM_TYPE_TAG,-1);
  408. if(SQ_FAILED(sq_get(v,-2))) {
  409. sq_pushstring(v,SQSTD_STREAM_TYPE_TAG,-1);
  410. sq_newclass(v,SQFalse);
  411. sq_settypetag(v,-1,(SQUserPointer)SQSTD_STREAM_TYPE_TAG);
  412. SQInteger i = 0;
  413. while(_stream_methods[i].name != 0) {
  414. SQRegFunction &f = _stream_methods[i];
  415. sq_pushstring(v,f.name,-1);
  416. sq_newclosure(v,f.f,0);
  417. sq_setparamscheck(v,f.nparamscheck,f.typemask);
  418. sq_newslot(v,-3,SQFalse);
  419. i++;
  420. }
  421. sq_newslot(v,-3,SQFalse);
  422. sq_pushroottable(v);
  423. sq_pushstring(v,_SC("stream"),-1);
  424. sq_pushstring(v,_SC("std_stream"),-1);
  425. sq_get(v,-4);
  426. sq_newslot(v,-3,SQFalse);
  427. sq_pop(v,1);
  428. }
  429. else {
  430. sq_pop(v,1); //result
  431. }
  432. sq_pop(v,1);
  433. }
  434. SQRESULT declare_stream(HSQUIRRELVM v,const SQChar* name,SQUserPointer typetag,const SQChar* reg_name,const SQRegFunction *methods,const SQRegFunction *globals)
  435. {
  436. if(sq_gettype(v,-1) != OT_TABLE)
  437. return sq_throwerror(v,_SC("table expected"));
  438. SQInteger top = sq_gettop(v);
  439. //create delegate
  440. init_streamclass(v);
  441. sq_pushregistrytable(v);
  442. sq_pushstring(v,reg_name,-1);
  443. sq_pushstring(v,_SC("std_stream"),-1);
  444. if(SQ_SUCCEEDED(sq_get(v,-3))) {
  445. sq_newclass(v,SQTrue);
  446. sq_settypetag(v,-1,typetag);
  447. SQInteger i = 0;
  448. while(methods[i].name != 0) {
  449. const SQRegFunction &f = methods[i];
  450. sq_pushstring(v,f.name,-1);
  451. sq_newclosure(v,f.f,0);
  452. sq_setparamscheck(v,f.nparamscheck,f.typemask);
  453. sq_setnativeclosurename(v,-1,f.name);
  454. sq_newslot(v,-3,SQFalse);
  455. i++;
  456. }
  457. sq_newslot(v,-3,SQFalse);
  458. sq_pop(v,1);
  459. i = 0;
  460. while(globals[i].name!=0)
  461. {
  462. const SQRegFunction &f = globals[i];
  463. sq_pushstring(v,f.name,-1);
  464. sq_newclosure(v,f.f,0);
  465. sq_setparamscheck(v,f.nparamscheck,f.typemask);
  466. sq_setnativeclosurename(v,-1,f.name);
  467. sq_newslot(v,-3,SQFalse);
  468. i++;
  469. }
  470. //register the class in the target table
  471. sq_pushstring(v,name,-1);
  472. sq_pushregistrytable(v);
  473. sq_pushstring(v,reg_name,-1);
  474. sq_get(v,-2);
  475. sq_remove(v,-2);
  476. sq_newslot(v,-3,SQFalse);
  477. sq_settop(v,top);
  478. return SQ_OK;
  479. }
  480. sq_settop(v,top);
  481. return SQ_ERROR;
  482. }