kernaux 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of kernaux might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/.gitignore +44 -0
- data/.rubocop.yml +77 -0
- data/.simplecov +9 -0
- data/.yardopts +4 -0
- data/Gemfile +8 -0
- data/README.md +29 -0
- data/Rakefile +80 -0
- data/bin/console +8 -0
- data/bin/setup +7 -0
- data/ext/default/assert.c +62 -0
- data/ext/default/cmdline.c +95 -0
- data/ext/default/dynarg.c +45 -0
- data/ext/default/dynarg.h +35 -0
- data/ext/default/extconf.rb +31 -0
- data/ext/default/main.c +28 -0
- data/ext/default/ntoa.c +191 -0
- data/ext/default/printf.c +120 -0
- data/kernaux.gemspec +57 -0
- data/lib/kernaux/version.rb +6 -0
- data/lib/kernaux.rb +238 -0
- metadata +222 -0
data/ext/default/ntoa.c
ADDED
@@ -0,0 +1,191 @@
|
|
1
|
+
#include <kernaux.h>
|
2
|
+
#include <ruby.h>
|
3
|
+
|
4
|
+
#ifdef HAVE_KERNAUX_UTOA
|
5
|
+
static VALUE rb_KernAux_utoa(VALUE self, VALUE number, VALUE base);
|
6
|
+
#endif
|
7
|
+
#ifdef HAVE_KERNAUX_ITOA
|
8
|
+
static VALUE rb_KernAux_itoa(VALUE self, VALUE number, VALUE base);
|
9
|
+
#endif
|
10
|
+
#ifdef HAVE_KERNAUX_UTOA10
|
11
|
+
static VALUE rb_KernAux_utoa10(VALUE self, VALUE number);
|
12
|
+
#endif
|
13
|
+
#ifdef HAVE_KERNAUX_ITOA10
|
14
|
+
static VALUE rb_KernAux_itoa10(VALUE self, VALUE number);
|
15
|
+
#endif
|
16
|
+
#ifdef HAVE_KERNAUX_UTOA16
|
17
|
+
static VALUE rb_KernAux_utoa16(VALUE self, VALUE number);
|
18
|
+
#endif
|
19
|
+
#ifdef HAVE_KERNAUX_ITOA16
|
20
|
+
static VALUE rb_KernAux_itoa16(VALUE self, VALUE number);
|
21
|
+
#endif
|
22
|
+
|
23
|
+
static ID rb_intern_LESS = Qnil;
|
24
|
+
static ID rb_intern_b = Qnil;
|
25
|
+
static ID rb_intern_B = Qnil;
|
26
|
+
static ID rb_intern_freeze = Qnil;
|
27
|
+
static ID rb_intern_h = Qnil;
|
28
|
+
static ID rb_intern_H = Qnil;
|
29
|
+
static ID rb_intern_o = Qnil;
|
30
|
+
static ID rb_intern_O = Qnil;
|
31
|
+
static ID rb_intern_d = Qnil;
|
32
|
+
static ID rb_intern_D = Qnil;
|
33
|
+
static ID rb_intern_x = Qnil;
|
34
|
+
static ID rb_intern_X = Qnil;
|
35
|
+
|
36
|
+
static VALUE rb_KernAux = Qnil;
|
37
|
+
static VALUE rb_KernAux_Error = Qnil;
|
38
|
+
static VALUE rb_KernAux_InvalidNtoaBaseError = Qnil;
|
39
|
+
|
40
|
+
#if defined(HAVE_KERNAUX_UTOA) || defined(HAVE_KERNAUX_ITOA)
|
41
|
+
static int convert_base(VALUE base);
|
42
|
+
#endif
|
43
|
+
|
44
|
+
void init_ntoa()
|
45
|
+
{
|
46
|
+
rb_gc_register_mark_object(ID2SYM(rb_intern_LESS = rb_intern("<")));
|
47
|
+
rb_gc_register_mark_object(ID2SYM(rb_intern_b = rb_intern("b")));
|
48
|
+
rb_gc_register_mark_object(ID2SYM(rb_intern_B = rb_intern("B")));
|
49
|
+
rb_gc_register_mark_object(ID2SYM(rb_intern_freeze = rb_intern("freeze")));
|
50
|
+
rb_gc_register_mark_object(ID2SYM(rb_intern_h = rb_intern("h")));
|
51
|
+
rb_gc_register_mark_object(ID2SYM(rb_intern_H = rb_intern("H")));
|
52
|
+
rb_gc_register_mark_object(ID2SYM(rb_intern_o = rb_intern("o")));
|
53
|
+
rb_gc_register_mark_object(ID2SYM(rb_intern_O = rb_intern("O")));
|
54
|
+
rb_gc_register_mark_object(ID2SYM(rb_intern_d = rb_intern("d")));
|
55
|
+
rb_gc_register_mark_object(ID2SYM(rb_intern_D = rb_intern("D")));
|
56
|
+
rb_gc_register_mark_object(ID2SYM(rb_intern_x = rb_intern("x")));
|
57
|
+
rb_gc_register_mark_object(ID2SYM(rb_intern_X = rb_intern("X")));
|
58
|
+
|
59
|
+
rb_gc_register_mark_object(rb_KernAux = rb_define_module("KernAux"));
|
60
|
+
rb_gc_register_mark_object(rb_KernAux_Error =
|
61
|
+
rb_define_class_under(rb_KernAux, "Error", rb_eRuntimeError));
|
62
|
+
rb_gc_register_mark_object(rb_KernAux_InvalidNtoaBaseError =
|
63
|
+
rb_define_class_under(rb_KernAux, "InvalidNtoaBaseError",
|
64
|
+
rb_KernAux_Error));
|
65
|
+
|
66
|
+
#ifdef HAVE_KERNAUX_UTOA
|
67
|
+
rb_define_singleton_method(rb_KernAux, "utoa", rb_KernAux_utoa, 2);
|
68
|
+
#endif
|
69
|
+
#ifdef HAVE_KERNAUX_ITOA
|
70
|
+
rb_define_singleton_method(rb_KernAux, "itoa", rb_KernAux_itoa, 2);
|
71
|
+
#endif
|
72
|
+
#ifdef HAVE_KERNAUX_UTOA10
|
73
|
+
rb_define_singleton_method(rb_KernAux, "utoa10", rb_KernAux_utoa10, 1);
|
74
|
+
#endif
|
75
|
+
#ifdef HAVE_KERNAUX_ITOA10
|
76
|
+
rb_define_singleton_method(rb_KernAux, "itoa10", rb_KernAux_itoa10, 1);
|
77
|
+
#endif
|
78
|
+
#ifdef HAVE_KERNAUX_UTOA16
|
79
|
+
rb_define_singleton_method(rb_KernAux, "utoa16", rb_KernAux_utoa16, 1);
|
80
|
+
#endif
|
81
|
+
#ifdef HAVE_KERNAUX_ITOA16
|
82
|
+
rb_define_singleton_method(rb_KernAux, "itoa16", rb_KernAux_itoa16, 1);
|
83
|
+
#endif
|
84
|
+
}
|
85
|
+
|
86
|
+
#ifdef HAVE_KERNAUX_UTOA
|
87
|
+
VALUE rb_KernAux_utoa(
|
88
|
+
const VALUE self_rb __attribute__((unused)),
|
89
|
+
const VALUE number_rb,
|
90
|
+
const VALUE base_rb
|
91
|
+
) {
|
92
|
+
RB_INTEGER_TYPE_P(number_rb);
|
93
|
+
if (rb_funcall(number_rb, rb_intern_LESS, 1, INT2FIX(0))) {
|
94
|
+
rb_raise(rb_eRangeError, "can't convert negative number to uint64_t");
|
95
|
+
}
|
96
|
+
char buffer[KERNAUX_UTOA_BUFFER_SIZE];
|
97
|
+
kernaux_utoa(NUM2ULL(number_rb), buffer, convert_base(base_rb));
|
98
|
+
return rb_funcall(rb_str_new2(buffer), rb_intern_freeze, 0);
|
99
|
+
}
|
100
|
+
#endif
|
101
|
+
|
102
|
+
#ifdef HAVE_KERNAUX_ITOA
|
103
|
+
VALUE rb_KernAux_itoa(
|
104
|
+
const VALUE self_rb __attribute__((unused)),
|
105
|
+
const VALUE number_rb,
|
106
|
+
const VALUE base_rb
|
107
|
+
) {
|
108
|
+
RB_INTEGER_TYPE_P(number_rb);
|
109
|
+
char buffer[KERNAUX_ITOA_BUFFER_SIZE];
|
110
|
+
kernaux_itoa(NUM2LL(number_rb), buffer, convert_base(base_rb));
|
111
|
+
return rb_funcall(rb_str_new2(buffer), rb_intern_freeze, 0);
|
112
|
+
}
|
113
|
+
#endif
|
114
|
+
|
115
|
+
#ifdef HAVE_KERNAUX_UTOA10
|
116
|
+
VALUE rb_KernAux_utoa10(
|
117
|
+
const VALUE self_rb __attribute__((unused)),
|
118
|
+
const VALUE number_rb
|
119
|
+
) {
|
120
|
+
RB_INTEGER_TYPE_P(number_rb);
|
121
|
+
if (rb_funcall(number_rb, rb_intern_LESS, 1, INT2FIX(0))) {
|
122
|
+
rb_raise(rb_eRangeError, "can't convert negative number to uint64_t");
|
123
|
+
}
|
124
|
+
char buffer[KERNAUX_UTOA10_BUFFER_SIZE];
|
125
|
+
kernaux_utoa10(NUM2ULL(number_rb), buffer);
|
126
|
+
return rb_funcall(rb_str_new2(buffer), rb_intern_freeze, 0);
|
127
|
+
}
|
128
|
+
#endif
|
129
|
+
|
130
|
+
#ifdef HAVE_KERNAUX_ITOA10
|
131
|
+
VALUE rb_KernAux_itoa10(
|
132
|
+
const VALUE self_rb __attribute__((unused)),
|
133
|
+
const VALUE number_rb
|
134
|
+
) {
|
135
|
+
RB_INTEGER_TYPE_P(number_rb);
|
136
|
+
char buffer[KERNAUX_ITOA10_BUFFER_SIZE];
|
137
|
+
kernaux_itoa10(NUM2LL(number_rb), buffer);
|
138
|
+
return rb_funcall(rb_str_new2(buffer), rb_intern_freeze, 0);
|
139
|
+
}
|
140
|
+
#endif
|
141
|
+
|
142
|
+
#ifdef HAVE_KERNAUX_UTOA16
|
143
|
+
VALUE rb_KernAux_utoa16(
|
144
|
+
const VALUE self_rb __attribute__((unused)),
|
145
|
+
const VALUE number_rb
|
146
|
+
) {
|
147
|
+
RB_INTEGER_TYPE_P(number_rb);
|
148
|
+
if (rb_funcall(number_rb, rb_intern_LESS, 1, INT2FIX(0))) {
|
149
|
+
rb_raise(rb_eRangeError, "can't convert negative number to uint64_t");
|
150
|
+
}
|
151
|
+
char buffer[KERNAUX_UTOA16_BUFFER_SIZE];
|
152
|
+
kernaux_utoa16(NUM2ULL(number_rb), buffer);
|
153
|
+
return rb_funcall(rb_str_new2(buffer), rb_intern_freeze, 0);
|
154
|
+
}
|
155
|
+
#endif
|
156
|
+
|
157
|
+
#ifdef HAVE_KERNAUX_ITOA16
|
158
|
+
VALUE rb_KernAux_itoa16(
|
159
|
+
const VALUE self_rb __attribute__((unused)),
|
160
|
+
const VALUE number_rb
|
161
|
+
) {
|
162
|
+
RB_INTEGER_TYPE_P(number_rb);
|
163
|
+
char buffer[KERNAUX_ITOA16_BUFFER_SIZE];
|
164
|
+
kernaux_itoa16(NUM2LL(number_rb), buffer);
|
165
|
+
return rb_funcall(rb_str_new2(buffer), rb_intern_freeze, 0);
|
166
|
+
}
|
167
|
+
#endif
|
168
|
+
|
169
|
+
#if defined(HAVE_KERNAUX_UTOA) || defined(HAVE_KERNAUX_ITOA)
|
170
|
+
int convert_base(const VALUE base_rb)
|
171
|
+
{
|
172
|
+
if (TYPE(base_rb) == T_SYMBOL) {
|
173
|
+
const ID base_id = SYM2ID(base_rb);
|
174
|
+
if (base_id == rb_intern_b) return 'b';
|
175
|
+
else if (base_id == rb_intern_B) return 'B';
|
176
|
+
else if (base_id == rb_intern_h) return 'h';
|
177
|
+
else if (base_id == rb_intern_H) return 'H';
|
178
|
+
else if (base_id == rb_intern_o) return 'o';
|
179
|
+
else if (base_id == rb_intern_O) return 'O';
|
180
|
+
else if (base_id == rb_intern_d) return 'd';
|
181
|
+
else if (base_id == rb_intern_D) return 'D';
|
182
|
+
else if (base_id == rb_intern_x) return 'x';
|
183
|
+
else if (base_id == rb_intern_X) return 'X';
|
184
|
+
else {
|
185
|
+
rb_raise(rb_KernAux_InvalidNtoaBaseError, "invalid base");
|
186
|
+
}
|
187
|
+
} else {
|
188
|
+
return NUM2INT(base_rb);
|
189
|
+
}
|
190
|
+
}
|
191
|
+
#endif
|
@@ -0,0 +1,120 @@
|
|
1
|
+
#include <kernaux.h>
|
2
|
+
#include <ruby.h>
|
3
|
+
|
4
|
+
#include "dynarg.h"
|
5
|
+
|
6
|
+
#ifdef HAVE_KERNAUX_SNPRINTF
|
7
|
+
|
8
|
+
static VALUE rb_KernAux_snprintf1(int argc, const VALUE *argv, VALUE self);
|
9
|
+
|
10
|
+
static ID rb_intern_freeze = Qnil;
|
11
|
+
static VALUE rb_KernAux = Qnil;
|
12
|
+
|
13
|
+
void init_printf()
|
14
|
+
{
|
15
|
+
rb_gc_register_mark_object(ID2SYM(rb_intern_freeze = rb_intern("freeze")));
|
16
|
+
rb_gc_register_mark_object(rb_KernAux = rb_define_module("KernAux"));
|
17
|
+
|
18
|
+
rb_define_singleton_method(rb_KernAux, "snprintf1",
|
19
|
+
rb_KernAux_snprintf1, -1);
|
20
|
+
}
|
21
|
+
|
22
|
+
// TODO: is this implementation correct?
|
23
|
+
// FIXME: rewrite to ensure no memory leak on exception.
|
24
|
+
VALUE rb_KernAux_snprintf1(
|
25
|
+
const int argc,
|
26
|
+
const VALUE *const argv_rb,
|
27
|
+
const VALUE self __attribute__((unused))
|
28
|
+
) {
|
29
|
+
if (argc < 2 || argc > 5) rb_raise(rb_eArgError, "expected 2, 3, 4 or 5 args");
|
30
|
+
|
31
|
+
const VALUE size_rb = argv_rb[0];
|
32
|
+
VALUE format_rb = argv_rb[1];
|
33
|
+
|
34
|
+
const int size = NUM2INT(size_rb);
|
35
|
+
const char *const format = StringValueCStr(format_rb);
|
36
|
+
|
37
|
+
if (size < 0) rb_raise(rb_eRangeError, "expected non-negative size");
|
38
|
+
|
39
|
+
const char *fmt = format;
|
40
|
+
|
41
|
+
while (*fmt && *fmt != '%') ++fmt;
|
42
|
+
if (*(fmt++) != '%') rb_raise(rb_eArgError, "invalid format");
|
43
|
+
|
44
|
+
struct KernAux_PrintfFmt_Spec spec = KernAux_PrintfFmt_Spec_create();
|
45
|
+
|
46
|
+
fmt = KernAux_PrintfFmt_Spec_parse(&spec, fmt);
|
47
|
+
|
48
|
+
while (*fmt) {
|
49
|
+
if (*(fmt++) == '%') rb_raise(rb_eArgError, "invalid format");
|
50
|
+
}
|
51
|
+
|
52
|
+
int arg_index = 2;
|
53
|
+
if (spec.set_width && argc > arg_index) {
|
54
|
+
KernAux_PrintfFmt_Spec_set_width(&spec, NUM2INT(argv_rb[arg_index++]));
|
55
|
+
}
|
56
|
+
if (spec.set_precision && argc > arg_index) {
|
57
|
+
KernAux_PrintfFmt_Spec_set_precision(&spec, NUM2INT(argv_rb[arg_index++]));
|
58
|
+
}
|
59
|
+
|
60
|
+
struct DynArg dynarg = DynArg_create();
|
61
|
+
if (argc > arg_index) {
|
62
|
+
VALUE arg_rb = argv_rb[arg_index];
|
63
|
+
|
64
|
+
if (spec.type == KERNAUX_PRINTF_FMT_TYPE_INT) {
|
65
|
+
RB_INTEGER_TYPE_P(arg_rb);
|
66
|
+
DynArg_use_long_long(&dynarg, NUM2LL(arg_rb));
|
67
|
+
} else if (spec.type == KERNAUX_PRINTF_FMT_TYPE_UINT) {
|
68
|
+
RB_INTEGER_TYPE_P(arg_rb);
|
69
|
+
DynArg_use_unsigned_long_long(&dynarg, NUM2ULL(arg_rb));
|
70
|
+
} else if (spec.type == KERNAUX_PRINTF_FMT_TYPE_FLOAT ||
|
71
|
+
spec.type == KERNAUX_PRINTF_FMT_TYPE_EXP)
|
72
|
+
{
|
73
|
+
RB_FLOAT_TYPE_P(arg_rb);
|
74
|
+
DynArg_use_double(&dynarg, NUM2DBL(arg_rb));
|
75
|
+
} else if (spec.type == KERNAUX_PRINTF_FMT_TYPE_CHAR) {
|
76
|
+
Check_Type(arg_rb, T_STRING);
|
77
|
+
DynArg_use_char(&dynarg, *StringValuePtr(arg_rb));
|
78
|
+
} else if (spec.type == KERNAUX_PRINTF_FMT_TYPE_STR) {
|
79
|
+
Check_Type(arg_rb, T_STRING);
|
80
|
+
DynArg_use_str(&dynarg, StringValueCStr(arg_rb));
|
81
|
+
}
|
82
|
+
}
|
83
|
+
|
84
|
+
char *const str = malloc(size);
|
85
|
+
if (!str) rb_raise(rb_eNoMemError, "snprintf1 buffer malloc");
|
86
|
+
|
87
|
+
int slen;
|
88
|
+
if (spec.set_width) {
|
89
|
+
if (spec.set_precision) {
|
90
|
+
slen = dynarg.use_dbl
|
91
|
+
? kernaux_snprintf(str, size, format, spec.width, spec.precision, dynarg.dbl)
|
92
|
+
: kernaux_snprintf(str, size, format, spec.width, spec.precision, dynarg.arg);
|
93
|
+
} else {
|
94
|
+
slen = dynarg.use_dbl
|
95
|
+
? kernaux_snprintf(str, size, format, spec.width, dynarg.dbl)
|
96
|
+
: kernaux_snprintf(str, size, format, spec.width, dynarg.arg);
|
97
|
+
}
|
98
|
+
} else {
|
99
|
+
if (spec.set_precision) {
|
100
|
+
slen = dynarg.use_dbl
|
101
|
+
? kernaux_snprintf(str, size, format, spec.precision, dynarg.dbl)
|
102
|
+
: kernaux_snprintf(str, size, format, spec.precision, dynarg.arg);
|
103
|
+
} else {
|
104
|
+
slen = dynarg.use_dbl
|
105
|
+
? kernaux_snprintf(str, size, format, dynarg.dbl)
|
106
|
+
: kernaux_snprintf(str, size, format, dynarg.arg);
|
107
|
+
}
|
108
|
+
}
|
109
|
+
|
110
|
+
const VALUE output_rb =
|
111
|
+
rb_funcall(rb_str_new2(str), rb_intern_freeze, 0);
|
112
|
+
free(str);
|
113
|
+
|
114
|
+
const VALUE result_rb = rb_ary_new2(2);
|
115
|
+
rb_ary_push(result_rb, output_rb);
|
116
|
+
rb_ary_push(result_rb, INT2NUM(slen));
|
117
|
+
return rb_funcall(result_rb, rb_intern_freeze, 0);
|
118
|
+
}
|
119
|
+
|
120
|
+
#endif // HAVE_KERNAUX_SNPRINTF
|
data/kernaux.gemspec
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'lib/kernaux/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
repo = 'https://github.com/tailix/libkernaux'
|
7
|
+
home = "#{repo}/tree/master/pkgs/ruby"
|
8
|
+
bugs = "#{repo}/issues"
|
9
|
+
|
10
|
+
spec.name = 'kernaux'
|
11
|
+
spec.version = KernAux::VERSION
|
12
|
+
spec.license = 'MIT'
|
13
|
+
spec.homepage = home
|
14
|
+
spec.platform = Gem::Platform::RUBY
|
15
|
+
|
16
|
+
spec.required_ruby_version = '~> 3.0'
|
17
|
+
|
18
|
+
spec.authors = ['Alex Kotov']
|
19
|
+
spec.email = %w[kotovalexarian@gmail.com]
|
20
|
+
|
21
|
+
spec.summary =
|
22
|
+
'Binding to libkernaux - auxiliary library for kernel development'
|
23
|
+
|
24
|
+
spec.description = <<~DESCRIPTION.split("\n").map(&:strip).join ' '
|
25
|
+
Binding to libkernaux - auxiliary library for kernel development.
|
26
|
+
DESCRIPTION
|
27
|
+
|
28
|
+
spec.metadata['homepage_uri'] = home
|
29
|
+
spec.metadata['source_code_uri'] = home
|
30
|
+
spec.metadata['bug_tracker_uri'] = bugs
|
31
|
+
spec.metadata['rubygems_mfa_required'] = 'true'
|
32
|
+
|
33
|
+
spec.bindir = 'exe'
|
34
|
+
spec.require_paths = ['lib']
|
35
|
+
|
36
|
+
spec.files = Dir.chdir File.expand_path __dir__ do
|
37
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
38
|
+
f.match %r{\A(?:test|spec|features)/}
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename f }
|
43
|
+
|
44
|
+
spec.extensions << 'ext/default/extconf.rb'
|
45
|
+
|
46
|
+
spec.add_development_dependency 'bundler', '~> 2.2'
|
47
|
+
spec.add_development_dependency 'pry', '~> 0.14'
|
48
|
+
spec.add_development_dependency 'rake', '~> 13.0'
|
49
|
+
spec.add_development_dependency 'rake-compiler', '~> 1.1'
|
50
|
+
spec.add_development_dependency 'rspec', '~> 3.10'
|
51
|
+
spec.add_development_dependency 'rubocop', '~> 1.25'
|
52
|
+
spec.add_development_dependency 'rubocop-performance', '~> 1.13'
|
53
|
+
spec.add_development_dependency 'rubocop-rake', '~> 0.6'
|
54
|
+
spec.add_development_dependency 'rubocop-rspec', '~> 2.7'
|
55
|
+
spec.add_development_dependency 'simplecov', '~> 0.21'
|
56
|
+
spec.add_development_dependency 'yard', '~> 0.9'
|
57
|
+
end
|
data/lib/kernaux.rb
ADDED
@@ -0,0 +1,238 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'kernaux/version'
|
4
|
+
|
5
|
+
# Native extensions
|
6
|
+
require_relative 'kernaux/default'
|
7
|
+
|
8
|
+
##
|
9
|
+
# Binding to [libkernaux](https://github.com/tailix/libkernaux) - auxiliary
|
10
|
+
# library for kernel development.
|
11
|
+
#
|
12
|
+
module KernAux
|
13
|
+
# Default callback for assertions.
|
14
|
+
# @see .assert_cb
|
15
|
+
DEFAULT_ASSERT_CB = @assert_cb = lambda { |file, line, msg|
|
16
|
+
raise AssertError, "#{file}:#{line}:#{msg}"
|
17
|
+
}
|
18
|
+
|
19
|
+
# Buffer size for {.sprintf1}.
|
20
|
+
# @todo Make it dynamic.
|
21
|
+
SPRINTF1_BUFFER_SIZE = 10_000
|
22
|
+
|
23
|
+
# @!scope class
|
24
|
+
|
25
|
+
##
|
26
|
+
# @!attribute [rw] assert_cb
|
27
|
+
# Panic callback.
|
28
|
+
#
|
29
|
+
# @see .panic
|
30
|
+
# @see .assert_do
|
31
|
+
##
|
32
|
+
|
33
|
+
##
|
34
|
+
# Raise assertion with implicit file and line, retrieved from `caller`, and
|
35
|
+
# explicit message.
|
36
|
+
#
|
37
|
+
# @param msg [String] any message
|
38
|
+
# @return [nil]
|
39
|
+
#
|
40
|
+
# @raise [AssertError] if {.assert_cb} have not been changed
|
41
|
+
#
|
42
|
+
# @see .assert_do Explicit file and line.
|
43
|
+
#
|
44
|
+
def self.panic(msg)
|
45
|
+
file, line = caller(1..1).first.split(':')[0..1]
|
46
|
+
assert_do file, Integer(line), msg
|
47
|
+
end
|
48
|
+
|
49
|
+
##
|
50
|
+
# @!method assert_do(file, line, msg)
|
51
|
+
# Raise assertion with explicit file, line and message.
|
52
|
+
#
|
53
|
+
# @param file [String] file name, usually from `__FILE__`
|
54
|
+
# @param line [Integer] line number, usually from `__LINE__`
|
55
|
+
# @param msg [String] any message
|
56
|
+
# @return [nil]
|
57
|
+
#
|
58
|
+
# @raise [AssertError] if {.assert_cb} have not been changed
|
59
|
+
#
|
60
|
+
# @see .panic Implicit file and line
|
61
|
+
|
62
|
+
# @!parse [ruby]
|
63
|
+
|
64
|
+
if singleton_class.method_defined? :snprintf1
|
65
|
+
##
|
66
|
+
# Typical `printf`.
|
67
|
+
#
|
68
|
+
# @param args [Array<String,
|
69
|
+
# Array<(String, Object)>,
|
70
|
+
# Array<(String, Integer, Object)>>]
|
71
|
+
# @return [String] formatted output
|
72
|
+
#
|
73
|
+
# @example
|
74
|
+
# KernAux.sprintf 'foo', ['%*s', 5, 'bar'], 'car', ['%d', 123]
|
75
|
+
# #=> "foo barcar123"
|
76
|
+
#
|
77
|
+
def self.sprintf(*args)
|
78
|
+
args.map do |arg|
|
79
|
+
if arg.is_a? Array
|
80
|
+
sprintf1(*arg)
|
81
|
+
else
|
82
|
+
arg
|
83
|
+
end
|
84
|
+
end.join.freeze
|
85
|
+
end
|
86
|
+
|
87
|
+
##
|
88
|
+
# `printf` for single formatting parameter.
|
89
|
+
#
|
90
|
+
# @param format [String] formatting string
|
91
|
+
# @return [String] formatted output
|
92
|
+
#
|
93
|
+
# @see .sprintf Multiple formatting parameters
|
94
|
+
#
|
95
|
+
# @example
|
96
|
+
# KernAux.sprintf1 '%%' #=> "%"
|
97
|
+
# KernAux.sprintf1 '%s', 'foo' #=> "foo"
|
98
|
+
# KernAux.sprintf1 '%5s', 'foo' #=> " foo"
|
99
|
+
# KernAux.sprintf1 '%*s', 5, 'foo' #=> " foo"
|
100
|
+
#
|
101
|
+
def self.sprintf1(format, *args)
|
102
|
+
snprintf1(SPRINTF1_BUFFER_SIZE, format, *args).first
|
103
|
+
end
|
104
|
+
|
105
|
+
##
|
106
|
+
# @!method snprintf1(buffer_size, format, ...)
|
107
|
+
# `printf` for single formatting parameter with manual buffer size.
|
108
|
+
#
|
109
|
+
# @param buffer_size [Integer] buffer size (including terminating null
|
110
|
+
# character)
|
111
|
+
# @param format [String] formatting string
|
112
|
+
# @return [Array<(String, Integer)>] formatted output and it's size
|
113
|
+
#
|
114
|
+
# @see .sprintf1 Automatic buffer size
|
115
|
+
##
|
116
|
+
end
|
117
|
+
|
118
|
+
##
|
119
|
+
# @!method cmdline(str)
|
120
|
+
# Parse command line.
|
121
|
+
#
|
122
|
+
# @param str [String] command line string
|
123
|
+
# @return [Array<String>] command line arguments
|
124
|
+
#
|
125
|
+
# @raise [CmdlineError] syntax is invalid
|
126
|
+
|
127
|
+
# @!parse [ruby]
|
128
|
+
|
129
|
+
##
|
130
|
+
# @!method utoa(number, base)
|
131
|
+
# Convert `uint64_t` to a string in multiple numeral systems.
|
132
|
+
#
|
133
|
+
# Base can be a positive or negative integer between 2 and 36, or a symbol
|
134
|
+
# which is an alias to a valid integer value. Positive integers and lowercase
|
135
|
+
# symbols mean lowercase output when base is greater than 10. Negative
|
136
|
+
# integers and uppercase symbols mean uppercase output when base is greater
|
137
|
+
# than 10. Aliases are: `:b`, `:B` - 2; `:o`, `:O` - 8; `:d`, `:D` - 10; `:h`,
|
138
|
+
# `:x` - 16 (lowercase); `:H`, `:X` - -10 (uppercase).
|
139
|
+
#
|
140
|
+
# @param number [Integer] a number between 0 and `UINT64_MAX`
|
141
|
+
# @param base [Integer, Symbol] base of a numeral system
|
142
|
+
# @return [String]
|
143
|
+
#
|
144
|
+
# @raise [RangeError] number is out of range
|
145
|
+
# @raise [InvalidNtoaBaseError] base is invalid
|
146
|
+
#
|
147
|
+
# @see .itoa Convert signed integers
|
148
|
+
##
|
149
|
+
|
150
|
+
##
|
151
|
+
# @!method itoa(number, base)
|
152
|
+
# Convert `int64_t` to a string in multiple numeral systems.
|
153
|
+
#
|
154
|
+
# Base can be a positive or negative integer between 2 and 36, or a symbol
|
155
|
+
# which is an alias to a valid integer value. Positive integers and lowercase
|
156
|
+
# symbols mean lowercase output when base is greater than 10. Negative
|
157
|
+
# integers and uppercase symbols mean uppercase output when base is greater
|
158
|
+
# than 10. Aliases are: `:b`, `:B` - 2; `:o`, `:O` - 8; `:d`, `:D` - 10; `:h`,
|
159
|
+
# `:x` - 16 (lowercase); `:H`, `:X` - -10 (uppercase).
|
160
|
+
#
|
161
|
+
# @param number [Integer] a number between `INT64_MIN` and `INT64_MAX`
|
162
|
+
# @param base [Integer, Symbol] base of a numeral system
|
163
|
+
# @return [String]
|
164
|
+
#
|
165
|
+
# @raise [RangeError] number is out of range
|
166
|
+
# @raise [InvalidNtoaBaseError] base is invalid
|
167
|
+
#
|
168
|
+
# @see .utoa Convert unsigned integers
|
169
|
+
##
|
170
|
+
|
171
|
+
##
|
172
|
+
# @!method utoa10(number)
|
173
|
+
# Convert `uint64_t` to a decimal string.
|
174
|
+
#
|
175
|
+
# @param number [Integer] a number between 0 and `UINT64_MAX`
|
176
|
+
# @return [String]
|
177
|
+
#
|
178
|
+
# @raise [RangeError] number is out of range
|
179
|
+
##
|
180
|
+
|
181
|
+
##
|
182
|
+
# @!method itoa10(number)
|
183
|
+
# Convert `int64_t` to a decimal string.
|
184
|
+
#
|
185
|
+
# @param number [Integer] a number between `INT64_MIN` and `INT64_MAX`
|
186
|
+
# @return [String]
|
187
|
+
#
|
188
|
+
# @raise [RangeError] number is out of range
|
189
|
+
##
|
190
|
+
|
191
|
+
##
|
192
|
+
# @!method utoa16(number)
|
193
|
+
# Convert `uint64_t` to a hexadecimal string.
|
194
|
+
#
|
195
|
+
# @param number [Integer] a number between 0 and `UINT64_MAX`
|
196
|
+
# @return [String]
|
197
|
+
#
|
198
|
+
# @raise [RangeError] number is out of range
|
199
|
+
##
|
200
|
+
|
201
|
+
##
|
202
|
+
# @!method itoa16(number)
|
203
|
+
# Convert `int64_t` to a hexadecimal string.
|
204
|
+
#
|
205
|
+
# @param number [Integer] a number between `INT64_MIN` and `INT64_MAX`
|
206
|
+
# @return [String]
|
207
|
+
#
|
208
|
+
# @raise [RangeError] number is out of range
|
209
|
+
##
|
210
|
+
|
211
|
+
##
|
212
|
+
# Our base class for runtime errors.
|
213
|
+
#
|
214
|
+
class Error < RuntimeError; end
|
215
|
+
|
216
|
+
##
|
217
|
+
# Raised when assertion has failed or panic has been called.
|
218
|
+
#
|
219
|
+
# @see .panic
|
220
|
+
# @see .assert_do
|
221
|
+
#
|
222
|
+
class AssertError < Error; end
|
223
|
+
|
224
|
+
##
|
225
|
+
# Raised when command line parsing goes wrong.
|
226
|
+
#
|
227
|
+
# @see .cmdline
|
228
|
+
#
|
229
|
+
class CmdlineError < Error; end
|
230
|
+
|
231
|
+
##
|
232
|
+
# Raised when integer base is invalid.
|
233
|
+
#
|
234
|
+
# @see .utoa
|
235
|
+
# @see .itoa
|
236
|
+
#
|
237
|
+
class InvalidNtoaBaseError < Error; end
|
238
|
+
end
|