The Sol Programming Language!
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

object.c 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646
  1. #include "ast.h" // For CALL_METHOD
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <stdio.h>
  5. #include <assert.h>
  6. #include <dlfcn.h>
  7. #include <stdarg.h>
  8. sol_object_t *sol_cast_int(sol_state_t *state, sol_object_t *obj) {
  9. sol_object_t *res, *ls;
  10. if(sol_is_int(obj)) {
  11. return sol_incref(obj);
  12. }
  13. ls = sol_new_list(state);
  14. sol_list_insert(state, ls, 0, obj);
  15. res = obj->ops->toint(state, ls);
  16. sol_obj_free(ls);
  17. return res;
  18. }
  19. sol_object_t *sol_cast_float(sol_state_t *state, sol_object_t *obj) {
  20. sol_object_t *res, *ls;
  21. if(sol_is_float(obj)) {
  22. return sol_incref(obj);
  23. }
  24. ls = sol_new_list(state);
  25. sol_list_insert(state, ls, 0, obj);
  26. res = obj->ops->tofloat(state, ls);
  27. sol_obj_free(ls);
  28. return res;
  29. }
  30. sol_object_t *sol_cast_string(sol_state_t *state, sol_object_t *obj) {
  31. sol_object_t *res, *ls;
  32. if(sol_is_string(obj)) {
  33. return sol_incref(obj);
  34. }
  35. ls = sol_new_list(state);
  36. sol_list_insert(state, ls, 0, obj);
  37. res = obj->ops->tostring(state, ls);
  38. sol_obj_free(ls);
  39. return res;
  40. }
  41. sol_object_t *sol_cast_repr(sol_state_t *state, sol_object_t *obj) {
  42. sol_object_t *res, *ls = sol_new_list(state);
  43. sol_list_insert(state, ls, 0, obj);
  44. res = obj->ops->repr(state, ls);
  45. sol_obj_free(ls);
  46. return res;
  47. }
  48. // This will not fail here; error checking is done in sol_state_init().
  49. sol_object_t *sol_new_singlet(sol_state_t *state, const char *name) {
  50. sol_object_t *res = malloc(sizeof(sol_object_t));
  51. if(res) {
  52. res->type = SOL_SINGLET;
  53. res->refcnt = 0;
  54. res->ops = &(state->SingletOps);
  55. res->str = strdup(name);
  56. }
  57. return sol_incref(res); // XXX Segfault
  58. }
  59. // And, now, for the rest of the checked stuff...
  60. void sol_init_object(sol_state_t *state, sol_object_t *obj) {
  61. if(obj->ops->init) {
  62. obj->ops->init(state, obj);
  63. }
  64. }
  65. sol_object_t *sol_new_int(sol_state_t *state, long i) {
  66. sol_object_t *res;
  67. #ifdef SOL_ICACHE
  68. if(!state->icache_bypass && i >= SOL_ICACHE_MIN && i <= SOL_ICACHE_MAX) {
  69. return sol_incref(state->icache[i - SOL_ICACHE_MIN]);
  70. }
  71. #endif
  72. res = sol_alloc_object(state);
  73. res->type = SOL_INTEGER;
  74. res->ival = i;
  75. res->ops = &(state->IntOps);
  76. sol_init_object(state, res);
  77. return res;
  78. }
  79. sol_object_t *sol_new_float(sol_state_t *state, double f) {
  80. sol_object_t *res = sol_alloc_object(state);
  81. res->type = SOL_FLOAT;
  82. res->fval = f;
  83. res->ops = &(state->FloatOps);
  84. sol_init_object(state, res);
  85. return res;
  86. }
  87. sol_object_t *sol_new_string(sol_state_t *state, const char *s) {
  88. sol_object_t *res = sol_alloc_object(state);
  89. res->type = SOL_STRING;
  90. res->str = strdup(s);
  91. if(!res->str) {
  92. sol_obj_free(res);
  93. sol_set_error(state, state->OutOfMemory);
  94. return sol_incref(state->None);
  95. }
  96. res->ops = &(state->StringOps);
  97. sol_init_object(state, res);
  98. return res;
  99. }
  100. int sol_string_cmp(sol_state_t *state, sol_object_t *str, const char *s) {
  101. return strcmp(str->str, s);
  102. }
  103. sol_object_t *sol_string_concat(sol_state_t *state, sol_object_t *a, sol_object_t *b) {
  104. sol_object_t *res, *sa = sol_cast_string(state, a), *sb = sol_cast_string(state, b);
  105. int n = strlen(sa->str) + strlen(sb->str) + 1;
  106. char *s = malloc(n);
  107. res = sol_new_string(state, strncat(strncpy(s, a->str, n), b->str, n));
  108. sol_obj_free(sa);
  109. sol_obj_free(sb);
  110. free(s);
  111. return res;
  112. }
  113. sol_object_t *sol_string_concat_cstr(sol_state_t *state, sol_object_t *a, char *s) {
  114. sol_object_t *b = sol_new_string(state, s);
  115. sol_object_t *res = sol_string_concat(state, a, b);
  116. sol_obj_free(b);
  117. return res;
  118. }
  119. sol_object_t *sol_f_str_free(sol_state_t *state, sol_object_t *obj) {
  120. free(obj->str);
  121. return obj;
  122. }
  123. sol_object_t *sol_new_list(sol_state_t *state) {
  124. sol_object_t *res = sol_alloc_object(state);
  125. res->type = SOL_LIST;
  126. res->seq = dsl_seq_new_array(NULL, &(state->obfuncs));
  127. res->ops = &(state->ListOps);
  128. sol_init_object(state, res);
  129. return res;
  130. }
  131. sol_object_t *sol_list_from_seq(sol_state_t *state, dsl_seq *seq) {
  132. sol_object_t *res = sol_alloc_object(state);
  133. res->type = SOL_LIST;
  134. res->seq = seq;
  135. res->ops = &(state->ListOps);
  136. sol_init_object(state, res);
  137. return res;
  138. }
  139. int sol_list_len(sol_state_t *state, sol_object_t *list) {
  140. return dsl_seq_len(list->seq);
  141. }
  142. sol_object_t *sol_list_sublist(sol_state_t *state, sol_object_t *list, int idx) {
  143. int i = 0;
  144. dsl_seq *subl;
  145. if(idx < 0) {
  146. return sol_set_error_string(state, "Create sublist at negative index");
  147. }
  148. subl = dsl_seq_copy(list->seq);
  149. for(i = 0; i < idx; i++) {
  150. dsl_seq_delete(subl, 0);
  151. }
  152. return sol_list_from_seq(state, subl);
  153. }
  154. sol_object_t *sol_list_get_index(sol_state_t *state, sol_object_t *list, int idx) {
  155. if(idx < 0 || idx >= dsl_seq_len(list->seq)) {
  156. return sol_incref(state->None);
  157. }
  158. return sol_incref(AS_OBJ(dsl_seq_get(list->seq, idx)));
  159. }
  160. void sol_list_set_index(sol_state_t *state, sol_object_t *list, int idx, sol_object_t *obj) {
  161. if(idx < 0 || idx >= dsl_seq_len(list->seq)) {
  162. return;
  163. }
  164. dsl_seq_set(list->seq, idx, obj);
  165. }
  166. void sol_list_insert(sol_state_t *state, sol_object_t *list, int idx, sol_object_t *obj) {
  167. if(idx < 0 || idx > dsl_seq_len(list->seq)) {
  168. return;
  169. }
  170. dsl_seq_insert(list->seq, idx, obj);
  171. }
  172. sol_object_t *sol_list_remove(sol_state_t *state, sol_object_t *list, int idx) {
  173. if(idx < 0 || idx >= dsl_seq_len(list->seq)) {
  174. return sol_incref(state->None);
  175. }
  176. return dsl_seq_remove(list->seq, idx);
  177. }
  178. sol_object_t *sol_list_copy(sol_state_t *state, sol_object_t *list) {
  179. return sol_list_from_seq(state, dsl_seq_copy(list->seq));
  180. }
  181. sol_object_t *sol_list_truncate(sol_state_t *state, sol_object_t *list, int len) {
  182. dsl_seq *newseq = dsl_seq_copy(list->seq);
  183. dsl_seq_iter *iter = dsl_new_seq_iter(newseq);
  184. int pos = dsl_seq_iter_seek(iter, len);
  185. int sz = dsl_seq_len(newseq);
  186. int i;
  187. if(pos >= len) {
  188. for(i = 0; i < sz - pos; i++) {
  189. dsl_seq_iter_delete_at(iter);
  190. }
  191. }
  192. dsl_free_seq_iter(iter);
  193. return sol_list_from_seq(state, newseq);
  194. }
  195. void sol_list_append(sol_state_t *state, sol_object_t *dest, sol_object_t *src) {
  196. dsl_seq *oldseq = dest->seq;
  197. dest->seq = dsl_seq_append(dest->seq, src->seq);
  198. dsl_free_seq(oldseq);
  199. }
  200. sol_object_t *sol_f_list_free(sol_state_t *state, sol_object_t *list) {
  201. dsl_free_seq(list->seq);
  202. return list;
  203. }
  204. /*int sol_test_cycle(sol_state_t *state, sol_object_t *seq) {
  205. sol_object_t *seen[1024]={};
  206. sol_object_t *cur = seq, **item;
  207. while(cur) {
  208. item = seen;
  209. while(*item) {
  210. if(*item == cur) return 1;
  211. item++;
  212. }
  213. *item = cur;
  214. if(sol_is_list(seq)) {
  215. cur = cur->lnext;
  216. } else {
  217. cur = cur->mnext;
  218. }
  219. }
  220. return 0;
  221. }
  222. int sol_validate_list(sol_state_t *state, sol_object_t *list) {
  223. sol_object_t *cur = list;
  224. int i = 0;
  225. char msg[128];
  226. while(cur) {
  227. if(!sol_is_list(cur)) {
  228. snprintf(msg, 128, "Node at index %d not a list node", i);
  229. sol_obj_free(sol_set_error_string(state, msg));
  230. return 1;
  231. }
  232. /*if(cur->lnext && !cur->lvalue) {
  233. snprintf(msg, 128, "Node at index %d has a next node but NULL value", i);
  234. sol_obj_free(sol_set_error_string(state, msg));
  235. return 1;
  236. }*//*
  237. cur = cur->lnext;
  238. i++;
  239. }
  240. if(sol_test_cycle(state, list)) {
  241. snprintf(msg, 128, "Cycle detected");
  242. sol_obj_free(sol_set_error_string(state, msg));
  243. return 1;
  244. }
  245. return 0;
  246. }*/
  247. sol_object_t *sol_new_map(sol_state_t *state) {
  248. sol_object_t *map = sol_alloc_object(state);
  249. map->type = SOL_MAP;
  250. map->ops = &(state->MapOps);
  251. map->seq = dsl_seq_new_array(NULL, &(state->obfuncs));
  252. sol_init_object(state, map);
  253. return map;
  254. }
  255. sol_object_t *sol_map_from_seq(sol_state_t *state, dsl_seq *seq) {
  256. sol_object_t *map = sol_alloc_object(state);
  257. if(sol_has_error(state)) {
  258. return sol_incref(state->None);
  259. }
  260. map->type = SOL_MAP;
  261. map->ops = &(state->MapOps);
  262. map->seq = seq;
  263. return map;
  264. }
  265. int sol_map_len(sol_state_t *state, sol_object_t *map) {
  266. return dsl_seq_len(map->seq);
  267. }
  268. sol_object_t *sol_map_mcell(sol_state_t *state, sol_object_t *map, sol_object_t *key) {
  269. sol_object_t *list, *cmp, *icmp, *res = NULL;
  270. dsl_seq_iter *iter;
  271. if(!sol_is_map(map)) {
  272. printf("WARNING: Attempt to index non-map as map\n");
  273. return sol_incref(state->None);
  274. }
  275. list = sol_new_list(state);
  276. iter = dsl_new_seq_iter(map->seq);
  277. if(sol_has_error(state)) {
  278. dsl_free_seq_iter(iter);
  279. sol_obj_free(list);
  280. return sol_incref(state->None);
  281. }
  282. sol_list_insert(state, list, 0, key);
  283. sol_list_insert(state, list, 1, state->None);
  284. if(!dsl_seq_iter_is_invalid(iter)) do {
  285. sol_list_set_index(state, list, 1, AS_OBJ(dsl_seq_iter_at(iter))->key);
  286. cmp = CALL_METHOD(state, key, cmp, list);
  287. icmp = sol_cast_int(state, cmp);
  288. sol_obj_free(cmp);
  289. if(icmp->ival == 0) {
  290. res = AS_OBJ(dsl_seq_iter_at(iter));
  291. }
  292. sol_obj_free(icmp);
  293. } while(dsl_seq_iter_next(iter));
  294. dsl_free_seq_iter(iter);
  295. sol_obj_free(list);
  296. if(res) {
  297. return res;
  298. }
  299. return sol_incref(state->None);
  300. }
  301. int sol_map_has(sol_state_t *state, sol_object_t *map, sol_object_t *key) {
  302. sol_object_t *mcell = sol_map_mcell(state, map, key);
  303. int res = sol_is_none(state, mcell);
  304. if(sol_is_none(state, mcell)) sol_decref(mcell);
  305. return res;
  306. }
  307. sol_object_t *sol_map_get(sol_state_t *state, sol_object_t *map, sol_object_t *key) {
  308. sol_object_t *mcell = sol_map_mcell(state, map, key);
  309. if(sol_is_none(state, mcell)) {
  310. return mcell;
  311. }
  312. return sol_incref(mcell->val);
  313. }
  314. sol_object_t *sol_map_get_name(sol_state_t *state, sol_object_t *map, char *name) {
  315. sol_object_t *key = sol_new_string(state, name);
  316. sol_object_t *res = sol_map_get(state, map, key);
  317. sol_obj_free(key);
  318. return res;
  319. }
  320. void sol_map_set(sol_state_t *state, sol_object_t *map, sol_object_t *key, sol_object_t *val) {
  321. sol_object_t *mcell = sol_map_mcell(state, map, key), *newcell, *temp;
  322. if(sol_is_none(state, mcell)) {
  323. newcell = sol_alloc_object(state);
  324. newcell->type = SOL_MCELL;
  325. newcell->ops = &(state->MCellOps);
  326. newcell->key = sol_incref(key);
  327. newcell->val = sol_incref(val);
  328. dsl_seq_insert(map->seq, 0, newcell);
  329. sol_obj_free(newcell);
  330. } else {
  331. temp = mcell->val;
  332. mcell->val = sol_incref(val);
  333. sol_obj_free(temp);
  334. }
  335. }
  336. void sol_map_set_name(sol_state_t *state, sol_object_t *map, char *name, sol_object_t *val) {
  337. sol_object_t *key = sol_new_string(state, name);
  338. sol_map_set(state, map, key, val);
  339. sol_obj_free(key);
  340. }
  341. void sol_map_set_existing(sol_state_t *state, sol_object_t *map, sol_object_t *key, sol_object_t *val) {
  342. sol_object_t *mcell = sol_map_mcell(state, map, key), *temp;
  343. if(!sol_is_none(state, mcell)) {
  344. temp = mcell->val;
  345. mcell->val = sol_incref(val);
  346. sol_obj_free(temp);
  347. }
  348. }
  349. sol_object_t *sol_map_copy(sol_state_t *state, sol_object_t *map) {
  350. return sol_map_from_seq(state, dsl_seq_copy(map->seq));
  351. }
  352. void sol_map_merge(sol_state_t *state, sol_object_t *dest, sol_object_t *src) {
  353. dsl_seq_iter *iter = dsl_new_seq_iter(src->seq);
  354. if(!dsl_seq_iter_is_invalid(iter)) do {
  355. sol_map_set(state, dest, AS_OBJ(dsl_seq_iter_at(iter))->key, AS_OBJ(dsl_seq_iter_at(iter))->val);
  356. } while(dsl_seq_iter_next(iter));
  357. dsl_free_seq_iter(iter);
  358. }
  359. void sol_map_merge_existing(sol_state_t *state, sol_object_t *dest, sol_object_t *src) {
  360. dsl_seq_iter *iter = dsl_new_seq_iter(src->seq);
  361. if(!dsl_seq_iter_is_invalid(iter)) do {
  362. sol_map_set_existing(state, dest, AS_OBJ(dsl_seq_iter_at(iter))->key, AS_OBJ(dsl_seq_iter_at(iter))->val);
  363. } while(dsl_seq_iter_next(iter));
  364. dsl_free_seq_iter(iter);
  365. }
  366. void sol_map_invert(sol_state_t *state, sol_object_t *map) {
  367. dsl_seq *pairs = dsl_seq_copy(map->seq);
  368. dsl_seq_iter *iter = dsl_new_seq_iter(pairs);
  369. sol_object_t *mcell;
  370. while(!dsl_seq_iter_is_invalid(iter)) {
  371. mcell = dsl_seq_iter_at(iter);
  372. sol_map_set(state, map, mcell->val, mcell->key);
  373. dsl_seq_iter_next(iter);
  374. }
  375. dsl_free_seq_iter(iter);
  376. dsl_free_seq(pairs);
  377. }
  378. sol_object_t *sol_f_map_free(sol_state_t *state, sol_object_t *map) {
  379. dsl_free_seq(map->seq);
  380. return map;
  381. }
  382. sol_object_t *sol_f_mcell_free(sol_state_t *state, sol_object_t *mcell) {
  383. if(mcell->key) {
  384. sol_obj_free(mcell->key);
  385. }
  386. if(mcell->val) {
  387. sol_obj_free(mcell->val);
  388. }
  389. return mcell;
  390. }
  391. /*int sol_validate_map(sol_state_t *state, sol_object_t *map) {
  392. sol_object_t *cur = map;
  393. int i = 0;
  394. char msg[128];
  395. while(cur) {
  396. if(!sol_is_map(cur)) {
  397. snprintf(msg, 128, "Node at index %d not a map node", i);
  398. sol_obj_free(sol_set_error_string(state, msg));
  399. return 1;
  400. }
  401. if(cur->mnext && (!cur->mkey || !cur->mval)) {
  402. snprintf(msg, 128, "Node at index %d has a next node but NULL key or value", i);
  403. sol_obj_free(sol_set_error_string(state, msg));
  404. return 1;
  405. }
  406. cur = cur->mnext;
  407. i++;
  408. }
  409. return 0;
  410. }*/
  411. sol_object_t *sol_new_cfunc(sol_state_t *state, sol_cfunc_t cfunc) {
  412. sol_object_t *res = sol_alloc_object(state);
  413. res->type = SOL_CFUNCTION;
  414. res->ops = &(state->CFuncOps);
  415. res->cfunc = cfunc;
  416. sol_init_object(state, res);
  417. return res;
  418. }
  419. sol_object_t *sol_new_cdata(sol_state_t *state, void *cdata, sol_ops_t *ops) {
  420. sol_object_t *res = sol_alloc_object(state);
  421. res->type = SOL_CDATA;
  422. res->ops = ops;
  423. res->cdata = cdata;
  424. sol_init_object(state, res);
  425. return res;
  426. }
  427. sol_object_t *sol_new_buffer(sol_state_t *state, void *buffer, ssize_t sz, sol_owntype_t own, sol_freefunc_t freef, sol_movefunc_t movef) {
  428. sol_object_t *res = sol_alloc_object(state);
  429. res->type = SOL_BUFFER;
  430. res->ops = &(state->BufferOps);
  431. res->buffer = buffer;
  432. res->sz = sz;
  433. res->own = own;
  434. res->freef = freef;
  435. res->movef = movef;
  436. sol_init_object(state, res);
  437. return res;
  438. }
  439. sol_object_t *sol_f_buffer_free(sol_state_t *state, sol_object_t *buf) {
  440. switch(buf->own) {
  441. case OWN_FREE:
  442. free(buf->buffer);
  443. break;
  444. case OWN_CALLF:
  445. if(buf->freef) buf->freef(buf->buffer, buf->sz);
  446. break;
  447. }
  448. return buf;
  449. }
  450. sol_object_t *sol_new_dylib(sol_state_t *state, void *handle) {
  451. sol_object_t *res = sol_alloc_object(state);
  452. res->type = SOL_DYLIB;
  453. res->ops = &(state->DyLibOps);
  454. res->dlhandle = handle;
  455. sol_init_object(state, res);
  456. return res;
  457. }
  458. sol_object_t *sol_f_dylib_free(sol_state_t *state, sol_object_t *dylib) {
  459. dlclose(dylib->dlhandle);
  460. return dylib;
  461. }
  462. sol_object_t *sol_new_dysym(sol_state_t *state, void *sym, dsl_seq *argtp, sol_buftype_t rettp) {
  463. sol_object_t *res = sol_alloc_object(state);
  464. res->type = SOL_DYSYM;
  465. res->ops = &(state->DySymOps);
  466. res->dlsym = sym;
  467. if(argtp) {
  468. res->argtp = dsl_seq_copy(argtp);
  469. } else {
  470. res->argtp = dsl_seq_new_array(NULL, &(state->obfuncs));
  471. }
  472. res->rettp = rettp;
  473. sol_init_object(state, res);
  474. return res;
  475. }
  476. sol_object_t *sol_new_stream(sol_state_t *state, FILE *stream, sol_modes_t modes) {
  477. sol_object_t *res = sol_alloc_object(state);
  478. res->type = SOL_STREAM;
  479. res->ops = &(state->StreamOps);
  480. res->stream = stream;
  481. res->modes = modes;
  482. sol_init_object(state, res);
  483. return res;
  484. }
  485. size_t sol_stream_printf(sol_state_t *state, sol_object_t *stream, const char *fmt, ...) {
  486. va_list va;
  487. size_t res;
  488. if(!(stream->modes & MODE_WRITE)) {
  489. if(state) {
  490. sol_obj_free(sol_set_error_string(state, "Write to non-writable stream"));
  491. }
  492. return 0;
  493. }
  494. va_start(va, fmt);
  495. res = vfprintf(stream->stream, fmt, va);
  496. va_end(va);
  497. return res;
  498. }
  499. size_t sol_stream_vprintf(sol_state_t *state, sol_object_t *stream, const char *fmt, va_list va) {
  500. if(!(stream->modes & MODE_WRITE)) {
  501. if(state) {
  502. sol_obj_free(sol_set_error_string(state, "Write to non-writable stream"));
  503. }
  504. return 0;
  505. }
  506. return vfprintf(stream->stream, fmt, va);
  507. }
  508. size_t sol_stream_scanf(sol_state_t *state, sol_object_t *stream, const char *fmt, ...) {
  509. va_list va;
  510. size_t res;
  511. if(!(stream->modes & MODE_READ)) {
  512. if(state) {
  513. sol_obj_free(sol_set_error_string(state, "Read from non-readable stream"));
  514. }
  515. return 0;
  516. }
  517. va_start(va, fmt);
  518. res = vfscanf(stream->stream, fmt, va);
  519. va_end(va);
  520. return res;
  521. }
  522. size_t sol_stream_fread(sol_state_t *state, sol_object_t *stream, char *buffer, size_t sz, size_t memb) {
  523. if(!(stream->modes & MODE_READ)) {
  524. if(state) {
  525. sol_obj_free(sol_set_error_string(state, "Read from non-readable stream"));
  526. }
  527. return 0;
  528. }
  529. return fread(buffer, sz, memb, stream->stream);
  530. }
  531. size_t sol_stream_fwrite(sol_state_t *state, sol_object_t *stream, char *buffer, size_t sz, size_t memb) {
  532. if(!(stream->modes & MODE_WRITE)) {
  533. if(state) {
  534. sol_obj_free(sol_set_error_string(state, "Write to non-writable stream"));
  535. }
  536. return 0;
  537. }
  538. return fwrite(buffer, sz, memb, stream->stream);
  539. }
  540. char *sol_stream_fgets(sol_state_t *state, sol_object_t *stream, char *buffer, size_t sz) {
  541. if(!(stream->modes & MODE_READ)) {
  542. if(state) {
  543. sol_obj_free(sol_set_error_string(state, "Read from non-readable stream"));
  544. }
  545. return NULL;
  546. }
  547. return fgets(buffer, sz, stream->stream);
  548. }
  549. int sol_stream_fputc(sol_state_t *state, sol_object_t *stream, int ch) {
  550. if(!(stream->modes & MODE_WRITE)) {
  551. if(state) {
  552. sol_obj_free(sol_set_error_string(state, "Write to non-writable stream"));
  553. }
  554. return 0;
  555. }
  556. return fputc(ch, stream->stream);
  557. }
  558. int sol_stream_feof(sol_state_t *state, sol_object_t *stream) {
  559. return feof(stream->stream);
  560. }
  561. int sol_stream_ferror(sol_state_t *state, sol_object_t *stream) {
  562. return ferror(stream->stream);
  563. }
  564. int sol_stream_fseek(sol_state_t *state, sol_object_t *stream, long offset, int whence) {
  565. return fseek(stream->stream, offset, whence);
  566. }
  567. long sol_stream_ftell(sol_state_t *state, sol_object_t *stream) {
  568. return ftell(stream->stream);
  569. }
  570. int sol_stream_fflush(sol_state_t *state, sol_object_t *stream) {
  571. return fflush(stream->stream);
  572. }
  573. sol_object_t *sol_f_stream_free(sol_state_t *state, sol_object_t *stream) {
  574. //printf("IO: Closing open file\n");
  575. fclose(stream->stream);
  576. return stream;
  577. }