summaryrefslogtreecommitdiff
path: root/mailinfo.c
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2016-09-29 16:57:12 -0700
committerJunio C Hamano <gitster@pobox.com>2016-09-29 16:57:12 -0700
commit4cff50b3fb50940e57dc10769b2f92d5cec1a05a (patch)
tree94ff1cf727557623e3b68fb4b3efbfce4e1e2766 /mailinfo.c
parent21f862b498925194f8f1ebe8203b7a7df756555b (diff)
parent6b4b013f1884a3b5e67877d65a9f1da598ab4a6f (diff)
downloadgit-4cff50b3fb50940e57dc10769b2f92d5cec1a05a.tar.gz
Merge branch 'jt/mailinfo-fold-in-body-headers'
When "git format-patch --stdout" output is placed as an in-body header and it uses the RFC2822 header folding, "git am" failed to put the header line back into a single logical line. The underlying "git mailinfo" was taught to handle this properly. * jt/mailinfo-fold-in-body-headers: mailinfo: handle in-body header continuations mailinfo: make is_scissors_line take plain char * mailinfo: separate in-body header processing
Diffstat (limited to 'mailinfo.c')
-rw-r--r--mailinfo.c116
1 files changed, 83 insertions, 33 deletions
diff --git a/mailinfo.c b/mailinfo.c
index e19abe3cb9..2275b285f0 100644
--- a/mailinfo.c
+++ b/mailinfo.c
@@ -495,26 +495,26 @@ static int check_header(struct mailinfo *mi,
goto check_header_out;
}
- /* for inbody stuff */
- if (starts_with(line->buf, ">From") && isspace(line->buf[5])) {
- ret = is_format_patch_separator(line->buf + 1, line->len - 1);
- goto check_header_out;
- }
- if (starts_with(line->buf, "[PATCH]") && isspace(line->buf[7])) {
- for (i = 0; header[i]; i++) {
- if (!strcmp("Subject", header[i])) {
- handle_header(&hdr_data[i], line);
- ret = 1;
- goto check_header_out;
- }
- }
- }
-
check_header_out:
strbuf_release(&sb);
return ret;
}
+/*
+ * Returns 1 if the given line or any line beginning with the given line is an
+ * in-body header (that is, check_header will succeed when passed
+ * mi->s_hdr_data).
+ */
+static int is_inbody_header(const struct mailinfo *mi,
+ const struct strbuf *line)
+{
+ int i;
+ for (i = 0; header[i]; i++)
+ if (!mi->s_hdr_data[i] && cmp_header(line, header[i]))
+ return 1;
+ return 0;
+}
+
static void decode_transfer_encoding(struct mailinfo *mi, struct strbuf *line)
{
struct strbuf *ret;
@@ -572,37 +572,35 @@ static inline int patchbreak(const struct strbuf *line)
return 0;
}
-static int is_scissors_line(const struct strbuf *line)
+static int is_scissors_line(const char *line)
{
- size_t i, len = line->len;
+ const char *c;
int scissors = 0, gap = 0;
- int first_nonblank = -1;
- int last_nonblank = 0, visible, perforation = 0, in_perforation = 0;
- const char *buf = line->buf;
+ const char *first_nonblank = NULL, *last_nonblank = NULL;
+ int visible, perforation = 0, in_perforation = 0;
- for (i = 0; i < len; i++) {
- if (isspace(buf[i])) {
+ for (c = line; *c; c++) {
+ if (isspace(*c)) {
if (in_perforation) {
perforation++;
gap++;
}
continue;
}
- last_nonblank = i;
- if (first_nonblank < 0)
- first_nonblank = i;
- if (buf[i] == '-') {
+ last_nonblank = c;
+ if (first_nonblank == NULL)
+ first_nonblank = c;
+ if (*c == '-') {
in_perforation = 1;
perforation++;
continue;
}
- if (i + 1 < len &&
- (!memcmp(buf + i, ">8", 2) || !memcmp(buf + i, "8<", 2) ||
- !memcmp(buf + i, ">%", 2) || !memcmp(buf + i, "%<", 2))) {
+ if ((!memcmp(c, ">8", 2) || !memcmp(c, "8<", 2) ||
+ !memcmp(c, ">%", 2) || !memcmp(c, "%<", 2))) {
in_perforation = 1;
perforation += 2;
scissors += 2;
- i++;
+ c++;
continue;
}
in_perforation = 0;
@@ -617,12 +615,60 @@ static int is_scissors_line(const struct strbuf *line)
* than half of the perforation.
*/
- visible = last_nonblank - first_nonblank + 1;
+ if (first_nonblank && last_nonblank)
+ visible = last_nonblank - first_nonblank + 1;
+ else
+ visible = 0;
return (scissors && 8 <= visible &&
visible < perforation * 3 &&
gap * 2 < perforation);
}
+static void flush_inbody_header_accum(struct mailinfo *mi)
+{
+ if (!mi->inbody_header_accum.len)
+ return;
+ assert(check_header(mi, &mi->inbody_header_accum, mi->s_hdr_data, 0));
+ strbuf_reset(&mi->inbody_header_accum);
+}
+
+static int check_inbody_header(struct mailinfo *mi, const struct strbuf *line)
+{
+ if (mi->inbody_header_accum.len &&
+ (line->buf[0] == ' ' || line->buf[0] == '\t')) {
+ if (mi->use_scissors && is_scissors_line(line->buf)) {
+ /*
+ * This is a scissors line; do not consider this line
+ * as a header continuation line.
+ */
+ flush_inbody_header_accum(mi);
+ return 0;
+ }
+ strbuf_strip_suffix(&mi->inbody_header_accum, "\n");
+ strbuf_addbuf(&mi->inbody_header_accum, line);
+ return 1;
+ }
+
+ flush_inbody_header_accum(mi);
+
+ if (starts_with(line->buf, ">From") && isspace(line->buf[5]))
+ return is_format_patch_separator(line->buf + 1, line->len - 1);
+ if (starts_with(line->buf, "[PATCH]") && isspace(line->buf[7])) {
+ int i;
+ for (i = 0; header[i]; i++)
+ if (!strcmp("Subject", header[i])) {
+ handle_header(&mi->s_hdr_data[i], line);
+ return 1;
+ }
+ return 0;
+ }
+ if (is_inbody_header(mi, line)) {
+ strbuf_addbuf(&mi->inbody_header_accum, line);
+ return 1;
+ }
+ return 0;
+}
+
static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)
{
assert(!mi->filter_stage);
@@ -633,7 +679,7 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)
}
if (mi->use_inbody_headers && mi->header_stage) {
- mi->header_stage = check_header(mi, line, mi->s_hdr_data, 0);
+ mi->header_stage = check_inbody_header(mi, line);
if (mi->header_stage)
return 0;
} else
@@ -646,7 +692,7 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)
if (convert_to_utf8(mi, line, mi->charset.buf))
return 0; /* mi->input_error already set */
- if (mi->use_scissors && is_scissors_line(line)) {
+ if (mi->use_scissors && is_scissors_line(line->buf)) {
int i;
strbuf_setlen(&mi->log_message, 0);
@@ -886,6 +932,8 @@ static void handle_body(struct mailinfo *mi, struct strbuf *line)
break;
} while (!strbuf_getwholeline(line, mi->input, '\n'));
+ flush_inbody_header_accum(mi);
+
handle_body_out:
strbuf_release(&prev);
}
@@ -1001,6 +1049,7 @@ void setup_mailinfo(struct mailinfo *mi)
strbuf_init(&mi->email, 0);
strbuf_init(&mi->charset, 0);
strbuf_init(&mi->log_message, 0);
+ strbuf_init(&mi->inbody_header_accum, 0);
mi->header_stage = 1;
mi->use_inbody_headers = 1;
mi->content_top = mi->content;
@@ -1014,6 +1063,7 @@ void clear_mailinfo(struct mailinfo *mi)
strbuf_release(&mi->name);
strbuf_release(&mi->email);
strbuf_release(&mi->charset);
+ strbuf_release(&mi->inbody_header_accum);
free(mi->message_id);
for (i = 0; mi->p_hdr_data[i]; i++)