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.

715 lines
19 KiB

  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 = CALL_METHOD(state, obj, toint, 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 = CALL_METHOD(state, obj, tofloat, 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 = CALL_METHOD(state, obj, tostring, 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 = CALL_METHOD(state, obj, repr, 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. sol_object_t *sol_f_singlet_free(sol_state_t *state, sol_object_t *singlet) {
  60. free(singlet->str);
  61. }
  62. // And, now, for the rest of the checked stuff...
  63. void sol_init_object(sol_state_t *state, sol_object_t *obj) {
  64. if(obj->ops->init) {
  65. obj->ops->init(state, obj);
  66. }
  67. }
  68. sol_object_t *sol_new_int(sol_state_t *state, long i) {
  69. sol_object_t *res;
  70. #ifdef SOL_ICACHE
  71. if(!state->icache_bypass && i >= SOL_ICACHE_MIN && i <= SOL_ICACHE_MAX) {
  72. res = sol_incref(state->icache[i - SOL_ICACHE_MIN]);
  73. if(res->ival != i) {
  74. printf("WARNING: Integer at %ld mutated to %ld! Resetting...\n", i, res->ival);
  75. res->ival = i;
  76. }
  77. return res;
  78. }
  79. #endif
  80. res = sol_alloc_object(state);
  81. res->type = SOL_INTEGER;
  82. res->ival = i;
  83. res->ops = &(state->IntOps);
  84. sol_init_object(state, res);
  85. return res;
  86. }
  87. sol_object_t *sol_new_float(sol_state_t *state, double f) {
  88. sol_object_t *res = sol_alloc_object(state);
  89. res->type = SOL_FLOAT;
  90. res->fval = f;
  91. res->ops = &(state->FloatOps);
  92. sol_init_object(state, res);
  93. return res;
  94. }
  95. sol_object_t *sol_new_string(sol_state_t *state, const char *s) {
  96. sol_object_t *res = sol_alloc_object(state);
  97. res->type = SOL_STRING;
  98. res->str = strdup(s);
  99. if(!res->str) {
  100. sol_obj_free(res);
  101. sol_set_error(state, state->OutOfMemory);
  102. return sol_incref(state->None);
  103. }
  104. res->ops = &(state->StringOps);
  105. sol_init_object(state, res);
  106. return res;
  107. }
  108. int sol_string_cmp(sol_state_t *state, sol_object_t *str, const char *s) {
  109. return strcmp(str->str, s);
  110. }
  111. sol_object_t *sol_string_concat(sol_state_t *state, sol_object_t *a, sol_object_t *b) {
  112. sol_object_t *res, *sa = sol_cast_string(state, a), *sb = sol_cast_string(state, b);
  113. int n = strlen(sa->str) + strlen(sb->str) + 1;
  114. char *s = malloc(n);
  115. res = sol_new_string(state, strncat(strncpy(s, a->str, n), b->str, n));
  116. sol_obj_free(sa);
  117. sol_obj_free(sb);
  118. free(s);
  119. return res;
  120. }
  121. sol_object_t *sol_string_concat_cstr(sol_state_t *state, sol_object_t *a, char *s) {
  122. sol_object_t *b = sol_new_string(state, s);
  123. sol_object_t *res = sol_string_concat(state, a, b);
  124. sol_obj_free(b);
  125. return res;
  126. }
  127. sol_object_t *sol_f_str_free(sol_state_t *state, sol_object_t *obj) {
  128. free(obj->str);
  129. return obj;
  130. }
  131. sol_object_t *sol_new_list(sol_state_t *state) {
  132. sol_object_t *res = sol_alloc_object(state);
  133. res->type = SOL_LIST;
  134. res->seq = dsl_seq_new_array(NULL, &(state->obfuncs));
  135. res->ops = &(state->ListOps);
  136. sol_init_object(state, res);
  137. return res;
  138. }
  139. sol_object_t *sol_list_from_seq(sol_state_t *state, dsl_seq *seq) {
  140. sol_object_t *res = sol_alloc_object(state);
  141. res->type = SOL_LIST;
  142. res->seq = seq;
  143. res->ops = &(state->ListOps);
  144. sol_init_object(state, res);
  145. return res;
  146. }
  147. int sol_list_len(sol_state_t *state, sol_object_t *list) {
  148. return dsl_seq_len(list->seq);
  149. }
  150. sol_object_t *sol_list_sublist(sol_state_t *state, sol_object_t *list, int idx) {
  151. int i = 0;
  152. dsl_seq *subl;
  153. if(idx < 0) {
  154. return sol_set_error_string(state, "Create sublist at negative index");
  155. }
  156. subl = dsl_seq_copy(list->seq);
  157. for(i = 0; i < idx; i++) {
  158. dsl_seq_delete(subl, 0);
  159. }
  160. return sol_list_from_seq(state, subl);
  161. }
  162. sol_object_t *sol_list_get_index(sol_state_t *state, sol_object_t *list, int idx) {
  163. if(idx < 0 || idx >= dsl_seq_len(list->seq)) {
  164. return sol_incref(state->None);
  165. }
  166. return sol_incref(AS_OBJ(dsl_seq_get(list->seq, idx)));
  167. }
  168. void sol_list_set_index(sol_state_t *state, sol_object_t *list, int idx, sol_object_t *obj) {
  169. if(idx < 0 || idx >= dsl_seq_len(list->seq)) {
  170. return;
  171. }
  172. dsl_seq_set(list->seq, idx, obj);
  173. }
  174. void sol_list_insert(sol_state_t *state, sol_object_t *list, int idx, sol_object_t *obj) {
  175. if(idx < 0 || idx > dsl_seq_len(list->seq)) {
  176. return;
  177. }
  178. dsl_seq_insert(list->seq, idx, obj);
  179. }
  180. sol_object_t *sol_list_remove(sol_state_t *state, sol_object_t *list, int idx) {
  181. if(idx < 0 || idx >= dsl_seq_len(list->seq)) {
  182. return sol_incref(state->None);
  183. }
  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)) {
  266. return sol_incref(state->None);
  267. }
  268. map->type = SOL_MAP;
  269. map->ops = &(state->MapOps);
  270. map->seq = seq;
  271. return map;
  272. }
  273. int sol_map_len(sol_state_t *state, sol_object_t *map) {
  274. return dsl_seq_len(map->seq);
  275. }
  276. sol_object_t *sol_map_mcell_index(sol_state_t *state, sol_object_t *map, int index) {
  277. sol_object_t *res = dsl_seq_get(map->seq, index);
  278. if(res) {
  279. return sol_incref(res);
  280. }
  281. return sol_incref(state->None);
  282. }
  283. sol_object_t *sol_map_mcell(sol_state_t *state, sol_object_t *map, sol_object_t *key) {
  284. sol_object_t *list, *cmp, *icmp, *res = NULL;
  285. dsl_seq_iter *iter;
  286. if(!sol_is_map(map)) {
  287. printf("WARNING: Attempt to index non-map as map\n");
  288. return sol_incref(state->None);
  289. }
  290. list = sol_new_list(state);
  291. iter = dsl_new_seq_iter(map->seq);
  292. if(sol_has_error(state)) {
  293. dsl_free_seq_iter(iter);
  294. sol_obj_free(list);
  295. return sol_incref(state->None);
  296. }
  297. sol_list_insert(state, list, 0, state->None);
  298. sol_list_insert(state, list, 1, key);
  299. while(!res && !dsl_seq_iter_is_invalid(iter)) {
  300. sol_list_set_index(state, list, 0, AS_OBJ(dsl_seq_iter_at(iter))->key);
  301. cmp = CALL_METHOD(state, AS_OBJ(dsl_seq_iter_at(iter))->key, cmp, list);
  302. if(sol_has_error(state)) {
  303. sol_obj_free(cmp);
  304. sol_clear_error(state);
  305. continue;
  306. }
  307. icmp = sol_cast_int(state, cmp);
  308. sol_obj_free(cmp);
  309. if(icmp->ival == 0) {
  310. res = AS_OBJ(dsl_seq_iter_at(iter));
  311. }
  312. sol_obj_free(icmp);
  313. dsl_seq_iter_next(iter);
  314. }
  315. dsl_free_seq_iter(iter);
  316. sol_obj_free(list);
  317. if(res) {
  318. return sol_incref(res);
  319. }
  320. return sol_incref(state->None);
  321. }
  322. int sol_map_has(sol_state_t *state, sol_object_t *map, sol_object_t *key) {
  323. sol_object_t *mcell = sol_map_mcell(state, map, key);
  324. int res = !sol_is_none(state, mcell);
  325. sol_decref(mcell);
  326. return res;
  327. }
  328. sol_object_t *sol_map_get(sol_state_t *state, sol_object_t *map, sol_object_t *key) {
  329. sol_object_t *mcell = sol_map_mcell(state, map, key), *ret;
  330. if(sol_is_none(state, mcell)) {
  331. ret = mcell;
  332. } else {
  333. ret = mcell->val;
  334. }
  335. sol_obj_free(mcell);
  336. return sol_incref(ret);
  337. }
  338. sol_object_t *sol_map_get_name(sol_state_t *state, sol_object_t *map, char *name) {
  339. sol_object_t *key = sol_new_string(state, name);
  340. sol_object_t *res = sol_map_get(state, map, key);
  341. sol_obj_free(key);
  342. return res;
  343. }
  344. void sol_map_set(sol_state_t *state, sol_object_t *map, sol_object_t *key, sol_object_t *val) {
  345. sol_object_t *mcell = sol_map_mcell(state, map, key), *newcell, *temp;
  346. if(sol_is_none(state, val)) {
  347. if(!sol_is_none(state, mcell)) {
  348. // XXX hacky
  349. dsl_seq_iter *iter = dsl_new_seq_iter(map->seq);
  350. while(!dsl_seq_iter_is_invalid(iter)) {
  351. if(mcell == dsl_seq_iter_at(iter)) {
  352. dsl_seq_iter_delete_at(iter);
  353. break;
  354. }
  355. dsl_seq_iter_next(iter);
  356. }
  357. }
  358. return;
  359. }
  360. if(sol_is_none(state, mcell)) {
  361. newcell = sol_alloc_object(state);
  362. newcell->type = SOL_MCELL;
  363. newcell->ops = &(state->MCellOps);
  364. newcell->key = sol_incref(key);
  365. newcell->val = sol_incref(val);
  366. dsl_seq_insert(map->seq, 0, newcell);
  367. sol_obj_free(newcell);
  368. } else {
  369. temp = mcell->val;
  370. mcell->val = sol_incref(val);
  371. sol_obj_free(temp);
  372. }
  373. sol_obj_free(mcell);
  374. }
  375. void sol_map_set_name(sol_state_t *state, sol_object_t *map, char *name, sol_object_t *val) {
  376. sol_object_t *key = sol_new_string(state, name);
  377. sol_map_set(state, map, key, val);
  378. sol_obj_free(key);
  379. }
  380. void sol_map_set_existing(sol_state_t *state, sol_object_t *map, sol_object_t *key, sol_object_t *val) {
  381. sol_object_t *mcell = sol_map_mcell(state, map, key), *temp;
  382. if(!sol_is_none(state, mcell)) {
  383. temp = mcell->val;
  384. mcell->val = sol_incref(val);
  385. sol_obj_free(temp);
  386. }
  387. sol_obj_free(mcell);
  388. }
  389. sol_object_t *sol_map_copy(sol_state_t *state, sol_object_t *map) {
  390. return sol_map_from_seq(state, dsl_seq_copy(map->seq));
  391. }
  392. void sol_map_merge(sol_state_t *state, sol_object_t *dest, sol_object_t *src) {
  393. dsl_seq_iter *iter = dsl_new_seq_iter(src->seq);
  394. while(!dsl_seq_iter_is_invalid(iter)) {
  395. sol_map_set(state, dest, AS_OBJ(dsl_seq_iter_at(iter))->key, AS_OBJ(dsl_seq_iter_at(iter))->val);
  396. dsl_seq_iter_next(iter);
  397. }
  398. dsl_free_seq_iter(iter);
  399. }
  400. void sol_map_merge_existing(sol_state_t *state, sol_object_t *dest, sol_object_t *src) {
  401. dsl_seq_iter *iter = dsl_new_seq_iter(src->seq);
  402. while(!dsl_seq_iter_is_invalid(iter)) {
  403. sol_map_set_existing(state, dest, AS_OBJ(dsl_seq_iter_at(iter))->key, AS_OBJ(dsl_seq_iter_at(iter))->val);
  404. dsl_seq_iter_next(iter);
  405. }
  406. dsl_free_seq_iter(iter);
  407. }
  408. void sol_map_invert(sol_state_t *state, sol_object_t *map) {
  409. dsl_seq *pairs = dsl_seq_copy(map->seq);
  410. dsl_seq_iter *iter = dsl_new_seq_iter(pairs);
  411. sol_object_t *mcell;
  412. while(!dsl_seq_iter_is_invalid(iter)) {
  413. mcell = dsl_seq_iter_at(iter);
  414. sol_map_set(state, map, mcell->val, mcell->key);
  415. dsl_seq_iter_next(iter);
  416. }
  417. dsl_free_seq_iter(iter);
  418. dsl_free_seq(pairs);
  419. }
  420. sol_object_t *sol_f_map_free(sol_state_t *state, sol_object_t *map) {
  421. dsl_free_seq(map->seq);
  422. return map;
  423. }
  424. sol_object_t *sol_f_mcell_free(sol_state_t *state, sol_object_t *mcell) {
  425. if(mcell->key) {
  426. sol_obj_free(mcell->key);
  427. } else {
  428. printf("WARNING: Freed mcell with NULL key\n");
  429. }
  430. if(mcell->val) {
  431. sol_obj_free(mcell->val);
  432. } else {
  433. printf("WARNING: Freed mcell with NULL value\n");
  434. }
  435. return mcell;
  436. }
  437. /*int sol_validate_map(sol_state_t *state, sol_object_t *map) {
  438. sol_object_t *cur = map;
  439. int i = 0;
  440. char msg[128];
  441. while(cur) {
  442. if(!sol_is_map(cur)) {
  443. snprintf(msg, 128, "Node at index %d not a map node", i);
  444. sol_obj_free(sol_set_error_string(state, msg));
  445. return 1;
  446. }
  447. if(cur->mnext && (!cur->mkey || !cur->mval)) {
  448. snprintf(msg, 128, "Node at index %d has a next node but NULL key or value", i);
  449. sol_obj_free(sol_set_error_string(state, msg));
  450. return 1;
  451. }
  452. cur = cur->mnext;
  453. i++;
  454. }
  455. return 0;
  456. }*/
  457. sol_object_t *sol_new_cfunc(sol_state_t *state, sol_cfunc_t cfunc, char *name) {
  458. sol_object_t *res = sol_alloc_object(state);
  459. res->type = SOL_CFUNCTION;
  460. res->ops = &(state->CFuncOps);
  461. res->cfunc = cfunc;
  462. res->cfname = name ? strdup(name) : NULL;
  463. sol_init_object(state, res);
  464. return res;
  465. }
  466. sol_object_t *sol_f_cfunc_free(sol_state_t *state, sol_object_t *cfunc) {
  467. free(cfunc->cfname);
  468. return cfunc;
  469. }
  470. sol_object_t *sol_new_cdata(sol_state_t *state, void *cdata, sol_ops_t *ops) {
  471. sol_object_t *res = sol_alloc_object(state);
  472. res->type = SOL_CDATA;
  473. res->ops = ops;
  474. res->cdata = cdata;
  475. sol_init_object(state, res);
  476. return res;
  477. }
  478. sol_object_t *sol_f_astnode_free(sol_state_t *state, sol_object_t *node) {
  479. switch(node->type) {
  480. case SOL_STMT:
  481. st_free((stmt_node *) node->node);
  482. break;
  483. case SOL_EXPR:
  484. ex_free((expr_node *) node->node);
  485. break;
  486. }
  487. return node;
  488. }
  489. 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) {
  490. sol_object_t *res = sol_alloc_object(state);
  491. res->type = SOL_BUFFER;
  492. res->ops = &(state->BufferOps);
  493. res->buffer = buffer;
  494. res->sz = sz;
  495. res->own = own;
  496. res->freef = freef;
  497. res->movef = movef;
  498. sol_init_object(state, res);
  499. return res;
  500. }
  501. sol_object_t *sol_f_buffer_free(sol_state_t *state, sol_object_t *buf) {
  502. switch(buf->own) {
  503. case OWN_FREE:
  504. free(buf->buffer);
  505. break;
  506. case OWN_CALLF:
  507. if(buf->freef) buf->freef(buf->buffer, buf->sz);
  508. break;
  509. }
  510. return buf;
  511. }
  512. sol_object_t *sol_new_dylib(sol_state_t *state, void *handle) {
  513. sol_object_t *res = sol_alloc_object(state);
  514. res->type = SOL_DYLIB;
  515. res->ops = &(state->DyLibOps);
  516. res->dlhandle = handle;
  517. sol_init_object(state, res);
  518. return res;
  519. }
  520. sol_object_t *sol_f_dylib_free(sol_state_t *state, sol_object_t *dylib) {
  521. dlclose(dylib->dlhandle);
  522. return dylib;
  523. }
  524. sol_object_t *sol_new_dysym(sol_state_t *state, void *sym, dsl_seq *argtp, sol_buftype_t rettp) {
  525. sol_object_t *res = sol_alloc_object(state);
  526. res->type = SOL_DYSYM;
  527. res->ops = &(state->DySymOps);
  528. res->dlsym = sym;
  529. if(argtp) {
  530. res->argtp = dsl_seq_copy(argtp);
  531. } else {
  532. res->argtp = dsl_seq_new_array(NULL, &(state->obfuncs));
  533. }
  534. res->rettp = rettp;
  535. sol_init_object(state, res);
  536. return res;
  537. }
  538. sol_object_t *sol_new_stream(sol_state_t *state, FILE *stream, sol_modes_t modes) {
  539. sol_object_t *res = sol_alloc_object(state);
  540. res->type = SOL_STREAM;
  541. res->ops = &(state->StreamOps);
  542. res->stream = stream;
  543. res->modes = modes;
  544. sol_init_object(state, res);
  545. return res;
  546. }
  547. size_t sol_stream_printf(sol_state_t *state, sol_object_t *stream, const char *fmt, ...) {
  548. va_list va;
  549. size_t res;
  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. va_start(va, fmt);
  557. //res = vfprintf(stream->stream, fmt, va);
  558. res = vprintf(fmt, va);
  559. va_end(va);
  560. return res;
  561. }
  562. size_t sol_stream_vprintf(sol_state_t *state, sol_object_t *stream, const char *fmt, va_list va) {
  563. if(!(stream->modes & MODE_WRITE)) {
  564. if(state) {
  565. sol_obj_free(sol_set_error_string(state, "Write to non-writable stream"));
  566. }
  567. return 0;
  568. }
  569. //return vfprintf(stream->stream, fmt, va);
  570. return vprintf(fmt, va);
  571. }
  572. size_t sol_stream_scanf(sol_state_t *state, sol_object_t *stream, const char *fmt, ...) {
  573. va_list va;
  574. size_t res;
  575. if(!(stream->modes & MODE_READ)) {
  576. if(state) {
  577. sol_obj_free(sol_set_error_string(state, "Read from non-readable stream"));
  578. }
  579. return 0;
  580. }
  581. va_start(va, fmt);
  582. res = vfscanf(stream->stream, fmt, va);
  583. va_end(va);
  584. return res;
  585. }
  586. size_t sol_stream_fread(sol_state_t *state, sol_object_t *stream, char *buffer, size_t sz, size_t memb) {
  587. if(!(stream->modes & MODE_READ)) {
  588. if(state) {
  589. sol_obj_free(sol_set_error_string(state, "Read from non-readable stream"));
  590. }
  591. return 0;
  592. }
  593. return fread(buffer, sz, memb, stream->stream);
  594. }
  595. size_t sol_stream_fwrite(sol_state_t *state, sol_object_t *stream, char *buffer, size_t sz, size_t memb) {
  596. if(!(stream->modes & MODE_WRITE)) {
  597. if(state) {
  598. sol_obj_free(sol_set_error_string(state, "Write to non-writable stream"));
  599. }
  600. return 0;
  601. }
  602. return fwrite(buffer, sz, memb, stream->stream);
  603. }
  604. char *sol_stream_fgets(sol_state_t *state, sol_object_t *stream, char *buffer, size_t sz) {
  605. if(!(stream->modes & MODE_READ)) {
  606. if(state) {
  607. sol_obj_free(sol_set_error_string(state, "Read from non-readable stream"));
  608. }
  609. return NULL;
  610. }
  611. return fgets(buffer, sz, stream->stream);
  612. }
  613. int sol_stream_fputc(sol_state_t *state, sol_object_t *stream, int ch) {
  614. if(!(stream->modes & MODE_WRITE)) {
  615. if(state) {
  616. sol_obj_free(sol_set_error_string(state, "Write to non-writable stream"));
  617. }
  618. return 0;
  619. }
  620. return fputc(ch, stream->stream);
  621. }
  622. int sol_stream_feof(sol_state_t *state, sol_object_t *stream) {
  623. return feof(stream->stream);
  624. }
  625. int sol_stream_ferror(sol_state_t *state, sol_object_t *stream) {
  626. return ferror(stream->stream);
  627. }
  628. int sol_stream_fseek(sol_state_t *state, sol_object_t *stream, long offset, int whence) {
  629. return fseek(stream->stream, offset, whence);
  630. }
  631. long sol_stream_ftell(sol_state_t *state, sol_object_t *stream) {
  632. return ftell(stream->stream);
  633. }
  634. int sol_stream_fflush(sol_state_t *state, sol_object_t *stream) {
  635. return fflush(stream->stream);
  636. }
  637. sol_object_t *sol_f_stream_free(sol_state_t *state, sol_object_t *stream) {
  638. //printf("IO: Closing open file\n");
  639. fclose(stream->stream);
  640. return stream;
  641. }