45 #ifndef CGU_EXTENSION_H
46 #define CGU_EXTENSION_H
483 #include <libguile.h>
486 #ifndef DOXYGEN_PARSING
489 namespace Extension {
496 enum VectorDeleteType {Long, Double, String};
498 struct VectorDeleteArgs {
499 VectorDeleteType type;
505 extern bool init_mutex();
512 static inline SCM cgu_format_try_handler(
void* data) {
513 using Cgu::Extension::FormatArgs;
514 FormatArgs* format_args =
static_cast<FormatArgs*
>(data);
515 return scm_simple_format(SCM_BOOL_F, format_args->text, format_args->rest);
517 static inline SCM cgu_format_catch_handler(
void*, SCM, SCM) {
520 static inline void* cgu_guile_wrapper(
void* data) {
535 static inline void cgu_delete_vector(
void* data) {
536 using Cgu::Extension::VectorDeleteArgs;
537 VectorDeleteArgs* args =
static_cast<VectorDeleteArgs*
>(data);
538 switch (args->type) {
539 case Cgu::Extension::Long:
540 delete static_cast<std::vector<long>*
>(args->vec);
542 case Cgu::Extension::Double:
543 delete static_cast<std::vector<double>*
>(args->vec);
545 case Cgu::Extension::String:
546 delete static_cast<std::vector<std::string>*
>(args->vec);
549 g_critical(
"Incorrect argument passed to cgu_delete_vector");
553 static inline void cgu_unlock_module_mutex(
void*) {
556 Cgu::Extension::get_user_module_mutex()->unlock();
559 #endif // DOXYGEN_PARSING
563 namespace Extension {
569 virtual const char*
what()
const throw() {
return (
const char*)message.
get();}
570 const char*
guile_text()
const throw() {
return (
const char*)guile_message.
get();}
572 message(g_strdup_printf(
"Cgu::Extension::GuileException: %s", msg)),
573 guile_message(g_strdup(msg)) {}
581 virtual const char*
what()
const throw() {
return (
const char*)message.
get();}
582 const char*
err_text()
const throw() {
return (
const char*)err_message.
get();}
584 message(g_strdup_printf(
"Cgu::Extension::ReturnValueError: %s", msg)),
585 err_message(g_strdup(msg)) {}
592 virtual const char*
what()
const throw() {
return (
const char*)message.
get();}
594 message(g_strdup_printf(
"Cgu::Extension::WrapperError: %s", msg)) {}
598 #ifndef DOXYGEN_PARSING
601 struct GuileWrapperArgs {
602 Ret (*translator)(SCM);
606 std::string* guile_except;
607 std::string* guile_ret_val_err;
608 std::string* gen_err;
616 void guile_wrapper_cb2(GuileWrapperArgs<Ret> args) {
619 scm = scm_eval_string_in_module(scm_from_utf8_string(args.loader->c_str()),
620 scm_c_resolve_module(
"guile-user"));
624 throw std::bad_alloc();
626 scm_dynwind_begin(scm_t_dynwind_flags(0));
627 scm_dynwind_unwind_handler(&cgu_unlock_module_mutex, 0, SCM_F_WIND_EXPLICITLY);
628 get_user_module_mutex()->lock();
636 SCM new_mod = scm_call_0(scm_c_public_ref(
"guile",
"make-fresh-user-module"));
637 #if SCM_MAJOR_VERSION >= 3
638 scm_call_2(scm_c_public_ref(
"guile",
"set-module-declarative?!"),
639 new_mod, SCM_BOOL_F);
643 scm = scm_eval_string_in_module(scm_from_utf8_string(args.loader->c_str()),
665 #ifndef CGU_GUILE_HAS_BROKEN_LINKING
666 scm_dynwind_begin(scm_t_dynwind_flags(0));
667 scm_dynwind_block_asyncs();
673 bool badalloc =
false;
675 *args.retval = (*args.translator)(scm);
701 *args.guile_ret_val_err = e.
err_text();
707 catch (std::exception& e) {
709 *args.gen_err = e.what();
717 *args.gen_err =
"C++ exception thrown in guile_wrapper_cb()";
723 #ifndef CGU_GUILE_HAS_BROKEN_LINKING
726 if (badalloc)
throw std::bad_alloc();
730 Ret exec_impl(
const std::string& preamble,
731 const std::string& file,
732 Ret (*translator)(SCM),
741 loader +=
"((lambda ()";
747 loader +=
"primitive-load \"";
752 "(lambda (key . details)"
753 "(cons \"***cgu-guile-exception***\" (cons key details))))";
760 std::string guile_except;
761 std::string guile_ret_val_err;
783 GuileWrapperArgs<Ret> args = {translator,
797 if (scm_with_guile(&cgu_guile_wrapper, cb.get()))
798 throw WrapperError(
"cgu_guile_wrapper() has trapped std::bad_alloc");
799 if (!guile_except.empty())
800 throw GuileException(guile_except.c_str());
801 if (!guile_ret_val_err.empty())
802 throw ReturnValueError(guile_ret_val_err.c_str());
803 if (!gen_err.empty())
804 throw WrapperError(gen_err.c_str());
806 throw WrapperError(
"the preamble or translator threw a native guile exception");
810 #endif // DOXYGEN_PARSING
846 SCM ret = SCM_BOOL_F;
847 int length = scm_to_int(scm_length(args));
849 SCM first = scm_car(args);
850 if (scm_is_true(scm_string_p(first))) {
853 ret = scm_string_append(scm_list_4(scm_from_utf8_string(
"Exception "),
854 scm_symbol_to_string(key),
855 scm_from_utf8_string(
": "),
859 SCM second = scm_cadr(args);
860 if (scm_is_true(scm_string_p(second))) {
862 SCM text = scm_string_append(scm_list_n(scm_from_utf8_string(
"Exception "),
863 scm_symbol_to_string(key),
864 scm_from_utf8_string(
" in procedure "),
866 scm_from_utf8_string(
": "),
872 SCM third = scm_caddr(args);
873 if (scm_is_false(third))
875 else if (scm_is_true(scm_list_p(third))) {
876 FormatArgs format_args = {text, third};
877 ret = scm_internal_catch(SCM_BOOL_T,
878 &cgu_format_try_handler,
880 &cgu_format_catch_handler,
890 if (scm_is_false(ret)) {
893 ret = scm_simple_format(SCM_BOOL_F,
894 scm_from_utf8_string(
"Exception ~S: ~S"),
895 scm_list_2(key, args));
928 if (scm_is_false(scm_list_p(scm))
929 || scm_is_true(scm_null_p(scm)))
return;
930 SCM first = scm_car(scm);
931 if (scm_is_true(scm_string_p(first))) {
933 const char* text = 0;
937 scm_dynwind_begin(scm_t_dynwind_flags(0));
938 char* car = scm_to_utf8_stringn(first, &len);
948 scm_dynwind_unwind_handler(&free, car, scm_t_wind_flags(0));
949 if (len == strlen(
"***cgu-guile-exception***")
950 && !strncmp(car,
"***cgu-guile-exception***", len)) {
955 text = scm_to_utf8_stringn(str, &len);
1009 if (scm_is_false(scm_list_p(scm)))
1015 scm_dynwind_begin(scm_t_dynwind_flags(0));
1023 bool badalloc =
false;
1024 const char* rv_error = 0;
1025 std::vector<long>* res = 0;
1026 VectorDeleteArgs* args = 0;
1032 res =
new std::vector<long>;
1035 args =
new VectorDeleteArgs;
1052 scm_dynwind_unwind_handler(&cgu_delete_vector, args, scm_t_wind_flags(0));
1058 SCM guile_vec = scm_vector(scm);
1081 size_t length = scm_to_size_t(scm_vector_length(guile_vec));
1083 res->reserve(length);
1088 for (
size_t count = 0;
1089 count < length && !rv_error && !badalloc;
1091 SCM item = scm_vector_ref(guile_vec, scm_from_size_t(count));
1092 if (scm_is_false(scm_integer_p(item)))
1093 rv_error =
"scheme code did not evaluate to a homogeneous list of integer\n";
1095 SCM min = scm_from_long(std::numeric_limits<long>::min());
1096 SCM max = scm_from_long(std::numeric_limits<long>::max());
1097 if (scm_is_false(scm_leq_p(item, max)) || scm_is_false(scm_geq_p(item, min)))
1098 rv_error =
"scheme code evaluated out of range for long\n";
1101 res->push_back(scm_to_long(item));
1114 std::auto_ptr<std::vector<long> > up_res(res);
1115 std::auto_ptr<VectorDeleteArgs> up_args(args);
1116 if (badalloc)
throw std::bad_alloc();
1167 if (scm_is_false(scm_list_p(scm)))
1173 scm_dynwind_begin(scm_t_dynwind_flags(0));
1181 bool badalloc =
false;
1182 const char* rv_error = 0;
1183 std::vector<double>* res = 0;
1184 VectorDeleteArgs* args = 0;
1190 res =
new std::vector<double>;
1193 args =
new VectorDeleteArgs;
1194 args->type = Double;
1210 scm_dynwind_unwind_handler(&cgu_delete_vector, args, scm_t_wind_flags(0));
1216 SCM guile_vec = scm_vector(scm);
1239 size_t length = scm_to_size_t(scm_vector_length(guile_vec));
1241 res->reserve(length);
1246 for (
size_t count = 0;
1247 count < length && !rv_error && !badalloc;
1249 SCM item = scm_vector_ref(guile_vec, scm_from_size_t(count));
1250 if (scm_is_false(scm_real_p(item)))
1251 rv_error =
"scheme code did not evaluate to a homogeneous list of real numbers\n";
1253 SCM min = scm_from_double(-std::numeric_limits<double>::max());
1254 SCM max = scm_from_double(std::numeric_limits<double>::max());
1255 if (scm_is_false(scm_leq_p(item, max)) || scm_is_false(scm_geq_p(item, min)))
1256 rv_error =
"scheme code evaluated out of range for double\n";
1259 res->push_back(scm_to_double(item));
1272 std::auto_ptr<std::vector<double> > up_res(res);
1273 std::auto_ptr<VectorDeleteArgs> up_args(args);
1274 if (badalloc)
throw std::bad_alloc();
1325 if (scm_is_false(scm_list_p(scm)))
1331 scm_dynwind_begin(scm_t_dynwind_flags(0));
1339 bool badalloc =
false;
1340 const char* rv_error = 0;
1341 std::vector<std::string>* res = 0;
1342 VectorDeleteArgs* args = 0;
1348 res =
new std::vector<std::string>;
1351 args =
new VectorDeleteArgs;
1352 args->type = String;
1368 scm_dynwind_unwind_handler(&cgu_delete_vector, args, scm_t_wind_flags(0));
1374 SCM guile_vec = scm_vector(scm);
1397 size_t length = scm_to_size_t(scm_vector_length(guile_vec));
1399 res->reserve(length);
1404 for (
size_t count = 0;
1405 count < length && !rv_error && !badalloc;
1407 SCM item = scm_vector_ref(guile_vec, scm_from_size_t(count));
1408 if (scm_is_false(scm_string_p(item)))
1409 rv_error =
"scheme code did not evaluate to a homogeneous list of string\n";
1415 char* str = scm_to_utf8_stringn(item, &len);
1417 res->push_back(std::string(str, len));
1430 std::auto_ptr<std::vector<std::string> > up_res(res);
1431 std::auto_ptr<VectorDeleteArgs> up_args(args);
1432 if (badalloc)
throw std::bad_alloc();
1473 if (scm_is_false(scm_integer_p(scm)))
1475 SCM min = scm_from_long(std::numeric_limits<long>::min());
1476 SCM max = scm_from_long(std::numeric_limits<long>::max());
1477 if (scm_is_false(scm_leq_p(scm, max)) || scm_is_false(scm_geq_p(scm, min)))
1479 return scm_to_long(scm);
1523 if (scm_is_false(scm_real_p(scm)))
1525 SCM min = scm_from_double(-std::numeric_limits<double>::max());
1526 SCM max = scm_from_double(std::numeric_limits<double>::max());
1527 if (scm_is_false(scm_leq_p(scm, max)) || scm_is_false(scm_geq_p(scm, min)))
1529 return scm_to_double(scm);
1569 if (scm_is_false(scm_string_p(scm)))
1576 return std::string(s.
get(), len);
1697 template <
class Ret>
1698 Ret
exec(
const std::string& preamble,
1699 const std::string& file,
1700 Ret (*translator)(SCM)) {
1701 return exec_impl(preamble, file, translator,
false);
1780 template <
class Ret>
1782 const std::string& file,
1783 Ret (*translator)(SCM)) {
1784 return exec_impl(preamble, file, translator,
true);
1791 #endif // CGU_EXTENSION_H