aboutsummaryrefslogtreecommitdiffstats
path: root/common/stringhelp.c
diff options
context:
space:
mode:
authorNeal H. Walfield <[email protected]>2015-11-23 21:20:28 +0000
committerNeal H. Walfield <[email protected]>2015-11-23 21:23:38 +0000
commit19362a8dd7ee986c082a5afc5a446f939991ec0f (patch)
treea5f4b3d346583ada7518bda71fcc50153815506a /common/stringhelp.c
parentcommon: Extend utf8_charcount to include the string's length. (diff)
downloadgnupg-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.c129
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;
+}