Skip to content

Commit 768b1fc

Browse files
committed
rb_sprintf implementation for VALUE arguments.
1 parent c31eb63 commit 768b1fc

File tree

6 files changed

+120
-9
lines changed

6 files changed

+120
-9
lines changed

lib/cext/include/ruby/ruby.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ typedef char ruby_check_sizeof_voidp[SIZEOF_VOIDP == sizeof(void*) ? 1 : -1];
137137
#define PRIuVALUE PRI_VALUE_PREFIX"u"
138138
#define PRIxVALUE PRI_VALUE_PREFIX"x"
139139
#define PRIXVALUE PRI_VALUE_PREFIX"X"
140-
#define PRIsVALUE PRI_VALUE_PREFIX"i" RUBY_PRI_VALUE_MARK
140+
#define PRIsVALUE "Y"
141141

142142

143143
#ifndef PRI_TIMET_PREFIX

lib/cext/include/truffleruby/truffleruby.h

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,6 @@
1818
extern "C" {
1919
#endif
2020

21-
#define rb_sprintf(format, ...) \
22-
rb_tr_wrap(polyglot_invoke(RUBY_CEXT, "rb_sprintf", rb_tr_unwrap(rb_str_new_cstr(format)), ##__VA_ARGS__))
23-
2421
NORETURN(VALUE rb_f_notimplement(int args_count, const VALUE *args, VALUE object));
2522

2623
// Non-standard
@@ -83,13 +80,13 @@ typedef void *(*gvl_call)(void *);
8380

8481
#define rb_warn(FORMAT, ...) do { \
8582
if (polyglot_as_boolean(polyglot_invoke(RUBY_CEXT, "warn?"))) { \
86-
polyglot_invoke(rb_tr_unwrap(rb_mKernel), "warn", (VALUE) polyglot_invoke(rb_tr_unwrap(rb_mKernel), "sprintf", rb_tr_unwrap(rb_str_new_cstr(FORMAT)), ##__VA_ARGS__)); \
83+
RUBY_INVOKE(rb_mKernel, "warn", rb_sprintf(FORMAT, ##__VA_ARGS__)); \
8784
} \
8885
} while (0);
8986

9087
#define rb_warning(FORMAT, ...) do { \
9188
if (polyglot_as_boolean(polyglot_invoke(RUBY_CEXT, "warning?"))) { \
92-
polyglot_invoke(rb_tr_unwrap(rb_mKernel), "warn", (VALUE) polyglot_invoke(rb_tr_unwrap(rb_mKernel), "sprintf", rb_tr_unwrap(rb_str_new_cstr(FORMAT)), ##__VA_ARGS__)); \
89+
RUBY_INVOKE(rb_mKernel, "warn", rb_sprintf(FORMAT, ##__VA_ARGS__)); \
9390
} \
9491
} while (0);
9592

@@ -153,7 +150,7 @@ MUST_INLINE int rb_tr_scan_args(int argc, VALUE *argv, const char *format, VALUE
153150
// Exceptions
154151

155152
#define rb_raise(EXCEPTION, FORMAT, ...) \
156-
rb_exc_raise(rb_exc_new_str(EXCEPTION, (VALUE) rb_tr_wrap(polyglot_invoke(RUBY_CEXT, "rb_sprintf", rb_tr_unwrap(rb_str_new_cstr(FORMAT)), ##__VA_ARGS__))))
153+
rb_exc_raise(rb_exc_new_str(EXCEPTION, rb_sprintf(FORMAT, ##__VA_ARGS__)))
157154

158155
// Additional non-standard
159156
VALUE rb_java_class_of(VALUE val);

lib/truffle/truffle/cext.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,8 @@ def RB_TYPE_P(value, type)
365365
value.is_a?(Data)
366366
when T_FLOAT
367367
value.is_a?(Float)
368+
when T_CLASS
369+
value.is_a?(Class)
368370
else
369371
raise "unknown type #{type}"
370372
end

spec/ruby/optional/capi/ext/string_spec.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,14 @@ static VALUE string_spec_rb_sprintf2(VALUE self, VALUE str, VALUE repl1, VALUE r
358358
return rb_sprintf(RSTRING_PTR(str), RSTRING_PTR(repl1), RSTRING_PTR(repl2));
359359
}
360360

361+
static VALUE string_spec_rb_sprintf3(VALUE self, VALUE str) {
362+
return rb_sprintf("Result: %"PRIsVALUE".", str);
363+
}
364+
365+
static VALUE string_spec_rb_sprintf4(VALUE self, VALUE str) {
366+
return rb_sprintf("Result: %+"PRIsVALUE".", str);
367+
}
368+
361369
static VALUE string_spec_rb_vsprintf_worker(char* fmt, ...) {
362370
va_list varargs;
363371
VALUE str;
@@ -463,6 +471,8 @@ void Init_string_spec(void) {
463471
rb_define_method(cls, "rb_str_free", string_spec_rb_str_free, 1);
464472
rb_define_method(cls, "rb_sprintf1", string_spec_rb_sprintf1, 2);
465473
rb_define_method(cls, "rb_sprintf2", string_spec_rb_sprintf2, 3);
474+
rb_define_method(cls, "rb_sprintf3", string_spec_rb_sprintf3, 1);
475+
rb_define_method(cls, "rb_sprintf4", string_spec_rb_sprintf4, 1);
466476
rb_define_method(cls, "rb_vsprintf", string_spec_rb_vsprintf, 4);
467477
rb_define_method(cls, "rb_str_equal", string_spec_rb_str_equal, 2);
468478
rb_define_method(cls, "rb_usascii_str_new", string_spec_rb_usascii_str_new, 2);

spec/ruby/optional/capi/string_spec.rb

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,16 @@ def to_str
3232
end
3333
end
3434

35+
class ToSOrInspect
36+
def to_s
37+
'A string'
38+
end
39+
40+
def inspect
41+
'A different string'
42+
end
43+
end
44+
3545
[Encoding::BINARY, Encoding::UTF_8].each do |enc|
3646
describe "rb_str_set_len on a #{enc.name} String" do
3747
before :each do
@@ -875,6 +885,16 @@ def to_str
875885
s = "Awesome %s is here with %s"
876886
@s.rb_sprintf2(s, "string", "content").should == "Awesome string is here with content"
877887
end
888+
889+
it "formats a string VALUE using to_s if sign not specified in format" do
890+
s = 'Result: A string.'
891+
@s.rb_sprintf3(ToSOrInspect.new).should == s
892+
end
893+
894+
it "formats a string VALUE using to inspect if sign specified in format" do
895+
s = 'Result: A different string.'
896+
@s.rb_sprintf4(ToSOrInspect.new).should == s
897+
end
878898
end
879899

880900
describe "rb_vsprintf" do

src/main/c/cext/ruby.c

Lines changed: 84 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include <stdio.h>
2525
#include <errno.h>
2626
#include <fcntl.h>
27+
#include <printf.h>
2728

2829
void* rb_tr_cext;
2930
void* rb_tr_undef;
@@ -33,12 +34,78 @@ void* rb_tr_nil;
3334

3435
// Run when loading C-extension support
3536

37+
#ifdef __APPLE__
38+
static printf_domain_t printf_domain;
39+
40+
static int rb_tr_fprintf_value_arginfo(const struct printf_info *info,
41+
size_t n,
42+
int *argtypes) {
43+
if (n > 0) {
44+
*argtypes = PA_POINTER;
45+
}
46+
return 1;
47+
}
48+
49+
#else
50+
static int rb_tr_fprintf_value_arginfo(const struct printf_info *info,
51+
size_t n,
52+
int *argtypes, int *argsize) {
53+
if (n > 0) {
54+
*argtypes = PA_POINTER;
55+
*argsize = sizeof(VALUE);
56+
}
57+
return 1;
58+
}
59+
#endif
60+
61+
static int rb_tr_fprintf_value(FILE *stream,
62+
const struct printf_info *info,
63+
const void *const *args) {
64+
char *cstr = NULL;
65+
VALUE v;
66+
int len;
67+
68+
v = *((const VALUE *) (args[0]));
69+
if (info->showsign) {
70+
if(RB_TYPE_P(v, T_CLASS)) {
71+
if (v == rb_cNilClass) {
72+
cstr = "nil";
73+
} else if (v == rb_cInteger) {
74+
cstr = "Integer";
75+
} else if (v == rb_cSymbol) {
76+
cstr = "Symbol";
77+
} else if (v == rb_cTrueClass) {
78+
cstr = "true";
79+
} else if (v == rb_cFalseClass) {
80+
cstr = "false";
81+
}
82+
}
83+
if (cstr == NULL) {
84+
VALUE str = rb_inspect(v);
85+
len = rb_str_len(str);
86+
cstr = RSTRING_PTR(str);
87+
}
88+
} else {
89+
VALUE str = rb_obj_as_string(v);
90+
len = rb_str_len(str);
91+
cstr = RSTRING_PTR(str);
92+
}
93+
len = fprintf(stream, "%s", cstr);
94+
return len;
95+
}
96+
3697
void rb_tr_init(void *ruby_cext) {
3798
truffle_assign_managed(&rb_tr_cext, ruby_cext);
3899
truffle_assign_managed(&rb_tr_undef, rb_tr_get_undef());
39100
truffle_assign_managed(&rb_tr_true, rb_tr_get_true());
40101
truffle_assign_managed(&rb_tr_false, rb_tr_get_false());
41102
truffle_assign_managed(&rb_tr_nil, rb_tr_get_nil());
103+
#ifdef __APPLE__
104+
printf_domain = new_printf_domain();
105+
register_printf_domain_function(printf_domain, 'Y', rb_tr_fprintf_value, rb_tr_fprintf_value_arginfo);
106+
#else
107+
register_printf_specifier('Y', rb_tr_fprintf_value, rb_tr_fprintf_value_arginfo);
108+
#endif
42109
}
43110

44111
// Private helper macros just for ruby.c
@@ -844,6 +911,18 @@ VALUE rb_str_buf_new(long capacity) {
844911
return str;
845912
}
846913

914+
VALUE rb_sprintf(const char *format, ...)
915+
{
916+
VALUE result;
917+
va_list ap;
918+
919+
va_start(ap, format);
920+
result = rb_vsprintf(format, ap);
921+
va_end(ap);
922+
923+
return result;
924+
}
925+
847926
VALUE rb_vsprintf(const char *format, va_list args) {
848927
return rb_enc_vsprintf(rb_ascii8bit_encoding(), format, args);
849928
}
@@ -2282,7 +2361,7 @@ VALUE rb_range_beg_len(VALUE range, long *begp, long *lenp, long len, int err) {
22822361

22832362
out_of_range:
22842363
if (err) {
2285-
rb_raise(rb_eRangeError, "%d..%s%d out of range",
2364+
rb_raise(rb_eRangeError, "%ld..%s%ld out of range",
22862365
origbeg, excl ? "." : "", origend);
22872366
}
22882367
return Qnil;
@@ -3053,9 +3132,12 @@ VALUE rb_enc_reg_new(const char *s, long len, rb_encoding *enc, int options) {
30533132
}
30543133

30553134
VALUE rb_enc_vsprintf(rb_encoding *enc, const char *format, va_list args) {
3056-
// TODO CS 7-May-17 this needs to use the Ruby sprintf, not C's
30573135
char *buffer;
3136+
#ifdef __APPLE__
3137+
if (vasxprintf(&buffer, printf_domain, NULL, format, args) < 0) {
3138+
#else
30583139
if (vasprintf(&buffer, format, args) < 0) {
3140+
#endif
30593141
rb_tr_error("vasprintf error");
30603142
}
30613143
VALUE string = rb_enc_str_new_cstr(buffer, enc);

0 commit comments

Comments
 (0)