mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
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 <neal@g10code.com>
This commit is contained in:
parent
5b84b0d660
commit
19362a8dd7
@ -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;
|
||||
}
|
||||
|
@ -148,6 +148,11 @@ char **strsplit (char *string, char delim, char replacement, int *count);
|
||||
/* Tokenize STRING using the set of delimiters in DELIM. */
|
||||
char **strtokenize (const char *string, const char *delim);
|
||||
|
||||
/* Format a string so that it fits within about TARGET_COLS columns.
|
||||
If IN_PLACE is 0, then TEXT is copied to a new buffer, which is
|
||||
returned. Otherwise, TEXT is modified in place and returned.
|
||||
Normally, target_cols will be 72 and max_cols is 80. */
|
||||
char *format_text (char *text, int in_place, int target_cols, int max_cols);
|
||||
|
||||
/*-- mapstrings.c --*/
|
||||
const char *map_static_macro_string (const char *string);
|
||||
|
@ -677,6 +677,142 @@ test_strtokenize (void)
|
||||
}
|
||||
}
|
||||
|
||||
static char *
|
||||
stresc (char *s)
|
||||
{
|
||||
char *p;
|
||||
int l = strlen (s) + 1;
|
||||
|
||||
for (p = s; *p; p ++)
|
||||
if (*p == '\n')
|
||||
l ++;
|
||||
|
||||
p = xmalloc (l);
|
||||
for (l = 0; *s; s ++, l ++)
|
||||
{
|
||||
if (*s == ' ')
|
||||
p[l] = '_';
|
||||
else if (*p == '\n')
|
||||
{
|
||||
p[l ++] = '\\';
|
||||
p[l ++] = 'n';
|
||||
p[l] = '\n';
|
||||
}
|
||||
else
|
||||
p[l] = *s;
|
||||
}
|
||||
p[l] = *s;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
static void
|
||||
test_format_text (void)
|
||||
{
|
||||
struct test
|
||||
{
|
||||
int target_cols, max_cols;
|
||||
char *input;
|
||||
char *expected;
|
||||
};
|
||||
|
||||
struct test tests[] = {
|
||||
{
|
||||
10, 12,
|
||||
"",
|
||||
"",
|
||||
},
|
||||
{
|
||||
10, 12,
|
||||
" ",
|
||||
"",
|
||||
},
|
||||
{
|
||||
10, 12,
|
||||
" ",
|
||||
"",
|
||||
},
|
||||
{
|
||||
10, 12,
|
||||
" \n ",
|
||||
" \n",
|
||||
},
|
||||
{
|
||||
10, 12,
|
||||
" \n \n ",
|
||||
" \n \n",
|
||||
},
|
||||
{
|
||||
10, 12,
|
||||
"0123456789 0123456789 0",
|
||||
"0123456789\n0123456789\n0",
|
||||
},
|
||||
{
|
||||
10, 12,
|
||||
" 0123456789 0123456789 0 ",
|
||||
" 0123456789\n0123456789\n0",
|
||||
},
|
||||
{
|
||||
10, 12,
|
||||
"01 34 67 90 23 56 89 12 45 67 89 1",
|
||||
"01 34 67\n90 23 56\n89 12 45\n67 89 1"
|
||||
},
|
||||
{
|
||||
10, 12,
|
||||
"01 34 67 90 23 56 89 12 45 67 89 1",
|
||||
"01 34 67\n90 23 56\n89 12 45\n67 89 1"
|
||||
},
|
||||
{
|
||||
72, 80,
|
||||
"Warning: if you think you've seen more than 10 messages "
|
||||
"signed by this key, then this key might be a forgery! "
|
||||
"Carefully examine the email address for small variations "
|
||||
"(e.g., additional white space). If the key is suspect, "
|
||||
"then use 'gpg --tofu-policy bad \"FINGERPRINT\"' to mark it as being bad.\n",
|
||||
"Warning: if you think you've seen more than 10 messages signed by this\n"
|
||||
"key, then this key might be a forgery! Carefully examine the email\n"
|
||||
"address for small variations (e.g., additional white space). If the key\n"
|
||||
"is suspect, then use 'gpg --tofu-policy bad \"FINGERPRINT\"' to mark it as\n"
|
||||
"being bad.\n"
|
||||
|
||||
},
|
||||
{
|
||||
72, 80,
|
||||
"Normally, there is only a single key associated with an email "
|
||||
"address. However, people sometimes generate a new key if "
|
||||
"their key is too old or they think it might be compromised. "
|
||||
"Alternatively, a new key may indicate a man-in-the-middle "
|
||||
"attack! Before accepting this key, you should talk to or "
|
||||
"call the person to make sure this new key is legitimate.",
|
||||
"Normally, there is only a single key associated with an email "
|
||||
"address.\nHowever, people sometimes generate a new key if "
|
||||
"their key is too old or\nthey think it might be compromised. "
|
||||
"Alternatively, a new key may indicate\na man-in-the-middle "
|
||||
"attack! Before accepting this key, you should talk\nto or "
|
||||
"call the person to make sure this new key is legitimate.",
|
||||
}
|
||||
};
|
||||
|
||||
int i;
|
||||
int failed = 0;
|
||||
|
||||
for (i = 0; i < sizeof (tests) / sizeof (tests[0]); i ++)
|
||||
{
|
||||
struct test *test = &tests[i];
|
||||
char *result =
|
||||
format_text (test->input, 0, test->target_cols, test->max_cols);
|
||||
if (strcmp (result, test->expected) != 0)
|
||||
{
|
||||
printf ("%s: Test #%d failed.\nExpected: '%s'\nResult: '%s'\n",
|
||||
__func__, i + 1, stresc (test->expected), stresc (result));
|
||||
failed ++;
|
||||
}
|
||||
xfree (result);
|
||||
}
|
||||
|
||||
if (failed)
|
||||
fail(0);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
@ -692,6 +828,7 @@ main (int argc, char **argv)
|
||||
test_make_absfilename_try ();
|
||||
test_strsplit ();
|
||||
test_strtokenize ();
|
||||
test_format_text ();
|
||||
|
||||
xfree (home_buffer);
|
||||
return 0;
|
||||
|
16
g10/tofu.c
16
g10/tofu.c
@ -2038,7 +2038,9 @@ get_trust (struct dbs *dbs, const char *fingerprint, const char *email,
|
||||
"Alternatively, a new key may indicate a man-in-the-middle "
|
||||
"attack! Before accepting this key, you should talk to or "
|
||||
"call the person to make sure this new key is legitimate.";
|
||||
text = format_text (text, 0, 72, 80);
|
||||
es_fprintf (fp, "\n%s\n", text);
|
||||
xfree (text);
|
||||
}
|
||||
|
||||
es_fputc ('\n', fp);
|
||||
@ -2440,7 +2442,8 @@ show_statistics (struct dbs *dbs, const char *fingerprint,
|
||||
if (policy == TOFU_POLICY_AUTO && messages < 10)
|
||||
{
|
||||
char *set_policy_command;
|
||||
const char *text;
|
||||
char *text;
|
||||
char *tmp;
|
||||
|
||||
if (messages == 0)
|
||||
log_info (_("Warning: we've have yet to see"
|
||||
@ -2462,9 +2465,14 @@ show_statistics (struct dbs *dbs, const char *fingerprint,
|
||||
"Carefully examine the email address for small variations "
|
||||
"(e.g., additional white space). If the key is suspect, "
|
||||
"then use '%s' to mark it as being bad.\n";
|
||||
log_info (text,
|
||||
messages, messages == 1 ? _("message") : _("message"),
|
||||
set_policy_command);
|
||||
tmp = xasprintf
|
||||
(text,
|
||||
messages, messages == 1 ? _("message") : _("message"),
|
||||
set_policy_command);
|
||||
text = format_text (tmp, 0, 72, 80);
|
||||
xfree (tmp);
|
||||
log_info ("%s", text);
|
||||
xfree (text);
|
||||
free (set_policy_command);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user