diff options
author | Neal H. Walfield <[email protected]> | 2015-11-23 21:20:28 +0000 |
---|---|---|
committer | Neal H. Walfield <[email protected]> | 2015-11-23 21:23:38 +0000 |
commit | 19362a8dd7ee986c082a5afc5a446f939991ec0f (patch) | |
tree | a5f4b3d346583ada7518bda71fcc50153815506a /common/stringhelp.c | |
parent | common: Extend utf8_charcount to include the string's length. (diff) | |
download | gnupg-19362a8dd7ee986c082a5afc5a446f939991ec0f.tar.gz gnupg-19362a8dd7ee986c082a5afc5a446f939991ec0f.zip |
gpg: Reflow long texts.
* common/stringhelp.c (format_text): New function.
* common/t-stringhelp.c (stresc): New function.
(test_format_text): New function. Test format_text.
* g10/tofu.c (get_trust): Use format_text to reflow long texts.
(show_statistics): Likewise.
--
Signed-off-by: Neal H. Walfield <[email protected]>
Diffstat (limited to 'common/stringhelp.c')
-rw-r--r-- | common/stringhelp.c | 129 |
1 files changed, 129 insertions, 0 deletions
diff --git a/common/stringhelp.c b/common/stringhelp.c index d0b55615d..6748d1eab 100644 --- a/common/stringhelp.c +++ b/common/stringhelp.c @@ -1327,3 +1327,132 @@ strtokenize (const char *string, const char *delim) return result; } + +char * +format_text (char *text, int in_place, int target_cols, int max_cols) +{ + const int do_debug = 0; + + /* The character under consideration. */ + char *p; + /* The start of the current line. */ + char *line; + /* The last space that we saw. */ + char *last_space = NULL; + int last_space_cols = 0; + int copied_last_space = 0; + + if (! in_place) + text = xstrdup (text); + + p = line = text; + while (1) + { + /* The number of columns including any trailing space. */ + int cols; + + p = p + strcspn (p, "\n "); + if (! p) + /* P now points to the NUL character. */ + p = &text[strlen (text)]; + + if (*p == '\n') + /* Pass through any newlines. */ + { + p ++; + line = p; + last_space = NULL; + last_space_cols = 0; + copied_last_space = 1; + continue; + } + + /* Have a space or a NUL. Note: we don't count the trailing + space. */ + cols = utf8_charcount (line, (uintptr_t) p - (uintptr_t) line); + if (cols < target_cols) + { + if (! *p) + /* Nothing left to break. */ + break; + + last_space = p; + last_space_cols = cols; + p ++; + /* Skip any immediately following spaces. If we break: + "... foo bar ..." between "foo" and "bar" then we want: + "... foo\nbar ...", which means that the left space has + to be the first space after foo, not the last space + before bar. */ + while (*p == ' ') + p ++; + } + else + { + int cols_with_left_space; + int cols_with_right_space; + int left_penalty; + int right_penalty; + + cols_with_left_space = last_space_cols; + cols_with_right_space = cols; + + if (do_debug) + log_debug ("Breaking: '%.*s'\n", + (int) ((uintptr_t) p - (uintptr_t) line), line); + + /* The number of columns away from TARGET_COLS. We prefer + to underflow than to overflow. */ + left_penalty = target_cols - cols_with_left_space; + right_penalty = 2 * (cols_with_right_space - target_cols); + + if (cols_with_right_space > max_cols) + /* Add a large penalty for each column that exceeds + max_cols. */ + right_penalty += 4 * (cols_with_right_space - max_cols); + + if (do_debug) + log_debug ("Left space => %d cols (penalty: %d); right space => %d cols (penalty: %d)\n", + cols_with_left_space, left_penalty, + cols_with_right_space, right_penalty); + if (last_space_cols && left_penalty <= right_penalty) + /* Prefer the left space. */ + { + if (do_debug) + log_debug ("Breaking at left space.\n"); + p = last_space; + } + else + { + if (do_debug) + log_debug ("Breaking at right space.\n"); + } + + if (! *p) + break; + + *p = '\n'; + p ++; + if (*p == ' ') + { + int spaces; + for (spaces = 1; p[spaces] == ' '; spaces ++) + ; + memmove (p, &p[spaces], strlen (&p[spaces]) + 1); + } + line = p; + last_space = NULL; + last_space_cols = 0; + copied_last_space = 0; + } + } + + /* Chop off any trailing space. */ + while (text[strlen (text) - 1] == ' ') + text[strlen (text) - 1] = '\0'; + /* If we inserted the trailing newline, then remove it. */ + if (! copied_last_space && text[strlen (text) - 1] == '\n') + text[strlen (text) - 1] = '\0'; + + return text; +} |