diff --git a/pkgs/ruby/ext/default/dynarg.c b/pkgs/ruby/ext/default/dynarg.c new file mode 100644 index 0000000..d45b72c --- /dev/null +++ b/pkgs/ruby/ext/default/dynarg.c @@ -0,0 +1,45 @@ +#include "dynarg.h" + +struct DynArg DynArg_create() +{ + struct DynArg dynarg; + DynArg_init(&dynarg); + return dynarg; +} + +void DynArg_init(struct DynArg *const dynarg) +{ + dynarg->use_dbl = false; + dynarg->dbl = 0.0; + dynarg->arg.str = ""; +} + +void DynArg_use_char(struct DynArg *const dynarg, const char chr) +{ + dynarg->use_dbl = false; + dynarg->arg.chr = chr; +} + +void DynArg_use_double(struct DynArg *const dynarg, const double dbl) +{ + dynarg->use_dbl = true; + dynarg->dbl = dbl; +} + +void DynArg_use_long_long(struct DynArg *const dynarg, const long long ll) +{ + dynarg->use_dbl = false; + dynarg->arg.ll = ll; +} + +void DynArg_use_str(struct DynArg *const dynarg, const char *const str) +{ + dynarg->use_dbl = false; + dynarg->arg.str = str; +} + +void DynArg_use_unsigned_long_long(struct DynArg *const dynarg, const unsigned long long ull) +{ + dynarg->use_dbl = false; + dynarg->arg.ull = ull; +} diff --git a/pkgs/ruby/ext/default/dynarg.h b/pkgs/ruby/ext/default/dynarg.h new file mode 100644 index 0000000..e6f70c0 --- /dev/null +++ b/pkgs/ruby/ext/default/dynarg.h @@ -0,0 +1,35 @@ +#ifndef INCLUDED_DYNARG +#define INCLUDED_DYNARG + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +struct DynArg { + bool use_dbl; + double dbl; + // TODO: check if this will work on different endianness. + union { + char chr; + long long ll; + const char *str; + unsigned long long ull; + } __attribute__((packed)) arg; +}; + +struct DynArg DynArg_create(); +void DynArg_init(struct DynArg *dynarg); + +void DynArg_use_char(struct DynArg *dynarg, char chr); +void DynArg_use_double(struct DynArg *dynarg, double dbl); +void DynArg_use_long_long(struct DynArg *dynarg, long long ll); +void DynArg_use_str(struct DynArg *dynarg, const char *str); +void DynArg_use_unsigned_long_long(struct DynArg *dynarg, unsigned long long ull); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/pkgs/ruby/ext/default/printf.c b/pkgs/ruby/ext/default/printf.c index 5a893bc..acf4c95 100644 --- a/pkgs/ruby/ext/default/printf.c +++ b/pkgs/ruby/ext/default/printf.c @@ -1,6 +1,8 @@ #include #include +#include "dynarg.h" + #ifdef HAVE_KERNAUX_SNPRINTF static VALUE rb_KernAux_snprintf1(int argc, const VALUE *argv, VALUE self); @@ -89,37 +91,29 @@ VALUE rb_KernAux_snprintf1( int width = 0; if (has_width && argc > 2) width = NUM2INT(argv_rb[2]); - bool use_dbl = false; - double dbl; - union { - const char *str; - long long ll; - unsigned long long ull; - char chr; - } __attribute__((packed)) arg = { .str = "" }; + struct DynArg dynarg = DynArg_create(); if (argc == (has_width ? 4 : 3)) { VALUE arg_rb = argv_rb[has_width ? 3 : 2]; if (c == 'd' || c == 'i') { RB_INTEGER_TYPE_P(arg_rb); - arg.ll = NUM2LL(arg_rb); + DynArg_use_long_long(&dynarg, 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); + DynArg_use_unsigned_long_long(&dynarg, 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); + DynArg_use_double(&dynarg, NUM2DBL(arg_rb)); } else if (c == 'c') { Check_Type(arg_rb, T_STRING); - arg.chr = *StringValuePtr(arg_rb); + DynArg_use_char(&dynarg, *StringValuePtr(arg_rb)); } else if (c == 's') { Check_Type(arg_rb, T_STRING); - arg.str = StringValueCStr(arg_rb); + DynArg_use_str(&dynarg, StringValueCStr(arg_rb)); } } @@ -128,13 +122,13 @@ VALUE rb_KernAux_snprintf1( int slen; if (has_width) { - slen = use_dbl - ? kernaux_snprintf(str, size, format, width, dbl) - : kernaux_snprintf(str, size, format, width, arg); + slen = dynarg.use_dbl + ? kernaux_snprintf(str, size, format, width, dynarg.dbl) + : kernaux_snprintf(str, size, format, width, dynarg.arg); } else { - slen = use_dbl - ? kernaux_snprintf(str, size, format, dbl) - : kernaux_snprintf(str, size, format, arg); + slen = dynarg.use_dbl + ? kernaux_snprintf(str, size, format, dynarg.dbl) + : kernaux_snprintf(str, size, format, dynarg.arg); } const VALUE output_rb =