external.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958
  1. /* Copyright (c) 1993-2004 by Richard Kelsey and Jonathan Rees.
  2. See file COPYING. */
  3. #include <stdlib.h>
  4. #include <stdio.h>
  5. #include <string.h>
  6. #include <setjmp.h>
  7. #include <stdarg.h>
  8. #include "c-mods.h"
  9. #include "scheme48.h"
  10. #include "scheme48vm.h"
  11. #include "bignum.h"
  12. /*
  13. * The Joy of C
  14. * I don't understand why we need this, but we do.
  15. */
  16. struct s_jmp_buf {
  17. jmp_buf buf;
  18. };
  19. /*
  20. * Longjump target set up by the most recent call into C.
  21. */
  22. static struct s_jmp_buf current_return_point;
  23. /*
  24. * The name of the procedure we are currently executing; used for error messages.
  25. */
  26. static s48_value current_procedure;
  27. /*
  28. * Stack of Scheme stack-block records which represent portions of the process
  29. * stack.
  30. */
  31. static s48_value current_stack_block = S48_FALSE;
  32. /*
  33. * These need to agree with the record definition in callback.scm.
  34. */
  35. #define STACK_BLOCK_FREE(stack_block) S48_UNSAFE_RECORD_REF(stack_block, 0)
  36. #define STACK_BLOCK_UNWIND(stack_block) S48_UNSAFE_RECORD_REF(stack_block, 1)
  37. #define STACK_BLOCK_PROC(stack_block) S48_UNSAFE_RECORD_REF(stack_block, 2)
  38. #define STACK_BLOCK_THREAD(stack_block) S48_UNSAFE_RECORD_REF(stack_block, 3)
  39. #define STACK_BLOCK_NEXT(stack_block) S48_UNSAFE_RECORD_REF(stack_block, 4)
  40. /*
  41. * For debugging.
  42. */
  43. /*
  44. static int callback_depth()
  45. {
  46. int depth = 0;
  47. s48_value stack = current_stack_block;
  48. for(; stack != S48_FALSE; depth++, stack = STACK_BLOCK_NEXT(stack));
  49. return depth;
  50. }
  51. */
  52. /*
  53. * The value being returned from an external call. The returns may be preceded
  54. * by a longjmp(), so we stash the value here.
  55. */
  56. static s48_value external_return_value;
  57. /* Exports to Scheme */
  58. static s48_value s48_clear_stack_top(void);
  59. static s48_value s48_trampoline(s48_value proc, s48_value nargs);
  60. static s48_value s48_system(s48_value string);
  61. /* Imports from Scheme */
  62. static s48_value the_record_type_binding = S48_FALSE;
  63. static s48_value stack_block_type_binding = S48_FALSE;
  64. static s48_value callback_binding = S48_FALSE;
  65. static s48_value delay_callback_return_binding = S48_FALSE;
  66. void
  67. s48_initialize_external()
  68. {
  69. S48_GC_PROTECT_GLOBAL(the_record_type_binding);
  70. the_record_type_binding = s48_get_imported_binding("s48-the-record-type");
  71. S48_GC_PROTECT_GLOBAL(stack_block_type_binding);
  72. stack_block_type_binding = s48_get_imported_binding("s48-stack-block-type");
  73. S48_GC_PROTECT_GLOBAL(callback_binding);
  74. callback_binding = s48_get_imported_binding("s48-callback");
  75. S48_GC_PROTECT_GLOBAL(delay_callback_return_binding);
  76. delay_callback_return_binding =
  77. s48_get_imported_binding("s48-delay-callback-return");
  78. S48_GC_PROTECT_GLOBAL(current_stack_block);
  79. S48_GC_PROTECT_GLOBAL(current_procedure);
  80. S48_EXPORT_FUNCTION(s48_clear_stack_top);
  81. S48_EXPORT_FUNCTION(s48_trampoline);
  82. S48_EXPORT_FUNCTION(s48_system);
  83. }
  84. /* The three reasons for an extern-call longjump. */
  85. #define NO_THROW 0
  86. #define EXCEPTION_THROW 1
  87. #define CLEANUP_THROW 2
  88. /*
  89. * Used to call `proc' from Scheme code. `nargs' the number of arguments in
  90. * vector `argv'. If `spread_p' is true the procedure is applied to the
  91. * arguments, otherwise `proc' is just called on `nargs' and `argv'.
  92. *
  93. * We do a setjmp() to get a return point for clearing off this portion of
  94. * the process stack. This is used when `proc' calls back to Scheme and
  95. * then a throw transfers control up past the call to `proc'.
  96. */
  97. typedef s48_value (*proc_0_t)(void);
  98. typedef s48_value (*proc_1_t)(s48_value);
  99. typedef s48_value (*proc_2_t)(s48_value, s48_value);
  100. typedef s48_value (*proc_3_t)(s48_value, s48_value, s48_value);
  101. typedef s48_value (*proc_4_t)(s48_value, s48_value, s48_value, s48_value);
  102. typedef s48_value (*proc_5_t)(s48_value, s48_value, s48_value, s48_value,
  103. s48_value);
  104. typedef s48_value (*proc_6_t)(s48_value, s48_value, s48_value, s48_value,
  105. s48_value, s48_value);
  106. typedef s48_value (*proc_7_t)(s48_value, s48_value, s48_value, s48_value,
  107. s48_value, s48_value, s48_value);
  108. typedef s48_value (*proc_8_t)(s48_value, s48_value, s48_value, s48_value,
  109. s48_value, s48_value, s48_value, s48_value);
  110. typedef s48_value (*proc_9_t)(s48_value, s48_value, s48_value, s48_value,
  111. s48_value, s48_value, s48_value, s48_value,
  112. s48_value);
  113. typedef s48_value (*proc_10_t)(s48_value, s48_value, s48_value, s48_value,
  114. s48_value, s48_value, s48_value, s48_value,
  115. s48_value, s48_value);
  116. typedef s48_value (*proc_11_t)(s48_value, s48_value, s48_value, s48_value,
  117. s48_value, s48_value, s48_value, s48_value,
  118. s48_value, s48_value, s48_value);
  119. typedef s48_value (*proc_12_t)(s48_value, s48_value, s48_value, s48_value,
  120. s48_value, s48_value, s48_value, s48_value,
  121. s48_value, s48_value, s48_value, s48_value);
  122. typedef s48_value (*proc_n_t)(int, s48_value []);
  123. s48_value
  124. s48_external_call(s48_value sch_proc, s48_value proc_name,
  125. long nargs, char *char_argv)
  126. {
  127. volatile char *gc_roots_marker; /* volatile to survive longjumps */
  128. volatile s48_value name = proc_name; /* volatile to survive longjumps */
  129. /* int depth = callback_depth(); */ /* debugging */
  130. long *argv = (long *) char_argv;
  131. proc_0_t proc = S48_EXTRACT_VALUE(sch_proc, proc_0_t);
  132. int throw_reason;
  133. current_procedure = name;
  134. S48_CHECK_VALUE(sch_proc);
  135. S48_CHECK_STRING(name);
  136. gc_roots_marker = s48_set_gc_roots_baseB();
  137. /* fprintf(stderr, "[external_call at depth %d]\n", depth); */
  138. throw_reason = setjmp(current_return_point.buf);
  139. if (throw_reason == NO_THROW) { /* initial entry */
  140. switch (nargs) {
  141. case 0:
  142. external_return_value = proc();
  143. break;
  144. case 1:
  145. external_return_value = ((proc_1_t)proc)(argv[0]);
  146. break;
  147. case 2:
  148. external_return_value = ((proc_2_t)proc)(argv[1], argv[0]);
  149. break;
  150. case 3:
  151. external_return_value = ((proc_3_t)proc)(argv[2], argv[1], argv[0]);
  152. break;
  153. case 4:
  154. external_return_value = ((proc_4_t)proc)(argv[3], argv[2], argv[1], argv[0]);
  155. break;
  156. case 5:
  157. external_return_value = ((proc_5_t)proc)(argv[4],
  158. argv[3], argv[2], argv[1], argv[0]);
  159. break;
  160. case 6:
  161. external_return_value = ((proc_6_t)proc)(argv[5], argv[4],
  162. argv[3], argv[2], argv[1], argv[0]);
  163. break;
  164. case 7:
  165. external_return_value = ((proc_7_t)proc)(argv[6], argv[5], argv[4],
  166. argv[3], argv[2], argv[1], argv[0]);
  167. break;
  168. case 8:
  169. external_return_value = ((proc_8_t)proc)(argv[7], argv[6], argv[5], argv[4],
  170. argv[3], argv[2], argv[1], argv[0]);
  171. break;
  172. case 9:
  173. external_return_value = ((proc_9_t)proc)(argv[8],
  174. argv[7], argv[6], argv[5], argv[4],
  175. argv[3], argv[2], argv[1], argv[0]);
  176. break;
  177. case 10:
  178. external_return_value = ((proc_10_t)proc)(argv[9], argv[8],
  179. argv[7], argv[6], argv[5], argv[4],
  180. argv[3], argv[2], argv[1], argv[0]);
  181. break;
  182. case 11:
  183. external_return_value = ((proc_11_t)proc)(argv[10], argv[9], argv[8],
  184. argv[7], argv[6], argv[5], argv[4],
  185. argv[3], argv[2], argv[1], argv[0]);
  186. break;
  187. case 12:
  188. external_return_value = ((proc_12_t)proc)(argv[11], argv[10], argv[9], argv[8],
  189. argv[7], argv[6], argv[5], argv[4],
  190. argv[3], argv[2], argv[1], argv[0]);
  191. break;
  192. default:
  193. external_return_value = ((proc_n_t)proc)((int)nargs, (s48_value *)argv);
  194. }
  195. /* Raise an exception if the user neglected to pop off some gc roots. */
  196. if (! s48_release_gc_roots_baseB((char *)gc_roots_marker)) {
  197. s48_raise_scheme_exception(S48_EXCEPTION_GC_PROTECTION_MISMATCH, 0);
  198. }
  199. /* Clear any free stack-blocks off of the top of the stack-block stack and
  200. then longjmp past the corresponding portions of the process stack. */
  201. if (current_stack_block != S48_FALSE &&
  202. STACK_BLOCK_FREE(current_stack_block) == S48_TRUE) {
  203. s48_value bottom_free_block;
  204. do {
  205. bottom_free_block = current_stack_block;
  206. current_stack_block = STACK_BLOCK_NEXT(current_stack_block);
  207. }
  208. while (current_stack_block != S48_FALSE &&
  209. STACK_BLOCK_FREE(current_stack_block) == S48_TRUE);
  210. /* fprintf(stderr, "[Freeing stack blocks from %d to %d]\n",
  211. depth,
  212. callback_depth()); */
  213. longjmp(S48_EXTRACT_VALUE_POINTER(STACK_BLOCK_UNWIND(bottom_free_block),
  214. struct s_jmp_buf)->buf,
  215. CLEANUP_THROW);
  216. }
  217. }
  218. else { /* throwing an exception or uwinding the stack */
  219. /* fprintf(stderr, "[external_call throw; was %d and now %d]\n",
  220. depth,
  221. callback_depth());
  222. fprintf(stderr, "[throw unrolling to %ld]\n", gc_roots_marker); */
  223. s48_release_gc_roots_baseB((char *)gc_roots_marker);
  224. }
  225. /* Check to see if a thread is waiting to return to the next block down. */
  226. if (current_stack_block != S48_FALSE &&
  227. STACK_BLOCK_THREAD(current_stack_block) != S48_FALSE) {
  228. /* fprintf(stderr, "[releasing return at %d]\n", callback_depth()); */
  229. if (throw_reason == EXCEPTION_THROW) {
  230. /* We are in the midst of raising an exception, so we need to piggyback
  231. our exception on that one. */
  232. s48_value old_exception
  233. = s48_resetup_external_exception(S48_EXCEPTION_CALLBACK_RETURN_UNCOVERED,
  234. 2);
  235. s48_push(old_exception);
  236. s48_push(current_stack_block);
  237. external_return_value = S48_UNSPECIFIC;
  238. }
  239. else {
  240. s48_setup_external_exception(S48_EXCEPTION_CALLBACK_RETURN_UNCOVERED, 2);
  241. s48_push(current_stack_block);
  242. s48_push(external_return_value);
  243. external_return_value = S48_UNSPECIFIC;
  244. }
  245. }
  246. return external_return_value;
  247. }
  248. /*
  249. * Call Scheme function `proc' from C. We push the call-back depth, `proc',
  250. * and the arguments on the Scheme stack and then restart the VM. The restarted
  251. * VM calls the Scheme procedure `callback' which wraps the call to `proc' with
  252. * a dynamic-wind. This prevents downward throws back into the call to `proc',
  253. * which C can't handle, and allows the C stack to be cleaned up if an upward
  254. * throw occurs.
  255. *
  256. * The maximum number of arguments is determined by the amount of space reserved
  257. * on the Scheme stack for exceptions. See the definition of stack-slack in
  258. * scheme/vm/stack.scm.
  259. */
  260. s48_value
  261. s48_call_scheme(s48_value proc, long nargs, ...)
  262. {
  263. int i;
  264. va_list arguments;
  265. s48_value value;
  266. s48_value unwind, stack_block;
  267. S48_DECLARE_GC_PROTECT(2);
  268. S48_GC_PROTECT_2(unwind, proc);
  269. va_start(arguments, nargs);
  270. S48_SHARED_BINDING_CHECK(callback_binding);
  271. /* It would be nice to push a list of the arguments, but we have no way
  272. of preserving them across a cons. */
  273. if (nargs < 0 || 12 < nargs) { /* DO NOT INCREASE THIS NUMBER */
  274. s48_value sch_nargs = s48_enter_integer(nargs); /* `proc' is protected */
  275. s48_raise_scheme_exception(S48_EXCEPTION_TOO_MANY_ARGUMENTS_IN_CALLBACK,
  276. 2, proc, sch_nargs);
  277. }
  278. /* fprintf(stderr, "[s48_call, %ld args, depth %d]\n",
  279. nargs, callback_depth()); */
  280. s48_push(S48_UNSPECIFIC); /* placeholder */
  281. s48_push(proc);
  282. for (i = 0; i < nargs; i++)
  283. s48_push(va_arg(arguments, s48_value));
  284. va_end(arguments);
  285. /* With everything safely on the stack we can do the necessary allocation. */
  286. unwind = S48_MAKE_VALUE(struct s_jmp_buf);
  287. S48_EXTRACT_VALUE(unwind, struct s_jmp_buf) = current_return_point;
  288. stack_block = s48_make_record(stack_block_type_binding);
  289. STACK_BLOCK_UNWIND(stack_block) = unwind;
  290. STACK_BLOCK_PROC(stack_block) = current_procedure;
  291. STACK_BLOCK_NEXT(stack_block) = current_stack_block;
  292. STACK_BLOCK_FREE(stack_block) = S48_FALSE;
  293. STACK_BLOCK_THREAD(stack_block) = S48_FALSE;
  294. S48_GC_UNPROTECT(); /* no more references to `unwind' or `proc'. */
  295. current_stack_block = stack_block;
  296. /* if(s48_stack_ref(nargs + 1) != S48_UNSPECIFIC)
  297. fprintf(stderr, "[stack_block set missed]\n"); */
  298. s48_stack_setB(nargs + 1, stack_block);
  299. /* fprintf(stderr, "[s48_call, %ld args, depth %d, off we go]\n",
  300. nargs, callback_depth()); */
  301. value = s48_restart(S48_UNSAFE_SHARED_BINDING_REF(callback_binding),
  302. nargs + 2);
  303. for (;s48_Scallback_return_stack_blockS != current_stack_block;) {
  304. if (s48_Scallback_return_stack_blockS == S48_FALSE) {
  305. /* fprintf(stderr, "[s48_call returning from VM %ld]\n", callback_depth()); */
  306. exit(value);
  307. }
  308. else {
  309. /* Someone has returned (because of threads) to the wrong section of the
  310. C stack. We call back to a Scheme procedure that will suspend until
  311. out block is at the top of the stack. */
  312. s48_push(s48_Scallback_return_stack_blockS);
  313. s48_push(S48_UNSAFE_SHARED_BINDING_REF(delay_callback_return_binding));
  314. s48_push(s48_Scallback_return_stack_blockS);
  315. s48_push(value);
  316. /* fprintf(stderr, "[Premature return, %ld args, depth %d, back we go]\n",
  317. nargs, callback_depth()); */
  318. s48_disable_interruptsB();
  319. value = s48_restart(S48_UNSAFE_SHARED_BINDING_REF(callback_binding), 4);
  320. }
  321. }
  322. /* Restore the state of the current stack block. */
  323. unwind = STACK_BLOCK_UNWIND(current_stack_block);
  324. current_return_point = S48_EXTRACT_VALUE(unwind, struct s_jmp_buf);
  325. current_procedure = STACK_BLOCK_PROC(current_stack_block);
  326. current_stack_block = STACK_BLOCK_NEXT(current_stack_block);
  327. /* fprintf(stderr, "[s48_call returns from depth %d]\n", callback_depth()); */
  328. return value;
  329. }
  330. /*
  331. * Because the top of the stack is cleared on the return from every external
  332. * call, this doesn't have to do anything but exist.
  333. */
  334. static s48_value
  335. s48_clear_stack_top()
  336. {
  337. /* fprintf(stderr, "[Clearing stack top]\n"); */
  338. return S48_UNSPECIFIC;
  339. }
  340. /*
  341. * For testing callbacks. This just calls its argument on the specified number
  342. * of values.
  343. */
  344. static s48_value
  345. s48_trampoline(s48_value proc, s48_value nargs)
  346. {
  347. fprintf(stderr, "[C trampoline, %ld args]\n", S48_UNSAFE_EXTRACT_FIXNUM(nargs));
  348. switch (s48_extract_fixnum(nargs)) {
  349. case -2: {
  350. S48_DECLARE_GC_PROTECT(1);
  351. S48_GC_PROTECT_1(proc);
  352. return S48_FALSE;
  353. }
  354. case -1: {
  355. long n = - s48_extract_integer(proc);
  356. fprintf(stderr, "[extract magnitude is %ld (%lx)]\n", n, n);
  357. return s48_enter_integer(n);
  358. }
  359. case 0: {
  360. s48_value value = s48_call_scheme(proc, 0);
  361. if (value == S48_FALSE)
  362. s48_raise_string_os_error("trampoline bouncing");
  363. return value;
  364. }
  365. case 1:
  366. return s48_call_scheme(proc, 1, s48_enter_fixnum(100));
  367. case 2:
  368. return s48_call_scheme(proc, 2, s48_enter_fixnum(100), s48_enter_fixnum(200));
  369. case 3:
  370. return s48_call_scheme(proc, 3, s48_enter_fixnum(100), s48_enter_fixnum(200),
  371. s48_enter_fixnum(300));
  372. default:
  373. s48_raise_range_error(nargs, s48_enter_fixnum(0), s48_enter_fixnum(3));
  374. return S48_UNDEFINED; /* not that we ever get here */
  375. }
  376. }
  377. static s48_value
  378. s48_system(s48_value string)
  379. {
  380. return s48_enter_integer(system((string == S48_FALSE)
  381. ? NULL
  382. : s48_extract_string(string)));
  383. }
  384. /********************************/
  385. /*
  386. * Raising exceptions. We push the arguments on the stack end then throw out
  387. * of the most recent call from Scheme.
  388. *
  389. * The maximum number of arguments is determined by the amount of space reserved
  390. * on the Scheme stack for exceptions. See the definition of stack-slack in
  391. * scheme/vm/stack.scm.
  392. */
  393. void
  394. s48_raise_scheme_exception(long why, long nargs, ...)
  395. {
  396. int i;
  397. va_list irritants;
  398. va_start(irritants, nargs);
  399. s48_setup_external_exception(why, nargs + 1);
  400. if (10 < nargs) { /* DO NOT INCREASE THIS NUMBER */
  401. fprintf(stderr, "s48_raise_scheme_exception() called with more than 10 arguments, discarding surplus\n");
  402. nargs = 10;
  403. }
  404. s48_push(current_procedure);
  405. for (i = 0; i < nargs; i++)
  406. s48_push(va_arg(irritants, s48_value));
  407. va_end(irritants);
  408. external_return_value = S48_UNSPECIFIC;
  409. longjmp(current_return_point.buf, EXCEPTION_THROW);
  410. }
  411. /* Specific exceptions */
  412. void
  413. s48_raise_argument_type_error(s48_value value) {
  414. s48_raise_scheme_exception(S48_EXCEPTION_WRONG_TYPE_ARGUMENT, 1, value);
  415. }
  416. /* Superceded name for preceding function, retained for compatibility. */
  417. void
  418. s48_raise_argtype_error(s48_value value) {
  419. s48_raise_scheme_exception(S48_EXCEPTION_WRONG_TYPE_ARGUMENT, 1, value);
  420. }
  421. void
  422. s48_raise_argument_number_error(s48_value value, s48_value min, s48_value max) {
  423. s48_raise_scheme_exception(S48_EXCEPTION_WRONG_NUMBER_OF_ARGUMENTS,
  424. 3, value, min, max);
  425. }
  426. /* Superceded name for preceding function, retained for compatibility. */
  427. void
  428. s48_raise_argnumber_error(s48_value value, s48_value min, s48_value max) {
  429. s48_raise_scheme_exception(S48_EXCEPTION_WRONG_NUMBER_OF_ARGUMENTS,
  430. 3, value, min, max);
  431. }
  432. void
  433. s48_raise_range_error(s48_value value, s48_value min, s48_value max) {
  434. s48_raise_scheme_exception(S48_EXCEPTION_INDEX_OUT_OF_RANGE,
  435. 3, value, min, max);
  436. }
  437. void
  438. s48_raise_closed_channel_error() {
  439. s48_raise_scheme_exception(S48_EXCEPTION_CLOSED_CHANNEL, 0);
  440. }
  441. void
  442. s48_raise_os_error(int the_errno) {
  443. s48_raise_scheme_exception(S48_EXCEPTION_OS_ERROR, 2,
  444. s48_enter_fixnum(the_errno),
  445. s48_enter_string(strerror(the_errno)));
  446. }
  447. void
  448. s48_raise_string_os_error(char *reason) {
  449. s48_raise_scheme_exception(S48_EXCEPTION_OS_ERROR, 1,
  450. s48_enter_string(reason));
  451. }
  452. void
  453. s48_raise_out_of_memory_error() {
  454. s48_raise_scheme_exception(S48_EXCEPTION_OUT_OF_MEMORY, 0);
  455. }
  456. /********************************/
  457. /* Support routines for external code */
  458. /*
  459. * Type-safe procedures for checking types and dereferencing and setting slots.
  460. */
  461. int
  462. s48_stob_has_type(s48_value thing, int type)
  463. {
  464. return S48_STOB_P(thing) && (S48_STOB_TYPE(thing) == type);
  465. }
  466. long
  467. s48_stob_length(s48_value thing, int type)
  468. {
  469. if (!(S48_STOB_P(thing) && (S48_STOB_TYPE(thing) == type)))
  470. s48_raise_argument_type_error(thing);
  471. return S48_STOB_DESCRIPTOR_LENGTH(thing);
  472. }
  473. long
  474. s48_stob_byte_length(s48_value thing, int type)
  475. {
  476. if (!(S48_STOB_P(thing) && (S48_STOB_TYPE(thing) == type)))
  477. s48_raise_argument_type_error(thing);
  478. if (type == S48_STOBTYPE_STRING)
  479. return S48_STOB_BYTE_LENGTH(thing) - 1;
  480. else
  481. return S48_STOB_BYTE_LENGTH(thing);
  482. }
  483. s48_value
  484. s48_stob_ref(s48_value thing, int type, long offset)
  485. {
  486. long length;
  487. if (!(S48_STOB_P(thing) && (S48_STOB_TYPE(thing) == type)))
  488. s48_raise_argument_type_error(thing);
  489. length = S48_STOB_DESCRIPTOR_LENGTH(thing);
  490. if (offset < 0 || length <= offset)
  491. s48_raise_range_error(s48_enter_integer(offset),
  492. S48_UNSAFE_ENTER_FIXNUM(0),
  493. S48_UNSAFE_ENTER_FIXNUM(length - 1));
  494. return S48_STOB_REF(thing, offset);
  495. }
  496. void
  497. s48_stob_set(s48_value thing, int type, long offset, s48_value value)
  498. {
  499. long length;
  500. if (!(S48_STOB_P(thing) &&
  501. (S48_STOB_TYPE(thing) == type) &&
  502. !S48_STOB_IMMUTABLEP(thing)))
  503. s48_raise_argument_type_error(thing);
  504. length = S48_STOB_DESCRIPTOR_LENGTH(thing);
  505. if (offset < 0 || length <= offset)
  506. s48_raise_range_error(s48_enter_integer(offset),
  507. S48_UNSAFE_ENTER_FIXNUM(0),
  508. S48_UNSAFE_ENTER_FIXNUM(length - 1));
  509. S48_STOB_SET(thing, offset, value);
  510. }
  511. char
  512. s48_stob_byte_ref(s48_value thing, int type, long offset)
  513. {
  514. long length;
  515. if (!(S48_STOB_P(thing) && (S48_STOB_TYPE(thing) == type)))
  516. s48_raise_argument_type_error(thing);
  517. length = (type == S48_STOBTYPE_STRING) ?
  518. S48_STOB_BYTE_LENGTH(thing) - 1 :
  519. S48_STOB_BYTE_LENGTH(thing);
  520. if (offset < 0 || length <= offset)
  521. s48_raise_range_error(s48_enter_integer(offset),
  522. S48_UNSAFE_ENTER_FIXNUM(0),
  523. S48_UNSAFE_ENTER_FIXNUM(length - 1));
  524. return S48_STOB_BYTE_REF(thing, offset);
  525. }
  526. void
  527. s48_stob_byte_set(s48_value thing, int type, long offset, char value)
  528. {
  529. long length;
  530. if (!(S48_STOB_P(thing) && (S48_STOB_TYPE(thing) == type)))
  531. s48_raise_argument_type_error(thing);
  532. length = (type == S48_STOBTYPE_STRING) ?
  533. S48_STOB_BYTE_LENGTH(thing) - 1 :
  534. S48_STOB_BYTE_LENGTH(thing);
  535. if (offset < 0 || length <= offset)
  536. s48_raise_range_error(s48_enter_integer(offset),
  537. S48_UNSAFE_ENTER_FIXNUM(0),
  538. S48_UNSAFE_ENTER_FIXNUM(length - 1));
  539. S48_STOB_BYTE_SET(thing, offset, value);
  540. }
  541. void *
  542. s48_value_pointer(s48_value value)
  543. {
  544. S48_CHECK_VALUE(value);
  545. return S48_ADDRESS_AFTER_HEADER(value, void *);
  546. }
  547. /********************************/
  548. /* Numbers, characters, and pointers. */
  549. /*
  550. * These two functions have the same range as the unsafe macros, but they signal
  551. * an error if things go wrong, instead of silently producing garbage. Unlike
  552. * the integer versions they cannot cause a GC.
  553. */
  554. s48_value
  555. s48_enter_fixnum(long value)
  556. {
  557. if (value < S48_MIN_FIXNUM_VALUE || S48_MAX_FIXNUM_VALUE < value)
  558. s48_raise_argument_type_error(s48_enter_integer(value));
  559. return S48_UNSAFE_ENTER_FIXNUM(value);
  560. }
  561. long
  562. s48_extract_fixnum(s48_value value)
  563. {
  564. if (! S48_FIXNUM_P(value))
  565. s48_raise_argument_type_error(value);
  566. return S48_UNSAFE_EXTRACT_FIXNUM(value);
  567. }
  568. /* If we have a fixnum we just extract it. For bignums call the
  569. * functions in bignum.c.
  570. */
  571. long
  572. s48_extract_integer(s48_value value)
  573. {
  574. if (S48_FIXNUM_P(value))
  575. return S48_UNSAFE_EXTRACT_FIXNUM(value);
  576. if (S48_BIGNUM_P(value)){
  577. bignum_type bignum = S48_ADDRESS_AFTER_HEADER(value, long);
  578. if (! s48_bignum_fits_in_word_p(bignum, 32, 1))
  579. s48_raise_argument_type_error (value);
  580. else return s48_bignum_to_long(bignum);
  581. }
  582. else s48_raise_argument_type_error(value);
  583. }
  584. /*
  585. * Doubles and characters are straightforward.
  586. */
  587. s48_value
  588. s48_enter_double(double value)
  589. {
  590. s48_value obj;
  591. obj = s48_allocate_stob(S48_STOBTYPE_DOUBLE, sizeof(double));
  592. S48_UNSAFE_EXTRACT_DOUBLE(obj) = value;
  593. return obj;
  594. }
  595. double
  596. s48_extract_double(s48_value s48_double)
  597. {
  598. if (! S48_DOUBLE_P(s48_double))
  599. s48_raise_argument_type_error(s48_double);
  600. return S48_UNSAFE_EXTRACT_DOUBLE(s48_double);
  601. }
  602. s48_value
  603. s48_enter_char(unsigned char a_char)
  604. {
  605. if (a_char > 255)
  606. s48_raise_range_error(s48_enter_fixnum(a_char),
  607. s48_enter_fixnum(0),
  608. s48_enter_fixnum(255));
  609. return S48_UNSAFE_ENTER_CHAR(a_char);
  610. }
  611. unsigned char
  612. s48_extract_char(s48_value a_char)
  613. {
  614. if (! S48_CHAR_P(a_char))
  615. s48_raise_argument_type_error(a_char);
  616. return S48_UNSAFE_EXTRACT_CHAR(a_char);
  617. }
  618. /********************************/
  619. /* Allocation */
  620. s48_value
  621. s48_enter_pointer(void *pointer)
  622. {
  623. s48_value obj;
  624. obj = s48_allocate_stob(S48_STOBTYPE_BYTE_VECTOR, sizeof(void *));
  625. *(S48_ADDRESS_AFTER_HEADER(obj, void *)) = pointer;
  626. return obj;
  627. }
  628. s48_value
  629. s48_cons(s48_value v1, s48_value v2)
  630. {
  631. s48_value obj;
  632. S48_DECLARE_GC_PROTECT(2);
  633. S48_GC_PROTECT_2(v1, v2);
  634. obj = s48_allocate_stob(S48_STOBTYPE_PAIR, 2);
  635. S48_UNSAFE_SET_CAR(obj, v1);
  636. S48_UNSAFE_SET_CDR(obj, v2);
  637. S48_GC_UNPROTECT();
  638. return obj;
  639. }
  640. s48_value
  641. s48_make_weak_pointer(s48_value value)
  642. {
  643. s48_value obj;
  644. S48_DECLARE_GC_PROTECT(1);
  645. S48_GC_PROTECT_1(value);
  646. obj = s48_allocate_stob(S48_STOBTYPE_WEAK_POINTER, 1);
  647. S48_STOB_SET(obj, 0, value);
  648. S48_GC_UNPROTECT();
  649. return obj;
  650. }
  651. /*
  652. * Entering and extracting strings.
  653. */
  654. s48_value
  655. s48_enter_substring(char *str, long length)
  656. {
  657. s48_value obj = s48_allocate_stob(S48_STOBTYPE_STRING, length + 1);
  658. memcpy(S48_UNSAFE_EXTRACT_STRING(obj), str, length);
  659. *(S48_UNSAFE_EXTRACT_STRING(obj) + length) = '\0';
  660. return obj;
  661. }
  662. s48_value
  663. s48_enter_string(char *str)
  664. {
  665. return s48_enter_substring(str, strlen(str));
  666. }
  667. char *
  668. s48_extract_string(s48_value string)
  669. {
  670. S48_CHECK_STRING(string);
  671. return S48_UNSAFE_EXTRACT_STRING(string);
  672. }
  673. /*
  674. * Entering and extracting byte vectors.
  675. */
  676. s48_value
  677. s48_enter_byte_vector(char *bytes, long length)
  678. {
  679. s48_value obj = s48_allocate_stob(S48_STOBTYPE_BYTE_VECTOR, length);
  680. memcpy(S48_UNSAFE_EXTRACT_STRING(obj), bytes, length);
  681. return obj;
  682. }
  683. char *
  684. s48_extract_byte_vector(s48_value byte_vector)
  685. {
  686. S48_CHECK_VALUE(byte_vector);
  687. return S48_UNSAFE_EXTRACT_STRING(byte_vector);
  688. }
  689. /*
  690. * Making various kinds of stored objects.
  691. */
  692. s48_value
  693. s48_make_string(int length, char init)
  694. {
  695. s48_value obj = s48_allocate_stob(S48_STOBTYPE_STRING, length+1);
  696. memset(S48_UNSAFE_EXTRACT_STRING(obj), init, length);
  697. S48_UNSAFE_EXTRACT_STRING(obj)[length] = '\0';
  698. return obj;
  699. }
  700. s48_value
  701. s48_make_vector(int length, s48_value init)
  702. {
  703. int i;
  704. s48_value obj;
  705. S48_DECLARE_GC_PROTECT(1);
  706. S48_GC_PROTECT_1(init);
  707. obj = s48_allocate_stob(S48_STOBTYPE_VECTOR, length);
  708. for (i = 0; i < length; ++i)
  709. S48_UNSAFE_VECTOR_SET(obj, i, init);
  710. S48_GC_UNPROTECT();
  711. return obj;
  712. }
  713. s48_value
  714. s48_make_byte_vector(int length)
  715. {
  716. return s48_allocate_stob(S48_STOBTYPE_BYTE_VECTOR, length);
  717. }
  718. s48_value
  719. s48_make_record(s48_value type_shared_binding)
  720. {
  721. int i, number_of_fields;
  722. s48_value record = S48_FALSE;
  723. s48_value record_type = S48_FALSE;
  724. S48_DECLARE_GC_PROTECT(1);
  725. S48_GC_PROTECT_1(record_type);
  726. S48_SHARED_BINDING_CHECK(type_shared_binding);
  727. S48_SHARED_BINDING_CHECK(the_record_type_binding);
  728. record_type = S48_SHARED_BINDING_REF(type_shared_binding);
  729. s48_check_record_type(record_type, the_record_type_binding);
  730. number_of_fields =
  731. S48_UNSAFE_EXTRACT_FIXNUM(S48_RECORD_TYPE_NUMBER_OF_FIELDS(record_type));
  732. record = s48_allocate_stob(S48_STOBTYPE_RECORD, number_of_fields + 1);
  733. S48_UNSAFE_RECORD_SET(record, -1, record_type);
  734. for (i = 0; i < number_of_fields; ++i)
  735. S48_UNSAFE_RECORD_SET(record, i, S48_UNSPECIFIC);
  736. S48_GC_UNPROTECT();
  737. return record;
  738. }
  739. /*
  740. * Raise an exception if `record' is not a record whose type is the one
  741. * found in `type_binding'.
  742. */
  743. void
  744. s48_check_record_type(s48_value record, s48_value type_binding)
  745. {
  746. if (! S48_RECORD_P(S48_SHARED_BINDING_REF(type_binding)))
  747. s48_raise_scheme_exception(S48_EXCEPTION_UNBOUND_EXTERNAL_NAME, 1,
  748. S48_SHARED_BINDING_NAME(type_binding));
  749. if ((! S48_RECORD_P(record)) ||
  750. (S48_UNSAFE_SHARED_BINDING_REF(type_binding) !=
  751. S48_UNSAFE_RECORD_REF(record, -1)))
  752. s48_raise_argument_type_error(record);
  753. }
  754. long
  755. s48_length(s48_value list)
  756. {
  757. long i = 0;
  758. while (!(S48_EQ(list, S48_NULL)))
  759. {
  760. list = S48_CDR(list);
  761. ++i;
  762. }
  763. return S48_UNSAFE_ENTER_FIXNUM(i);
  764. }