Skip to content

Commit

Permalink
support floating-point number in option value
Browse files Browse the repository at this point in the history
  • Loading branch information
Yao Yue committed Mar 14, 2016
1 parent c163bf8 commit c6baec1
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 8 deletions.
8 changes: 8 additions & 0 deletions include/cc_option.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ extern "C" {

#define OPTION_TYPE_BOOL_VAR vbool
#define OPTION_TYPE_UINT_VAR vuint
#define OPTION_TYPE_FPN_VAR vfpn
#define OPTION_TYPE_STR_VAR vstr

#define OPTION_DECLARE(_name, _type, _default, _description) \
Expand All @@ -62,6 +63,7 @@ extern "C" {
typedef enum option_type {
OPTION_TYPE_BOOL,
OPTION_TYPE_UINT,
OPTION_TYPE_FPN,
OPTION_TYPE_STR,
OPTION_TYPE_SENTINEL
} option_type_e;
Expand All @@ -72,6 +74,7 @@ extern char *option_type_str[];
typedef union option_val {
bool vbool;
uintmax_t vuint;
double vfpn;
char *vstr;
} option_val_u;

Expand All @@ -95,6 +98,11 @@ option_uint(struct option *opt) {
return opt->val.vuint;
}

static inline double
option_fpn(struct option *opt) {
return opt->val.vfpn;
}

static inline char *
option_str(struct option *opt) {
return opt->val.vstr;
Expand Down
32 changes: 32 additions & 0 deletions src/cc_option.c
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,31 @@ _option_parse_uint(struct option *opt, const char *val_str)
return CC_OK;
}

static rstatus_i
_option_parse_fpn(struct option *opt, const char *val_str)
{
/* TODO: handle expressions similar to what's allowed with integers */
double val = 0;
char *loc;

val = strtod(val_str, &loc);
if (errno == ERANGE) {
log_stderr("option value %s out of range for double type", val_str);
return CC_ERROR;
}

if (*loc != '\0') {
log_stderr("option value %s could not be fully parsed, check char at "
"offset %ld", val_str, loc - val_str);
return CC_ERROR;
}

opt->set = true;
opt->val.vfpn = val;

return CC_OK;
}

static rstatus_i
_option_parse_str(struct option *opt, const char *val_str)
{
Expand Down Expand Up @@ -358,6 +383,10 @@ option_default(struct option *opt)
opt->val.vuint = opt->default_val.vuint;
break;

case OPTION_TYPE_FPN:
opt->val.vfpn = opt->default_val.vfpn;
break;

case OPTION_TYPE_STR:
if (opt->default_val.vstr == NULL) {
opt->val.vstr = NULL;
Expand Down Expand Up @@ -390,6 +419,9 @@ option_set(struct option *opt, char *val_str)
case OPTION_TYPE_UINT:
return _option_parse_uint(opt, val_str);

case OPTION_TYPE_FPN:
return _option_parse_fpn(opt, val_str);

case OPTION_TYPE_STR:
return _option_parse_str(opt, val_str);

Expand Down
1 change: 1 addition & 0 deletions test/option/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ set(source check_${suite}.c)

add_executable(${test_name} ${source})
target_link_libraries(${test_name} ccommon-static ${CHECK_LIBRARIES})
target_link_libraries(${test_name} m)

add_dependencies(check ${test_name})
add_test(${test_name} ${test_name})
49 changes: 41 additions & 8 deletions test/option/check_option.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <check.h>

#include <math.h>
#include <stdlib.h>
#include <stdio.h>

Expand Down Expand Up @@ -73,31 +74,57 @@ START_TEST(test_parse_uinteger)
ck_assert_int_eq(opt.set, false);

opt.set = false;
opt.val.vuint = false;
opt.val.vuint = 0;
ck_assert_int_eq(option_set(&opt, "1"), CC_OK);
ck_assert_int_eq(opt.val.vuint, 1);
ck_assert_int_eq(opt.set, true);

opt.set = false;
opt.val.vuint = false;
opt.val.vuint = 0;
ck_assert_int_eq(option_set(&opt, "1 + 1"), CC_OK);
ck_assert_int_eq(opt.val.vuint, 2);
ck_assert_int_eq(opt.set, true);

opt.set = false;
opt.val.vuint = false;
opt.val.vuint = 0;
ck_assert_int_eq(option_set(&opt, "1 + 2 * 3"), CC_OK);
ck_assert_int_eq(opt.val.vuint, 7);
ck_assert_int_eq(opt.set, true);

opt.set = false;
opt.val.vuint = false;
opt.val.vuint = 0;
ck_assert_int_eq(option_set(&opt, "(1 + 2) * 3"), CC_OK);
ck_assert_int_eq(opt.val.vuint, 9);
ck_assert_int_eq(opt.set, true);
}
END_TEST

START_TEST(test_parse_float)
{
struct option opt;
opt.type = OPTION_TYPE_FPN;
opt.set = false;

ck_assert_int_ne(option_set(&opt, "invalid"), CC_OK);
ck_assert_int_eq(opt.set, false);

ck_assert_int_ne(option_set(&opt, "1.25ab"), CC_OK);
ck_assert_int_eq(opt.set, false);

opt.set = false;
opt.val.vfpn = 0;
ck_assert_int_eq(option_set(&opt, "1.25"), CC_OK);
ck_assert_msg(fabs(opt.val.vfpn - 1.25) < 1e-5, "value = %f", opt.val.vfpn);
ck_assert_int_eq(opt.set, true);

opt.set = false;
opt.val.vfpn = 0;
ck_assert_int_eq(option_set(&opt, "-1"), CC_OK);
ck_assert(fabs(opt.val.vfpn + 1) < 1e-5);
ck_assert_int_eq(opt.set, true);
}
END_TEST

START_TEST(test_parse_string)
{
struct option opt;
Expand Down Expand Up @@ -154,9 +181,10 @@ tmpname_destroy(char *path)
START_TEST(test_load_file)
{
#define TEST_OPTION(ACTION) \
ACTION( boolean, OPTION_TYPE_BOOL, true, "it may be true of false" )\
ACTION( string, OPTION_TYPE_STR, "foo", "it is a sequence of bytes" )\
ACTION( uinteger, OPTION_TYPE_UINT, 2, "it is a non-negative integer number" )
ACTION( boolean, OPTION_TYPE_BOOL, true, "it may be true of false" )\
ACTION( uinteger, OPTION_TYPE_UINT, 2, "it is a non-negative integer number" )\
ACTION( fpn, OPTION_TYPE_FPN, 1.25, "it is a floating point number" )\
ACTION( string, OPTION_TYPE_STR, "foo", "it is a sequence of bytes" )

#define SETTING(ACTION) \
TEST_OPTION(ACTION)
Expand All @@ -175,8 +203,9 @@ START_TEST(test_load_file)

tmpname = tmpname_create(
"boolean: no\n"
"string: bar\n"
"uinteger: 3\n"
"fpn: 2.5\n"
"string: bar\n"
);
ck_assert_ptr_ne(tmpname, NULL);

Expand All @@ -187,12 +216,15 @@ START_TEST(test_load_file)
CC_OK);
ck_assert_int_eq(setting.boolean.val.vbool, true);
ck_assert_int_eq(setting.uinteger.val.vuint, 2);
ck_assert_msg(fabs(setting.fpn.val.vfpn - 1.25) < 1e-5, "value = %f",
setting.fpn.val.vfpn);
ck_assert_str_eq(setting.string.val.vstr, "foo");

ck_assert_int_eq(option_load_file(fp, (struct option *)&setting, nopt),
CC_OK);
ck_assert_int_eq(setting.boolean.val.vbool, false);
ck_assert_int_eq(setting.uinteger.val.vuint, 3);
ck_assert(fabs(setting.fpn.val.vfpn - 2.5) < 1e-5);
ck_assert_str_eq(setting.string.val.vstr, "bar");

option_free((struct option *)&setting, nopt);
Expand All @@ -215,6 +247,7 @@ option_suite(void)
TCase *tc_option = tcase_create("option test");
tcase_add_test(tc_option, test_parse_bool);
tcase_add_test(tc_option, test_parse_uinteger);
tcase_add_test(tc_option, test_parse_float);
tcase_add_test(tc_option, test_parse_string);
tcase_add_test(tc_option, test_load_file);
suite_add_tcase(s, tc_option);
Expand Down

0 comments on commit c6baec1

Please sign in to comment.