diff --git a/client/common/cmdline.c b/client/common/cmdline.c index ce3b2f016..18b3d36f8 100644 --- a/client/common/cmdline.c +++ b/client/common/cmdline.c @@ -308,66 +308,122 @@ static void freerdp_client_print_scancodes(void) } } -static BOOL is_delimiter(const char* delimiters, char c) +static BOOL is_delimiter(char c, const char* delimiters) { char d; while ((d = *delimiters++) != '\0') { - if (d == c) + if (c == d) return TRUE; } return FALSE; } -static char* print_token(char* text, size_t start_offset, size_t* current, size_t limit, - const char* delimiters) +static const char* get_last(const char* start, size_t len, const char* delimiters) { - int rc; - size_t len = strlen(text); + const char* last = NULL; + for (size_t x = 0; x < len; x++) + { + char c = start[x]; + if (is_delimiter(c, delimiters)) + last = &start[x]; + } + return last; +} +static SSIZE_T next_delimiter(const char* text, size_t len, size_t max, const char* delimiters) +{ + if (len < max) + return -1; + + const char* last = get_last(text, max, delimiters); + if (!last) + return -1; + + return (SSIZE_T)(last - text); +} + +static SSIZE_T forced_newline_at(const char* text, size_t len, size_t limit, + const char* force_newline) +{ + char d; + while ((d = *force_newline++) != '\0') + { + const char* tok = strchr(text, d); + if (tok) + { + const size_t offset = tok - text; + if ((offset > len) || (offset > limit)) + continue; + return (SSIZE_T)(offset); + } + } + return -1; +} + +static BOOL print_align(size_t start_offset, size_t* current) +{ + WINPR_ASSERT(current); if (*current < start_offset) { - rc = printf("%*c", (int)(start_offset - *current), ' '); + const int rc = printf("%*c", (int)(start_offset - *current), ' '); if (rc < 0) - return NULL; + return FALSE; *current += (size_t)rc; } + return TRUE; +} - if (*current + len > limit) - { - size_t x; +static char* print_token(char* text, size_t start_offset, size_t* current, size_t limit, + const char* delimiters, const char* force_newline) +{ + int rc; + const size_t tlen = strnlen(text, limit); + size_t len = tlen; + const SSIZE_T force_at = forced_newline_at(text, len, limit - *current, force_newline); + BOOL isForce = (force_at > 0); - for (x = MIN(len, limit - start_offset); x > 1; x--) - { - if (is_delimiter(delimiters, text[x])) - { - printf("%.*s\n", (int)x, text); - *current = 0; - return &text[x]; - } - } + if (isForce) + len = MIN(len, (size_t)force_at); + if (!print_align(start_offset, current)) return NULL; + + const SSIZE_T delim = next_delimiter(text, len, limit - *current, delimiters); + const BOOL isDelim = delim > 0; + if (isDelim) + { + len = MIN(len, (size_t)delim + 1); } - rc = printf("%s", text); + rc = printf("%.*s", (int)len, text); if (rc < 0) return NULL; + + if (isForce || isDelim) + { + printf("\n"); + *current = 0; + + const size_t offset = len + (isForce ? 1 : 0); + return &text[offset]; + } + *current += (size_t)rc; - return NULL; + + if (tlen == (size_t)rc) + return NULL; + return &text[(size_t)rc]; } static size_t print_optionals(const char* text, size_t start_offset, size_t current) { const size_t limit = 80; char* str = _strdup(text); - char* cur = print_token(str, start_offset, ¤t, limit, "[], "); + char* cur = str; - while (cur) - { - cur++; - cur = print_token(cur, start_offset + 1, ¤t, limit, "[], "); - } + while ((cur = print_token(cur, start_offset + 1, ¤t, limit, "[], ", "\r\n")) != NULL) + ; free(str); return current; @@ -377,13 +433,10 @@ static size_t print_description(const char* text, size_t start_offset, size_t cu { const size_t limit = 80; char* str = _strdup(text); - char* cur = print_token(str, start_offset, ¤t, limit, " "); + char* cur = str; - while (cur) - { - cur++; - cur = print_token(cur, start_offset, ¤t, limit, " "); - } + while ((cur = print_token(cur, start_offset, ¤t, limit, " ", "\r\n")) != NULL) + ; free(str); current += (size_t)printf("\n");