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.

642 lines
17 KiB

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