From 6fe0254dce1128d2dfb9e0b79d96fbf709f60877 Mon Sep 17 00:00:00 2001 From: Alex Kotov Date: Fri, 21 Jan 2022 18:55:03 +0500 Subject: [PATCH] Ruby: Mimic printf behavior --- pkgs/ruby/ext/default/main.c | 48 ++++++++++++++++---- pkgs/ruby/spec/lib/kernaux/snprintf1_spec.rb | 12 +++++ 2 files changed, 50 insertions(+), 10 deletions(-) diff --git a/pkgs/ruby/ext/default/main.c b/pkgs/ruby/ext/default/main.c index a97d5c3..2f1a8ae 100644 --- a/pkgs/ruby/ext/default/main.c +++ b/pkgs/ruby/ext/default/main.c @@ -129,16 +129,48 @@ VALUE rb_KernAux_snprintf1( const char *const format = StringValueCStr(format_rb); if (size < 0) rb_raise(rb_eRangeError, "expected non-negative size"); + if (strlen(format) > 100) rb_raise(rb_eArgError, "invalid format"); + const char *fmt = format; + + while (*fmt && *fmt != '%') ++fmt; + if (*(fmt++) != '%') rb_raise(rb_eArgError, "invalid format"); + + // Mimic printf behavior. + if (*fmt == '0' || *fmt == '-' || *fmt == '+' || *fmt == ' ' || + *fmt == '#') { - size_t fmt_size = 0, perc_count = 0; - for (const char *fmt = format; *fmt; ++fmt, ++fmt_size) { - if (*fmt == '%') ++perc_count; - } - if (fmt_size > 100 || perc_count == 0 || perc_count > 2) { - rb_raise(rb_eArgError, "invalid format"); + ++fmt; + } + 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 == 'z') { + ++fmt; + } + + const char c = *fmt; + + if (*fmt == '%') ++fmt; + while (*fmt) { + if (*(fmt++) == '%') rb_raise(rb_eArgError, "invalid format"); + } union { const char *str; @@ -149,10 +181,6 @@ VALUE rb_KernAux_snprintf1( } __attribute__((packed)) arg = { .str = "" }; if (argc == 3) { - const char *fmt = format; - while (*(fmt + 1)) ++fmt; - const char c = *fmt; - VALUE arg_rb = argv_rb[2]; if (c == 'd' || c == 'i') { diff --git a/pkgs/ruby/spec/lib/kernaux/snprintf1_spec.rb b/pkgs/ruby/spec/lib/kernaux/snprintf1_spec.rb index 66509b4..6a69f26 100644 --- a/pkgs/ruby/spec/lib/kernaux/snprintf1_spec.rb +++ b/pkgs/ruby/spec/lib/kernaux/snprintf1_spec.rb @@ -20,6 +20,12 @@ RSpec.describe KernAux, '.snprintf1' do specify { expect(snprintf1[0]).to eq '%' } specify { expect(snprintf1[1]).to eq 1 } + context 'with leading and trailing spaces' do + let(:format) { ' %% ' } + + specify { expect(snprintf1[0]).to eq ' % ' } + end + context 'with "%s" format' do let(:format) { '%s' } @@ -82,6 +88,12 @@ RSpec.describe KernAux, '.snprintf1' do specify { expect(snprintf1[0]).to eq arg } specify { expect(snprintf1[1]).to eq arg.size } + context 'with leading and trailing spaces' do + let(:format) { ' %s ' } + + specify { expect(snprintf1[0]).to eq " #{arg} " } + end + context 'with "%%" format' do let(:format) { '%%' }