From f7476784ce0057567a681579703d69eb390bdf47 Mon Sep 17 00:00:00 2001 From: Alex Kotov Date: Sun, 23 Jan 2022 00:37:34 +0500 Subject: [PATCH] Ruby: move printf to separate extension file --- pkgs/ruby/ext/default/main.c | 130 ++----------------------------- pkgs/ruby/ext/default/printf.c | 137 +++++++++++++++++++++++++++++++++ 2 files changed, 143 insertions(+), 124 deletions(-) create mode 100644 pkgs/ruby/ext/default/printf.c diff --git a/pkgs/ruby/ext/default/main.c b/pkgs/ruby/ext/default/main.c index 8ec6f7f..b4bc2ab 100644 --- a/pkgs/ruby/ext/default/main.c +++ b/pkgs/ruby/ext/default/main.c @@ -13,6 +13,9 @@ static VALUE rb_KernAux_Error = Qnil; static void assert_cb(const char *file, int line, const char *str); +#ifdef HAVE_KERNAUX_SNPRINTF +void init_printf(); +#endif // HAVE_KERNAUX_SNPRINTF #ifdef HAVE_KERNAUX_CMDLINE void init_cmdline(); #endif // HAVE_KERNAUX_CMDLINE @@ -28,12 +31,12 @@ static VALUE rb_KernAux_utoa10(VALUE self, VALUE number); #ifdef HAVE_KERNAUX_ITOA10 static VALUE rb_KernAux_itoa10(VALUE self, VALUE number); #endif -#ifdef HAVE_KERNAUX_SNPRINTF -static VALUE rb_KernAux_snprintf1(int argc, const VALUE *argv, VALUE self); -#endif void Init_default() { +#ifdef HAVE_KERNAUX_SNPRINTF + init_printf(); +#endif // HAVE_KERNAUX_SNPRINTF #ifdef HAVE_KERNAUX_CMDLINE init_cmdline(); #endif // HAVE_KERNAUX_CMDLINE @@ -62,10 +65,6 @@ void Init_default() #ifdef HAVE_KERNAUX_ITOA10 rb_define_singleton_method(rb_KernAux, "itoa10", rb_KernAux_itoa10, 1); #endif -#ifdef HAVE_KERNAUX_SNPRINTF - rb_define_singleton_method(rb_KernAux, "snprintf1", - rb_KernAux_snprintf1, -1); -#endif } void assert_cb(const char *const file, const int line, const char *const str) @@ -129,120 +128,3 @@ VALUE rb_KernAux_itoa10( return rb_funcall(rb_str_new2(buffer), rb_intern_freeze, 0); } #endif - -#ifdef HAVE_KERNAUX_SNPRINTF -// TODO: is this implementation correct? -// FIXME: rewrite to ensure no memory leak on exception. -VALUE rb_KernAux_snprintf1( - const int argc, - const VALUE *const argv_rb, - const VALUE self __attribute__((unused)) -) { - if (argc != 2 && argc != 3) rb_raise(rb_eArgError, "expected 2 or 3 args"); - - const VALUE size_rb = argv_rb[0]; - VALUE format_rb = argv_rb[1]; - - const int size = NUM2INT(size_rb); - const char *const format = StringValueCStr(format_rb); - - if (size < 0) rb_raise(rb_eRangeError, "expected non-negative size"); - - const char *fmt = format; - - while (*fmt && *fmt != '%') ++fmt; - if (*(fmt++) != '%') rb_raise(rb_eArgError, "invalid format"); - - // Mimic printf behavior. - { - bool flags; - do { - if (*fmt == '0' || *fmt == '-' || *fmt == '+' || *fmt == ' ' || - *fmt == '#') - { - ++fmt; - flags = true; - } else { - flags = false; - } - } while (flags); - } - if (*fmt >= '0' && *fmt <= '9') { - while (*fmt >= '0' && *fmt <= '9') ++fmt; - } else if (*fmt == '*') { - ++fmt; - } - if (*fmt == '.') { - ++fmt; - if (*fmt >= '0' && *fmt <= '9') { - while (*fmt >= '0' && *fmt <= '9') ++fmt; - } else if (*fmt == '*') { - ++fmt; - } - } - if (*fmt == 'l') { - ++fmt; - if (*fmt == 'l') ++fmt; - } else if (*fmt == 'h') { - ++fmt; - if (*fmt == 'h') ++fmt; - } else if (*fmt == 't' || *fmt == 'j' || *fmt == 'z') { - ++fmt; - } - - const char c = *fmt; - - if (*fmt == '%') ++fmt; - while (*fmt) { - if (*(fmt++) == '%') rb_raise(rb_eArgError, "invalid format"); - } - - bool use_dbl = false; - double dbl; - union { - const char *str; - long long ll; - unsigned long long ull; - char chr; - } __attribute__((packed)) arg = { .str = "" }; - - if (argc == 3) { - VALUE arg_rb = argv_rb[2]; - - if (c == 'd' || c == 'i') { - RB_INTEGER_TYPE_P(arg_rb); - arg.ll = NUM2LL(arg_rb); - } else if (c == 'u' || c == 'x' || c == 'X' || c == 'o' || c == 'b') { - RB_INTEGER_TYPE_P(arg_rb); - arg.ull = NUM2ULL(arg_rb); - } else if (c == 'f' || c == 'F' || - c == 'e' || c == 'E' || - c == 'g' || c == 'G') - { - RB_FLOAT_TYPE_P(arg_rb); - use_dbl = true; - dbl = NUM2DBL(arg_rb); - } else if (c == 'c') { - Check_Type(arg_rb, T_STRING); - arg.chr = *StringValuePtr(arg_rb); - } else if (c == 's') { - Check_Type(arg_rb, T_STRING); - arg.str = StringValueCStr(arg_rb); - } - } - - char *const str = malloc(size); - if (!str) rb_raise(rb_eNoMemError, "snprintf1 buffer malloc"); - const int slen = use_dbl - ? kernaux_snprintf(str, size, format, dbl) - : kernaux_snprintf(str, size, format, arg); - const VALUE output_rb = - rb_funcall(rb_str_new2(str), rb_intern_freeze, 0); - free(str); - - const VALUE result_rb = rb_ary_new2(2); - rb_ary_push(result_rb, output_rb); - rb_ary_push(result_rb, INT2NUM(slen)); - return rb_funcall(result_rb, rb_intern_freeze, 0); -} -#endif diff --git a/pkgs/ruby/ext/default/printf.c b/pkgs/ruby/ext/default/printf.c new file mode 100644 index 0000000..5611e71 --- /dev/null +++ b/pkgs/ruby/ext/default/printf.c @@ -0,0 +1,137 @@ +#include +#include + +#ifdef HAVE_KERNAUX_SNPRINTF + +static VALUE rb_KernAux_snprintf1(int argc, const VALUE *argv, VALUE self); + +static ID rb_intern_freeze; + +static VALUE rb_KernAux = Qnil; + +void init_printf() +{ + rb_gc_register_mark_object(rb_intern_freeze = rb_intern("freeze")); + + rb_gc_register_mark_object(rb_KernAux = rb_define_module("KernAux")); + + rb_define_singleton_method(rb_KernAux, "snprintf1", + rb_KernAux_snprintf1, -1); +} + +// TODO: is this implementation correct? +// FIXME: rewrite to ensure no memory leak on exception. +VALUE rb_KernAux_snprintf1( + const int argc, + const VALUE *const argv_rb, + const VALUE self __attribute__((unused)) +) { + if (argc != 2 && argc != 3) rb_raise(rb_eArgError, "expected 2 or 3 args"); + + const VALUE size_rb = argv_rb[0]; + VALUE format_rb = argv_rb[1]; + + const int size = NUM2INT(size_rb); + const char *const format = StringValueCStr(format_rb); + + if (size < 0) rb_raise(rb_eRangeError, "expected non-negative size"); + + const char *fmt = format; + + while (*fmt && *fmt != '%') ++fmt; + if (*(fmt++) != '%') rb_raise(rb_eArgError, "invalid format"); + + // Mimic printf behavior. + { + bool flags; + do { + if (*fmt == '0' || *fmt == '-' || *fmt == '+' || *fmt == ' ' || + *fmt == '#') + { + ++fmt; + flags = true; + } else { + flags = false; + } + } while (flags); + } + if (*fmt >= '0' && *fmt <= '9') { + while (*fmt >= '0' && *fmt <= '9') ++fmt; + } else if (*fmt == '*') { + ++fmt; + } + if (*fmt == '.') { + ++fmt; + if (*fmt >= '0' && *fmt <= '9') { + while (*fmt >= '0' && *fmt <= '9') ++fmt; + } else if (*fmt == '*') { + ++fmt; + } + } + if (*fmt == 'l') { + ++fmt; + if (*fmt == 'l') ++fmt; + } else if (*fmt == 'h') { + ++fmt; + if (*fmt == 'h') ++fmt; + } else if (*fmt == 't' || *fmt == 'j' || *fmt == 'z') { + ++fmt; + } + + const char c = *fmt; + + if (*fmt == '%') ++fmt; + while (*fmt) { + if (*(fmt++) == '%') rb_raise(rb_eArgError, "invalid format"); + } + + bool use_dbl = false; + double dbl; + union { + const char *str; + long long ll; + unsigned long long ull; + char chr; + } __attribute__((packed)) arg = { .str = "" }; + + if (argc == 3) { + VALUE arg_rb = argv_rb[2]; + + if (c == 'd' || c == 'i') { + RB_INTEGER_TYPE_P(arg_rb); + arg.ll = NUM2LL(arg_rb); + } else if (c == 'u' || c == 'x' || c == 'X' || c == 'o' || c == 'b') { + RB_INTEGER_TYPE_P(arg_rb); + arg.ull = NUM2ULL(arg_rb); + } else if (c == 'f' || c == 'F' || + c == 'e' || c == 'E' || + c == 'g' || c == 'G') + { + RB_FLOAT_TYPE_P(arg_rb); + use_dbl = true; + dbl = NUM2DBL(arg_rb); + } else if (c == 'c') { + Check_Type(arg_rb, T_STRING); + arg.chr = *StringValuePtr(arg_rb); + } else if (c == 's') { + Check_Type(arg_rb, T_STRING); + arg.str = StringValueCStr(arg_rb); + } + } + + char *const str = malloc(size); + if (!str) rb_raise(rb_eNoMemError, "snprintf1 buffer malloc"); + const int slen = use_dbl + ? kernaux_snprintf(str, size, format, dbl) + : kernaux_snprintf(str, size, format, arg); + const VALUE output_rb = + rb_funcall(rb_str_new2(str), rb_intern_freeze, 0); + free(str); + + const VALUE result_rb = rb_ary_new2(2); + rb_ary_push(result_rb, output_rb); + rb_ary_push(result_rb, INT2NUM(slen)); + return rb_funcall(result_rb, rb_intern_freeze, 0); +} + +#endif // HAVE_KERNAUX_SNPRINTF