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

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