Skip to content

Commit 3fe0afa

Browse files
committed
Rb sprintf changes
PullRequest: truffleruby/735
2 parents 354ad9e + e69ff81 commit 3fe0afa

File tree

6 files changed

+125
-9
lines changed

6 files changed

+125
-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: 30 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,26 @@ 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 inspect if sign specified in format" do
895+
s = 'Result: A different string.'
896+
@s.rb_sprintf4(ToSOrInspect.new).should == s
897+
end
898+
899+
it "formats a TrueClass VALUE as `TrueClass` if sign not specified in format" do
900+
s = 'Result: TrueClass.'
901+
@s.rb_sprintf3(true.class).should == s
902+
end
903+
904+
it "formats a TrueClass VALUE as 'true' if sign specified in format" do
905+
s = 'Result: true.'
906+
@s.rb_sprintf4(true.class).should == s
907+
end
878908
end
879909

880910
describe "rb_vsprintf" do

src/main/c/cext/ruby.c

Lines changed: 79 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,70 @@
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;
3031
void* rb_tr_true;
3132
void* rb_tr_false;
3233
void* rb_tr_nil;
3334

35+
#ifdef __APPLE__
36+
static printf_domain_t printf_domain;
37+
38+
static int rb_tr_fprintf_value_arginfo(const struct printf_info *info,
39+
size_t n,
40+
int *argtypes) {
41+
if (n > 0) {
42+
*argtypes = PA_POINTER;
43+
}
44+
return 1;
45+
}
46+
47+
#else
48+
static int rb_tr_fprintf_value_arginfo(const struct printf_info *info,
49+
size_t n,
50+
int *argtypes, int *argsize) {
51+
if (n > 0) {
52+
*argtypes = PA_POINTER;
53+
*argsize = sizeof(VALUE);
54+
}
55+
return 1;
56+
}
57+
#endif
58+
59+
static int rb_tr_fprintf_value(FILE *stream,
60+
const struct printf_info *info,
61+
const void *const *args) {
62+
char *cstr = NULL;
63+
VALUE v;
64+
int len;
65+
66+
v = *((const VALUE *) (args[0]));
67+
if (info->showsign) {
68+
if (RB_TYPE_P(v, T_CLASS)) {
69+
if (v == rb_cNilClass) {
70+
cstr = "nil";
71+
} else if (v == rb_cTrueClass) {
72+
cstr = "true";
73+
} else if (v == rb_cFalseClass) {
74+
cstr = "false";
75+
}
76+
}
77+
if (cstr == NULL) {
78+
VALUE str = rb_inspect(v);
79+
len = rb_str_len(str);
80+
cstr = RSTRING_PTR(str);
81+
}
82+
} else {
83+
VALUE str = rb_obj_as_string(v);
84+
len = rb_str_len(str);
85+
cstr = RSTRING_PTR(str);
86+
}
87+
len = fprintf(stream, "%s", cstr);
88+
return len;
89+
}
90+
3491
// Run when loading C-extension support
3592

3693
void rb_tr_init(void *ruby_cext) {
@@ -39,6 +96,12 @@ void rb_tr_init(void *ruby_cext) {
3996
truffle_assign_managed(&rb_tr_true, rb_tr_get_true());
4097
truffle_assign_managed(&rb_tr_false, rb_tr_get_false());
4198
truffle_assign_managed(&rb_tr_nil, rb_tr_get_nil());
99+
#ifdef __APPLE__
100+
printf_domain = new_printf_domain();
101+
register_printf_domain_function(printf_domain, 'Y', rb_tr_fprintf_value, rb_tr_fprintf_value_arginfo, NULL);
102+
#else
103+
register_printf_specifier('Y', rb_tr_fprintf_value, rb_tr_fprintf_value_arginfo);
104+
#endif
42105
}
43106

44107
// Private helper macros just for ruby.c
@@ -844,6 +907,17 @@ VALUE rb_str_buf_new(long capacity) {
844907
return str;
845908
}
846909

910+
VALUE rb_sprintf(const char *format, ...) {
911+
VALUE result;
912+
va_list ap;
913+
914+
va_start(ap, format);
915+
result = rb_vsprintf(format, ap);
916+
va_end(ap);
917+
918+
return result;
919+
}
920+
847921
VALUE rb_vsprintf(const char *format, va_list args) {
848922
return rb_enc_vsprintf(rb_ascii8bit_encoding(), format, args);
849923
}
@@ -2282,7 +2356,7 @@ VALUE rb_range_beg_len(VALUE range, long *begp, long *lenp, long len, int err) {
22822356

22832357
out_of_range:
22842358
if (err) {
2285-
rb_raise(rb_eRangeError, "%d..%s%d out of range",
2359+
rb_raise(rb_eRangeError, "%ld..%s%ld out of range",
22862360
origbeg, excl ? "." : "", origend);
22872361
}
22882362
return Qnil;
@@ -3053,9 +3127,12 @@ VALUE rb_enc_reg_new(const char *s, long len, rb_encoding *enc, int options) {
30533127
}
30543128

30553129
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
30573130
char *buffer;
3131+
#ifdef __APPLE__
3132+
if (vasxprintf(&buffer, printf_domain, NULL, format, args) < 0) {
3133+
#else
30583134
if (vasprintf(&buffer, format, args) < 0) {
3135+
#endif
30593136
rb_tr_error("vasprintf error");
30603137
}
30613138
VALUE string = rb_enc_str_new_cstr(buffer, enc);

0 commit comments

Comments
 (0)