From ae83436ea714ed6a8a97c54f8128ab6b63ed557d Mon Sep 17 00:00:00 2001 From: Philippe Proulx Date: Tue, 11 Jun 2019 10:59:56 -0400 Subject: [PATCH] Add bt_common_sep_digits() This new utility function adds digit separators to a string representing a number. For example, `1983291832` can become `1,983,291,832`. See the function's comment for more details. Signed-off-by: Philippe Proulx Change-Id: I39dedc69fbc76b31252a64c68261a35d8ac7c7a8 Reviewed-on: https://review.lttng.org/c/babeltrace/+/1411 Tested-by: jenkins --- src/common/common.c | 103 ++++++++++++++++++++++++++++++++++++++++++++ src/common/common.h | 17 ++++++++ 2 files changed, 120 insertions(+) diff --git a/src/common/common.c b/src/common/common.c index a81f8e79..4aa8fcd2 100644 --- a/src/common/common.c +++ b/src/common/common.c @@ -1567,3 +1567,106 @@ void bt_common_custom_snprintf(char *buf, size_t buf_size, priv_data, fmt, &args); va_end(args); } + +BT_HIDDEN +void bt_common_sep_digits(char *str, unsigned int digits_per_group, char sep) +{ + const char *rd; + char *wr; + uint64_t i = 0; + uint64_t orig_len; + uint64_t sep_count; + uint64_t new_len; + + BT_ASSERT(digits_per_group > 0); + BT_ASSERT(sep != '\0'); + + /* Compute new length of `str` */ + orig_len = strlen(str); + BT_ASSERT(orig_len > 0); + sep_count = (orig_len - 1) / digits_per_group; + new_len = strlen(str) + sep_count; + + /* + * Do the work in place. Have the reading pointer `rd` start at + * the end of the original string, and the writing pointer `wr` + * start at the end of the new string, making sure to also put a + * null character there. + */ + rd = str + orig_len - 1; + wr = str + new_len; + *wr = '\0'; + wr--; + + /* + * Here's what the process looks like (3 digits per group): + * + * Source: 12345678 + * ^ + * Destination: 12345678#8 + * ^ + * + * Source: 12345678 + * ^ + * Destination: 1234567878 + * ^ + * + * Source: 12345678 + * ^ + * Destination: 1234567678 + * ^ + * + * Source: 12345678 + * ^ + * Destination: 123456,678 + * ^ + * + * Source: 12345678 + * ^ + * Destination: 123455,678 + * ^ + * + * Source: 12345678 + * ^ + * Destination: 123445,678 + * ^ + * + * Source: 12345678 + * ^ + * Destination: 123345,678 + * ^ + * + * Source: 12345678 + * ^ + * Destination: 12,345,678 + * ^ + * + * Source: 12345678 + * ^ + * Destination: 12,345,678 + * ^ + * + * Source: 12345678 + * ^ + * Destination: 12,345,678 + * ^ + */ + while (rd != str - 1) { + if (i == digits_per_group) { + /* + * Time to append the separator: decrement `wr`, + * but keep `rd` as is. + */ + i = 0; + *wr = sep; + wr--; + continue; + } + + /* Copy read-side character to write-side character */ + *wr = *rd; + wr--; + rd--; + i++; + } +} diff --git a/src/common/common.h b/src/common/common.h index d5f2d096..ef9a715f 100644 --- a/src/common/common.h +++ b/src/common/common.h @@ -311,6 +311,22 @@ void bt_common_custom_snprintf(char *buf, size_t buf_size, BT_HIDDEN size_t bt_common_get_page_size(void); +/* + * Adds the digit separator `sep` as many times as needed to form groups + * of `digits_per_group` digits within `str`. `str` must have enough + * room to accomodate the new separators, that is: + * + * strlen(str) + (strlen(str) / digits_per_group) + 1 + * + * Example: with `str` `1983198398213`, `digits_per_group` 3, and `sep` + * `,`, `str` becomes `1,983,198,398,213`. + * + * `strlen(str)` must not be 0. `digits_per_group` must not be 0. `sep` + * must not be `\0`. + */ +BT_HIDDEN +void bt_common_sep_digits(char *str, unsigned int digits_per_group, char sep); + /* * Wraps read() function to handle EINTR and partial reads. * On success, it returns `count` received as parameter. On error, it returns a @@ -643,4 +659,5 @@ enum bt_self_message_iterator_status bt_common_message_iterator_status_to_self( { return (int) status; } + #endif /* BABELTRACE_COMMON_INTERNAL_H */ -- 2.34.1