forked from elastic/kibana
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for number unit suffixes
There are a number of cases in the configuration where one needs to set a size (think buffer sizes), and counting zeroes is extremely annoying and unintuitive. For this reason, we introduce number unit suffixes for kilo-, mega- and giga-: K, M, G, respectively (case-insensitive, optionally followed by a 'b' or 'B', for byte). The parser also understands KiB, MiB, etc to indicate base-two units. Anywhere where you can specify a number, you'll be able to specify one with a unit suffix from now on: log-fifo-size(200M) A function to parse longs already existed in basic-funcs (tf_parse_int), which was moved to lib/parse-number.c now, and enhanced to recognise the unit suffixes too. This also closes elastic#28. Signed-off-by: Balazs Scheidler <[email protected]> Signed-off-by: Gergely Nagy <[email protected]>
- Loading branch information
Showing
9 changed files
with
310 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
#include "parse-number.h" | ||
|
||
#include <string.h> | ||
#include <errno.h> | ||
#include <stdlib.h> | ||
|
||
static gboolean | ||
_valid_unit(const gchar unit_char) | ||
{ | ||
return (unit_char == 'B' || unit_char == 'b'); | ||
} | ||
|
||
static gboolean | ||
_valid_exponent(const gchar exponent_char) | ||
{ | ||
gchar e = exponent_char; | ||
|
||
return e == 'k' || e == 'K' || | ||
e == 'm' || e == 'M' || | ||
e == 'g' || e == 'G'; | ||
} | ||
|
||
static gboolean | ||
_parse_suffix(const gchar *suffix, gchar *exponent_char, gchar *base_char, gchar *unit_char) | ||
{ | ||
gint suffix_len; | ||
|
||
suffix_len = strlen(suffix); | ||
if (suffix_len > 3) | ||
return FALSE; | ||
if (suffix_len == 0) | ||
return TRUE; | ||
|
||
if (suffix_len == 3) | ||
{ | ||
*exponent_char = suffix[0]; | ||
*base_char = suffix[1]; | ||
*unit_char = suffix[2]; | ||
} | ||
else if (suffix_len == 2) | ||
{ | ||
*exponent_char = suffix[0]; | ||
if (_valid_unit(suffix[1])) | ||
*unit_char = suffix[1]; | ||
else | ||
*base_char = suffix[1]; | ||
} | ||
else if (suffix_len == 1) | ||
{ | ||
if (_valid_exponent(suffix[0])) | ||
*exponent_char = suffix[0]; | ||
else if (_valid_unit(suffix[0])) | ||
*unit_char = suffix[0]; | ||
else | ||
return FALSE; | ||
} | ||
return TRUE; | ||
} | ||
|
||
static gboolean | ||
_determine_multiplier(gchar base_char, glong *multiplier) | ||
{ | ||
if (base_char == 0) | ||
*multiplier = 1000; | ||
else if (base_char == 'I' || base_char == 'i') | ||
*multiplier = 1024; | ||
else | ||
return FALSE; | ||
return TRUE; | ||
} | ||
|
||
static gboolean | ||
_validate_unit(gchar unit_char) | ||
{ | ||
if (unit_char && !_valid_unit(unit_char)) | ||
return FALSE; | ||
return TRUE; | ||
} | ||
|
||
static gboolean | ||
_process_exponent(gchar exponent_char, glong *d, glong multiplier) | ||
{ | ||
switch (exponent_char) | ||
{ | ||
case 'G': | ||
case 'g': | ||
(*d) *= multiplier; | ||
case 'm': | ||
case 'M': | ||
(*d) *= multiplier; | ||
case 'K': | ||
case 'k': | ||
(*d) *= multiplier; | ||
case 0: | ||
return TRUE; | ||
default: | ||
return FALSE; | ||
} | ||
} | ||
|
||
static gboolean | ||
_process_suffix(const gchar *suffix, glong *d) | ||
{ | ||
gchar exponent_char = 0, base_char = 0, unit_char = 0; | ||
glong multiplier = 0; | ||
|
||
if (!_parse_suffix(suffix, &exponent_char, &base_char, &unit_char)) | ||
return FALSE; | ||
|
||
if (!_determine_multiplier(base_char, &multiplier)) | ||
return FALSE; | ||
|
||
if (!_validate_unit(unit_char)) | ||
return FALSE; | ||
|
||
if (!_process_exponent(exponent_char, d, multiplier)) | ||
return FALSE; | ||
|
||
return TRUE; | ||
} | ||
|
||
static gboolean | ||
_parse_number(const gchar *s, gchar **endptr, long *d) | ||
{ | ||
glong val; | ||
|
||
errno = 0; | ||
val = strtoll(s, endptr, 10); | ||
|
||
if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) | ||
|| (errno != 0 && val == 0)) | ||
return FALSE; | ||
|
||
if (*endptr == s) | ||
return FALSE; | ||
|
||
*d = val; | ||
return TRUE; | ||
} | ||
|
||
gboolean | ||
parse_number(const gchar *s, glong *d) | ||
{ | ||
gchar *endptr; | ||
|
||
if (!_parse_number(s, &endptr, d)) | ||
return FALSE; | ||
if (*endptr) | ||
return FALSE; | ||
return TRUE; | ||
} | ||
|
||
gboolean | ||
parse_number_with_suffix(const gchar *s, glong *d) | ||
{ | ||
gchar *endptr; | ||
|
||
if (!_parse_number(s, &endptr, d)) | ||
return FALSE; | ||
return _process_suffix(endptr, d); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
#ifndef PARSE_NUMBER_H_INCLUDED | ||
#define PARSE_NUMBER_H_INCLUDED | ||
|
||
#include "syslog-ng.h" | ||
|
||
gboolean parse_number_with_suffix(const gchar *str, glong *result); | ||
gboolean parse_number(const gchar *str, glong *result); | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
#include <stdlib.h> | ||
|
||
#include "testutils.h" | ||
#include "parse-number.h" | ||
|
||
static void | ||
assert_parse_with_suffix(const gchar *str, long expected) | ||
{ | ||
long n; | ||
gboolean res; | ||
|
||
res = parse_number_with_suffix(str, &n); | ||
|
||
assert_gboolean(res, TRUE, "Parsing (w/ suffix) %s failed", str); | ||
assert_gint64(n, expected, "Parsing (w/ suffix) %s failed", str); | ||
} | ||
|
||
static void | ||
assert_parse_with_suffix_fails(const gchar *str) | ||
{ | ||
long n; | ||
gboolean res; | ||
|
||
res = parse_number_with_suffix(str, &n); | ||
assert_gboolean(res, FALSE, "Parsing (w/ suffix) %s succeeded, while expecting failure", str); | ||
} | ||
|
||
static void | ||
assert_parse(const gchar *str, long expected) | ||
{ | ||
long n; | ||
gboolean res; | ||
|
||
res = parse_number(str, &n); | ||
|
||
assert_gboolean(res, TRUE, "Parsing (w/o suffix) %s failed", str); | ||
assert_gint64(n, expected, "Parsing (w/o suffix) %s failed", str); | ||
} | ||
|
||
static void | ||
assert_parse_fails(const gchar *str) | ||
{ | ||
long n; | ||
gboolean res; | ||
|
||
res = parse_number(str, &n); | ||
|
||
assert_gboolean(res, FALSE, "Parsing (w/o suffix) %s succeeded, while expecting failure", str); | ||
} | ||
|
||
static void | ||
test_simple_numbers_are_parsed_properly(void) | ||
{ | ||
assert_parse_with_suffix("1234", 1234); | ||
assert_parse_with_suffix("+1234", 1234); | ||
assert_parse_with_suffix("-1234", -1234); | ||
|
||
assert_parse("1234", 1234); | ||
} | ||
|
||
static void | ||
test_exponent_suffix_is_parsed_properly(void) | ||
{ | ||
assert_parse_with_suffix("1K", 1000); | ||
assert_parse_with_suffix("1k", 1000); | ||
assert_parse_with_suffix("1m", 1000 * 1000); | ||
assert_parse_with_suffix("1M", 1000 * 1000); | ||
assert_parse_with_suffix("1G", 1000 * 1000 * 1000); | ||
assert_parse_with_suffix("1g", 1000 * 1000 * 1000); | ||
} | ||
|
||
static void | ||
test_byte_units_are_accepted(void) | ||
{ | ||
assert_parse_with_suffix("1b", 1); | ||
assert_parse_with_suffix("1B", 1); | ||
assert_parse_with_suffix("1Kb", 1000); | ||
assert_parse_with_suffix("1kB", 1000); | ||
assert_parse_with_suffix("1mb", 1000 * 1000); | ||
assert_parse_with_suffix("1MB", 1000 * 1000); | ||
assert_parse_with_suffix("1Gb", 1000 * 1000 * 1000); | ||
assert_parse_with_suffix("1gB", 1000 * 1000 * 1000); | ||
} | ||
|
||
static void | ||
test_base2_is_selected_by_an_i_modifier(void) | ||
{ | ||
assert_parse_with_suffix("1Kib", 1024); | ||
assert_parse_with_suffix("1kiB", 1024); | ||
assert_parse_with_suffix("1Ki", 1024); | ||
assert_parse_with_suffix("1kI", 1024); | ||
assert_parse_with_suffix("1mib", 1024 * 1024); | ||
assert_parse_with_suffix("1MiB", 1024 * 1024); | ||
assert_parse_with_suffix("1Gib", 1024 * 1024 * 1024); | ||
assert_parse_with_suffix("1giB", 1024 * 1024 * 1024); | ||
} | ||
|
||
static void | ||
test_invalid_formats_are_not_accepted(void) | ||
{ | ||
assert_parse_with_suffix_fails("1234Z"); | ||
assert_parse_with_suffix_fails("1234kZ"); | ||
assert_parse_with_suffix_fails("1234kdZ"); | ||
assert_parse_with_suffix_fails("1234kiZ"); | ||
assert_parse_fails("1234kiZ"); | ||
} | ||
|
||
int | ||
main(int argc, char *argv[]) | ||
{ | ||
test_simple_numbers_are_parsed_properly(); | ||
test_exponent_suffix_is_parsed_properly(); | ||
test_byte_units_are_accepted(); | ||
test_base2_is_selected_by_an_i_modifier(); | ||
test_invalid_formats_are_not_accepted(); | ||
|
||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.