Ruby: move dynamic argument handling to separate module

This commit is contained in:
Alex Kotov 2022-05-23 20:31:53 +03:00
parent bac9b21145
commit bdc80917b4
Signed by: kotovalexarian
GPG Key ID: 553C0EBBEB5D5F08
3 changed files with 94 additions and 20 deletions

View File

@ -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;
}

View File

@ -0,0 +1,35 @@
#ifndef INCLUDED_DYNARG
#define INCLUDED_DYNARG
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
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

View File

@ -1,6 +1,8 @@
#include <kernaux.h>
#include <ruby.h>
#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 =