diff --git a/app/src/util/str.c b/app/src/util/str.c index ab1c8783..1564ffe2 100644 --- a/app/src/util/str.c +++ b/app/src/util/str.c @@ -304,3 +304,29 @@ sc_str_truncate(char *data, size_t len, const char *endchars) { data[idx] = '\0'; return idx; } + +ssize_t +sc_str_index_of_column(const char *s, unsigned col, const char *seps) { + size_t colidx = 0; + + size_t idx = 0; + while (s[idx] != '\0' && colidx != col) { + size_t r = strcspn(&s[idx], seps); + idx += r; + + if (s[idx] == '\0') { + // Not found + return -1; + } + + size_t consecutive_seps = strspn(&s[idx], seps); + assert(consecutive_seps); // At least one + idx += consecutive_seps; + + if (s[idx] != '\0') { + ++colidx; + } + } + + return col == colidx ? (ssize_t) idx : -1; +} diff --git a/app/src/util/str.h b/app/src/util/str.h index 521dfff5..2c7d7829 100644 --- a/app/src/util/str.h +++ b/app/src/util/str.h @@ -114,4 +114,24 @@ sc_str_wrap_lines(const char *input, unsigned columns, unsigned indent); size_t sc_str_truncate(char *data, size_t len, const char *endchars); +/** + * Find the start of a column in a string + * + * A string may represent several columns, separated by some "spaces" + * (separators). This function aims to find the start of the column number + * `col`. + * + * For example, to find the 4th column (column number 3): + * + * // here + * // v + * const char *s = "abc def ghi jk"; + * ssize_t index = sc_str_index_of_column(s, 3, " "); + * assert(index == 16); // points to "jk" + * + * Return -1 if no such column exists. + */ +ssize_t +sc_str_index_of_column(const char *s, unsigned col, const char *seps); + #endif diff --git a/app/tests/test_str.c b/app/tests/test_str.c index c66bb2f4..bd976b3c 100644 --- a/app/tests/test_str.c +++ b/app/tests/test_str.c @@ -364,6 +364,26 @@ static void test_truncate(void) { assert(!strcmp("hello", s4)); } +static void test_index_of_column(void) { + assert(sc_str_index_of_column("a bc d", 0, " ") == 0); + assert(sc_str_index_of_column("a bc d", 1, " ") == 2); + assert(sc_str_index_of_column("a bc d", 2, " ") == 6); + assert(sc_str_index_of_column("a bc d", 3, " ") == -1); + + assert(sc_str_index_of_column("a ", 0, " ") == 0); + assert(sc_str_index_of_column("a ", 1, " ") == -1); + + assert(sc_str_index_of_column("", 0, " ") == 0); + assert(sc_str_index_of_column("", 1, " ") == -1); + + assert(sc_str_index_of_column("a \t \t bc \t d\t", 0, " \t") == 0); + assert(sc_str_index_of_column("a \t \t bc \t d\t", 1, " \t") == 8); + assert(sc_str_index_of_column("a \t \t bc \t d\t", 2, " \t") == 15); + assert(sc_str_index_of_column("a \t \t bc \t d\t", 3, " \t") == -1); + + assert(sc_str_index_of_column(" a bc d", 1, " ") == 2); +} + int main(int argc, char *argv[]) { (void) argc; (void) argv; @@ -384,5 +404,6 @@ int main(int argc, char *argv[]) { test_strlist_contains(); test_wrap_lines(); test_truncate(); + test_index_of_column(); return 0; }