Skip to content

Commit c3d1a43

Browse files
committed
Merge branch 'jk/format-patch-multiline-header' into maint
* jk/format-patch-multiline-header: format-patch: rfc2047-encode newlines in headers format-patch: wrap long header lines strbuf: add fixed-length version of add_wrapped_text
2 parents 7a4750a + c22e7de commit c3d1a43

File tree

4 files changed

+121
-10
lines changed

4 files changed

+121
-10
lines changed

pretty.c

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -216,36 +216,53 @@ static int is_rfc2047_special(char ch)
216216
static void add_rfc2047(struct strbuf *sb, const char *line, int len,
217217
const char *encoding)
218218
{
219-
int i, last;
219+
static const int max_length = 78; /* per rfc2822 */
220+
int i;
221+
int line_len;
222+
223+
/* How many bytes are already used on the current line? */
224+
for (i = sb->len - 1; i >= 0; i--)
225+
if (sb->buf[i] == '\n')
226+
break;
227+
line_len = sb->len - (i+1);
220228

221229
for (i = 0; i < len; i++) {
222230
int ch = line[i];
223-
if (non_ascii(ch))
231+
if (non_ascii(ch) || ch == '\n')
224232
goto needquote;
225233
if ((i + 1 < len) && (ch == '=' && line[i+1] == '?'))
226234
goto needquote;
227235
}
228-
strbuf_add(sb, line, len);
236+
strbuf_add_wrapped_bytes(sb, line, len, 0, 1, max_length - line_len);
229237
return;
230238

231239
needquote:
232240
strbuf_grow(sb, len * 3 + strlen(encoding) + 100);
233241
strbuf_addf(sb, "=?%s?q?", encoding);
234-
for (i = last = 0; i < len; i++) {
242+
line_len += strlen(encoding) + 5; /* 5 for =??q? */
243+
for (i = 0; i < len; i++) {
235244
unsigned ch = line[i] & 0xFF;
245+
246+
if (line_len >= max_length - 2) {
247+
strbuf_addf(sb, "?=\n =?%s?q?", encoding);
248+
line_len = strlen(encoding) + 5 + 1; /* =??q? plus SP */
249+
}
250+
236251
/*
237252
* We encode ' ' using '=20' even though rfc2047
238253
* allows using '_' for readability. Unfortunately,
239254
* many programs do not understand this and just
240255
* leave the underscore in place.
241256
*/
242-
if (is_rfc2047_special(ch) || ch == ' ') {
243-
strbuf_add(sb, line + last, i - last);
257+
if (is_rfc2047_special(ch) || ch == ' ' || ch == '\n') {
244258
strbuf_addf(sb, "=%02X", ch);
245-
last = i + 1;
259+
line_len += 3;
260+
}
261+
else {
262+
strbuf_addch(sb, ch);
263+
line_len++;
246264
}
247265
}
248-
strbuf_add(sb, line + last, len - last);
249266
strbuf_addstr(sb, "?=");
250267
}
251268

@@ -1106,11 +1123,10 @@ void pp_title_line(enum cmit_fmt fmt,
11061123
const char *encoding,
11071124
int need_8bit_cte)
11081125
{
1109-
const char *line_separator = (fmt == CMIT_FMT_EMAIL) ? "\n " : " ";
11101126
struct strbuf title;
11111127

11121128
strbuf_init(&title, 80);
1113-
*msg_p = format_subject(&title, *msg_p, line_separator);
1129+
*msg_p = format_subject(&title, *msg_p, " ");
11141130

11151131
strbuf_grow(sb, title.len + 1024);
11161132
if (subject) {

t/t4014-format-patch.sh

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -709,4 +709,88 @@ test_expect_success TTY 'format-patch --stdout paginates' '
709709
test_path_is_missing .git/pager_used
710710
'
711711

712+
test_expect_success 'format-patch handles multi-line subjects' '
713+
rm -rf patches/ &&
714+
echo content >>file &&
715+
for i in one two three; do echo $i; done >msg &&
716+
git add file &&
717+
git commit -F msg &&
718+
git format-patch -o patches -1 &&
719+
grep ^Subject: patches/0001-one.patch >actual &&
720+
echo "Subject: [PATCH] one two three" >expect &&
721+
test_cmp expect actual
722+
'
723+
724+
test_expect_success 'format-patch handles multi-line encoded subjects' '
725+
rm -rf patches/ &&
726+
echo content >>file &&
727+
for i in en två tre; do echo $i; done >msg &&
728+
git add file &&
729+
git commit -F msg &&
730+
git format-patch -o patches -1 &&
731+
grep ^Subject: patches/0001-en.patch >actual &&
732+
echo "Subject: [PATCH] =?UTF-8?q?en=20tv=C3=A5=20tre?=" >expect &&
733+
test_cmp expect actual
734+
'
735+
736+
M8="foo bar "
737+
M64=$M8$M8$M8$M8$M8$M8$M8$M8
738+
M512=$M64$M64$M64$M64$M64$M64$M64$M64
739+
cat >expect <<'EOF'
740+
Subject: [PATCH] foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
741+
bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
742+
foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
743+
bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
744+
foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
745+
bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
746+
foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
747+
bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
748+
foo bar foo bar foo bar foo bar
749+
EOF
750+
test_expect_success 'format-patch wraps extremely long headers (ascii)' '
751+
echo content >>file &&
752+
git add file &&
753+
git commit -m "$M512" &&
754+
git format-patch --stdout -1 >patch &&
755+
sed -n "/^Subject/p; /^ /p; /^$/q" <patch >subject &&
756+
test_cmp expect subject
757+
'
758+
759+
M8="föö bar "
760+
M64=$M8$M8$M8$M8$M8$M8$M8$M8
761+
M512=$M64$M64$M64$M64$M64$M64$M64$M64
762+
cat >expect <<'EOF'
763+
Subject: [PATCH] =?UTF-8?q?f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
764+
=?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
765+
=?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
766+
=?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
767+
=?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
768+
=?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
769+
=?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
770+
=?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
771+
=?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
772+
=?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
773+
=?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
774+
=?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
775+
=?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
776+
=?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
777+
=?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
778+
=?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
779+
=?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
780+
=?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
781+
=?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
782+
=?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
783+
=?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
784+
=?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
785+
EOF
786+
test_expect_success 'format-patch wraps extremely long headers (rfc2047)' '
787+
rm -rf patches/ &&
788+
echo content >>file &&
789+
git add file &&
790+
git commit -m "$M512" &&
791+
git format-patch --stdout -1 >patch &&
792+
sed -n "/^Subject/p; /^ /p; /^$/q" <patch >subject &&
793+
test_cmp expect subject
794+
'
795+
712796
test_done

utf8.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,15 @@ int strbuf_add_wrapped_text(struct strbuf *buf,
405405
}
406406
}
407407

408+
int strbuf_add_wrapped_bytes(struct strbuf *buf, const char *data, int len,
409+
int indent, int indent2, int width)
410+
{
411+
char *tmp = xstrndup(data, len);
412+
int r = strbuf_add_wrapped_text(buf, tmp, indent, indent2, width);
413+
free(tmp);
414+
return r;
415+
}
416+
408417
int is_encoding_utf8(const char *name)
409418
{
410419
if (!name)

utf8.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ int is_encoding_utf8(const char *name);
1010

1111
int strbuf_add_wrapped_text(struct strbuf *buf,
1212
const char *text, int indent, int indent2, int width);
13+
int strbuf_add_wrapped_bytes(struct strbuf *buf, const char *data, int len,
14+
int indent, int indent2, int width);
1315

1416
#ifndef NO_ICONV
1517
char *reencode_string(const char *in, const char *out_encoding, const char *in_encoding);

0 commit comments

Comments
 (0)