mirror of
https://github.com/tailix/libkernaux.git
synced 2025-02-24 15:55:41 -05:00
mruby: add method KernAux.cmdline
This commit is contained in:
parent
eadae265cc
commit
507eea0de2
4 changed files with 143 additions and 0 deletions
71
pkgs/mruby/src/cmdline.c
Normal file
71
pkgs/mruby/src/cmdline.c
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
#include "main.h"
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <kernaux.h>
|
||||||
|
|
||||||
|
#include <mruby.h>
|
||||||
|
#include <mruby/array.h>
|
||||||
|
#include <mruby/presym.h>
|
||||||
|
#include <mruby/string.h>
|
||||||
|
|
||||||
|
#define ARGV_COUNT_MAX 256
|
||||||
|
#define BUFFER_SIZE 4096
|
||||||
|
|
||||||
|
static mrb_value rb_KernAux_cmdline(mrb_state *mrb, mrb_value self);
|
||||||
|
|
||||||
|
void init_cmdline(mrb_state *const mrb)
|
||||||
|
{
|
||||||
|
struct RClass *const rb_KernAux = mrb_module_get_id(mrb, MRB_SYM(KernAux));
|
||||||
|
struct RClass *const rb_KernAux_Error =
|
||||||
|
mrb_class_get_under_id(mrb, rb_KernAux, MRB_SYM(Error));
|
||||||
|
|
||||||
|
mrb_define_class_under_id(mrb, rb_KernAux, MRB_SYM(CmdlineError),
|
||||||
|
rb_KernAux_Error);
|
||||||
|
|
||||||
|
mrb_define_class_method(mrb, rb_KernAux, "cmdline",
|
||||||
|
rb_KernAux_cmdline, MRB_ARGS_REQ(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
mrb_value rb_KernAux_cmdline(mrb_state *const mrb, mrb_value self)
|
||||||
|
{
|
||||||
|
const char *str;
|
||||||
|
mrb_get_args(mrb, "z", &str);
|
||||||
|
size_t argc;
|
||||||
|
char error_msg[KERNAUX_CMDLINE_ERROR_MSG_SIZE_MAX];
|
||||||
|
char **const argv = malloc(sizeof(char*) * ARGV_COUNT_MAX);
|
||||||
|
char *const buffer = malloc(BUFFER_SIZE);
|
||||||
|
|
||||||
|
const bool status = kernaux_cmdline(
|
||||||
|
str,
|
||||||
|
error_msg,
|
||||||
|
&argc,
|
||||||
|
argv,
|
||||||
|
buffer,
|
||||||
|
ARGV_COUNT_MAX,
|
||||||
|
BUFFER_SIZE
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!status) {
|
||||||
|
free(argv);
|
||||||
|
free(buffer);
|
||||||
|
struct RClass *const rb_KernAux =
|
||||||
|
mrb_module_get_id(mrb, MRB_SYM(KernAux));
|
||||||
|
struct RClass *const rb_KernAux_CmdlineError =
|
||||||
|
mrb_class_get_under_id(mrb, rb_KernAux, MRB_SYM(CmdlineError));
|
||||||
|
mrb_raise(mrb, rb_KernAux_CmdlineError, error_msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
mrb_value values[argc];
|
||||||
|
for (size_t index = 0; index < argc; ++index) {
|
||||||
|
values[index] = mrb_obj_freeze(
|
||||||
|
mrb,
|
||||||
|
mrb_str_cat_cstr(mrb, mrb_str_new_lit(mrb, ""), argv[index])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
free(argv);
|
||||||
|
free(buffer);
|
||||||
|
return mrb_obj_freeze(mrb, mrb_ary_new_from_values(mrb, argc, values));
|
||||||
|
}
|
|
@ -26,6 +26,7 @@ void mrb_mruby_kernaux_gem_init(mrb_state *const mrb)
|
||||||
|
|
||||||
init_assert(mrb);
|
init_assert(mrb);
|
||||||
init_ntoa(mrb);
|
init_ntoa(mrb);
|
||||||
|
init_cmdline(mrb);
|
||||||
}
|
}
|
||||||
|
|
||||||
void current_mrb_start(mrb_state *mrb)
|
void current_mrb_start(mrb_state *mrb)
|
||||||
|
|
|
@ -9,5 +9,6 @@ mrb_state *current_mrb_get();
|
||||||
|
|
||||||
void init_assert(mrb_state *mrb);
|
void init_assert(mrb_state *mrb);
|
||||||
void init_ntoa(mrb_state *mrb);
|
void init_ntoa(mrb_state *mrb);
|
||||||
|
void init_cmdline(mrb_state *mrb);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
70
pkgs/mruby/test/cmdline.rb
Normal file
70
pkgs/mruby/test/cmdline.rb
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
def test_cmdline(str, expected)
|
||||||
|
result = KernAux.cmdline str
|
||||||
|
|
||||||
|
assert_true result.instance_of? Array
|
||||||
|
assert_true result.frozen?
|
||||||
|
result.each do |item|
|
||||||
|
assert_true item.instance_of? String
|
||||||
|
assert_true item.frozen?
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_equal result, expected
|
||||||
|
end
|
||||||
|
|
||||||
|
assert 'default' do
|
||||||
|
test_cmdline 'foo bar\\ baz "car cdr"', ['foo', 'bar baz', 'car cdr']
|
||||||
|
end
|
||||||
|
|
||||||
|
assert 'when str is empty' do
|
||||||
|
test_cmdline '', []
|
||||||
|
end
|
||||||
|
|
||||||
|
assert 'when str has invalid type' do
|
||||||
|
assert_raise TypeError, 'Integer cannot be converted to String' do
|
||||||
|
KernAux.cmdline 123
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assert 'when str has EOL after backslash' do
|
||||||
|
assert_raise KernAux::CmdlineError, 'EOL after backslash' do
|
||||||
|
KernAux.cmdline '\\'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assert 'when str has EOL after backslash inside quote' do
|
||||||
|
assert_raise KernAux::CmdlineError, 'EOL after backslash inside quote' do
|
||||||
|
KernAux.cmdline '"\\'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assert 'when str has unescaped quotation mark' do
|
||||||
|
assert_raise KernAux::CmdlineError, 'unescaped quotation mark' do
|
||||||
|
KernAux.cmdline 'foo"'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assert 'when str has EOL inside quote' do
|
||||||
|
assert_raise KernAux::CmdlineError, 'EOL inside quote' do
|
||||||
|
KernAux.cmdline '"'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assert 'when there are not too many args' do
|
||||||
|
test_cmdline 'a ' * 256, ['a'] * 256
|
||||||
|
end
|
||||||
|
|
||||||
|
assert 'when there are too many args' do
|
||||||
|
assert_raise KernAux::CmdlineError, 'too many args' do
|
||||||
|
KernAux.cmdline 'a ' * 257
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assert 'when args don\'t cause buffer overflow' do
|
||||||
|
test_cmdline 'a' * 4095, ['a' * 4095]
|
||||||
|
end
|
||||||
|
|
||||||
|
assert 'when args cause buffer overflow' do
|
||||||
|
assert_raise KernAux::CmdlineError, 'buffer overflow' do
|
||||||
|
KernAux.cmdline 'a' * 4096
|
||||||
|
end
|
||||||
|
end
|
Loading…
Add table
Reference in a new issue