Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add MRI 1.8 Support #163

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions binding-mri/binding-mri.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@
#include "boost-hash.h"

#include <ruby.h>
#ifndef RUBY_LEGACY_VERSION
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this defined by a ruby header, or do we define it?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I define it. Problem is that checking for 1.8 vs. 1.9 is ugly to write so I introduced a new macro for 1.8 only. You can suggest a better macro name :D

#include <ruby/encoding.h>
#endif

#include <assert.h>
#include <string>
Expand Down Expand Up @@ -204,7 +206,7 @@ RB_METHOD(mriP)
RB_METHOD(mkxpDataDirectory)
{
RB_UNUSED_PARAM;

const std::string &path = shState->config().customDataPath;
const char *s = path.empty() ? "." : path.c_str();

Expand Down Expand Up @@ -580,9 +582,14 @@ static void mriBindingExecute()
* stdio streams on some platforms (eg. Windows) */
int argc = 0;
char **argv = 0;
ruby_sysinit(&argc, &argv);

#if RUBY_API_VERSION_MAJOR == 1
ruby_init();
#else
ruby_sysinit(&argc, &argv);
ruby_setup();
#endif

rb_enc_set_default_external(rb_enc_from_encoding(rb_utf8_encoding()));

Config &conf = shState->rtData().config;
Expand Down
123 changes: 123 additions & 0 deletions binding-mri/binding-util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,11 @@ void raiseRbExc(const Exception &exc)
void
raiseDisposedAccess(VALUE self)
{
#ifdef RUBY_LEGACY_VERSION
const char *klassName = rb_class2name(self);
#else
const char *klassName = RTYPEDDATA_TYPE(self)->wrap_struct_name;
#endif
char buf[32];

strncpy(buf, klassName, sizeof(buf));
Expand Down Expand Up @@ -319,3 +323,122 @@ rb_get_args(int argc, VALUE *argv, const char *format, ...)

return argI;
}

#if RUBY_API_VERSION_MAJOR == 1
NORETURN(void rb_error_arity(int, int, int))
{
assert(false);
}

#if RUBY_API_VERSION_MINOR == 8
/*
Functions providing Ruby 1.8 compatibililty.
All encoding related functions return dummy values because mkxp only uses them
to retrieve the UTF-8 encoding.
*/
VALUE rb_sprintf_vararg(const char* fmt, va_list args) {
char buf[4096];
int result = vsnprintf(buf, sizeof(buf), fmt, args);

if (result < 0) {
buf[0] = '\0';
}

return rb_str_new2(buf);
}

VALUE rb_sprintf(const char* fmt, ...)
{
va_list args;
va_start(args, fmt);
VALUE val = rb_sprintf_vararg(fmt, args);
va_end(args);

return val;
}

VALUE rb_data_typed_object_alloc(VALUE klass, void *datap, const rb_data_type_t *rbType)
{
return rb_data_object_alloc(klass, 0, rbType->function.dmark, rbType->function.dfree);
}

void *rb_check_typeddata(VALUE value, const rb_data_type_t* typed)
{
// FIXME: Won't work because rb_typeddata_is_kind_of is not implemented
if (!rb_typeddata_is_kind_of(value, typed)) {
rb_raise(getRbData()->exc[RGSS],
"wrong data type %s (expected %s)", rb_class2name(value), typed->wrap_struct_name
);
}

return RTYPEDDATA_DATA(value);
}

VALUE rb_enc_str_new(const char* ch, long len, rb_encoding*)
{
// Encoding is ignored
return rb_str_new(ch, len);
}

rb_encoding *rb_utf8_encoding(void)
{
// not relevant
return NULL;
}

void rb_enc_set_default_external(VALUE)
{
// not relevant
}

VALUE rb_enc_from_encoding(rb_encoding*)
{
// not relevant
return Qnil;
}

VALUE rb_str_catf(VALUE value, const char* fmt, ...)
{
va_list args;
va_start(args, fmt);
VALUE second = rb_sprintf_vararg(fmt, args);
va_end(args);

return rb_str_concat(value, second);
}

VALUE rb_errinfo(void)
{
return ruby_errinfo;
}

int rb_typeddata_is_kind_of(VALUE value, const rb_data_type_t* typed)
{
// FIXME: rb_typeddata_is_kind_of not implemented
return 1;
}

VALUE rb_file_open_str(VALUE filename, const char* mode)
{
return rb_file_open(RB_OBJ_STRING(filename), mode);
}

VALUE rb_enc_associate_index(VALUE, int)
{
// not relevant
return Qnil;
}

int rb_utf8_encindex(void)
{
// not relevant
return 0;
}

VALUE rb_hash_lookup2(VALUE hash, VALUE key, VALUE def)
{
VALUE v = rb_hash_lookup(hash, key);
return (v == Qnil) ? def : v;
}
#endif // RUBY_API_VERSION_MINOR == 8
#endif // RUBY_API_VERSION_MAJOR == 1
126 changes: 123 additions & 3 deletions binding-mri/binding-util.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,131 @@
#define BINDING_UTIL_H

#include <ruby.h>
#include <ruby/version.h>

#include "exception.h"

// Ruby 1.8 and Ruby 1.9+ use different version macros
#ifndef RUBY_API_VERSION_MAJOR
#define RUBY_API_VERSION_MAJOR RUBY_VERSION_MAJOR
#endif

#ifndef RUBY_API_VERSION_MINOR
#define RUBY_API_VERSION_MINOR RUBY_VERSION_MINOR
#endif

#if RUBY_API_VERSION_MAJOR == 1
#define PRIsVALUE "s"
#define RB_OBJ_CLASSNAME(obj) rb_obj_classname(obj)
#define RB_OBJ_STRING(obj) StringValueCStr(obj)

NORETURN(void rb_error_arity(int, int, int));

#define OBJ_INIT_COPY(obj, orig) \
((obj) != (orig) && (rb_obj_init_copy((obj), (orig)), 1))
#if RUBY_API_VERSION_MINOR == 8
// Makes version checks easier
#define RUBY_LEGACY_VERSION
// Functions and macros providing Ruby 1.8 compatibililty
#define FLONUM_P(x) 0

#define RB_FLOAT_TYPE_P(obj) (FLONUM_P(obj) || (!SPECIAL_CONST_P(obj) && BUILTIN_TYPE(obj) == T_FLOAT))

#define RB_TYPE_P(obj, type) ( \
((type) == T_FIXNUM) ? FIXNUM_P(obj) : \
((type) == T_TRUE) ? ((obj) == Qtrue) : \
((type) == T_FALSE) ? ((obj) == Qfalse) : \
((type) == T_NIL) ? ((obj) == Qnil) : \
((type) == T_UNDEF) ? ((obj) == Qundef) : \
((type) == T_SYMBOL) ? SYMBOL_P(obj) : \
((type) == T_FLOAT) ? RB_FLOAT_TYPE_P(obj) : \
(!SPECIAL_CONST_P(obj) && BUILTIN_TYPE(obj) == (type)))

#define RUBY_T_ARRAY T_ARRAY
#define RUBY_T_STRING T_STRING
#define RUBY_T_FLOAT T_FLOAT
#define RUBY_T_FIXNUM T_FIXNUM
#define RUBY_T_TRUE T_TRUE
#define RUBY_T_FALSE T_FALSE
#define RUBY_T_NIL T_NIL

#define rb_str_new_cstr rb_str_new2

#define RUBY_DEFAULT_FREE ((RUBY_DATA_FUNC)-1)
#define RUBY_NEVER_FREE ((RUBY_DATA_FUNC)0)
#define RUBY_TYPED_DEFAULT_FREE RUBY_DEFAULT_FREE
#define RUBY_TYPED_NEVER_FREE RUBY_NEVER_FREE

#define RTYPEDDATA_DATA DATA_PTR

#define RFLOAT_VALUE(d) RFLOAT(d)->value

#define ENCODING_INLINE_MAX 127
#define ENCODING_SHIFT (FL_USHIFT+10)
#define ENCODING_MASK (((VALUE)ENCODING_INLINE_MAX)<<ENCODING_SHIFT) /* FL_USER10|FL_USER11|FL_USER12|FL_USER13|FL_USER14|FL_USER15|FL_USER16 */

#define ENCODING_SET_INLINED(obj,i) do {\
RBASIC(obj)->flags &= ~ENCODING_MASK;\
RBASIC(obj)->flags |= (VALUE)(i) << ENCODING_SHIFT;\
} while (0)
#define ENCODING_SET(obj,i) rb_enc_set_index((obj), (i))

#define ENCODING_GET_INLINED(obj) (int)((RBASIC(obj)->flags & ENCODING_MASK)>>ENCODING_SHIFT)
#define ENCODING_GET(obj) \
(ENCODING_GET_INLINED(obj) != ENCODING_INLINE_MAX ? \
ENCODING_GET_INLINED(obj) : \
rb_enc_get_index(obj))

#define ENCODING_IS_ASCII8BIT(obj) (ENCODING_GET_INLINED(obj) == 0)

typedef struct {
const char *wrap_struct_name;
struct {
void (*dmark)(void*);
void (*dfree)(void*);
size_t (*dsize)(const void *);
void *reserved[2];
} function;
const char *parent;
void *data;
VALUE flags;
} rb_data_type_t;

VALUE rb_sprintf(const char* fmt, ...);

VALUE rb_data_typed_object_alloc(VALUE klass, void *datap, const rb_data_type_t *);

void *rb_check_typeddata(VALUE, const rb_data_type_t *);

#define Check_TypedStruct(v,t) rb_check_typeddata((VALUE)(v),(t))

typedef void rb_encoding;

VALUE rb_enc_str_new(const char*, long, rb_encoding*);

rb_encoding *rb_utf8_encoding(void);

void rb_enc_set_default_external(VALUE encoding);

VALUE rb_enc_from_encoding(rb_encoding *enc);

VALUE rb_str_catf(VALUE, const char*, ...);

VALUE rb_errinfo(void);

int rb_typeddata_is_kind_of(VALUE, const rb_data_type_t *);

VALUE rb_file_open_str(VALUE, const char*);

VALUE rb_enc_associate_index(VALUE, int);

int rb_utf8_encindex(void);

VALUE rb_hash_lookup2(VALUE, VALUE, VALUE);

#endif // RUBY_API_VERSION_MINOR == 8
#endif // RUBY_API_VERSION_MAJOR == 1

enum RbException
{
RGSS = 0,
Expand Down Expand Up @@ -66,8 +188,7 @@ raiseRbExc(const Exception &exc);
extern rb_data_type_t Klass##Type

/* 2.1 has added a new field (flags) to rb_data_type_t */
#include <ruby/version.h>
#if RUBY_API_VERSION_MAJOR >= 2 && RUBY_API_VERSION_MINOR >= 1
#if RUBY_API_VERSION_MAJOR > 1 && RUBY_API_VERSION_MINOR > 0
/* TODO: can mkxp use RUBY_TYPED_FREE_IMMEDIATELY here? */
#define DEF_TYPE_FLAGS 0
#else
Expand Down Expand Up @@ -383,5 +504,4 @@ rb_check_argc(int actual, int expected)
_rb_define_method(klass, prop_name_s "=", Klass##Set##PropName); \
}


#endif // BINDING_UTIL_H
11 changes: 11 additions & 0 deletions binding-mri/filesystem-binding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@
#include "filesystem.h"
#include "util.h"

#ifndef RUBY_LEGACY_VERSION
#include "ruby/encoding.h"
#endif
#include "ruby/intern.h"

static void
Expand Down Expand Up @@ -195,14 +197,21 @@ RB_METHOD(_marshalLoad)
rb_get_args(argc, argv, "o|o", &port, &proc RB_ARG_END);

VALUE utf8Proc;
// FIXME: Not implemented for Ruby 1.8
#ifndef RUBY_LEGACY_VERSION
if (NIL_P(proc))
utf8Proc = rb_proc_new(RUBY_METHOD_FUNC(stringForceUTF8), Qnil);
else
utf8Proc = rb_proc_new(RUBY_METHOD_FUNC(customProc), proc);
#endif

VALUE marsh = rb_const_get(rb_cObject, rb_intern("Marshal"));

#ifndef RUBY_LEGACY_VERSION
VALUE v[] = { port, utf8Proc };
#else
VALUE v[] = { port, proc };
#endif
return rb_funcall2(marsh, rb_intern("_mkxp_load_alias"), ARRAY_SIZE(v), v);
}

Expand All @@ -214,6 +223,8 @@ fileIntBindingInit()

_rb_define_method(klass, "read", fileIntRead);
_rb_define_method(klass, "getbyte", fileIntGetByte);
// Used by Ruby 1.8 Marshaller
_rb_define_method(klass, "getc", fileIntGetByte);
_rb_define_method(klass, "binmode", fileIntBinmode);
_rb_define_method(klass, "close", fileIntClose);

Expand Down