summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pretty.c36
-rwxr-xr-xt/t4014-format-patch.sh84
-rw-r--r--utf8.c9
-rw-r--r--utf8.h2
4 files changed, 121 insertions, 10 deletions
diff --git a/pretty.c b/pretty.c
index 8549934751..65d20a7a2e 100644
--- a/pretty.c
+++ b/pretty.c
@@ -216,36 +216,53 @@ static int is_rfc2047_special(char ch)
static void add_rfc2047(struct strbuf *sb, const char *line, int len,
const char *encoding)
{
- int i, last;
+ static const int max_length = 78; /* per rfc2822 */
+ int i;
+ int line_len;
+
+ /* How many bytes are already used on the current line? */
+ for (i = sb->len - 1; i >= 0; i--)
+ if (sb->buf[i] == '\n')
+ break;
+ line_len = sb->len - (i+1);
for (i = 0; i < len; i++) {
int ch = line[i];
- if (non_ascii(ch))
+ if (non_ascii(ch) || ch == '\n')
goto needquote;
if ((i + 1 < len) && (ch == '=' && line[i+1] == '?'))
goto needquote;
}
- strbuf_add(sb, line, len);
+ strbuf_add_wrapped_bytes(sb, line, len, 0, 1, max_length - line_len);
return;
needquote:
strbuf_grow(sb, len * 3 + strlen(encoding) + 100);
strbuf_addf(sb, "=?%s?q?", encoding);
- for (i = last = 0; i < len; i++) {
+ line_len += strlen(encoding) + 5; /* 5 for =??q? */
+ for (i = 0; i < len; i++) {
unsigned ch = line[i] & 0xFF;
+
+ if (line_len >= max_length - 2) {
+ strbuf_addf(sb, "?=\n =?%s?q?", encoding);
+ line_len = strlen(encoding) + 5 + 1; /* =??q? plus SP */
+ }
+
/*
* We encode ' ' using '=20' even though rfc2047
* allows using '_' for readability. Unfortunately,
* many programs do not understand this and just
* leave the underscore in place.
*/
- if (is_rfc2047_special(ch) || ch == ' ') {
- strbuf_add(sb, line + last, i - last);
+ if (is_rfc2047_special(ch) || ch == ' ' || ch == '\n') {
strbuf_addf(sb, "=%02X", ch);
- last = i + 1;
+ line_len += 3;
+ }
+ else {
+ strbuf_addch(sb, ch);
+ line_len++;
}
}
- strbuf_add(sb, line + last, len - last);
strbuf_addstr(sb, "?=");
}
@@ -1106,11 +1123,10 @@ void pp_title_line(enum cmit_fmt fmt,
const char *encoding,
int need_8bit_cte)
{
- const char *line_separator = (fmt == CMIT_FMT_EMAIL) ? "\n " : " ";
struct strbuf title;
strbuf_init(&title, 80);
- *msg_p = format_subject(&title, *msg_p, line_separator);
+ *msg_p = format_subject(&title, *msg_p, " ");
strbuf_grow(sb, title.len + 1024);
if (subject) {
diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh
index 027c13d52c..9c663677df 100755
--- a/t/t4014-format-patch.sh
+++ b/t/t4014-format-patch.sh
@@ -709,4 +709,88 @@ test_expect_success TTY 'format-patch --stdout paginates' '
test_path_is_missing .git/pager_used
'
+test_expect_success 'format-patch handles multi-line subjects' '
+ rm -rf patches/ &&
+ echo content >>file &&
+ for i in one two three; do echo $i; done >msg &&
+ git add file &&
+ git commit -F msg &&
+ git format-patch -o patches -1 &&
+ grep ^Subject: patches/0001-one.patch >actual &&
+ echo "Subject: [PATCH] one two three" >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'format-patch handles multi-line encoded subjects' '
+ rm -rf patches/ &&
+ echo content >>file &&
+ for i in en två tre; do echo $i; done >msg &&
+ git add file &&
+ git commit -F msg &&
+ git format-patch -o patches -1 &&
+ grep ^Subject: patches/0001-en.patch >actual &&
+ echo "Subject: [PATCH] =?UTF-8?q?en=20tv=C3=A5=20tre?=" >expect &&
+ test_cmp expect actual
+'
+
+M8="foo bar "
+M64=$M8$M8$M8$M8$M8$M8$M8$M8
+M512=$M64$M64$M64$M64$M64$M64$M64$M64
+cat >expect <<'EOF'
+Subject: [PATCH] foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
+ bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
+ foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
+ bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
+ foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
+ bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
+ foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
+ bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
+ foo bar foo bar foo bar foo bar
+EOF
+test_expect_success 'format-patch wraps extremely long headers (ascii)' '
+ echo content >>file &&
+ git add file &&
+ git commit -m "$M512" &&
+ git format-patch --stdout -1 >patch &&
+ sed -n "/^Subject/p; /^ /p; /^$/q" <patch >subject &&
+ test_cmp expect subject
+'
+
+M8="föö bar "
+M64=$M8$M8$M8$M8$M8$M8$M8$M8
+M512=$M64$M64$M64$M64$M64$M64$M64$M64
+cat >expect <<'EOF'
+Subject: [PATCH] =?UTF-8?q?f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
+EOF
+test_expect_success 'format-patch wraps extremely long headers (rfc2047)' '
+ rm -rf patches/ &&
+ echo content >>file &&
+ git add file &&
+ git commit -m "$M512" &&
+ git format-patch --stdout -1 >patch &&
+ sed -n "/^Subject/p; /^ /p; /^$/q" <patch >subject &&
+ test_cmp expect subject
+'
+
test_done
diff --git a/utf8.c b/utf8.c
index 84cfc72e6d..8acbc660d3 100644
--- a/utf8.c
+++ b/utf8.c
@@ -405,6 +405,15 @@ new_line:
}
}
+int strbuf_add_wrapped_bytes(struct strbuf *buf, const char *data, int len,
+ int indent, int indent2, int width)
+{
+ char *tmp = xstrndup(data, len);
+ int r = strbuf_add_wrapped_text(buf, tmp, indent, indent2, width);
+ free(tmp);
+ return r;
+}
+
int is_encoding_utf8(const char *name)
{
if (!name)
diff --git a/utf8.h b/utf8.h
index ebc4d2fa85..81f2c82fab 100644
--- a/utf8.h
+++ b/utf8.h
@@ -10,6 +10,8 @@ int is_encoding_utf8(const char *name);
int strbuf_add_wrapped_text(struct strbuf *buf,
const char *text, int indent, int indent2, int width);
+int strbuf_add_wrapped_bytes(struct strbuf *buf, const char *data, int len,
+ int indent, int indent2, int width);
#ifndef NO_ICONV
char *reencode_string(const char *in, const char *out_encoding, const char *in_encoding);