{"thread":{"id":"40552","subject":"[PATCH 00/26] mailinfo libification","startedAt":"2015-10-13T23:16:21Z","lastAt":"2015-10-26T18:42:33Z","messageCount":124,"participants":["Junio C Hamano","Stefan Beller","Eric Sunshine","Ramsay Jones","Johannes Sixt","Johannes Schindelin"],"isPatch":true,"patchVersion":1,"patchTotal":26},"messages":[{"id":"271603","messageId":"1444778207-859-1-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":null,"subject":"[PATCH 00/26] mailinfo libification","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-13T23:16:21Z","receivedAt":"2015-10-13T23:16:21Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"So here is an attempt to libify \"git mailinfo\" so that the built-in\nversion of \"git am\" does not have to run it via run_command()\ninterface.  \"git am\", when fed an N-patch series, runs one\n\"mailsplit\", N \"mailinfo\" and N \"apply\" all via run_command()\ninterface (plus 2 more \"apply\" and 1 \"merge-recursive\" per a patch\nthat does not apply cleanly, when run with the \"-3\" option), and\namong the various programs spawned from \"git am\", \"mailinfo\" is the\nmost straight-forward, stupid and light-weight program, so it is a\nno-brainer to pick it as the candidate for libification.\n\nThis goes on top of c5920b21 (mailinfo: ignore in-body header that\nwe do not care about, 2015-10-08) that was posted earlier as a\nweatherbaloon patch.\n\nJunio C Hamano (26):\n  mailinfo: remove a no-op call convert_to_utf8(it, \"\")\n  mailinfo: fix for off-by-one error in boundary stack\n  mailinfo: fold decode_header_bq() into decode_header()\n  mailinfo: move handle_boundary() lower\n  mailinfo: get rid of function-local static states\n  mailinfo: always pass \"line\" as an argument\n  mailinfo: move global \"line\" into mailinfo() function\n  mailinfo: introduce \"struct mailinfo\" to hold globals\n  mailinfo: move keep_subject & keep_non_patch_bracket to struct mailinfo\n  mailinfo: move global \"FILE *fin, *fout\" to struct mailinfo\n  mailinfo: move filter/header stage to struct mailinfo\n  mailinfo: move patch_lines to struct mailinfo\n  mailinfo: move add_message_id and message_id to struct mailinfo\n  mailinfo: move use_scissors and use_inbody_headers to struct mailinfo\n  mailinfo: move metainfo_charset to struct mailinfo\n  mailinfo: move transfer_encoding to struct mailinfo\n  mailinfo: move charset to struct mailinfo\n  mailinfo: handle_commit_msg() shouldn't be called after finding patchbreak\n  mailinfo: move cmitmsg and patchfile to struct mailinfo\n  mailinfo: move [ps]_hdr_data to struct mailinfo\n  mailinfo: keep the parsed log message in a strbuf\n  mailinfo: move content/content_top to struct mailinfo\n  mailinfo: handle errors found in decode_header() better\n  mailinfo: handle charset conversion errors in the caller\n  mailinfo: remove calls to exit() and die() deep in the callchain\n  mailinfo: libify the whole thing\n\n Makefile           |    1 +\n builtin/mailinfo.c | 1083 +---------------------------------------------------\n mailinfo.c         | 1058 ++++++++++++++++++++++++++++++++++++++++++++++++++\n mailinfo.h         |   41 ++\n 4 files changed, 1120 insertions(+), 1063 deletions(-)\n create mode 100644 mailinfo.c\n create mode 100644 mailinfo.h\n\n-- \n2.6.1-320-g86a1181\n"},{"id":"271604","messageId":"1444778207-859-2-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444778207-859-1-git-send-email-gitster@pobox.com","subject":"[PATCH 01/26] mailinfo: remove a no-op call convert_to_utf8(it, \"\")","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-13T23:16:22Z","receivedAt":"2015-10-13T23:16:22Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The called function checks if the second parameter is either a NULL\nor an empty string at the very beginning and returns without doing\nanything.  Remove the useless call.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 5 -----\n 1 file changed, 5 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 169ee54..330bef4 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -612,11 +612,6 @@ static void decode_header(struct strbuf *it)\n {\n \tif (decode_header_bq(it))\n \t\treturn;\n-\t/* otherwise \"it\" is a straight copy of the input.\n-\t * This can be binary guck but there is no charset specified.\n-\t */\n-\tif (metainfo_charset)\n-\t\tconvert_to_utf8(it, \"\");\n }\n \n static void decode_transfer_encoding(struct strbuf *line)\n-- \n2.6.1-320-g86a1181\n"},{"id":"271606","messageId":"1444778207-859-3-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444778207-859-1-git-send-email-gitster@pobox.com","subject":"[PATCH 02/26] mailinfo: fix for off-by-one error in boundary stack","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-13T23:16:23Z","receivedAt":"2015-10-13T23:16:23Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"We pre-increment the pointer that we will use to store something at,\nso the pointer is already beyond the end of the array if it points\nat content[MAX_BOUNDARIES].\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n\n As always, I am very bad at checking and fixing off-by-one errors.\n A few extra sets of eyeballs are very much appreciated.\n---\n builtin/mailinfo.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 330bef4..2742d0d 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -185,7 +185,7 @@ static void handle_content_type(struct strbuf *line)\n \n \tif (slurp_attr(line->buf, \"boundary=\", boundary)) {\n \t\tstrbuf_insert(boundary, 0, \"--\", 2);\n-\t\tif (++content_top > &content[MAX_BOUNDARIES]) {\n+\t\tif (++content_top >= &content[MAX_BOUNDARIES]) {\n \t\t\tfprintf(stderr, \"Too many boundaries to handle\\n\");\n \t\t\texit(1);\n \t\t}\n-- \n2.6.1-320-g86a1181\n"},{"id":"271605","messageId":"1444778207-859-4-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444778207-859-1-git-send-email-gitster@pobox.com","subject":"[PATCH 03/26] mailinfo: fold decode_header_bq() into decode_header()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-13T23:16:24Z","receivedAt":"2015-10-13T23:16:24Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"In olden days we might have wanted to behave differently in\ndecode_header() if the header line was encoded with RFC2047, but we\napparently do not do so, hence this helper function can go, together\nwith its return value.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 23 +++++++----------------\n 1 file changed, 7 insertions(+), 16 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 2742d0d..3b015a5 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -525,19 +525,17 @@ static void convert_to_utf8(struct strbuf *line, const char *charset)\n \tstrbuf_attach(line, out, strlen(out), strlen(out));\n }\n \n-static int decode_header_bq(struct strbuf *it)\n+static void decode_header(struct strbuf *it)\n {\n \tchar *in, *ep, *cp;\n \tstruct strbuf outbuf = STRBUF_INIT, *dec;\n \tstruct strbuf charset_q = STRBUF_INIT, piecebuf = STRBUF_INIT;\n-\tint rfc2047 = 0;\n \n \tin = it->buf;\n \twhile (in - it->buf <= it->len && (ep = strstr(in, \"=?\")) != NULL) {\n \t\tint encoding;\n \t\tstrbuf_reset(&charset_q);\n \t\tstrbuf_reset(&piecebuf);\n-\t\trfc2047 = 1;\n \n \t\tif (in != ep) {\n \t\t\t/*\n@@ -567,22 +565,22 @@ static int decode_header_bq(struct strbuf *it)\n \t\tep += 2;\n \n \t\tif (ep - it->buf >= it->len || !(cp = strchr(ep, '?')))\n-\t\t\tgoto decode_header_bq_out;\n+\t\t\tgoto release_return;\n \n \t\tif (cp + 3 - it->buf > it->len)\n-\t\t\tgoto decode_header_bq_out;\n+\t\t\tgoto release_return;\n \t\tstrbuf_add(&charset_q, ep, cp - ep);\n \n \t\tencoding = cp[1];\n \t\tif (!encoding || cp[2] != '?')\n-\t\t\tgoto decode_header_bq_out;\n+\t\t\tgoto release_return;\n \t\tep = strstr(cp + 3, \"?=\");\n \t\tif (!ep)\n-\t\t\tgoto decode_header_bq_out;\n+\t\t\tgoto release_return;\n \t\tstrbuf_add(&piecebuf, cp + 3, ep - cp - 3);\n \t\tswitch (tolower(encoding)) {\n \t\tdefault:\n-\t\t\tgoto decode_header_bq_out;\n+\t\t\tgoto release_return;\n \t\tcase 'b':\n \t\t\tdec = decode_b_segment(&piecebuf);\n \t\t\tbreak;\n@@ -601,17 +599,10 @@ static int decode_header_bq(struct strbuf *it)\n \tstrbuf_addstr(&outbuf, in);\n \tstrbuf_reset(it);\n \tstrbuf_addbuf(it, &outbuf);\n-decode_header_bq_out:\n+release_return:\n \tstrbuf_release(&outbuf);\n \tstrbuf_release(&charset_q);\n \tstrbuf_release(&piecebuf);\n-\treturn rfc2047;\n-}\n-\n-static void decode_header(struct strbuf *it)\n-{\n-\tif (decode_header_bq(it))\n-\t\treturn;\n }\n \n static void decode_transfer_encoding(struct strbuf *line)\n-- \n2.6.1-320-g86a1181\n"},{"id":"271625","messageId":"1444778207-859-5-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444778207-859-1-git-send-email-gitster@pobox.com","subject":"[PATCH 04/26] mailinfo: move handle_boundary() lower","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-13T23:16:25Z","receivedAt":"2015-10-13T23:16:25Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This function wants to call find_boundary() and is called only from\none place without any recursing, so it becomes easier to read if it\nappears after the called function.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 114 ++++++++++++++++++++++++++---------------------------\n 1 file changed, 56 insertions(+), 58 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 3b015a5..175c6ae 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -626,64 +626,6 @@ static void decode_transfer_encoding(struct strbuf *line)\n \tfree(ret);\n }\n \n-static void handle_filter(struct strbuf *line);\n-\n-static int find_boundary(void)\n-{\n-\twhile (!strbuf_getline(&line, fin, '\\n')) {\n-\t\tif (*content_top && is_multipart_boundary(&line))\n-\t\t\treturn 1;\n-\t}\n-\treturn 0;\n-}\n-\n-static int handle_boundary(void)\n-{\n-\tstruct strbuf newline = STRBUF_INIT;\n-\n-\tstrbuf_addch(&newline, '\\n');\n-again:\n-\tif (line.len >= (*content_top)->len + 2 &&\n-\t    !memcmp(line.buf + (*content_top)->len, \"--\", 2)) {\n-\t\t/* we hit an end boundary */\n-\t\t/* pop the current boundary off the stack */\n-\t\tstrbuf_release(*content_top);\n-\t\tfree(*content_top);\n-\t\t*content_top = NULL;\n-\n-\t\t/* technically won't happen as is_multipart_boundary()\n-\t\t   will fail first.  But just in case..\n-\t\t */\n-\t\tif (--content_top < content) {\n-\t\t\tfprintf(stderr, \"Detected mismatched boundaries, \"\n-\t\t\t\t\t\"can't recover\\n\");\n-\t\t\texit(1);\n-\t\t}\n-\t\thandle_filter(&newline);\n-\t\tstrbuf_release(&newline);\n-\n-\t\t/* skip to the next boundary */\n-\t\tif (!find_boundary())\n-\t\t\treturn 0;\n-\t\tgoto again;\n-\t}\n-\n-\t/* set some defaults */\n-\ttransfer_encoding = TE_DONTCARE;\n-\tstrbuf_reset(&charset);\n-\n-\t/* slurp in this section's info */\n-\twhile (read_one_header_line(&line, fin))\n-\t\tcheck_header(&line, p_hdr_data, 0);\n-\n-\tstrbuf_release(&newline);\n-\t/* replenish line */\n-\tif (strbuf_getline(&line, fin, '\\n'))\n-\t\treturn 0;\n-\tstrbuf_addch(&line, '\\n');\n-\treturn 1;\n-}\n-\n static inline int patchbreak(const struct strbuf *line)\n {\n \tsize_t i;\n@@ -879,6 +821,62 @@ static void handle_filter(struct strbuf *line)\n \t}\n }\n \n+static int find_boundary(void)\n+{\n+\twhile (!strbuf_getline(&line, fin, '\\n')) {\n+\t\tif (*content_top && is_multipart_boundary(&line))\n+\t\t\treturn 1;\n+\t}\n+\treturn 0;\n+}\n+\n+static int handle_boundary(void)\n+{\n+\tstruct strbuf newline = STRBUF_INIT;\n+\n+\tstrbuf_addch(&newline, '\\n');\n+again:\n+\tif (line.len >= (*content_top)->len + 2 &&\n+\t    !memcmp(line.buf + (*content_top)->len, \"--\", 2)) {\n+\t\t/* we hit an end boundary */\n+\t\t/* pop the current boundary off the stack */\n+\t\tstrbuf_release(*content_top);\n+\t\tfree(*content_top);\n+\t\t*content_top = NULL;\n+\n+\t\t/* technically won't happen as is_multipart_boundary()\n+\t\t   will fail first.  But just in case..\n+\t\t */\n+\t\tif (--content_top < content) {\n+\t\t\tfprintf(stderr, \"Detected mismatched boundaries, \"\n+\t\t\t\t\t\"can't recover\\n\");\n+\t\t\texit(1);\n+\t\t}\n+\t\thandle_filter(&newline);\n+\t\tstrbuf_release(&newline);\n+\n+\t\t/* skip to the next boundary */\n+\t\tif (!find_boundary())\n+\t\t\treturn 0;\n+\t\tgoto again;\n+\t}\n+\n+\t/* set some defaults */\n+\ttransfer_encoding = TE_DONTCARE;\n+\tstrbuf_reset(&charset);\n+\n+\t/* slurp in this section's info */\n+\twhile (read_one_header_line(&line, fin))\n+\t\tcheck_header(&line, p_hdr_data, 0);\n+\n+\tstrbuf_release(&newline);\n+\t/* replenish line */\n+\tif (strbuf_getline(&line, fin, '\\n'))\n+\t\treturn 0;\n+\tstrbuf_addch(&line, '\\n');\n+\treturn 1;\n+}\n+\n static void handle_body(void)\n {\n \tstruct strbuf prev = STRBUF_INIT;\n-- \n2.6.1-320-g86a1181\n"},{"id":"271623","messageId":"1444778207-859-6-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444778207-859-1-git-send-email-gitster@pobox.com","subject":"[PATCH 05/26] mailinfo: get rid of function-local static states","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-13T23:16:26Z","receivedAt":"2015-10-13T23:16:26Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Two helper functions use \"static int\" in their scope to keep track\nof the state while repeatedly getting called once for each input\nline.  Move these state variables their ultimate caller and pass\ndown pointers to them, as a small step in preparation for making\nthis entire callchain more reentrant.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 48 +++++++++++++++++++++++-------------------------\n 1 file changed, 23 insertions(+), 25 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 175c6ae..5a74811 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -713,21 +713,20 @@ static int is_scissors_line(const struct strbuf *line)\n \t\tgap * 2 < perforation);\n }\n \n-static int handle_commit_msg(struct strbuf *line)\n+static int handle_commit_msg(struct strbuf *line, int *still_looking)\n {\n \t/*\n \t * Are we still scanning and discarding in-body headers?\n \t * It is initially set to 1, set to 2 when we do see a\n \t * valid in-body header.\n \t */\n-\tstatic int still_looking = 1;\n \tint is_empty_line;\n \n \tif (!cmitmsg)\n \t\treturn 0;\n \n \tis_empty_line = (!line->len || (line->len == 1 && line->buf[0] == '\\n'));\n-\tif (still_looking == 1) {\n+\tif (*still_looking == 1) {\n \t\t/*\n \t\t * Haven't seen a known in-body header; discard an empty line.\n \t\t */\n@@ -735,33 +734,33 @@ static int handle_commit_msg(struct strbuf *line)\n \t\t\treturn 0;\n \t}\n \n-\tif (use_inbody_headers && still_looking) {\n+\tif (use_inbody_headers && *still_looking) {\n \t\tint is_known_header = check_header(line, s_hdr_data, 0);\n \n-\t\tif (still_looking == 2) {\n+\t\tif (*still_looking == 2) {\n \t\t\t/*\n \t\t\t * an empty line after the in-body header block,\n \t\t\t * or a line obviously not an attempt to invent\n \t\t\t * an unsupported in-body header.\n \t\t\t */\n \t\t\tif (is_empty_line || !is_rfc2822_header(line))\n-\t\t\t\tstill_looking = 0;\n+\t\t\t\t*still_looking = 0;\n \t\t\tif (is_empty_line)\n \t\t\t\treturn 0;\n \t\t\t/* otherwise do not discard the line, but keep going */\n \t\t} else if (is_known_header) {\n-\t\t\tstill_looking = 2;\n-\t\t} else if (still_looking != 2) {\n-\t\t\tstill_looking = 0;\n+\t\t\t*still_looking = 2;\n+\t\t} else if (*still_looking != 2) {\n+\t\t\t*still_looking = 0;\n \t\t}\n \n-\t\tif (still_looking)\n+\t\tif (*still_looking)\n \t\t\treturn 0;\n \t} else\n \t\t/* Only trim the first (blank) line of the commit message\n \t\t * when ignoring in-body headers.\n \t\t */\n-\t\tstill_looking = 0;\n+\t\t*still_looking = 0;\n \n \t/* normalize the log message to UTF-8. */\n \tif (metainfo_charset)\n@@ -773,7 +772,7 @@ static int handle_commit_msg(struct strbuf *line)\n \t\t\tdie_errno(\"Could not rewind output message file\");\n \t\tif (ftruncate(fileno(cmitmsg), 0))\n \t\t\tdie_errno(\"Could not truncate output message file at scissors\");\n-\t\tstill_looking = 1;\n+\t\t*still_looking = 1;\n \n \t\t/*\n \t\t * We may have already read \"secondary headers\"; purge\n@@ -805,16 +804,13 @@ static void handle_patch(const struct strbuf *line)\n \tpatch_lines++;\n }\n \n-static void handle_filter(struct strbuf *line)\n+static void handle_filter(struct strbuf *line, int *filter_stage, int *header_stage)\n {\n-\tstatic int filter = 0;\n-\n-\t/* filter tells us which part we left off on */\n-\tswitch (filter) {\n+\tswitch (*filter_stage) {\n \tcase 0:\n-\t\tif (!handle_commit_msg(line))\n+\t\tif (!handle_commit_msg(line, header_stage))\n \t\t\tbreak;\n-\t\tfilter++;\n+\t\t(*filter_stage)++;\n \tcase 1:\n \t\thandle_patch(line);\n \t\tbreak;\n@@ -830,7 +826,7 @@ static int find_boundary(void)\n \treturn 0;\n }\n \n-static int handle_boundary(void)\n+static int handle_boundary(int *filter_stage, int *header_stage)\n {\n \tstruct strbuf newline = STRBUF_INIT;\n \n@@ -852,7 +848,7 @@ again:\n \t\t\t\t\t\"can't recover\\n\");\n \t\t\texit(1);\n \t\t}\n-\t\thandle_filter(&newline);\n+\t\thandle_filter(&newline, filter_stage, header_stage);\n \t\tstrbuf_release(&newline);\n \n \t\t/* skip to the next boundary */\n@@ -880,6 +876,8 @@ again:\n static void handle_body(void)\n {\n \tstruct strbuf prev = STRBUF_INIT;\n+\tint filter_stage = 0;\n+\tint header_stage = 1;\n \n \t/* Skip up to the first boundary */\n \tif (*content_top) {\n@@ -892,10 +890,10 @@ static void handle_body(void)\n \t\tif (*content_top && is_multipart_boundary(&line)) {\n \t\t\t/* flush any leftover */\n \t\t\tif (prev.len) {\n-\t\t\t\thandle_filter(&prev);\n+\t\t\t\thandle_filter(&prev, &filter_stage, &header_stage);\n \t\t\t\tstrbuf_reset(&prev);\n \t\t\t}\n-\t\t\tif (!handle_boundary())\n+\t\t\tif (!handle_boundary(&filter_stage, &header_stage))\n \t\t\t\tgoto handle_body_out;\n \t\t}\n \n@@ -925,7 +923,7 @@ static void handle_body(void)\n \t\t\t\t\t\tstrbuf_addbuf(&prev, sb);\n \t\t\t\t\t\tbreak;\n \t\t\t\t\t}\n-\t\t\t\thandle_filter(sb);\n+\t\t\t\thandle_filter(sb, &filter_stage, &header_stage);\n \t\t\t}\n \t\t\t/*\n \t\t\t * The partial chunk is saved in \"prev\" and will be\n@@ -935,7 +933,7 @@ static void handle_body(void)\n \t\t\tbreak;\n \t\t}\n \t\tdefault:\n-\t\t\thandle_filter(&line);\n+\t\t\thandle_filter(&line, &filter_stage, &header_stage);\n \t\t}\n \n \t} while (!strbuf_getwholeline(&line, fin, '\\n'));\n-- \n2.6.1-320-g86a1181\n"},{"id":"271609","messageId":"1444778207-859-7-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444778207-859-1-git-send-email-gitster@pobox.com","subject":"[PATCH 06/26] mailinfo: always pass \"line\" as an argument","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-13T23:16:27Z","receivedAt":"2015-10-13T23:16:27Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Some functions in this module accessed the global \"struct strbuf\nline\" while many others used a strbuf passed as an argument.\nConvert the former to ensure that nobody deeper in the callchains\nrelies on the global one.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 48 ++++++++++++++++++++++++------------------------\n 1 file changed, 24 insertions(+), 24 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 5a74811..c3c7d67 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -12,7 +12,7 @@ static FILE *cmitmsg, *patchfile, *fin, *fout;\n static int keep_subject;\n static int keep_non_patch_brackets_in_subject;\n static const char *metainfo_charset;\n-static struct strbuf line = STRBUF_INIT;\n+static struct strbuf line_global = STRBUF_INIT;\n static struct strbuf name = STRBUF_INIT;\n static struct strbuf email = STRBUF_INIT;\n static char *message_id;\n@@ -817,23 +817,23 @@ static void handle_filter(struct strbuf *line, int *filter_stage, int *header_st\n \t}\n }\n \n-static int find_boundary(void)\n+static int find_boundary(struct strbuf *line)\n {\n-\twhile (!strbuf_getline(&line, fin, '\\n')) {\n-\t\tif (*content_top && is_multipart_boundary(&line))\n+\twhile (!strbuf_getline(line, fin, '\\n')) {\n+\t\tif (*content_top && is_multipart_boundary(line))\n \t\t\treturn 1;\n \t}\n \treturn 0;\n }\n \n-static int handle_boundary(int *filter_stage, int *header_stage)\n+static int handle_boundary(struct strbuf *line, int *filter_stage, int *header_stage)\n {\n \tstruct strbuf newline = STRBUF_INIT;\n \n \tstrbuf_addch(&newline, '\\n');\n again:\n-\tif (line.len >= (*content_top)->len + 2 &&\n-\t    !memcmp(line.buf + (*content_top)->len, \"--\", 2)) {\n+\tif (line->len >= (*content_top)->len + 2 &&\n+\t    !memcmp(line->buf + (*content_top)->len, \"--\", 2)) {\n \t\t/* we hit an end boundary */\n \t\t/* pop the current boundary off the stack */\n \t\tstrbuf_release(*content_top);\n@@ -852,7 +852,7 @@ again:\n \t\tstrbuf_release(&newline);\n \n \t\t/* skip to the next boundary */\n-\t\tif (!find_boundary())\n+\t\tif (!find_boundary(line))\n \t\t\treturn 0;\n \t\tgoto again;\n \t}\n@@ -862,18 +862,18 @@ again:\n \tstrbuf_reset(&charset);\n \n \t/* slurp in this section's info */\n-\twhile (read_one_header_line(&line, fin))\n-\t\tcheck_header(&line, p_hdr_data, 0);\n+\twhile (read_one_header_line(line, fin))\n+\t\tcheck_header(line, p_hdr_data, 0);\n \n \tstrbuf_release(&newline);\n \t/* replenish line */\n-\tif (strbuf_getline(&line, fin, '\\n'))\n+\tif (strbuf_getline(line, fin, '\\n'))\n \t\treturn 0;\n-\tstrbuf_addch(&line, '\\n');\n+\tstrbuf_addch(line, '\\n');\n \treturn 1;\n }\n \n-static void handle_body(void)\n+static void handle_body(struct strbuf *line)\n {\n \tstruct strbuf prev = STRBUF_INIT;\n \tint filter_stage = 0;\n@@ -881,24 +881,24 @@ static void handle_body(void)\n \n \t/* Skip up to the first boundary */\n \tif (*content_top) {\n-\t\tif (!find_boundary())\n+\t\tif (!find_boundary(line))\n \t\t\tgoto handle_body_out;\n \t}\n \n \tdo {\n \t\t/* process any boundary lines */\n-\t\tif (*content_top && is_multipart_boundary(&line)) {\n+\t\tif (*content_top && is_multipart_boundary(line)) {\n \t\t\t/* flush any leftover */\n \t\t\tif (prev.len) {\n \t\t\t\thandle_filter(&prev, &filter_stage, &header_stage);\n \t\t\t\tstrbuf_reset(&prev);\n \t\t\t}\n-\t\t\tif (!handle_boundary(&filter_stage, &header_stage))\n+\t\t\tif (!handle_boundary(line, &filter_stage, &header_stage))\n \t\t\t\tgoto handle_body_out;\n \t\t}\n \n \t\t/* Unwrap transfer encoding */\n-\t\tdecode_transfer_encoding(&line);\n+\t\tdecode_transfer_encoding(line);\n \n \t\tswitch (transfer_encoding) {\n \t\tcase TE_BASE64:\n@@ -907,7 +907,7 @@ static void handle_body(void)\n \t\t\tstruct strbuf **lines, **it, *sb;\n \n \t\t\t/* Prepend any previous partial lines */\n-\t\t\tstrbuf_insert(&line, 0, prev.buf, prev.len);\n+\t\t\tstrbuf_insert(line, 0, prev.buf, prev.len);\n \t\t\tstrbuf_reset(&prev);\n \n \t\t\t/*\n@@ -915,7 +915,7 @@ static void handle_body(void)\n \t\t\t * multiple new lines.  Pass only one chunk\n \t\t\t * at a time to handle_filter()\n \t\t\t */\n-\t\t\tlines = strbuf_split(&line, '\\n');\n+\t\t\tlines = strbuf_split(line, '\\n');\n \t\t\tfor (it = lines; (sb = *it); it++) {\n \t\t\t\tif (*(it + 1) == NULL) /* The last line */\n \t\t\t\t\tif (sb->buf[sb->len - 1] != '\\n') {\n@@ -933,10 +933,10 @@ static void handle_body(void)\n \t\t\tbreak;\n \t\t}\n \t\tdefault:\n-\t\t\thandle_filter(&line, &filter_stage, &header_stage);\n+\t\t\thandle_filter(line, &filter_stage, &header_stage);\n \t\t}\n \n-\t} while (!strbuf_getwholeline(&line, fin, '\\n'));\n+\t} while (!strbuf_getwholeline(line, fin, '\\n'));\n \n handle_body_out:\n \tstrbuf_release(&prev);\n@@ -1019,10 +1019,10 @@ static int mailinfo(FILE *in, FILE *out, const char *msg, const char *patch)\n \tungetc(peek, in);\n \n \t/* process the email header */\n-\twhile (read_one_header_line(&line, fin))\n-\t\tcheck_header(&line, p_hdr_data, 1);\n+\twhile (read_one_header_line(&line_global, fin))\n+\t\tcheck_header(&line_global, p_hdr_data, 1);\n \n-\thandle_body();\n+\thandle_body(&line_global);\n \thandle_info();\n \n \treturn 0;\n-- \n2.6.1-320-g86a1181\n"},{"id":"271626","messageId":"1444778207-859-8-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444778207-859-1-git-send-email-gitster@pobox.com","subject":"[PATCH 07/26] mailinfo: move global \"line\" into mailinfo() function","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-13T23:16:28Z","receivedAt":"2015-10-13T23:16:28Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The mailinfo() function is the only one that wants the \"line_global\"\nto be directly touchable.  Note that handle_body() has to be passed\nthis strbuf so that it sees the \"first line of the input\" after the\nloop in this function processes the headers.  It feels a bit dirty\nthat handle_body() then keeps reusing this strbuf to read more lines\nand does its processing, but that is how the code is structured now.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 9 +++++----\n 1 file changed, 5 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex c3c7d67..6c671fb 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -12,7 +12,6 @@ static FILE *cmitmsg, *patchfile, *fin, *fout;\n static int keep_subject;\n static int keep_non_patch_brackets_in_subject;\n static const char *metainfo_charset;\n-static struct strbuf line_global = STRBUF_INIT;\n static struct strbuf name = STRBUF_INIT;\n static struct strbuf email = STRBUF_INIT;\n static char *message_id;\n@@ -995,6 +994,8 @@ static void handle_info(void)\n static int mailinfo(FILE *in, FILE *out, const char *msg, const char *patch)\n {\n \tint peek;\n+\tstruct strbuf line = STRBUF_INIT;\n+\n \tfin = in;\n \tfout = out;\n \n@@ -1019,10 +1020,10 @@ static int mailinfo(FILE *in, FILE *out, const char *msg, const char *patch)\n \tungetc(peek, in);\n \n \t/* process the email header */\n-\twhile (read_one_header_line(&line_global, fin))\n-\t\tcheck_header(&line_global, p_hdr_data, 1);\n+\twhile (read_one_header_line(&line, fin))\n+\t\tcheck_header(&line, p_hdr_data, 1);\n \n-\thandle_body(&line_global);\n+\thandle_body(&line);\n \thandle_info();\n \n \treturn 0;\n-- \n2.6.1-320-g86a1181\n"},{"id":"271621","messageId":"1444778207-859-9-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444778207-859-1-git-send-email-gitster@pobox.com","subject":"[PATCH 08/26] mailinfo: introduce \"struct mailinfo\" to hold globals","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-13T23:16:29Z","receivedAt":"2015-10-13T23:16:29Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Initially have only 'email' and 'name' fields in there and remove\nthe corresponding globals.  In subsequent patches, more globals will\nbe moved to this and the structure will be passed around as a new\nparameter to more functions.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 61 +++++++++++++++++++++++++++++++++---------------------\n 1 file changed, 37 insertions(+), 24 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 6c671fb..7b61187 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -12,8 +12,11 @@ static FILE *cmitmsg, *patchfile, *fin, *fout;\n static int keep_subject;\n static int keep_non_patch_brackets_in_subject;\n static const char *metainfo_charset;\n-static struct strbuf name = STRBUF_INIT;\n-static struct strbuf email = STRBUF_INIT;\n+\n+struct mailinfo {\n+\tstruct strbuf name;\n+\tstruct strbuf email;\n+};\n static char *message_id;\n \n static enum  {\n@@ -45,7 +48,7 @@ static void get_sane_name(struct strbuf *out, struct strbuf *name, struct strbuf\n \tstrbuf_addbuf(out, src);\n }\n \n-static void parse_bogus_from(const struct strbuf *line)\n+static void parse_bogus_from(struct mailinfo *mi, const struct strbuf *line)\n {\n \t/* John Doe <johndoe> */\n \n@@ -53,7 +56,7 @@ static void parse_bogus_from(const struct strbuf *line)\n \t/* This is fallback, so do not bother if we already have an\n \t * e-mail address.\n \t */\n-\tif (email.len)\n+\tif (mi->email.len)\n \t\treturn;\n \n \tbra = strchr(line->buf, '<');\n@@ -63,16 +66,16 @@ static void parse_bogus_from(const struct strbuf *line)\n \tif (!ket)\n \t\treturn;\n \n-\tstrbuf_reset(&email);\n-\tstrbuf_add(&email, bra + 1, ket - bra - 1);\n+\tstrbuf_reset(&mi->email);\n+\tstrbuf_add(&mi->email, bra + 1, ket - bra - 1);\n \n-\tstrbuf_reset(&name);\n-\tstrbuf_add(&name, line->buf, bra - line->buf);\n-\tstrbuf_trim(&name);\n-\tget_sane_name(&name, &name, &email);\n+\tstrbuf_reset(&mi->name);\n+\tstrbuf_add(&mi->name, line->buf, bra - line->buf);\n+\tstrbuf_trim(&mi->name);\n+\tget_sane_name(&mi->name, &mi->name, &mi->email);\n }\n \n-static void handle_from(const struct strbuf *from)\n+static void handle_from(struct mailinfo *mi, const struct strbuf *from)\n {\n \tchar *at;\n \tsize_t el;\n@@ -83,14 +86,14 @@ static void handle_from(const struct strbuf *from)\n \n \tat = strchr(f.buf, '@');\n \tif (!at) {\n-\t\tparse_bogus_from(from);\n+\t\tparse_bogus_from(mi, from);\n \t\treturn;\n \t}\n \n \t/*\n \t * If we already have one email, don't take any confusing lines\n \t */\n-\tif (email.len && strchr(at + 1, '@')) {\n+\tif (mi->email.len && strchr(at + 1, '@')) {\n \t\tstrbuf_release(&f);\n \t\treturn;\n \t}\n@@ -109,8 +112,8 @@ static void handle_from(const struct strbuf *from)\n \t\tat--;\n \t}\n \tel = strcspn(at, \" \\n\\t\\r\\v\\f>\");\n-\tstrbuf_reset(&email);\n-\tstrbuf_add(&email, at, el);\n+\tstrbuf_reset(&mi->email);\n+\tstrbuf_add(&mi->email, at, el);\n \tstrbuf_remove(&f, at - f.buf, el + (at[el] ? 1 : 0));\n \n \t/* The remainder is name.  It could be\n@@ -132,7 +135,7 @@ static void handle_from(const struct strbuf *from)\n \t\tstrbuf_setlen(&f, f.len - 1);\n \t}\n \n-\tget_sane_name(&name, &f, &email);\n+\tget_sane_name(&mi->name, &f, &mi->email);\n \tstrbuf_release(&f);\n }\n \n@@ -958,7 +961,7 @@ static void output_header_lines(FILE *fout, const char *hdr, const struct strbuf\n \t}\n }\n \n-static void handle_info(void)\n+static void handle_info(struct mailinfo *mi)\n {\n \tstruct strbuf *hdr;\n \tint i;\n@@ -980,9 +983,9 @@ static void handle_info(void)\n \t\t\toutput_header_lines(fout, \"Subject\", hdr);\n \t\t} else if (!strcmp(header[i], \"From\")) {\n \t\t\tcleanup_space(hdr);\n-\t\t\thandle_from(hdr);\n-\t\t\tfprintf(fout, \"Author: %s\\n\", name.buf);\n-\t\t\tfprintf(fout, \"Email: %s\\n\", email.buf);\n+\t\t\thandle_from(mi, hdr);\n+\t\t\tfprintf(fout, \"Author: %s\\n\", mi->name.buf);\n+\t\t\tfprintf(fout, \"Email: %s\\n\", mi->email.buf);\n \t\t} else {\n \t\t\tcleanup_space(hdr);\n \t\t\tfprintf(fout, \"%s: %s\\n\", header[i], hdr->buf);\n@@ -991,7 +994,8 @@ static void handle_info(void)\n \tfprintf(fout, \"\\n\");\n }\n \n-static int mailinfo(FILE *in, FILE *out, const char *msg, const char *patch)\n+static int mailinfo(struct mailinfo *mi,\n+\t\t    FILE *in, FILE *out, const char *msg, const char *patch)\n {\n \tint peek;\n \tstruct strbuf line = STRBUF_INIT;\n@@ -1024,7 +1028,7 @@ static int mailinfo(FILE *in, FILE *out, const char *msg, const char *patch)\n \t\tcheck_header(&line, p_hdr_data, 1);\n \n \thandle_body(&line);\n-\thandle_info();\n+\thandle_info(mi);\n \n \treturn 0;\n }\n@@ -1041,17 +1045,26 @@ static int git_mailinfo_config(const char *var, const char *value, void *unused)\n \treturn 0;\n }\n \n+static void setup_mailinfo(struct mailinfo *mi)\n+{\n+\tmemset(mi, 0, sizeof(*mi));\n+\tstrbuf_init(&mi->name, 0);\n+\tstrbuf_init(&mi->email, 0);\n+\tgit_config(git_mailinfo_config, &mi);\n+}\n+\n static const char mailinfo_usage[] =\n \t\"git mailinfo [-k | -b] [-m | --message-id] [-u | --encoding=<encoding> | -n] [--scissors | --no-scissors] <msg> <patch> < mail >info\";\n \n int cmd_mailinfo(int argc, const char **argv, const char *prefix)\n {\n \tconst char *def_charset;\n+\tstruct mailinfo mi;\n \n \t/* NEEDSWORK: might want to do the optional .git/ directory\n \t * discovery\n \t */\n-\tgit_config(git_mailinfo_config, NULL);\n+\tsetup_mailinfo(&mi);\n \n \tdef_charset = get_commit_output_encoding();\n \tmetainfo_charset = def_charset;\n@@ -1083,5 +1096,5 @@ int cmd_mailinfo(int argc, const char **argv, const char *prefix)\n \tif (argc != 3)\n \t\tusage(mailinfo_usage);\n \n-\treturn !!mailinfo(stdin, stdout, argv[1], argv[2]);\n+\treturn !!mailinfo(&mi, stdin, stdout, argv[1], argv[2]);\n }\n-- \n2.6.1-320-g86a1181\n"},{"id":"271620","messageId":"1444778207-859-10-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444778207-859-1-git-send-email-gitster@pobox.com","subject":"[PATCH 09/26] mailinfo: move keep_subject & keep_non_patch_bracket to struct mailinfo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-13T23:16:30Z","receivedAt":"2015-10-13T23:16:30Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"These two are the only easy ones that do not require passing the\nstructure around to deep corners of the callchain.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 16 ++++++++--------\n 1 file changed, 8 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 7b61187..d642b0d 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -9,13 +9,13 @@\n \n static FILE *cmitmsg, *patchfile, *fin, *fout;\n \n-static int keep_subject;\n-static int keep_non_patch_brackets_in_subject;\n static const char *metainfo_charset;\n \n struct mailinfo {\n \tstruct strbuf name;\n \tstruct strbuf email;\n+\tint keep_subject;\n+\tint keep_non_patch_brackets_in_subject;\n };\n static char *message_id;\n \n@@ -224,7 +224,7 @@ static int is_multipart_boundary(const struct strbuf *line)\n \t\t!memcmp(line->buf, (*content_top)->buf, (*content_top)->len));\n }\n \n-static void cleanup_subject(struct strbuf *subject)\n+static void cleanup_subject(struct mailinfo *mi, struct strbuf *subject)\n {\n \tsize_t at = 0;\n \n@@ -252,7 +252,7 @@ static void cleanup_subject(struct strbuf *subject)\n \t\t\tif (!pos)\n \t\t\t\tbreak;\n \t\t\tremove = pos - subject->buf + at + 1;\n-\t\t\tif (!keep_non_patch_brackets_in_subject ||\n+\t\t\tif (!mi->keep_non_patch_brackets_in_subject ||\n \t\t\t    (7 <= remove &&\n \t\t\t     memmem(subject->buf + at, remove, \"PATCH\", 5)))\n \t\t\t\tstrbuf_remove(subject, at, remove);\n@@ -976,8 +976,8 @@ static void handle_info(struct mailinfo *mi)\n \t\t\tcontinue;\n \n \t\tif (!strcmp(header[i], \"Subject\")) {\n-\t\t\tif (!keep_subject) {\n-\t\t\t\tcleanup_subject(hdr);\n+\t\t\tif (!mi->keep_subject) {\n+\t\t\t\tcleanup_subject(mi, hdr);\n \t\t\t\tcleanup_space(hdr);\n \t\t\t}\n \t\t\toutput_header_lines(fout, \"Subject\", hdr);\n@@ -1071,9 +1071,9 @@ int cmd_mailinfo(int argc, const char **argv, const char *prefix)\n \n \twhile (1 < argc && argv[1][0] == '-') {\n \t\tif (!strcmp(argv[1], \"-k\"))\n-\t\t\tkeep_subject = 1;\n+\t\t\tmi.keep_subject = 1;\n \t\telse if (!strcmp(argv[1], \"-b\"))\n-\t\t\tkeep_non_patch_brackets_in_subject = 1;\n+\t\t\tmi.keep_non_patch_brackets_in_subject = 1;\n \t\telse if (!strcmp(argv[1], \"-m\") || !strcmp(argv[1], \"--message-id\"))\n \t\t\tadd_message_id = 1;\n \t\telse if (!strcmp(argv[1], \"-u\"))\n-- \n2.6.1-320-g86a1181\n"},{"id":"271611","messageId":"1444778207-859-11-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444778207-859-1-git-send-email-gitster@pobox.com","subject":"[PATCH 10/26] mailinfo: move global \"FILE *fin, *fout\" to struct mailinfo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-13T23:16:31Z","receivedAt":"2015-10-13T23:16:31Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This requires us to pass \"struct mailinfo\" to more functions\nthroughout the codepath that read input lines, which makes\nlater steps easier.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 54 ++++++++++++++++++++++++++++--------------------------\n 1 file changed, 28 insertions(+), 26 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex d642b0d..a9da338 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -7,11 +7,14 @@\n #include \"utf8.h\"\n #include \"strbuf.h\"\n \n-static FILE *cmitmsg, *patchfile, *fin, *fout;\n+static FILE *cmitmsg, *patchfile;\n \n static const char *metainfo_charset;\n \n struct mailinfo {\n+\tFILE *input;\n+\tFILE *output;\n+\n \tstruct strbuf name;\n \tstruct strbuf email;\n \tint keep_subject;\n@@ -819,16 +822,17 @@ static void handle_filter(struct strbuf *line, int *filter_stage, int *header_st\n \t}\n }\n \n-static int find_boundary(struct strbuf *line)\n+static int find_boundary(struct mailinfo *mi, struct strbuf *line)\n {\n-\twhile (!strbuf_getline(line, fin, '\\n')) {\n+\twhile (!strbuf_getline(line, mi->input, '\\n')) {\n \t\tif (*content_top && is_multipart_boundary(line))\n \t\t\treturn 1;\n \t}\n \treturn 0;\n }\n \n-static int handle_boundary(struct strbuf *line, int *filter_stage, int *header_stage)\n+static int handle_boundary(struct mailinfo *mi, struct strbuf *line,\n+\t\t\t   int *filter_stage, int *header_stage)\n {\n \tstruct strbuf newline = STRBUF_INIT;\n \n@@ -854,7 +858,7 @@ again:\n \t\tstrbuf_release(&newline);\n \n \t\t/* skip to the next boundary */\n-\t\tif (!find_boundary(line))\n+\t\tif (!find_boundary(mi, line))\n \t\t\treturn 0;\n \t\tgoto again;\n \t}\n@@ -864,18 +868,18 @@ again:\n \tstrbuf_reset(&charset);\n \n \t/* slurp in this section's info */\n-\twhile (read_one_header_line(line, fin))\n+\twhile (read_one_header_line(line, mi->input))\n \t\tcheck_header(line, p_hdr_data, 0);\n \n \tstrbuf_release(&newline);\n \t/* replenish line */\n-\tif (strbuf_getline(line, fin, '\\n'))\n+\tif (strbuf_getline(line, mi->input, '\\n'))\n \t\treturn 0;\n \tstrbuf_addch(line, '\\n');\n \treturn 1;\n }\n \n-static void handle_body(struct strbuf *line)\n+static void handle_body(struct mailinfo *mi, struct strbuf *line)\n {\n \tstruct strbuf prev = STRBUF_INIT;\n \tint filter_stage = 0;\n@@ -883,7 +887,7 @@ static void handle_body(struct strbuf *line)\n \n \t/* Skip up to the first boundary */\n \tif (*content_top) {\n-\t\tif (!find_boundary(line))\n+\t\tif (!find_boundary(mi, line))\n \t\t\tgoto handle_body_out;\n \t}\n \n@@ -895,7 +899,7 @@ static void handle_body(struct strbuf *line)\n \t\t\t\thandle_filter(&prev, &filter_stage, &header_stage);\n \t\t\t\tstrbuf_reset(&prev);\n \t\t\t}\n-\t\t\tif (!handle_boundary(line, &filter_stage, &header_stage))\n+\t\t\tif (!handle_boundary(mi, line, &filter_stage, &header_stage))\n \t\t\t\tgoto handle_body_out;\n \t\t}\n \n@@ -938,7 +942,7 @@ static void handle_body(struct strbuf *line)\n \t\t\thandle_filter(line, &filter_stage, &header_stage);\n \t\t}\n \n-\t} while (!strbuf_getwholeline(line, fin, '\\n'));\n+\t} while (!strbuf_getwholeline(line, mi->input, '\\n'));\n \n handle_body_out:\n \tstrbuf_release(&prev);\n@@ -980,29 +984,25 @@ static void handle_info(struct mailinfo *mi)\n \t\t\t\tcleanup_subject(mi, hdr);\n \t\t\t\tcleanup_space(hdr);\n \t\t\t}\n-\t\t\toutput_header_lines(fout, \"Subject\", hdr);\n+\t\t\toutput_header_lines(mi->output, \"Subject\", hdr);\n \t\t} else if (!strcmp(header[i], \"From\")) {\n \t\t\tcleanup_space(hdr);\n \t\t\thandle_from(mi, hdr);\n-\t\t\tfprintf(fout, \"Author: %s\\n\", mi->name.buf);\n-\t\t\tfprintf(fout, \"Email: %s\\n\", mi->email.buf);\n+\t\t\tfprintf(mi->output, \"Author: %s\\n\", mi->name.buf);\n+\t\t\tfprintf(mi->output, \"Email: %s\\n\", mi->email.buf);\n \t\t} else {\n \t\t\tcleanup_space(hdr);\n-\t\t\tfprintf(fout, \"%s: %s\\n\", header[i], hdr->buf);\n+\t\t\tfprintf(mi->output, \"%s: %s\\n\", header[i], hdr->buf);\n \t\t}\n \t}\n-\tfprintf(fout, \"\\n\");\n+\tfprintf(mi->output, \"\\n\");\n }\n \n-static int mailinfo(struct mailinfo *mi,\n-\t\t    FILE *in, FILE *out, const char *msg, const char *patch)\n+static int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)\n {\n \tint peek;\n \tstruct strbuf line = STRBUF_INIT;\n \n-\tfin = in;\n-\tfout = out;\n-\n \tcmitmsg = fopen(msg, \"w\");\n \tif (!cmitmsg) {\n \t\tperror(msg);\n@@ -1019,15 +1019,15 @@ static int mailinfo(struct mailinfo *mi,\n \ts_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*s_hdr_data));\n \n \tdo {\n-\t\tpeek = fgetc(in);\n+\t\tpeek = fgetc(mi->input);\n \t} while (isspace(peek));\n-\tungetc(peek, in);\n+\tungetc(peek, mi->input);\n \n \t/* process the email header */\n-\twhile (read_one_header_line(&line, fin))\n+\twhile (read_one_header_line(&line, mi->input))\n \t\tcheck_header(&line, p_hdr_data, 1);\n \n-\thandle_body(&line);\n+\thandle_body(mi, &line);\n \thandle_info(mi);\n \n \treturn 0;\n@@ -1096,5 +1096,7 @@ int cmd_mailinfo(int argc, const char **argv, const char *prefix)\n \tif (argc != 3)\n \t\tusage(mailinfo_usage);\n \n-\treturn !!mailinfo(&mi, stdin, stdout, argv[1], argv[2]);\n+\tmi.input = stdin;\n+\tmi.output = stdout;\n+\treturn !!mailinfo(&mi, argv[1], argv[2]);\n }\n-- \n2.6.1-320-g86a1181\n"},{"id":"271607","messageId":"1444778207-859-12-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444778207-859-1-git-send-email-gitster@pobox.com","subject":"[PATCH 11/26] mailinfo: move filter/header stage to struct mailinfo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-13T23:16:32Z","receivedAt":"2015-10-13T23:16:32Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Earlier we got rid of two function-scope static variables that kept\ntrack of the states of helper functions by making them extra arguments\nthat are passed throughout the callchain.  Now we have a convenient\nplace to store and pass them around in the form of \"struct mailinfo\",\nchange them into two fields in the struct.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 50 ++++++++++++++++++++++++++------------------------\n 1 file changed, 26 insertions(+), 24 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex a9da338..7e39769 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -19,6 +19,9 @@ struct mailinfo {\n \tstruct strbuf email;\n \tint keep_subject;\n \tint keep_non_patch_brackets_in_subject;\n+\n+\tint filter_stage; /* still reading log or are we copying patch? */\n+\tint header_stage; /* still checking in-body headers? */\n };\n static char *message_id;\n \n@@ -28,6 +31,7 @@ static enum  {\n \n static struct strbuf charset = STRBUF_INIT;\n static int patch_lines;\n+\n static struct strbuf **p_hdr_data, **s_hdr_data;\n static int use_scissors;\n static int add_message_id;\n@@ -718,7 +722,7 @@ static int is_scissors_line(const struct strbuf *line)\n \t\tgap * 2 < perforation);\n }\n \n-static int handle_commit_msg(struct strbuf *line, int *still_looking)\n+static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n {\n \t/*\n \t * Are we still scanning and discarding in-body headers?\n@@ -731,7 +735,7 @@ static int handle_commit_msg(struct strbuf *line, int *still_looking)\n \t\treturn 0;\n \n \tis_empty_line = (!line->len || (line->len == 1 && line->buf[0] == '\\n'));\n-\tif (*still_looking == 1) {\n+\tif (mi->header_stage == 1) {\n \t\t/*\n \t\t * Haven't seen a known in-body header; discard an empty line.\n \t\t */\n@@ -739,33 +743,33 @@ static int handle_commit_msg(struct strbuf *line, int *still_looking)\n \t\t\treturn 0;\n \t}\n \n-\tif (use_inbody_headers && *still_looking) {\n+\tif (use_inbody_headers && mi->header_stage) {\n \t\tint is_known_header = check_header(line, s_hdr_data, 0);\n \n-\t\tif (*still_looking == 2) {\n+\t\tif (mi->header_stage == 2) {\n \t\t\t/*\n \t\t\t * an empty line after the in-body header block,\n \t\t\t * or a line obviously not an attempt to invent\n \t\t\t * an unsupported in-body header.\n \t\t\t */\n \t\t\tif (is_empty_line || !is_rfc2822_header(line))\n-\t\t\t\t*still_looking = 0;\n+\t\t\t\tmi->header_stage = 0;\n \t\t\tif (is_empty_line)\n \t\t\t\treturn 0;\n \t\t\t/* otherwise do not discard the line, but keep going */\n \t\t} else if (is_known_header) {\n-\t\t\t*still_looking = 2;\n-\t\t} else if (*still_looking != 2) {\n-\t\t\t*still_looking = 0;\n+\t\t\tmi->header_stage = 2;\n+\t\t} else if (mi->header_stage != 2) {\n+\t\t\tmi->header_stage = 0;\n \t\t}\n \n-\t\tif (*still_looking)\n+\t\tif (mi->header_stage)\n \t\t\treturn 0;\n \t} else\n \t\t/* Only trim the first (blank) line of the commit message\n \t\t * when ignoring in-body headers.\n \t\t */\n-\t\t*still_looking = 0;\n+\t\tmi->header_stage = 0;\n \n \t/* normalize the log message to UTF-8. */\n \tif (metainfo_charset)\n@@ -777,7 +781,7 @@ static int handle_commit_msg(struct strbuf *line, int *still_looking)\n \t\t\tdie_errno(\"Could not rewind output message file\");\n \t\tif (ftruncate(fileno(cmitmsg), 0))\n \t\t\tdie_errno(\"Could not truncate output message file at scissors\");\n-\t\t*still_looking = 1;\n+\t\tmi->header_stage = 1;\n \n \t\t/*\n \t\t * We may have already read \"secondary headers\"; purge\n@@ -809,13 +813,13 @@ static void handle_patch(const struct strbuf *line)\n \tpatch_lines++;\n }\n \n-static void handle_filter(struct strbuf *line, int *filter_stage, int *header_stage)\n+static void handle_filter(struct mailinfo *mi, struct strbuf *line)\n {\n-\tswitch (*filter_stage) {\n+\tswitch (mi->filter_stage) {\n \tcase 0:\n-\t\tif (!handle_commit_msg(line, header_stage))\n+\t\tif (!handle_commit_msg(mi, line))\n \t\t\tbreak;\n-\t\t(*filter_stage)++;\n+\t\tmi->filter_stage++;\n \tcase 1:\n \t\thandle_patch(line);\n \t\tbreak;\n@@ -831,8 +835,7 @@ static int find_boundary(struct mailinfo *mi, struct strbuf *line)\n \treturn 0;\n }\n \n-static int handle_boundary(struct mailinfo *mi, struct strbuf *line,\n-\t\t\t   int *filter_stage, int *header_stage)\n+static int handle_boundary(struct mailinfo *mi, struct strbuf *line)\n {\n \tstruct strbuf newline = STRBUF_INIT;\n \n@@ -854,7 +857,7 @@ again:\n \t\t\t\t\t\"can't recover\\n\");\n \t\t\texit(1);\n \t\t}\n-\t\thandle_filter(&newline, filter_stage, header_stage);\n+\t\thandle_filter(mi, &newline);\n \t\tstrbuf_release(&newline);\n \n \t\t/* skip to the next boundary */\n@@ -882,8 +885,6 @@ again:\n static void handle_body(struct mailinfo *mi, struct strbuf *line)\n {\n \tstruct strbuf prev = STRBUF_INIT;\n-\tint filter_stage = 0;\n-\tint header_stage = 1;\n \n \t/* Skip up to the first boundary */\n \tif (*content_top) {\n@@ -896,10 +897,10 @@ static void handle_body(struct mailinfo *mi, struct strbuf *line)\n \t\tif (*content_top && is_multipart_boundary(line)) {\n \t\t\t/* flush any leftover */\n \t\t\tif (prev.len) {\n-\t\t\t\thandle_filter(&prev, &filter_stage, &header_stage);\n+\t\t\t\thandle_filter(mi, &prev);\n \t\t\t\tstrbuf_reset(&prev);\n \t\t\t}\n-\t\t\tif (!handle_boundary(mi, line, &filter_stage, &header_stage))\n+\t\t\tif (!handle_boundary(mi, line))\n \t\t\t\tgoto handle_body_out;\n \t\t}\n \n@@ -929,7 +930,7 @@ static void handle_body(struct mailinfo *mi, struct strbuf *line)\n \t\t\t\t\t\tstrbuf_addbuf(&prev, sb);\n \t\t\t\t\t\tbreak;\n \t\t\t\t\t}\n-\t\t\t\thandle_filter(sb, &filter_stage, &header_stage);\n+\t\t\t\thandle_filter(mi, sb);\n \t\t\t}\n \t\t\t/*\n \t\t\t * The partial chunk is saved in \"prev\" and will be\n@@ -939,7 +940,7 @@ static void handle_body(struct mailinfo *mi, struct strbuf *line)\n \t\t\tbreak;\n \t\t}\n \t\tdefault:\n-\t\t\thandle_filter(line, &filter_stage, &header_stage);\n+\t\t\thandle_filter(mi, line);\n \t\t}\n \n \t} while (!strbuf_getwholeline(line, mi->input, '\\n'));\n@@ -1050,6 +1051,7 @@ static void setup_mailinfo(struct mailinfo *mi)\n \tmemset(mi, 0, sizeof(*mi));\n \tstrbuf_init(&mi->name, 0);\n \tstrbuf_init(&mi->email, 0);\n+\tmi->header_stage = 1;\n \tgit_config(git_mailinfo_config, &mi);\n }\n \n-- \n2.6.1-320-g86a1181\n"},{"id":"271608","messageId":"1444778207-859-13-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444778207-859-1-git-send-email-gitster@pobox.com","subject":"[PATCH 12/26] mailinfo: move patch_lines to struct mailinfo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-13T23:16:33Z","receivedAt":"2015-10-13T23:16:33Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This one is trivial thanks to previous steps that started passing\nthe structure throughout the input codepaths.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 10 +++++-----\n 1 file changed, 5 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 7e39769..163032e 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -20,6 +20,7 @@ struct mailinfo {\n \tint keep_subject;\n \tint keep_non_patch_brackets_in_subject;\n \n+\tint patch_lines;\n \tint filter_stage; /* still reading log or are we copying patch? */\n \tint header_stage; /* still checking in-body headers? */\n };\n@@ -30,7 +31,6 @@ static enum  {\n } transfer_encoding;\n \n static struct strbuf charset = STRBUF_INIT;\n-static int patch_lines;\n \n static struct strbuf **p_hdr_data, **s_hdr_data;\n static int use_scissors;\n@@ -807,10 +807,10 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n \treturn 0;\n }\n \n-static void handle_patch(const struct strbuf *line)\n+static void handle_patch(struct mailinfo *mi, const struct strbuf *line)\n {\n \tfwrite(line->buf, 1, line->len, patchfile);\n-\tpatch_lines++;\n+\tmi->patch_lines++;\n }\n \n static void handle_filter(struct mailinfo *mi, struct strbuf *line)\n@@ -821,7 +821,7 @@ static void handle_filter(struct mailinfo *mi, struct strbuf *line)\n \t\t\tbreak;\n \t\tmi->filter_stage++;\n \tcase 1:\n-\t\thandle_patch(line);\n+\t\thandle_patch(mi, line);\n \t\tbreak;\n \t}\n }\n@@ -973,7 +973,7 @@ static void handle_info(struct mailinfo *mi)\n \n \tfor (i = 0; header[i]; i++) {\n \t\t/* only print inbody headers if we output a patch file */\n-\t\tif (patch_lines && s_hdr_data[i])\n+\t\tif (mi->patch_lines && s_hdr_data[i])\n \t\t\thdr = s_hdr_data[i];\n \t\telse if (p_hdr_data[i])\n \t\t\thdr = p_hdr_data[i];\n-- \n2.6.1-320-g86a1181\n"},{"id":"271610","messageId":"1444778207-859-14-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444778207-859-1-git-send-email-gitster@pobox.com","subject":"[PATCH 13/26] mailinfo: move add_message_id and message_id to struct mailinfo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-13T23:16:34Z","receivedAt":"2015-10-13T23:16:34Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This requires us to pass the structure into check_header() codepath.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 30 ++++++++++++++++--------------\n 1 file changed, 16 insertions(+), 14 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 163032e..35e1ab9 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -19,12 +19,13 @@ struct mailinfo {\n \tstruct strbuf email;\n \tint keep_subject;\n \tint keep_non_patch_brackets_in_subject;\n+\tint add_message_id;\n \n+\tchar *message_id;\n \tint patch_lines;\n \tint filter_stage; /* still reading log or are we copying patch? */\n \tint header_stage; /* still checking in-body headers? */\n };\n-static char *message_id;\n \n static enum  {\n \tTE_DONTCARE, TE_QP, TE_BASE64\n@@ -34,7 +35,6 @@ static struct strbuf charset = STRBUF_INIT;\n \n static struct strbuf **p_hdr_data, **s_hdr_data;\n static int use_scissors;\n-static int add_message_id;\n static int use_inbody_headers = 1;\n \n #define MAX_HDR_PARSED 10\n@@ -209,10 +209,10 @@ static void handle_content_type(struct strbuf *line)\n \t}\n }\n \n-static void handle_message_id(const struct strbuf *line)\n+static void handle_message_id(struct mailinfo *mi, const struct strbuf *line)\n {\n-\tif (add_message_id)\n-\t\tmessage_id = strdup(line->buf);\n+\tif (mi->add_message_id)\n+\t\tmi->message_id = strdup(line->buf);\n }\n \n static void handle_content_transfer_encoding(const struct strbuf *line)\n@@ -321,11 +321,13 @@ static int is_format_patch_separator(const char *line, int len)\n \treturn !memcmp(SAMPLE + (cp - line), cp, strlen(SAMPLE) - (cp - line));\n }\n \n-static int check_header(const struct strbuf *line,\n-\t\t\t\tstruct strbuf *hdr_data[], int overwrite)\n+static int check_header(struct mailinfo *mi,\n+\t\t\tconst struct strbuf *line,\n+\t\t\tstruct strbuf *hdr_data[], int overwrite)\n {\n \tint i, ret = 0, len;\n \tstruct strbuf sb = STRBUF_INIT;\n+\n \t/* search for the interesting parts */\n \tfor (i = 0; header[i]; i++) {\n \t\tint len = strlen(header[i]);\n@@ -363,7 +365,7 @@ static int check_header(const struct strbuf *line,\n \t\tlen = strlen(\"Message-Id: \");\n \t\tstrbuf_add(&sb, line->buf + len, line->len - len);\n \t\tdecode_header(&sb);\n-\t\thandle_message_id(&sb);\n+\t\thandle_message_id(mi, &sb);\n \t\tret = 1;\n \t\tgoto check_header_out;\n \t}\n@@ -744,7 +746,7 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n \t}\n \n \tif (use_inbody_headers && mi->header_stage) {\n-\t\tint is_known_header = check_header(line, s_hdr_data, 0);\n+\t\tint is_known_header = check_header(mi, line, s_hdr_data, 0);\n \n \t\tif (mi->header_stage == 2) {\n \t\t\t/*\n@@ -796,8 +798,8 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n \t}\n \n \tif (patchbreak(line)) {\n-\t\tif (message_id)\n-\t\t\tfprintf(cmitmsg, \"Message-Id: %s\\n\", message_id);\n+\t\tif (mi->message_id)\n+\t\t\tfprintf(cmitmsg, \"Message-Id: %s\\n\", mi->message_id);\n \t\tfclose(cmitmsg);\n \t\tcmitmsg = NULL;\n \t\treturn 1;\n@@ -872,7 +874,7 @@ again:\n \n \t/* slurp in this section's info */\n \twhile (read_one_header_line(line, mi->input))\n-\t\tcheck_header(line, p_hdr_data, 0);\n+\t\tcheck_header(mi, line, p_hdr_data, 0);\n \n \tstrbuf_release(&newline);\n \t/* replenish line */\n@@ -1026,7 +1028,7 @@ static int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)\n \n \t/* process the email header */\n \twhile (read_one_header_line(&line, mi->input))\n-\t\tcheck_header(&line, p_hdr_data, 1);\n+\t\tcheck_header(mi, &line, p_hdr_data, 1);\n \n \thandle_body(mi, &line);\n \thandle_info(mi);\n@@ -1077,7 +1079,7 @@ int cmd_mailinfo(int argc, const char **argv, const char *prefix)\n \t\telse if (!strcmp(argv[1], \"-b\"))\n \t\t\tmi.keep_non_patch_brackets_in_subject = 1;\n \t\telse if (!strcmp(argv[1], \"-m\") || !strcmp(argv[1], \"--message-id\"))\n-\t\t\tadd_message_id = 1;\n+\t\t\tmi.add_message_id = 1;\n \t\telse if (!strcmp(argv[1], \"-u\"))\n \t\t\tmetainfo_charset = def_charset;\n \t\telse if (!strcmp(argv[1], \"-n\"))\n-- \n2.6.1-320-g86a1181\n"},{"id":"271617","messageId":"1444778207-859-15-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444778207-859-1-git-send-email-gitster@pobox.com","subject":"[PATCH 14/26] mailinfo: move use_scissors and use_inbody_headers to struct mailinfo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-13T23:16:35Z","receivedAt":"2015-10-13T23:16:35Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Signed-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 23 +++++++++++++----------\n 1 file changed, 13 insertions(+), 10 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 35e1ab9..5302c03 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -20,6 +20,8 @@ struct mailinfo {\n \tint keep_subject;\n \tint keep_non_patch_brackets_in_subject;\n \tint add_message_id;\n+\tint use_scissors;\n+\tint use_inbody_headers; /* defaults to 1 */\n \n \tchar *message_id;\n \tint patch_lines;\n@@ -34,8 +36,6 @@ static enum  {\n static struct strbuf charset = STRBUF_INIT;\n \n static struct strbuf **p_hdr_data, **s_hdr_data;\n-static int use_scissors;\n-static int use_inbody_headers = 1;\n \n #define MAX_HDR_PARSED 10\n #define MAX_BOUNDARIES 5\n@@ -745,7 +745,7 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n \t\t\treturn 0;\n \t}\n \n-\tif (use_inbody_headers && mi->header_stage) {\n+\tif (mi->use_inbody_headers && mi->header_stage) {\n \t\tint is_known_header = check_header(mi, line, s_hdr_data, 0);\n \n \t\tif (mi->header_stage == 2) {\n@@ -777,7 +777,7 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n \tif (metainfo_charset)\n \t\tconvert_to_utf8(line, charset.buf);\n \n-\tif (use_scissors && is_scissors_line(line)) {\n+\tif (mi->use_scissors && is_scissors_line(line)) {\n \t\tint i;\n \t\tif (fseek(cmitmsg, 0L, SEEK_SET))\n \t\t\tdie_errno(\"Could not rewind output message file\");\n@@ -1036,12 +1036,14 @@ static int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)\n \treturn 0;\n }\n \n-static int git_mailinfo_config(const char *var, const char *value, void *unused)\n+static int git_mailinfo_config(const char *var, const char *value, void *mi_)\n {\n+\tstruct mailinfo *mi = mi_;\n+\n \tif (!starts_with(var, \"mailinfo.\"))\n-\t\treturn git_default_config(var, value, unused);\n+\t\treturn git_default_config(var, value, NULL);\n \tif (!strcmp(var, \"mailinfo.scissors\")) {\n-\t\tuse_scissors = git_config_bool(var, value);\n+\t\tmi->use_scissors = git_config_bool(var, value);\n \t\treturn 0;\n \t}\n \t/* perhaps others here */\n@@ -1054,6 +1056,7 @@ static void setup_mailinfo(struct mailinfo *mi)\n \tstrbuf_init(&mi->name, 0);\n \tstrbuf_init(&mi->email, 0);\n \tmi->header_stage = 1;\n+\tmi->use_inbody_headers = 1;\n \tgit_config(git_mailinfo_config, &mi);\n }\n \n@@ -1087,11 +1090,11 @@ int cmd_mailinfo(int argc, const char **argv, const char *prefix)\n \t\telse if (starts_with(argv[1], \"--encoding=\"))\n \t\t\tmetainfo_charset = argv[1] + 11;\n \t\telse if (!strcmp(argv[1], \"--scissors\"))\n-\t\t\tuse_scissors = 1;\n+\t\t\tmi.use_scissors = 1;\n \t\telse if (!strcmp(argv[1], \"--no-scissors\"))\n-\t\t\tuse_scissors = 0;\n+\t\t\tmi.use_scissors = 0;\n \t\telse if (!strcmp(argv[1], \"--no-inbody-headers\"))\n-\t\t\tuse_inbody_headers = 0;\n+\t\t\tmi.use_inbody_headers = 0;\n \t\telse\n \t\t\tusage(mailinfo_usage);\n \t\targc--; argv++;\n-- \n2.6.1-320-g86a1181\n"},{"id":"271613","messageId":"1444778207-859-16-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444778207-859-1-git-send-email-gitster@pobox.com","subject":"[PATCH 15/26] mailinfo: move metainfo_charset to struct mailinfo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-13T23:16:36Z","receivedAt":"2015-10-13T23:16:36Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This requires us to pass the struct down to decode_header() and\nconvert_to_utf8() callchain.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 40 +++++++++++++++++++---------------------\n 1 file changed, 19 insertions(+), 21 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 5302c03..7e01efa 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -9,8 +9,6 @@\n \n static FILE *cmitmsg, *patchfile;\n \n-static const char *metainfo_charset;\n-\n struct mailinfo {\n \tFILE *input;\n \tFILE *output;\n@@ -22,6 +20,7 @@ struct mailinfo {\n \tint add_message_id;\n \tint use_scissors;\n \tint use_inbody_headers; /* defaults to 1 */\n+\tconst char *metainfo_charset;\n \n \tchar *message_id;\n \tint patch_lines;\n@@ -293,7 +292,7 @@ static void cleanup_space(struct strbuf *sb)\n \t}\n }\n \n-static void decode_header(struct strbuf *line);\n+static void decode_header(struct mailinfo *mi, struct strbuf *line);\n static const char *header[MAX_HDR_PARSED] = {\n \t\"From\",\"Subject\",\"Date\",\n };\n@@ -336,7 +335,7 @@ static int check_header(struct mailinfo *mi,\n \t\t\t * normalize the meta information to utf8.\n \t\t\t */\n \t\t\tstrbuf_add(&sb, line->buf + len + 2, line->len - len - 2);\n-\t\t\tdecode_header(&sb);\n+\t\t\tdecode_header(mi, &sb);\n \t\t\thandle_header(&hdr_data[i], &sb);\n \t\t\tret = 1;\n \t\t\tgoto check_header_out;\n@@ -347,7 +346,7 @@ static int check_header(struct mailinfo *mi,\n \tif (cmp_header(line, \"Content-Type\")) {\n \t\tlen = strlen(\"Content-Type: \");\n \t\tstrbuf_add(&sb, line->buf + len, line->len - len);\n-\t\tdecode_header(&sb);\n+\t\tdecode_header(mi, &sb);\n \t\tstrbuf_insert(&sb, 0, \"Content-Type: \", len);\n \t\thandle_content_type(&sb);\n \t\tret = 1;\n@@ -356,7 +355,7 @@ static int check_header(struct mailinfo *mi,\n \tif (cmp_header(line, \"Content-Transfer-Encoding\")) {\n \t\tlen = strlen(\"Content-Transfer-Encoding: \");\n \t\tstrbuf_add(&sb, line->buf + len, line->len - len);\n-\t\tdecode_header(&sb);\n+\t\tdecode_header(mi, &sb);\n \t\thandle_content_transfer_encoding(&sb);\n \t\tret = 1;\n \t\tgoto check_header_out;\n@@ -364,7 +363,7 @@ static int check_header(struct mailinfo *mi,\n \tif (cmp_header(line, \"Message-Id\")) {\n \t\tlen = strlen(\"Message-Id: \");\n \t\tstrbuf_add(&sb, line->buf + len, line->len - len);\n-\t\tdecode_header(&sb);\n+\t\tdecode_header(mi, &sb);\n \t\thandle_message_id(mi, &sb);\n \t\tret = 1;\n \t\tgoto check_header_out;\n@@ -520,23 +519,24 @@ static struct strbuf *decode_b_segment(const struct strbuf *b_seg)\n \treturn out;\n }\n \n-static void convert_to_utf8(struct strbuf *line, const char *charset)\n+static void convert_to_utf8(struct mailinfo *mi,\n+\t\t\t    struct strbuf *line, const char *charset)\n {\n \tchar *out;\n \n-\tif (!charset || !*charset)\n+\tif (!mi->metainfo_charset || !charset || !*charset)\n \t\treturn;\n \n-\tif (same_encoding(metainfo_charset, charset))\n+\tif (same_encoding(mi->metainfo_charset, charset))\n \t\treturn;\n-\tout = reencode_string(line->buf, metainfo_charset, charset);\n+\tout = reencode_string(line->buf, mi->metainfo_charset, charset);\n \tif (!out)\n \t\tdie(\"cannot convert from %s to %s\",\n-\t\t    charset, metainfo_charset);\n+\t\t    charset, mi->metainfo_charset);\n \tstrbuf_attach(line, out, strlen(out), strlen(out));\n }\n \n-static void decode_header(struct strbuf *it)\n+static void decode_header(struct mailinfo *mi, struct strbuf *it)\n {\n \tchar *in, *ep, *cp;\n \tstruct strbuf outbuf = STRBUF_INIT, *dec;\n@@ -599,8 +599,7 @@ static void decode_header(struct strbuf *it)\n \t\t\tdec = decode_q_segment(&piecebuf, 1);\n \t\t\tbreak;\n \t\t}\n-\t\tif (metainfo_charset)\n-\t\t\tconvert_to_utf8(dec, charset_q.buf);\n+\t\tconvert_to_utf8(mi, dec, charset_q.buf);\n \n \t\tstrbuf_addbuf(&outbuf, dec);\n \t\tstrbuf_release(dec);\n@@ -774,8 +773,7 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n \t\tmi->header_stage = 0;\n \n \t/* normalize the log message to UTF-8. */\n-\tif (metainfo_charset)\n-\t\tconvert_to_utf8(line, charset.buf);\n+\tconvert_to_utf8(mi, line, charset.buf);\n \n \tif (mi->use_scissors && is_scissors_line(line)) {\n \t\tint i;\n@@ -1074,7 +1072,7 @@ int cmd_mailinfo(int argc, const char **argv, const char *prefix)\n \tsetup_mailinfo(&mi);\n \n \tdef_charset = get_commit_output_encoding();\n-\tmetainfo_charset = def_charset;\n+\tmi.metainfo_charset = def_charset;\n \n \twhile (1 < argc && argv[1][0] == '-') {\n \t\tif (!strcmp(argv[1], \"-k\"))\n@@ -1084,11 +1082,11 @@ int cmd_mailinfo(int argc, const char **argv, const char *prefix)\n \t\telse if (!strcmp(argv[1], \"-m\") || !strcmp(argv[1], \"--message-id\"))\n \t\t\tmi.add_message_id = 1;\n \t\telse if (!strcmp(argv[1], \"-u\"))\n-\t\t\tmetainfo_charset = def_charset;\n+\t\t\tmi.metainfo_charset = def_charset;\n \t\telse if (!strcmp(argv[1], \"-n\"))\n-\t\t\tmetainfo_charset = NULL;\n+\t\t\tmi.metainfo_charset = NULL;\n \t\telse if (starts_with(argv[1], \"--encoding=\"))\n-\t\t\tmetainfo_charset = argv[1] + 11;\n+\t\t\tmi.metainfo_charset = argv[1] + 11;\n \t\telse if (!strcmp(argv[1], \"--scissors\"))\n \t\t\tmi.use_scissors = 1;\n \t\telse if (!strcmp(argv[1], \"--no-scissors\"))\n-- \n2.6.1-320-g86a1181\n"},{"id":"271612","messageId":"1444778207-859-17-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444778207-859-1-git-send-email-gitster@pobox.com","subject":"[PATCH 16/26] mailinfo: move transfer_encoding to struct mailinfo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-13T23:16:37Z","receivedAt":"2015-10-13T23:16:37Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Signed-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 27 ++++++++++++++-------------\n 1 file changed, 14 insertions(+), 13 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 7e01efa..fbfa27e 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -23,14 +23,14 @@ struct mailinfo {\n \tconst char *metainfo_charset;\n \n \tchar *message_id;\n+\tenum  {\n+\t\tTE_DONTCARE, TE_QP, TE_BASE64\n+\t} transfer_encoding;\n \tint patch_lines;\n \tint filter_stage; /* still reading log or are we copying patch? */\n \tint header_stage; /* still checking in-body headers? */\n };\n \n-static enum  {\n-\tTE_DONTCARE, TE_QP, TE_BASE64\n-} transfer_encoding;\n \n static struct strbuf charset = STRBUF_INIT;\n \n@@ -214,14 +214,15 @@ static void handle_message_id(struct mailinfo *mi, const struct strbuf *line)\n \t\tmi->message_id = strdup(line->buf);\n }\n \n-static void handle_content_transfer_encoding(const struct strbuf *line)\n+static void handle_content_transfer_encoding(struct mailinfo *mi,\n+\t\t\t\t\t     const struct strbuf *line)\n {\n \tif (strcasestr(line->buf, \"base64\"))\n-\t\ttransfer_encoding = TE_BASE64;\n+\t\tmi->transfer_encoding = TE_BASE64;\n \telse if (strcasestr(line->buf, \"quoted-printable\"))\n-\t\ttransfer_encoding = TE_QP;\n+\t\tmi->transfer_encoding = TE_QP;\n \telse\n-\t\ttransfer_encoding = TE_DONTCARE;\n+\t\tmi->transfer_encoding = TE_DONTCARE;\n }\n \n static int is_multipart_boundary(const struct strbuf *line)\n@@ -356,7 +357,7 @@ static int check_header(struct mailinfo *mi,\n \t\tlen = strlen(\"Content-Transfer-Encoding: \");\n \t\tstrbuf_add(&sb, line->buf + len, line->len - len);\n \t\tdecode_header(mi, &sb);\n-\t\thandle_content_transfer_encoding(&sb);\n+\t\thandle_content_transfer_encoding(mi, &sb);\n \t\tret = 1;\n \t\tgoto check_header_out;\n \t}\n@@ -615,11 +616,11 @@ release_return:\n \tstrbuf_release(&piecebuf);\n }\n \n-static void decode_transfer_encoding(struct strbuf *line)\n+static void decode_transfer_encoding(struct mailinfo *mi, struct strbuf *line)\n {\n \tstruct strbuf *ret;\n \n-\tswitch (transfer_encoding) {\n+\tswitch (mi->transfer_encoding) {\n \tcase TE_QP:\n \t\tret = decode_q_segment(line, 0);\n \t\tbreak;\n@@ -867,7 +868,7 @@ again:\n \t}\n \n \t/* set some defaults */\n-\ttransfer_encoding = TE_DONTCARE;\n+\tmi->transfer_encoding = TE_DONTCARE;\n \tstrbuf_reset(&charset);\n \n \t/* slurp in this section's info */\n@@ -905,9 +906,9 @@ static void handle_body(struct mailinfo *mi, struct strbuf *line)\n \t\t}\n \n \t\t/* Unwrap transfer encoding */\n-\t\tdecode_transfer_encoding(line);\n+\t\tdecode_transfer_encoding(mi, line);\n \n-\t\tswitch (transfer_encoding) {\n+\t\tswitch (mi->transfer_encoding) {\n \t\tcase TE_BASE64:\n \t\tcase TE_QP:\n \t\t{\n-- \n2.6.1-320-g86a1181\n"},{"id":"271614","messageId":"1444778207-859-18-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444778207-859-1-git-send-email-gitster@pobox.com","subject":"[PATCH 17/26] mailinfo: move charset to struct mailinfo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-13T23:16:38Z","receivedAt":"2015-10-13T23:16:38Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Signed-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 15 +++++++--------\n 1 file changed, 7 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex fbfa27e..a51b2c5 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -22,6 +22,7 @@ struct mailinfo {\n \tint use_inbody_headers; /* defaults to 1 */\n \tconst char *metainfo_charset;\n \n+\tstruct strbuf charset;\n \tchar *message_id;\n \tenum  {\n \t\tTE_DONTCARE, TE_QP, TE_BASE64\n@@ -31,9 +32,6 @@ struct mailinfo {\n \tint header_stage; /* still checking in-body headers? */\n };\n \n-\n-static struct strbuf charset = STRBUF_INIT;\n-\n static struct strbuf **p_hdr_data, **s_hdr_data;\n \n #define MAX_HDR_PARSED 10\n@@ -186,7 +184,7 @@ static struct strbuf *content[MAX_BOUNDARIES];\n \n static struct strbuf **content_top = content;\n \n-static void handle_content_type(struct strbuf *line)\n+static void handle_content_type(struct mailinfo *mi, struct strbuf *line)\n {\n \tstruct strbuf *boundary = xmalloc(sizeof(struct strbuf));\n \tstrbuf_init(boundary, line->len);\n@@ -200,7 +198,7 @@ static void handle_content_type(struct strbuf *line)\n \t\t*content_top = boundary;\n \t\tboundary = NULL;\n \t}\n-\tslurp_attr(line->buf, \"charset=\", &charset);\n+\tslurp_attr(line->buf, \"charset=\", &mi->charset);\n \n \tif (boundary) {\n \t\tstrbuf_release(boundary);\n@@ -349,7 +347,7 @@ static int check_header(struct mailinfo *mi,\n \t\tstrbuf_add(&sb, line->buf + len, line->len - len);\n \t\tdecode_header(mi, &sb);\n \t\tstrbuf_insert(&sb, 0, \"Content-Type: \", len);\n-\t\thandle_content_type(&sb);\n+\t\thandle_content_type(mi, &sb);\n \t\tret = 1;\n \t\tgoto check_header_out;\n \t}\n@@ -774,7 +772,7 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n \t\tmi->header_stage = 0;\n \n \t/* normalize the log message to UTF-8. */\n-\tconvert_to_utf8(mi, line, charset.buf);\n+\tconvert_to_utf8(mi, line, mi->charset.buf);\n \n \tif (mi->use_scissors && is_scissors_line(line)) {\n \t\tint i;\n@@ -869,7 +867,7 @@ again:\n \n \t/* set some defaults */\n \tmi->transfer_encoding = TE_DONTCARE;\n-\tstrbuf_reset(&charset);\n+\tstrbuf_reset(&mi->charset);\n \n \t/* slurp in this section's info */\n \twhile (read_one_header_line(line, mi->input))\n@@ -1054,6 +1052,7 @@ static void setup_mailinfo(struct mailinfo *mi)\n \tmemset(mi, 0, sizeof(*mi));\n \tstrbuf_init(&mi->name, 0);\n \tstrbuf_init(&mi->email, 0);\n+\tstrbuf_init(&mi->charset, 0);\n \tmi->header_stage = 1;\n \tmi->use_inbody_headers = 1;\n \tgit_config(git_mailinfo_config, &mi);\n-- \n2.6.1-320-g86a1181\n"},{"id":"271616","messageId":"1444778207-859-19-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444778207-859-1-git-send-email-gitster@pobox.com","subject":"[PATCH 18/26] mailinfo: handle_commit_msg() shouldn't be called after finding patchbreak","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-13T23:16:39Z","receivedAt":"2015-10-13T23:16:39Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"There is a strange \"if (!cmitmsg) return 0\" at the very beginning of\nhandle_commit_msg(), but the condition should never trigger,\nbecause:\n\n * The only place cmitmsg is set to NULL is after this function sees\n   a patch break, closes the FILE * to write the commit log message\n   and returns 1.  This function returns non-zero only from that\n   codepath.\n\n * The caller of this function, upon seeing a non-zero return,\n   increments filter_stage, starts treating the input as patch text\n   and will never call handle_commit_msg() again.\n\nReplace it with an assert(!mi->filter_stage).\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 3 +--\n 1 file changed, 1 insertion(+), 2 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex a51b2c5..256d04a 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -731,8 +731,7 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n \t */\n \tint is_empty_line;\n \n-\tif (!cmitmsg)\n-\t\treturn 0;\n+\tassert(!mi->filter_stage);\n \n \tis_empty_line = (!line->len || (line->len == 1 && line->buf[0] == '\\n'));\n \tif (mi->header_stage == 1) {\n-- \n2.6.1-320-g86a1181\n"},{"id":"271629","messageId":"1444778207-859-20-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444778207-859-1-git-send-email-gitster@pobox.com","subject":"[PATCH 19/26] mailinfo: move cmitmsg and patchfile to struct mailinfo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-13T23:16:40Z","receivedAt":"2015-10-13T23:16:40Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Signed-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 28 ++++++++++++++--------------\n 1 file changed, 14 insertions(+), 14 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 256d04a..b591a2f 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -7,11 +7,11 @@\n #include \"utf8.h\"\n #include \"strbuf.h\"\n \n-static FILE *cmitmsg, *patchfile;\n-\n struct mailinfo {\n \tFILE *input;\n \tFILE *output;\n+\tFILE *cmitmsg;\n+\tFILE *patchfile;\n \n \tstruct strbuf name;\n \tstruct strbuf email;\n@@ -775,9 +775,9 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n \n \tif (mi->use_scissors && is_scissors_line(line)) {\n \t\tint i;\n-\t\tif (fseek(cmitmsg, 0L, SEEK_SET))\n+\t\tif (fseek(mi->cmitmsg, 0L, SEEK_SET))\n \t\t\tdie_errno(\"Could not rewind output message file\");\n-\t\tif (ftruncate(fileno(cmitmsg), 0))\n+\t\tif (ftruncate(fileno(mi->cmitmsg), 0))\n \t\t\tdie_errno(\"Could not truncate output message file at scissors\");\n \t\tmi->header_stage = 1;\n \n@@ -795,19 +795,19 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n \n \tif (patchbreak(line)) {\n \t\tif (mi->message_id)\n-\t\t\tfprintf(cmitmsg, \"Message-Id: %s\\n\", mi->message_id);\n-\t\tfclose(cmitmsg);\n-\t\tcmitmsg = NULL;\n+\t\t\tfprintf(mi->cmitmsg, \"Message-Id: %s\\n\", mi->message_id);\n+\t\tfclose(mi->cmitmsg);\n+\t\tmi->cmitmsg = NULL;\n \t\treturn 1;\n \t}\n \n-\tfputs(line->buf, cmitmsg);\n+\tfputs(line->buf, mi->cmitmsg);\n \treturn 0;\n }\n \n static void handle_patch(struct mailinfo *mi, const struct strbuf *line)\n {\n-\tfwrite(line->buf, 1, line->len, patchfile);\n+\tfwrite(line->buf, 1, line->len, mi->patchfile);\n \tmi->patch_lines++;\n }\n \n@@ -1002,15 +1002,15 @@ static int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)\n \tint peek;\n \tstruct strbuf line = STRBUF_INIT;\n \n-\tcmitmsg = fopen(msg, \"w\");\n-\tif (!cmitmsg) {\n+\tmi->cmitmsg = fopen(msg, \"w\");\n+\tif (!mi->cmitmsg) {\n \t\tperror(msg);\n \t\treturn -1;\n \t}\n-\tpatchfile = fopen(patch, \"w\");\n-\tif (!patchfile) {\n+\tmi->patchfile = fopen(patch, \"w\");\n+\tif (!mi->patchfile) {\n \t\tperror(patch);\n-\t\tfclose(cmitmsg);\n+\t\tfclose(mi->cmitmsg);\n \t\treturn -1;\n \t}\n \n-- \n2.6.1-320-g86a1181\n"},{"id":"271628","messageId":"1444778207-859-21-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444778207-859-1-git-send-email-gitster@pobox.com","subject":"[PATCH 20/26] mailinfo: move [ps]_hdr_data to struct mailinfo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-13T23:16:41Z","receivedAt":"2015-10-13T23:16:41Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Signed-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 28 ++++++++++++++--------------\n 1 file changed, 14 insertions(+), 14 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex b591a2f..c9629c8 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -30,10 +30,10 @@ struct mailinfo {\n \tint patch_lines;\n \tint filter_stage; /* still reading log or are we copying patch? */\n \tint header_stage; /* still checking in-body headers? */\n+\tstruct strbuf **p_hdr_data;\n+\tstruct strbuf **s_hdr_data;\n };\n \n-static struct strbuf **p_hdr_data, **s_hdr_data;\n-\n #define MAX_HDR_PARSED 10\n #define MAX_BOUNDARIES 5\n \n@@ -743,7 +743,7 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n \t}\n \n \tif (mi->use_inbody_headers && mi->header_stage) {\n-\t\tint is_known_header = check_header(mi, line, s_hdr_data, 0);\n+\t\tint is_known_header = check_header(mi, line, mi->s_hdr_data, 0);\n \n \t\tif (mi->header_stage == 2) {\n \t\t\t/*\n@@ -786,9 +786,9 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n \t\t * them to give ourselves a clean restart.\n \t\t */\n \t\tfor (i = 0; header[i]; i++) {\n-\t\t\tif (s_hdr_data[i])\n-\t\t\t\tstrbuf_release(s_hdr_data[i]);\n-\t\t\ts_hdr_data[i] = NULL;\n+\t\t\tif (mi->s_hdr_data[i])\n+\t\t\t\tstrbuf_release(mi->s_hdr_data[i]);\n+\t\t\tmi->s_hdr_data[i] = NULL;\n \t\t}\n \t\treturn 0;\n \t}\n@@ -870,7 +870,7 @@ again:\n \n \t/* slurp in this section's info */\n \twhile (read_one_header_line(line, mi->input))\n-\t\tcheck_header(mi, line, p_hdr_data, 0);\n+\t\tcheck_header(mi, line, mi->p_hdr_data, 0);\n \n \tstrbuf_release(&newline);\n \t/* replenish line */\n@@ -971,10 +971,10 @@ static void handle_info(struct mailinfo *mi)\n \n \tfor (i = 0; header[i]; i++) {\n \t\t/* only print inbody headers if we output a patch file */\n-\t\tif (mi->patch_lines && s_hdr_data[i])\n-\t\t\thdr = s_hdr_data[i];\n-\t\telse if (p_hdr_data[i])\n-\t\t\thdr = p_hdr_data[i];\n+\t\tif (mi->patch_lines && mi->s_hdr_data[i])\n+\t\t\thdr = mi->s_hdr_data[i];\n+\t\telse if (mi->p_hdr_data[i])\n+\t\t\thdr = mi->p_hdr_data[i];\n \t\telse\n \t\t\tcontinue;\n \n@@ -1014,8 +1014,8 @@ static int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)\n \t\treturn -1;\n \t}\n \n-\tp_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*p_hdr_data));\n-\ts_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*s_hdr_data));\n+\tmi->p_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*(mi->p_hdr_data)));\n+\tmi->s_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*(mi->s_hdr_data)));\n \n \tdo {\n \t\tpeek = fgetc(mi->input);\n@@ -1024,7 +1024,7 @@ static int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)\n \n \t/* process the email header */\n \twhile (read_one_header_line(&line, mi->input))\n-\t\tcheck_header(mi, &line, p_hdr_data, 1);\n+\t\tcheck_header(mi, &line, mi->p_hdr_data, 1);\n \n \thandle_body(mi, &line);\n \thandle_info(mi);\n-- \n2.6.1-320-g86a1181\n"},{"id":"271615","messageId":"1444778207-859-22-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444778207-859-1-git-send-email-gitster@pobox.com","subject":"[PATCH 21/26] mailinfo: keep the parsed log message in a strbuf","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-13T23:16:42Z","receivedAt":"2015-10-13T23:16:42Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"When mailinfo() is eventually libified, the calling \"git am\" still\nwill have to write out the log message in the \"msg\" file for hooks\nand other users of the information, but at least it does not have to\nreopen and reread what was written back if the function kept it in a\nstrbuf so that the caller can read it from there.\n\nThis also removes the need for seeking and truncating the output\nfile when we see a scissors mark in the input, which in turn reduces\ntwo callsites of die_errno().\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 41 ++++++++++++++++++++++++++++-------------\n 1 file changed, 28 insertions(+), 13 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex c9629c8..d38d716 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -10,7 +10,6 @@\n struct mailinfo {\n \tFILE *input;\n \tFILE *output;\n-\tFILE *cmitmsg;\n \tFILE *patchfile;\n \n \tstruct strbuf name;\n@@ -32,6 +31,8 @@ struct mailinfo {\n \tint header_stage; /* still checking in-body headers? */\n \tstruct strbuf **p_hdr_data;\n \tstruct strbuf **s_hdr_data;\n+\n+\tstruct strbuf log_message;\n };\n \n #define MAX_HDR_PARSED 10\n@@ -775,10 +776,8 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n \n \tif (mi->use_scissors && is_scissors_line(line)) {\n \t\tint i;\n-\t\tif (fseek(mi->cmitmsg, 0L, SEEK_SET))\n-\t\t\tdie_errno(\"Could not rewind output message file\");\n-\t\tif (ftruncate(fileno(mi->cmitmsg), 0))\n-\t\t\tdie_errno(\"Could not truncate output message file at scissors\");\n+\n+\t\tstrbuf_setlen(&mi->log_message, 0);\n \t\tmi->header_stage = 1;\n \n \t\t/*\n@@ -795,13 +794,12 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n \n \tif (patchbreak(line)) {\n \t\tif (mi->message_id)\n-\t\t\tfprintf(mi->cmitmsg, \"Message-Id: %s\\n\", mi->message_id);\n-\t\tfclose(mi->cmitmsg);\n-\t\tmi->cmitmsg = NULL;\n+\t\t\tstrbuf_addf(&mi->log_message,\n+\t\t\t\t    \"Message-Id: %s\\n\", mi->message_id);\n \t\treturn 1;\n \t}\n \n-\tfputs(line->buf, mi->cmitmsg);\n+\tstrbuf_addbuf(&mi->log_message, line);\n \treturn 0;\n }\n \n@@ -999,18 +997,19 @@ static void handle_info(struct mailinfo *mi)\n \n static int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)\n {\n+\tFILE *cmitmsg;\n \tint peek;\n \tstruct strbuf line = STRBUF_INIT;\n \n-\tmi->cmitmsg = fopen(msg, \"w\");\n-\tif (!mi->cmitmsg) {\n+\tcmitmsg = fopen(msg, \"w\");\n+\tif (!cmitmsg) {\n \t\tperror(msg);\n \t\treturn -1;\n \t}\n \tmi->patchfile = fopen(patch, \"w\");\n \tif (!mi->patchfile) {\n \t\tperror(patch);\n-\t\tfclose(mi->cmitmsg);\n+\t\tfclose(cmitmsg);\n \t\treturn -1;\n \t}\n \n@@ -1029,6 +1028,9 @@ static int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)\n \thandle_body(mi, &line);\n \thandle_info(mi);\n \n+\tfwrite(mi->log_message.buf, 1, mi->log_message.len, cmitmsg);\n+\tfclose(cmitmsg);\n+\n \treturn 0;\n }\n \n@@ -1052,11 +1054,20 @@ static void setup_mailinfo(struct mailinfo *mi)\n \tstrbuf_init(&mi->name, 0);\n \tstrbuf_init(&mi->email, 0);\n \tstrbuf_init(&mi->charset, 0);\n+\tstrbuf_init(&mi->log_message, 0);\n \tmi->header_stage = 1;\n \tmi->use_inbody_headers = 1;\n \tgit_config(git_mailinfo_config, &mi);\n }\n \n+static void clear_mailinfo(struct mailinfo *mi)\n+{\n+\tstrbuf_release(&mi->name);\n+\tstrbuf_release(&mi->email);\n+\tstrbuf_release(&mi->charset);\n+\tstrbuf_release(&mi->log_message);\n+}\n+\n static const char mailinfo_usage[] =\n \t\"git mailinfo [-k | -b] [-m | --message-id] [-u | --encoding=<encoding> | -n] [--scissors | --no-scissors] <msg> <patch> < mail >info\";\n \n@@ -1064,6 +1075,7 @@ int cmd_mailinfo(int argc, const char **argv, const char *prefix)\n {\n \tconst char *def_charset;\n \tstruct mailinfo mi;\n+\tint status;\n \n \t/* NEEDSWORK: might want to do the optional .git/ directory\n \t * discovery\n@@ -1102,5 +1114,8 @@ int cmd_mailinfo(int argc, const char **argv, const char *prefix)\n \n \tmi.input = stdin;\n \tmi.output = stdout;\n-\treturn !!mailinfo(&mi, argv[1], argv[2]);\n+\tstatus = !!mailinfo(&mi, argv[1], argv[2]);\n+\tclear_mailinfo(&mi);\n+\n+\treturn status;\n }\n-- \n2.6.1-320-g86a1181\n"},{"id":"271624","messageId":"1444778207-859-23-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444778207-859-1-git-send-email-gitster@pobox.com","subject":"[PATCH 22/26] mailinfo: move content/content_top to struct mailinfo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-13T23:16:43Z","receivedAt":"2015-10-13T23:16:43Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Signed-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 45 ++++++++++++++++++++++++++-------------------\n 1 file changed, 26 insertions(+), 19 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex d38d716..4b9b1cc 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -7,6 +7,8 @@\n #include \"utf8.h\"\n #include \"strbuf.h\"\n \n+#define MAX_BOUNDARIES 5\n+\n struct mailinfo {\n \tFILE *input;\n \tFILE *output;\n@@ -21,6 +23,8 @@ struct mailinfo {\n \tint use_inbody_headers; /* defaults to 1 */\n \tconst char *metainfo_charset;\n \n+\tstruct strbuf *content[MAX_BOUNDARIES];\n+\tstruct strbuf **content_top;\n \tstruct strbuf charset;\n \tchar *message_id;\n \tenum  {\n@@ -36,7 +40,6 @@ struct mailinfo {\n };\n \n #define MAX_HDR_PARSED 10\n-#define MAX_BOUNDARIES 5\n \n static void cleanup_space(struct strbuf *sb);\n \n@@ -181,10 +184,6 @@ static int slurp_attr(const char *line, const char *name, struct strbuf *attr)\n \treturn 1;\n }\n \n-static struct strbuf *content[MAX_BOUNDARIES];\n-\n-static struct strbuf **content_top = content;\n-\n static void handle_content_type(struct mailinfo *mi, struct strbuf *line)\n {\n \tstruct strbuf *boundary = xmalloc(sizeof(struct strbuf));\n@@ -192,11 +191,11 @@ static void handle_content_type(struct mailinfo *mi, struct strbuf *line)\n \n \tif (slurp_attr(line->buf, \"boundary=\", boundary)) {\n \t\tstrbuf_insert(boundary, 0, \"--\", 2);\n-\t\tif (++content_top >= &content[MAX_BOUNDARIES]) {\n+\t\tif (++mi->content_top >= &mi->content[MAX_BOUNDARIES]) {\n \t\t\tfprintf(stderr, \"Too many boundaries to handle\\n\");\n \t\t\texit(1);\n \t\t}\n-\t\t*content_top = boundary;\n+\t\t*(mi->content_top) = boundary;\n \t\tboundary = NULL;\n \t}\n \tslurp_attr(line->buf, \"charset=\", &mi->charset);\n@@ -224,10 +223,12 @@ static void handle_content_transfer_encoding(struct mailinfo *mi,\n \t\tmi->transfer_encoding = TE_DONTCARE;\n }\n \n-static int is_multipart_boundary(const struct strbuf *line)\n+static int is_multipart_boundary(struct mailinfo *mi, const struct strbuf *line)\n {\n-\treturn (((*content_top)->len <= line->len) &&\n-\t\t!memcmp(line->buf, (*content_top)->buf, (*content_top)->len));\n+\tstruct strbuf *content_top = *(mi->content_top);\n+\n+\treturn ((content_top->len <= line->len) &&\n+\t\t!memcmp(line->buf, content_top->buf, content_top->len));\n }\n \n static void cleanup_subject(struct mailinfo *mi, struct strbuf *subject)\n@@ -825,7 +826,7 @@ static void handle_filter(struct mailinfo *mi, struct strbuf *line)\n static int find_boundary(struct mailinfo *mi, struct strbuf *line)\n {\n \twhile (!strbuf_getline(line, mi->input, '\\n')) {\n-\t\tif (*content_top && is_multipart_boundary(line))\n+\t\tif (*(mi->content_top) && is_multipart_boundary(mi, line))\n \t\t\treturn 1;\n \t}\n \treturn 0;\n@@ -837,18 +838,18 @@ static int handle_boundary(struct mailinfo *mi, struct strbuf *line)\n \n \tstrbuf_addch(&newline, '\\n');\n again:\n-\tif (line->len >= (*content_top)->len + 2 &&\n-\t    !memcmp(line->buf + (*content_top)->len, \"--\", 2)) {\n+\tif (line->len >= (*(mi->content_top))->len + 2 &&\n+\t    !memcmp(line->buf + (*(mi->content_top))->len, \"--\", 2)) {\n \t\t/* we hit an end boundary */\n \t\t/* pop the current boundary off the stack */\n-\t\tstrbuf_release(*content_top);\n-\t\tfree(*content_top);\n-\t\t*content_top = NULL;\n+\t\tstrbuf_release(*(mi->content_top));\n+\t\tfree(*(mi->content_top));\n+\t\t*(mi->content_top) = NULL;\n \n \t\t/* technically won't happen as is_multipart_boundary()\n \t\t   will fail first.  But just in case..\n \t\t */\n-\t\tif (--content_top < content) {\n+\t\tif (--mi->content_top < mi->content) {\n \t\t\tfprintf(stderr, \"Detected mismatched boundaries, \"\n \t\t\t\t\t\"can't recover\\n\");\n \t\t\texit(1);\n@@ -883,14 +884,14 @@ static void handle_body(struct mailinfo *mi, struct strbuf *line)\n \tstruct strbuf prev = STRBUF_INIT;\n \n \t/* Skip up to the first boundary */\n-\tif (*content_top) {\n+\tif (*(mi->content_top)) {\n \t\tif (!find_boundary(mi, line))\n \t\t\tgoto handle_body_out;\n \t}\n \n \tdo {\n \t\t/* process any boundary lines */\n-\t\tif (*content_top && is_multipart_boundary(line)) {\n+\t\tif (*(mi->content_top) && is_multipart_boundary(mi, line)) {\n \t\t\t/* flush any leftover */\n \t\t\tif (prev.len) {\n \t\t\t\thandle_filter(mi, &prev);\n@@ -1057,6 +1058,7 @@ static void setup_mailinfo(struct mailinfo *mi)\n \tstrbuf_init(&mi->log_message, 0);\n \tmi->header_stage = 1;\n \tmi->use_inbody_headers = 1;\n+\tmi->content_top = mi->content;\n \tgit_config(git_mailinfo_config, &mi);\n }\n \n@@ -1066,6 +1068,11 @@ static void clear_mailinfo(struct mailinfo *mi)\n \tstrbuf_release(&mi->email);\n \tstrbuf_release(&mi->charset);\n \tstrbuf_release(&mi->log_message);\n+\n+\twhile (mi->content < mi->content_top) {\n+\t\tfree(*(mi->content_top));\n+\t\tmi->content_top--;\n+\t}\n }\n \n static const char mailinfo_usage[] =\n-- \n2.6.1-320-g86a1181\n"},{"id":"271627","messageId":"1444778207-859-24-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444778207-859-1-git-send-email-gitster@pobox.com","subject":"[PATCH 23/26] mailinfo: handle errors found in decode_header() better","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-13T23:16:44Z","receivedAt":"2015-10-13T23:16:44Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The decode_header() function tries to unwrap RFC2047-style quoted\nstrings but punts when it finds anything it cannot parse.  Allow the\nfunction to report if it punted to the caller, and use the resulting\nstring in the caller only when the function says it parsed the input\nsuccessfully.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 27 ++++++++++++++++-----------\n 1 file changed, 16 insertions(+), 11 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 4b9b1cc..6452a4c 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -293,7 +293,7 @@ static void cleanup_space(struct strbuf *sb)\n \t}\n }\n \n-static void decode_header(struct mailinfo *mi, struct strbuf *line);\n+static int decode_header(struct mailinfo *mi, struct strbuf *line);\n static const char *header[MAX_HDR_PARSED] = {\n \t\"From\",\"Subject\",\"Date\",\n };\n@@ -336,8 +336,8 @@ static int check_header(struct mailinfo *mi,\n \t\t\t * normalize the meta information to utf8.\n \t\t\t */\n \t\t\tstrbuf_add(&sb, line->buf + len + 2, line->len - len - 2);\n-\t\t\tdecode_header(mi, &sb);\n-\t\t\thandle_header(&hdr_data[i], &sb);\n+\t\t\tif (!decode_header(mi, &sb))\n+\t\t\t\thandle_header(&hdr_data[i], &sb);\n \t\t\tret = 1;\n \t\t\tgoto check_header_out;\n \t\t}\n@@ -347,25 +347,26 @@ static int check_header(struct mailinfo *mi,\n \tif (cmp_header(line, \"Content-Type\")) {\n \t\tlen = strlen(\"Content-Type: \");\n \t\tstrbuf_add(&sb, line->buf + len, line->len - len);\n-\t\tdecode_header(mi, &sb);\n-\t\tstrbuf_insert(&sb, 0, \"Content-Type: \", len);\n-\t\thandle_content_type(mi, &sb);\n+\t\tif (!decode_header(mi, &sb)) {\n+\t\t\tstrbuf_insert(&sb, 0, \"Content-Type: \", len);\n+\t\t\thandle_content_type(mi, &sb);\n+\t\t}\n \t\tret = 1;\n \t\tgoto check_header_out;\n \t}\n \tif (cmp_header(line, \"Content-Transfer-Encoding\")) {\n \t\tlen = strlen(\"Content-Transfer-Encoding: \");\n \t\tstrbuf_add(&sb, line->buf + len, line->len - len);\n-\t\tdecode_header(mi, &sb);\n-\t\thandle_content_transfer_encoding(mi, &sb);\n+\t\tif (!decode_header(mi, &sb))\n+\t\t\thandle_content_transfer_encoding(mi, &sb);\n \t\tret = 1;\n \t\tgoto check_header_out;\n \t}\n \tif (cmp_header(line, \"Message-Id\")) {\n \t\tlen = strlen(\"Message-Id: \");\n \t\tstrbuf_add(&sb, line->buf + len, line->len - len);\n-\t\tdecode_header(mi, &sb);\n-\t\thandle_message_id(mi, &sb);\n+\t\tif (!decode_header(mi, &sb))\n+\t\t\thandle_message_id(mi, &sb);\n \t\tret = 1;\n \t\tgoto check_header_out;\n \t}\n@@ -537,11 +538,12 @@ static void convert_to_utf8(struct mailinfo *mi,\n \tstrbuf_attach(line, out, strlen(out), strlen(out));\n }\n \n-static void decode_header(struct mailinfo *mi, struct strbuf *it)\n+static int decode_header(struct mailinfo *mi, struct strbuf *it)\n {\n \tchar *in, *ep, *cp;\n \tstruct strbuf outbuf = STRBUF_INIT, *dec;\n \tstruct strbuf charset_q = STRBUF_INIT, piecebuf = STRBUF_INIT;\n+\tint found_error = -1; /* pessimism */\n \n \tin = it->buf;\n \twhile (in - it->buf <= it->len && (ep = strstr(in, \"=?\")) != NULL) {\n@@ -610,10 +612,13 @@ static void decode_header(struct mailinfo *mi, struct strbuf *it)\n \tstrbuf_addstr(&outbuf, in);\n \tstrbuf_reset(it);\n \tstrbuf_addbuf(it, &outbuf);\n+\tfound_error = 0;\n release_return:\n \tstrbuf_release(&outbuf);\n \tstrbuf_release(&charset_q);\n \tstrbuf_release(&piecebuf);\n+\n+\treturn found_error;\n }\n \n static void decode_transfer_encoding(struct mailinfo *mi, struct strbuf *line)\n-- \n2.6.1-320-g86a1181\n"},{"id":"271618","messageId":"1444778207-859-25-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444778207-859-1-git-send-email-gitster@pobox.com","subject":"[PATCH 24/26] mailinfo: handle charset conversion errors in the caller","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-13T23:16:45Z","receivedAt":"2015-10-13T23:16:45Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Instead of dying in convert_to_utf8(), just report an error and let\nthe callers handle it.  Between the two callers:\n\n - decode_header() knows how to handle malformed line by reporting\n   the breakage to the caller, so let it follow the pattern it\n   already knows about;\n\n - handle_commit_msg() doesn't cope with a malformed line well, so\n   die there for now.  We'll lift this even higher in later changes\n   in this series.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 19 +++++++++++--------\n 1 file changed, 11 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 6452a4c..f14c504 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -521,21 +521,22 @@ static struct strbuf *decode_b_segment(const struct strbuf *b_seg)\n \treturn out;\n }\n \n-static void convert_to_utf8(struct mailinfo *mi,\n-\t\t\t    struct strbuf *line, const char *charset)\n+static int convert_to_utf8(struct mailinfo *mi,\n+\t\t\t   struct strbuf *line, const char *charset)\n {\n \tchar *out;\n \n \tif (!mi->metainfo_charset || !charset || !*charset)\n-\t\treturn;\n+\t\treturn 0;\n \n \tif (same_encoding(mi->metainfo_charset, charset))\n-\t\treturn;\n+\t\treturn 0;\n \tout = reencode_string(line->buf, mi->metainfo_charset, charset);\n \tif (!out)\n-\t\tdie(\"cannot convert from %s to %s\",\n-\t\t    charset, mi->metainfo_charset);\n+\t\treturn error(\"cannot convert from %s to %s\",\n+\t\t\t     charset, mi->metainfo_charset);\n \tstrbuf_attach(line, out, strlen(out), strlen(out));\n+\treturn 0;\n }\n \n static int decode_header(struct mailinfo *mi, struct strbuf *it)\n@@ -602,7 +603,8 @@ static int decode_header(struct mailinfo *mi, struct strbuf *it)\n \t\t\tdec = decode_q_segment(&piecebuf, 1);\n \t\t\tbreak;\n \t\t}\n-\t\tconvert_to_utf8(mi, dec, charset_q.buf);\n+\t\tif (convert_to_utf8(mi, dec, charset_q.buf))\n+\t\t\tgoto release_return;\n \n \t\tstrbuf_addbuf(&outbuf, dec);\n \t\tstrbuf_release(dec);\n@@ -778,7 +780,8 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n \t\tmi->header_stage = 0;\n \n \t/* normalize the log message to UTF-8. */\n-\tconvert_to_utf8(mi, line, mi->charset.buf);\n+\tif (convert_to_utf8(mi, line, mi->charset.buf))\n+\t\texit(128);\n \n \tif (mi->use_scissors && is_scissors_line(line)) {\n \t\tint i;\n-- \n2.6.1-320-g86a1181\n"},{"id":"271619","messageId":"1444778207-859-26-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444778207-859-1-git-send-email-gitster@pobox.com","subject":"[PATCH 25/26] mailinfo: remove calls to exit() and die() deep in the callchain","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-13T23:16:46Z","receivedAt":"2015-10-13T23:16:46Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The top-level mailinfo() would instead punt when the code in the\ndeeper part of the callchain detects an unrecoverable error in the\ninput.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 36 +++++++++++++++++++++++++-----------\n 1 file changed, 25 insertions(+), 11 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex f14c504..eb9ff96 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -37,6 +37,7 @@ struct mailinfo {\n \tstruct strbuf **s_hdr_data;\n \n \tstruct strbuf log_message;\n+\tint input_error;\n };\n \n #define MAX_HDR_PARSED 10\n@@ -192,8 +193,10 @@ static void handle_content_type(struct mailinfo *mi, struct strbuf *line)\n \tif (slurp_attr(line->buf, \"boundary=\", boundary)) {\n \t\tstrbuf_insert(boundary, 0, \"--\", 2);\n \t\tif (++mi->content_top >= &mi->content[MAX_BOUNDARIES]) {\n-\t\t\tfprintf(stderr, \"Too many boundaries to handle\\n\");\n-\t\t\texit(1);\n+\t\t\terror(\"Too many boundaries to handle\");\n+\t\t\tmi->input_error = -1;\n+\t\t\tmi->content_top = mi->content + MAX_BOUNDARIES - 1;\n+\t\t\treturn;\n \t\t}\n \t\t*(mi->content_top) = boundary;\n \t\tboundary = NULL;\n@@ -532,9 +535,11 @@ static int convert_to_utf8(struct mailinfo *mi,\n \tif (same_encoding(mi->metainfo_charset, charset))\n \t\treturn 0;\n \tout = reencode_string(line->buf, mi->metainfo_charset, charset);\n-\tif (!out)\n+\tif (!out) {\n+\t\tmi->input_error = -1;\n \t\treturn error(\"cannot convert from %s to %s\",\n \t\t\t     charset, mi->metainfo_charset);\n+\t}\n \tstrbuf_attach(line, out, strlen(out), strlen(out));\n \treturn 0;\n }\n@@ -781,7 +786,7 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n \n \t/* normalize the log message to UTF-8. */\n \tif (convert_to_utf8(mi, line, mi->charset.buf))\n-\t\texit(128);\n+\t\treturn 0; /* the caller will reject this input */\n \n \tif (mi->use_scissors && is_scissors_line(line)) {\n \t\tint i;\n@@ -820,6 +825,9 @@ static void handle_patch(struct mailinfo *mi, const struct strbuf *line)\n \n static void handle_filter(struct mailinfo *mi, struct strbuf *line)\n {\n+\tif (mi->input_error)\n+\t\treturn;\n+\n \tswitch (mi->filter_stage) {\n \tcase 0:\n \t\tif (!handle_commit_msg(mi, line))\n@@ -858,12 +866,15 @@ again:\n \t\t   will fail first.  But just in case..\n \t\t */\n \t\tif (--mi->content_top < mi->content) {\n-\t\t\tfprintf(stderr, \"Detected mismatched boundaries, \"\n-\t\t\t\t\t\"can't recover\\n\");\n-\t\t\texit(1);\n+\t\t\terror(\"Detected mismatched boundaries, can't recover\");\n+\t\t\tmi->input_error = -1;\n+\t\t\tmi->content_top = mi->content;\n+\t\t\treturn 0;\n \t\t}\n \t\thandle_filter(mi, &newline);\n \t\tstrbuf_release(&newline);\n+\t\tif (mi->input_error)\n+\t\t\treturn 0; /* punt to the end */\n \n \t\t/* skip to the next boundary */\n \t\tif (!find_boundary(mi, line))\n@@ -948,6 +959,8 @@ static void handle_body(struct mailinfo *mi, struct strbuf *line)\n \t\t\thandle_filter(mi, line);\n \t\t}\n \n+\t\tif (mi->input_error)\n+\t\t\tbreak;\n \t} while (!strbuf_getwholeline(line, mi->input, '\\n'));\n \n handle_body_out:\n@@ -1035,12 +1048,13 @@ static int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)\n \t\tcheck_header(mi, &line, mi->p_hdr_data, 1);\n \n \thandle_body(mi, &line);\n-\thandle_info(mi);\n-\n-\tfwrite(mi->log_message.buf, 1, mi->log_message.len, cmitmsg);\n+\tif (!mi->input_error) {\n+\t\thandle_info(mi);\n+\t\tfwrite(mi->log_message.buf, 1, mi->log_message.len, cmitmsg);\n+\t}\n \tfclose(cmitmsg);\n \n-\treturn 0;\n+\treturn mi->input_error;\n }\n \n static int git_mailinfo_config(const char *var, const char *value, void *mi_)\n-- \n2.6.1-320-g86a1181\n"},{"id":"271622","messageId":"1444778207-859-27-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444778207-859-1-git-send-email-gitster@pobox.com","subject":"[PATCH 26/26] mailinfo: libify the whole thing","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-13T23:16:47Z","receivedAt":"2015-10-13T23:16:47Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"With this, the builtin \"git am\" can hopefully make an internal call\nto the mailinfo() function without going through the run_command()\ninterface, whose overhead is heavyweight compared to what mailinfo()\nitself does on some platforms.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n Makefile           |    1 +\n builtin/mailinfo.c | 1091 +---------------------------------------------------\n mailinfo.c         | 1058 ++++++++++++++++++++++++++++++++++++++++++++++++++\n mailinfo.h         |   41 ++\n 4 files changed, 1101 insertions(+), 1090 deletions(-)\n create mode 100644 mailinfo.c\n create mode 100644 mailinfo.h\n\ndiff --git a/Makefile b/Makefile\nindex 8d5df7e..7dd3bff 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -726,6 +726,7 @@ LIB_OBJS += list-objects.o\n LIB_OBJS += ll-merge.o\n LIB_OBJS += lockfile.o\n LIB_OBJS += log-tree.o\n+LIB_OBJS += mailinfo.o\n LIB_OBJS += mailmap.o\n LIB_OBJS += match-trees.o\n LIB_OBJS += merge.o\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex eb9ff96..f6df274 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -6,1096 +6,7 @@\n #include \"builtin.h\"\n #include \"utf8.h\"\n #include \"strbuf.h\"\n-\n-#define MAX_BOUNDARIES 5\n-\n-struct mailinfo {\n-\tFILE *input;\n-\tFILE *output;\n-\tFILE *patchfile;\n-\n-\tstruct strbuf name;\n-\tstruct strbuf email;\n-\tint keep_subject;\n-\tint keep_non_patch_brackets_in_subject;\n-\tint add_message_id;\n-\tint use_scissors;\n-\tint use_inbody_headers; /* defaults to 1 */\n-\tconst char *metainfo_charset;\n-\n-\tstruct strbuf *content[MAX_BOUNDARIES];\n-\tstruct strbuf **content_top;\n-\tstruct strbuf charset;\n-\tchar *message_id;\n-\tenum  {\n-\t\tTE_DONTCARE, TE_QP, TE_BASE64\n-\t} transfer_encoding;\n-\tint patch_lines;\n-\tint filter_stage; /* still reading log or are we copying patch? */\n-\tint header_stage; /* still checking in-body headers? */\n-\tstruct strbuf **p_hdr_data;\n-\tstruct strbuf **s_hdr_data;\n-\n-\tstruct strbuf log_message;\n-\tint input_error;\n-};\n-\n-#define MAX_HDR_PARSED 10\n-\n-static void cleanup_space(struct strbuf *sb);\n-\n-\n-static void get_sane_name(struct strbuf *out, struct strbuf *name, struct strbuf *email)\n-{\n-\tstruct strbuf *src = name;\n-\tif (name->len < 3 || 60 < name->len || strchr(name->buf, '@') ||\n-\t\tstrchr(name->buf, '<') || strchr(name->buf, '>'))\n-\t\tsrc = email;\n-\telse if (name == out)\n-\t\treturn;\n-\tstrbuf_reset(out);\n-\tstrbuf_addbuf(out, src);\n-}\n-\n-static void parse_bogus_from(struct mailinfo *mi, const struct strbuf *line)\n-{\n-\t/* John Doe <johndoe> */\n-\n-\tchar *bra, *ket;\n-\t/* This is fallback, so do not bother if we already have an\n-\t * e-mail address.\n-\t */\n-\tif (mi->email.len)\n-\t\treturn;\n-\n-\tbra = strchr(line->buf, '<');\n-\tif (!bra)\n-\t\treturn;\n-\tket = strchr(bra, '>');\n-\tif (!ket)\n-\t\treturn;\n-\n-\tstrbuf_reset(&mi->email);\n-\tstrbuf_add(&mi->email, bra + 1, ket - bra - 1);\n-\n-\tstrbuf_reset(&mi->name);\n-\tstrbuf_add(&mi->name, line->buf, bra - line->buf);\n-\tstrbuf_trim(&mi->name);\n-\tget_sane_name(&mi->name, &mi->name, &mi->email);\n-}\n-\n-static void handle_from(struct mailinfo *mi, const struct strbuf *from)\n-{\n-\tchar *at;\n-\tsize_t el;\n-\tstruct strbuf f;\n-\n-\tstrbuf_init(&f, from->len);\n-\tstrbuf_addbuf(&f, from);\n-\n-\tat = strchr(f.buf, '@');\n-\tif (!at) {\n-\t\tparse_bogus_from(mi, from);\n-\t\treturn;\n-\t}\n-\n-\t/*\n-\t * If we already have one email, don't take any confusing lines\n-\t */\n-\tif (mi->email.len && strchr(at + 1, '@')) {\n-\t\tstrbuf_release(&f);\n-\t\treturn;\n-\t}\n-\n-\t/* Pick up the string around '@', possibly delimited with <>\n-\t * pair; that is the email part.\n-\t */\n-\twhile (at > f.buf) {\n-\t\tchar c = at[-1];\n-\t\tif (isspace(c))\n-\t\t\tbreak;\n-\t\tif (c == '<') {\n-\t\t\tat[-1] = ' ';\n-\t\t\tbreak;\n-\t\t}\n-\t\tat--;\n-\t}\n-\tel = strcspn(at, \" \\n\\t\\r\\v\\f>\");\n-\tstrbuf_reset(&mi->email);\n-\tstrbuf_add(&mi->email, at, el);\n-\tstrbuf_remove(&f, at - f.buf, el + (at[el] ? 1 : 0));\n-\n-\t/* The remainder is name.  It could be\n-\t *\n-\t * - \"John Doe <john.doe@xz>\"\t\t\t(a), or\n-\t * - \"john.doe@xz (John Doe)\"\t\t\t(b), or\n-\t * - \"John (zzz) Doe <john.doe@xz> (Comment)\"\t(c)\n-\t *\n-\t * but we have removed the email part, so\n-\t *\n-\t * - remove extra spaces which could stay after email (case 'c'), and\n-\t * - trim from both ends, possibly removing the () pair at the end\n-\t *   (cases 'a' and 'b').\n-\t */\n-\tcleanup_space(&f);\n-\tstrbuf_trim(&f);\n-\tif (f.buf[0] == '(' && f.len && f.buf[f.len - 1] == ')') {\n-\t\tstrbuf_remove(&f, 0, 1);\n-\t\tstrbuf_setlen(&f, f.len - 1);\n-\t}\n-\n-\tget_sane_name(&mi->name, &f, &mi->email);\n-\tstrbuf_release(&f);\n-}\n-\n-static void handle_header(struct strbuf **out, const struct strbuf *line)\n-{\n-\tif (!*out) {\n-\t\t*out = xmalloc(sizeof(struct strbuf));\n-\t\tstrbuf_init(*out, line->len);\n-\t} else\n-\t\tstrbuf_reset(*out);\n-\n-\tstrbuf_addbuf(*out, line);\n-}\n-\n-/* NOTE NOTE NOTE.  We do not claim we do full MIME.  We just attempt\n- * to have enough heuristics to grok MIME encoded patches often found\n- * on our mailing lists.  For example, we do not even treat header lines\n- * case insensitively.\n- */\n-\n-static int slurp_attr(const char *line, const char *name, struct strbuf *attr)\n-{\n-\tconst char *ends, *ap = strcasestr(line, name);\n-\tsize_t sz;\n-\n-\tstrbuf_setlen(attr, 0);\n-\tif (!ap)\n-\t\treturn 0;\n-\tap += strlen(name);\n-\tif (*ap == '\"') {\n-\t\tap++;\n-\t\tends = \"\\\"\";\n-\t}\n-\telse\n-\t\tends = \"; \\t\";\n-\tsz = strcspn(ap, ends);\n-\tstrbuf_add(attr, ap, sz);\n-\treturn 1;\n-}\n-\n-static void handle_content_type(struct mailinfo *mi, struct strbuf *line)\n-{\n-\tstruct strbuf *boundary = xmalloc(sizeof(struct strbuf));\n-\tstrbuf_init(boundary, line->len);\n-\n-\tif (slurp_attr(line->buf, \"boundary=\", boundary)) {\n-\t\tstrbuf_insert(boundary, 0, \"--\", 2);\n-\t\tif (++mi->content_top >= &mi->content[MAX_BOUNDARIES]) {\n-\t\t\terror(\"Too many boundaries to handle\");\n-\t\t\tmi->input_error = -1;\n-\t\t\tmi->content_top = mi->content + MAX_BOUNDARIES - 1;\n-\t\t\treturn;\n-\t\t}\n-\t\t*(mi->content_top) = boundary;\n-\t\tboundary = NULL;\n-\t}\n-\tslurp_attr(line->buf, \"charset=\", &mi->charset);\n-\n-\tif (boundary) {\n-\t\tstrbuf_release(boundary);\n-\t\tfree(boundary);\n-\t}\n-}\n-\n-static void handle_message_id(struct mailinfo *mi, const struct strbuf *line)\n-{\n-\tif (mi->add_message_id)\n-\t\tmi->message_id = strdup(line->buf);\n-}\n-\n-static void handle_content_transfer_encoding(struct mailinfo *mi,\n-\t\t\t\t\t     const struct strbuf *line)\n-{\n-\tif (strcasestr(line->buf, \"base64\"))\n-\t\tmi->transfer_encoding = TE_BASE64;\n-\telse if (strcasestr(line->buf, \"quoted-printable\"))\n-\t\tmi->transfer_encoding = TE_QP;\n-\telse\n-\t\tmi->transfer_encoding = TE_DONTCARE;\n-}\n-\n-static int is_multipart_boundary(struct mailinfo *mi, const struct strbuf *line)\n-{\n-\tstruct strbuf *content_top = *(mi->content_top);\n-\n-\treturn ((content_top->len <= line->len) &&\n-\t\t!memcmp(line->buf, content_top->buf, content_top->len));\n-}\n-\n-static void cleanup_subject(struct mailinfo *mi, struct strbuf *subject)\n-{\n-\tsize_t at = 0;\n-\n-\twhile (at < subject->len) {\n-\t\tchar *pos;\n-\t\tsize_t remove;\n-\n-\t\tswitch (subject->buf[at]) {\n-\t\tcase 'r': case 'R':\n-\t\t\tif (subject->len <= at + 3)\n-\t\t\t\tbreak;\n-\t\t\tif ((subject->buf[at + 1] == 'e' ||\n-\t\t\t     subject->buf[at + 1] == 'E') &&\n-\t\t\t    subject->buf[at + 2] == ':') {\n-\t\t\t\tstrbuf_remove(subject, at, 3);\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\t\t\tat++;\n-\t\t\tbreak;\n-\t\tcase ' ': case '\\t': case ':':\n-\t\t\tstrbuf_remove(subject, at, 1);\n-\t\t\tcontinue;\n-\t\tcase '[':\n-\t\t\tpos = strchr(subject->buf + at, ']');\n-\t\t\tif (!pos)\n-\t\t\t\tbreak;\n-\t\t\tremove = pos - subject->buf + at + 1;\n-\t\t\tif (!mi->keep_non_patch_brackets_in_subject ||\n-\t\t\t    (7 <= remove &&\n-\t\t\t     memmem(subject->buf + at, remove, \"PATCH\", 5)))\n-\t\t\t\tstrbuf_remove(subject, at, remove);\n-\t\t\telse {\n-\t\t\t\tat += remove;\n-\t\t\t\t/*\n-\t\t\t\t * If the input had a space after the ], keep\n-\t\t\t\t * it.  We don't bother with finding the end of\n-\t\t\t\t * the space, since we later normalize it\n-\t\t\t\t * anyway.\n-\t\t\t\t */\n-\t\t\t\tif (isspace(subject->buf[at]))\n-\t\t\t\t\tat += 1;\n-\t\t\t}\n-\t\t\tcontinue;\n-\t\t}\n-\t\tbreak;\n-\t}\n-\tstrbuf_trim(subject);\n-}\n-\n-static void cleanup_space(struct strbuf *sb)\n-{\n-\tsize_t pos, cnt;\n-\tfor (pos = 0; pos < sb->len; pos++) {\n-\t\tif (isspace(sb->buf[pos])) {\n-\t\t\tsb->buf[pos] = ' ';\n-\t\t\tfor (cnt = 0; isspace(sb->buf[pos + cnt + 1]); cnt++);\n-\t\t\tstrbuf_remove(sb, pos + 1, cnt);\n-\t\t}\n-\t}\n-}\n-\n-static int decode_header(struct mailinfo *mi, struct strbuf *line);\n-static const char *header[MAX_HDR_PARSED] = {\n-\t\"From\",\"Subject\",\"Date\",\n-};\n-\n-static inline int cmp_header(const struct strbuf *line, const char *hdr)\n-{\n-\tint len = strlen(hdr);\n-\treturn !strncasecmp(line->buf, hdr, len) && line->len > len &&\n-\t\t\tline->buf[len] == ':' && isspace(line->buf[len + 1]);\n-}\n-\n-static int is_format_patch_separator(const char *line, int len)\n-{\n-\tstatic const char SAMPLE[] =\n-\t\t\"From e6807f3efca28b30decfecb1732a56c7db1137ee Mon Sep 17 00:00:00 2001\\n\";\n-\tconst char *cp;\n-\n-\tif (len != strlen(SAMPLE))\n-\t\treturn 0;\n-\tif (!skip_prefix(line, \"From \", &cp))\n-\t\treturn 0;\n-\tif (strspn(cp, \"0123456789abcdef\") != 40)\n-\t\treturn 0;\n-\tcp += 40;\n-\treturn !memcmp(SAMPLE + (cp - line), cp, strlen(SAMPLE) - (cp - line));\n-}\n-\n-static int check_header(struct mailinfo *mi,\n-\t\t\tconst struct strbuf *line,\n-\t\t\tstruct strbuf *hdr_data[], int overwrite)\n-{\n-\tint i, ret = 0, len;\n-\tstruct strbuf sb = STRBUF_INIT;\n-\n-\t/* search for the interesting parts */\n-\tfor (i = 0; header[i]; i++) {\n-\t\tint len = strlen(header[i]);\n-\t\tif ((!hdr_data[i] || overwrite) && cmp_header(line, header[i])) {\n-\t\t\t/* Unwrap inline B and Q encoding, and optionally\n-\t\t\t * normalize the meta information to utf8.\n-\t\t\t */\n-\t\t\tstrbuf_add(&sb, line->buf + len + 2, line->len - len - 2);\n-\t\t\tif (!decode_header(mi, &sb))\n-\t\t\t\thandle_header(&hdr_data[i], &sb);\n-\t\t\tret = 1;\n-\t\t\tgoto check_header_out;\n-\t\t}\n-\t}\n-\n-\t/* Content stuff */\n-\tif (cmp_header(line, \"Content-Type\")) {\n-\t\tlen = strlen(\"Content-Type: \");\n-\t\tstrbuf_add(&sb, line->buf + len, line->len - len);\n-\t\tif (!decode_header(mi, &sb)) {\n-\t\t\tstrbuf_insert(&sb, 0, \"Content-Type: \", len);\n-\t\t\thandle_content_type(mi, &sb);\n-\t\t}\n-\t\tret = 1;\n-\t\tgoto check_header_out;\n-\t}\n-\tif (cmp_header(line, \"Content-Transfer-Encoding\")) {\n-\t\tlen = strlen(\"Content-Transfer-Encoding: \");\n-\t\tstrbuf_add(&sb, line->buf + len, line->len - len);\n-\t\tif (!decode_header(mi, &sb))\n-\t\t\thandle_content_transfer_encoding(mi, &sb);\n-\t\tret = 1;\n-\t\tgoto check_header_out;\n-\t}\n-\tif (cmp_header(line, \"Message-Id\")) {\n-\t\tlen = strlen(\"Message-Id: \");\n-\t\tstrbuf_add(&sb, line->buf + len, line->len - len);\n-\t\tif (!decode_header(mi, &sb))\n-\t\t\thandle_message_id(mi, &sb);\n-\t\tret = 1;\n-\t\tgoto check_header_out;\n-\t}\n-\n-\t/* for inbody stuff */\n-\tif (starts_with(line->buf, \">From\") && isspace(line->buf[5])) {\n-\t\tret = is_format_patch_separator(line->buf + 1, line->len - 1);\n-\t\tgoto check_header_out;\n-\t}\n-\tif (starts_with(line->buf, \"[PATCH]\") && isspace(line->buf[7])) {\n-\t\tfor (i = 0; header[i]; i++) {\n-\t\t\tif (!strcmp(\"Subject\", header[i])) {\n-\t\t\t\thandle_header(&hdr_data[i], line);\n-\t\t\t\tret = 1;\n-\t\t\t\tgoto check_header_out;\n-\t\t\t}\n-\t\t}\n-\t}\n-\n-check_header_out:\n-\tstrbuf_release(&sb);\n-\treturn ret;\n-}\n-\n-static int is_rfc2822_header(const struct strbuf *line)\n-{\n-\t/*\n-\t * The section that defines the loosest possible\n-\t * field name is \"3.6.8 Optional fields\".\n-\t *\n-\t * optional-field = field-name \":\" unstructured CRLF\n-\t * field-name = 1*ftext\n-\t * ftext = %d33-57 / %59-126\n-\t */\n-\tint ch;\n-\tchar *cp = line->buf;\n-\n-\t/* Count mbox From headers as headers */\n-\tif (starts_with(cp, \"From \") || starts_with(cp, \">From \"))\n-\t\treturn 1;\n-\n-\twhile ((ch = *cp++)) {\n-\t\tif (ch == ':')\n-\t\t\treturn 1;\n-\t\tif ((33 <= ch && ch <= 57) ||\n-\t\t    (59 <= ch && ch <= 126))\n-\t\t\tcontinue;\n-\t\tbreak;\n-\t}\n-\treturn 0;\n-}\n-\n-static int read_one_header_line(struct strbuf *line, FILE *in)\n-{\n-\t/* Get the first part of the line. */\n-\tif (strbuf_getline(line, in, '\\n'))\n-\t\treturn 0;\n-\n-\t/*\n-\t * Is it an empty line or not a valid rfc2822 header?\n-\t * If so, stop here, and return false (\"not a header\")\n-\t */\n-\tstrbuf_rtrim(line);\n-\tif (!line->len || !is_rfc2822_header(line)) {\n-\t\t/* Re-add the newline */\n-\t\tstrbuf_addch(line, '\\n');\n-\t\treturn 0;\n-\t}\n-\n-\t/*\n-\t * Now we need to eat all the continuation lines..\n-\t * Yuck, 2822 header \"folding\"\n-\t */\n-\tfor (;;) {\n-\t\tint peek;\n-\t\tstruct strbuf continuation = STRBUF_INIT;\n-\n-\t\tpeek = fgetc(in); ungetc(peek, in);\n-\t\tif (peek != ' ' && peek != '\\t')\n-\t\t\tbreak;\n-\t\tif (strbuf_getline(&continuation, in, '\\n'))\n-\t\t\tbreak;\n-\t\tcontinuation.buf[0] = ' ';\n-\t\tstrbuf_rtrim(&continuation);\n-\t\tstrbuf_addbuf(line, &continuation);\n-\t}\n-\n-\treturn 1;\n-}\n-\n-static struct strbuf *decode_q_segment(const struct strbuf *q_seg, int rfc2047)\n-{\n-\tconst char *in = q_seg->buf;\n-\tint c;\n-\tstruct strbuf *out = xmalloc(sizeof(struct strbuf));\n-\tstrbuf_init(out, q_seg->len);\n-\n-\twhile ((c = *in++) != 0) {\n-\t\tif (c == '=') {\n-\t\t\tint d = *in++;\n-\t\t\tif (d == '\\n' || !d)\n-\t\t\t\tbreak; /* drop trailing newline */\n-\t\t\tstrbuf_addch(out, (hexval(d) << 4) | hexval(*in++));\n-\t\t\tcontinue;\n-\t\t}\n-\t\tif (rfc2047 && c == '_') /* rfc2047 4.2 (2) */\n-\t\t\tc = 0x20;\n-\t\tstrbuf_addch(out, c);\n-\t}\n-\treturn out;\n-}\n-\n-static struct strbuf *decode_b_segment(const struct strbuf *b_seg)\n-{\n-\t/* Decode in..ep, possibly in-place to ot */\n-\tint c, pos = 0, acc = 0;\n-\tconst char *in = b_seg->buf;\n-\tstruct strbuf *out = xmalloc(sizeof(struct strbuf));\n-\tstrbuf_init(out, b_seg->len);\n-\n-\twhile ((c = *in++) != 0) {\n-\t\tif (c == '+')\n-\t\t\tc = 62;\n-\t\telse if (c == '/')\n-\t\t\tc = 63;\n-\t\telse if ('A' <= c && c <= 'Z')\n-\t\t\tc -= 'A';\n-\t\telse if ('a' <= c && c <= 'z')\n-\t\t\tc -= 'a' - 26;\n-\t\telse if ('0' <= c && c <= '9')\n-\t\t\tc -= '0' - 52;\n-\t\telse\n-\t\t\tcontinue; /* garbage */\n-\t\tswitch (pos++) {\n-\t\tcase 0:\n-\t\t\tacc = (c << 2);\n-\t\t\tbreak;\n-\t\tcase 1:\n-\t\t\tstrbuf_addch(out, (acc | (c >> 4)));\n-\t\t\tacc = (c & 15) << 4;\n-\t\t\tbreak;\n-\t\tcase 2:\n-\t\t\tstrbuf_addch(out, (acc | (c >> 2)));\n-\t\t\tacc = (c & 3) << 6;\n-\t\t\tbreak;\n-\t\tcase 3:\n-\t\t\tstrbuf_addch(out, (acc | c));\n-\t\t\tacc = pos = 0;\n-\t\t\tbreak;\n-\t\t}\n-\t}\n-\treturn out;\n-}\n-\n-static int convert_to_utf8(struct mailinfo *mi,\n-\t\t\t   struct strbuf *line, const char *charset)\n-{\n-\tchar *out;\n-\n-\tif (!mi->metainfo_charset || !charset || !*charset)\n-\t\treturn 0;\n-\n-\tif (same_encoding(mi->metainfo_charset, charset))\n-\t\treturn 0;\n-\tout = reencode_string(line->buf, mi->metainfo_charset, charset);\n-\tif (!out) {\n-\t\tmi->input_error = -1;\n-\t\treturn error(\"cannot convert from %s to %s\",\n-\t\t\t     charset, mi->metainfo_charset);\n-\t}\n-\tstrbuf_attach(line, out, strlen(out), strlen(out));\n-\treturn 0;\n-}\n-\n-static int decode_header(struct mailinfo *mi, struct strbuf *it)\n-{\n-\tchar *in, *ep, *cp;\n-\tstruct strbuf outbuf = STRBUF_INIT, *dec;\n-\tstruct strbuf charset_q = STRBUF_INIT, piecebuf = STRBUF_INIT;\n-\tint found_error = -1; /* pessimism */\n-\n-\tin = it->buf;\n-\twhile (in - it->buf <= it->len && (ep = strstr(in, \"=?\")) != NULL) {\n-\t\tint encoding;\n-\t\tstrbuf_reset(&charset_q);\n-\t\tstrbuf_reset(&piecebuf);\n-\n-\t\tif (in != ep) {\n-\t\t\t/*\n-\t\t\t * We are about to process an encoded-word\n-\t\t\t * that begins at ep, but there is something\n-\t\t\t * before the encoded word.\n-\t\t\t */\n-\t\t\tchar *scan;\n-\t\t\tfor (scan = in; scan < ep; scan++)\n-\t\t\t\tif (!isspace(*scan))\n-\t\t\t\t\tbreak;\n-\n-\t\t\tif (scan != ep || in == it->buf) {\n-\t\t\t\t/*\n-\t\t\t\t * We should not lose that \"something\",\n-\t\t\t\t * unless we have just processed an\n-\t\t\t\t * encoded-word, and there is only LWS\n-\t\t\t\t * before the one we are about to process.\n-\t\t\t\t */\n-\t\t\t\tstrbuf_add(&outbuf, in, ep - in);\n-\t\t\t}\n-\t\t}\n-\t\t/* E.g.\n-\t\t * ep : \"=?iso-2022-jp?B?GyR...?= foo\"\n-\t\t * ep : \"=?ISO-8859-1?Q?Foo=FCbar?= baz\"\n-\t\t */\n-\t\tep += 2;\n-\n-\t\tif (ep - it->buf >= it->len || !(cp = strchr(ep, '?')))\n-\t\t\tgoto release_return;\n-\n-\t\tif (cp + 3 - it->buf > it->len)\n-\t\t\tgoto release_return;\n-\t\tstrbuf_add(&charset_q, ep, cp - ep);\n-\n-\t\tencoding = cp[1];\n-\t\tif (!encoding || cp[2] != '?')\n-\t\t\tgoto release_return;\n-\t\tep = strstr(cp + 3, \"?=\");\n-\t\tif (!ep)\n-\t\t\tgoto release_return;\n-\t\tstrbuf_add(&piecebuf, cp + 3, ep - cp - 3);\n-\t\tswitch (tolower(encoding)) {\n-\t\tdefault:\n-\t\t\tgoto release_return;\n-\t\tcase 'b':\n-\t\t\tdec = decode_b_segment(&piecebuf);\n-\t\t\tbreak;\n-\t\tcase 'q':\n-\t\t\tdec = decode_q_segment(&piecebuf, 1);\n-\t\t\tbreak;\n-\t\t}\n-\t\tif (convert_to_utf8(mi, dec, charset_q.buf))\n-\t\t\tgoto release_return;\n-\n-\t\tstrbuf_addbuf(&outbuf, dec);\n-\t\tstrbuf_release(dec);\n-\t\tfree(dec);\n-\t\tin = ep + 2;\n-\t}\n-\tstrbuf_addstr(&outbuf, in);\n-\tstrbuf_reset(it);\n-\tstrbuf_addbuf(it, &outbuf);\n-\tfound_error = 0;\n-release_return:\n-\tstrbuf_release(&outbuf);\n-\tstrbuf_release(&charset_q);\n-\tstrbuf_release(&piecebuf);\n-\n-\treturn found_error;\n-}\n-\n-static void decode_transfer_encoding(struct mailinfo *mi, struct strbuf *line)\n-{\n-\tstruct strbuf *ret;\n-\n-\tswitch (mi->transfer_encoding) {\n-\tcase TE_QP:\n-\t\tret = decode_q_segment(line, 0);\n-\t\tbreak;\n-\tcase TE_BASE64:\n-\t\tret = decode_b_segment(line);\n-\t\tbreak;\n-\tcase TE_DONTCARE:\n-\tdefault:\n-\t\treturn;\n-\t}\n-\tstrbuf_reset(line);\n-\tstrbuf_addbuf(line, ret);\n-\tstrbuf_release(ret);\n-\tfree(ret);\n-}\n-\n-static inline int patchbreak(const struct strbuf *line)\n-{\n-\tsize_t i;\n-\n-\t/* Beginning of a \"diff -\" header? */\n-\tif (starts_with(line->buf, \"diff -\"))\n-\t\treturn 1;\n-\n-\t/* CVS \"Index: \" line? */\n-\tif (starts_with(line->buf, \"Index: \"))\n-\t\treturn 1;\n-\n-\t/*\n-\t * \"--- <filename>\" starts patches without headers\n-\t * \"---<sp>*\" is a manual separator\n-\t */\n-\tif (line->len < 4)\n-\t\treturn 0;\n-\n-\tif (starts_with(line->buf, \"---\")) {\n-\t\t/* space followed by a filename? */\n-\t\tif (line->buf[3] == ' ' && !isspace(line->buf[4]))\n-\t\t\treturn 1;\n-\t\t/* Just whitespace? */\n-\t\tfor (i = 3; i < line->len; i++) {\n-\t\t\tunsigned char c = line->buf[i];\n-\t\t\tif (c == '\\n')\n-\t\t\t\treturn 1;\n-\t\t\tif (!isspace(c))\n-\t\t\t\tbreak;\n-\t\t}\n-\t\treturn 0;\n-\t}\n-\treturn 0;\n-}\n-\n-static int is_scissors_line(const struct strbuf *line)\n-{\n-\tsize_t i, len = line->len;\n-\tint scissors = 0, gap = 0;\n-\tint first_nonblank = -1;\n-\tint last_nonblank = 0, visible, perforation = 0, in_perforation = 0;\n-\tconst char *buf = line->buf;\n-\n-\tfor (i = 0; i < len; i++) {\n-\t\tif (isspace(buf[i])) {\n-\t\t\tif (in_perforation) {\n-\t\t\t\tperforation++;\n-\t\t\t\tgap++;\n-\t\t\t}\n-\t\t\tcontinue;\n-\t\t}\n-\t\tlast_nonblank = i;\n-\t\tif (first_nonblank < 0)\n-\t\t\tfirst_nonblank = i;\n-\t\tif (buf[i] == '-') {\n-\t\t\tin_perforation = 1;\n-\t\t\tperforation++;\n-\t\t\tcontinue;\n-\t\t}\n-\t\tif (i + 1 < len &&\n-\t\t    (!memcmp(buf + i, \">8\", 2) || !memcmp(buf + i, \"8<\", 2) ||\n-\t\t     !memcmp(buf + i, \">%\", 2) || !memcmp(buf + i, \"%<\", 2))) {\n-\t\t\tin_perforation = 1;\n-\t\t\tperforation += 2;\n-\t\t\tscissors += 2;\n-\t\t\ti++;\n-\t\t\tcontinue;\n-\t\t}\n-\t\tin_perforation = 0;\n-\t}\n-\n-\t/*\n-\t * The mark must be at least 8 bytes long (e.g. \"-- >8 --\").\n-\t * Even though there can be arbitrary cruft on the same line\n-\t * (e.g. \"cut here\"), in order to avoid misidentification, the\n-\t * perforation must occupy more than a third of the visible\n-\t * width of the line, and dashes and scissors must occupy more\n-\t * than half of the perforation.\n-\t */\n-\n-\tvisible = last_nonblank - first_nonblank + 1;\n-\treturn (scissors && 8 <= visible &&\n-\t\tvisible < perforation * 3 &&\n-\t\tgap * 2 < perforation);\n-}\n-\n-static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n-{\n-\t/*\n-\t * Are we still scanning and discarding in-body headers?\n-\t * It is initially set to 1, set to 2 when we do see a\n-\t * valid in-body header.\n-\t */\n-\tint is_empty_line;\n-\n-\tassert(!mi->filter_stage);\n-\n-\tis_empty_line = (!line->len || (line->len == 1 && line->buf[0] == '\\n'));\n-\tif (mi->header_stage == 1) {\n-\t\t/*\n-\t\t * Haven't seen a known in-body header; discard an empty line.\n-\t\t */\n-\t\tif (is_empty_line)\n-\t\t\treturn 0;\n-\t}\n-\n-\tif (mi->use_inbody_headers && mi->header_stage) {\n-\t\tint is_known_header = check_header(mi, line, mi->s_hdr_data, 0);\n-\n-\t\tif (mi->header_stage == 2) {\n-\t\t\t/*\n-\t\t\t * an empty line after the in-body header block,\n-\t\t\t * or a line obviously not an attempt to invent\n-\t\t\t * an unsupported in-body header.\n-\t\t\t */\n-\t\t\tif (is_empty_line || !is_rfc2822_header(line))\n-\t\t\t\tmi->header_stage = 0;\n-\t\t\tif (is_empty_line)\n-\t\t\t\treturn 0;\n-\t\t\t/* otherwise do not discard the line, but keep going */\n-\t\t} else if (is_known_header) {\n-\t\t\tmi->header_stage = 2;\n-\t\t} else if (mi->header_stage != 2) {\n-\t\t\tmi->header_stage = 0;\n-\t\t}\n-\n-\t\tif (mi->header_stage)\n-\t\t\treturn 0;\n-\t} else\n-\t\t/* Only trim the first (blank) line of the commit message\n-\t\t * when ignoring in-body headers.\n-\t\t */\n-\t\tmi->header_stage = 0;\n-\n-\t/* normalize the log message to UTF-8. */\n-\tif (convert_to_utf8(mi, line, mi->charset.buf))\n-\t\treturn 0; /* the caller will reject this input */\n-\n-\tif (mi->use_scissors && is_scissors_line(line)) {\n-\t\tint i;\n-\n-\t\tstrbuf_setlen(&mi->log_message, 0);\n-\t\tmi->header_stage = 1;\n-\n-\t\t/*\n-\t\t * We may have already read \"secondary headers\"; purge\n-\t\t * them to give ourselves a clean restart.\n-\t\t */\n-\t\tfor (i = 0; header[i]; i++) {\n-\t\t\tif (mi->s_hdr_data[i])\n-\t\t\t\tstrbuf_release(mi->s_hdr_data[i]);\n-\t\t\tmi->s_hdr_data[i] = NULL;\n-\t\t}\n-\t\treturn 0;\n-\t}\n-\n-\tif (patchbreak(line)) {\n-\t\tif (mi->message_id)\n-\t\t\tstrbuf_addf(&mi->log_message,\n-\t\t\t\t    \"Message-Id: %s\\n\", mi->message_id);\n-\t\treturn 1;\n-\t}\n-\n-\tstrbuf_addbuf(&mi->log_message, line);\n-\treturn 0;\n-}\n-\n-static void handle_patch(struct mailinfo *mi, const struct strbuf *line)\n-{\n-\tfwrite(line->buf, 1, line->len, mi->patchfile);\n-\tmi->patch_lines++;\n-}\n-\n-static void handle_filter(struct mailinfo *mi, struct strbuf *line)\n-{\n-\tif (mi->input_error)\n-\t\treturn;\n-\n-\tswitch (mi->filter_stage) {\n-\tcase 0:\n-\t\tif (!handle_commit_msg(mi, line))\n-\t\t\tbreak;\n-\t\tmi->filter_stage++;\n-\tcase 1:\n-\t\thandle_patch(mi, line);\n-\t\tbreak;\n-\t}\n-}\n-\n-static int find_boundary(struct mailinfo *mi, struct strbuf *line)\n-{\n-\twhile (!strbuf_getline(line, mi->input, '\\n')) {\n-\t\tif (*(mi->content_top) && is_multipart_boundary(mi, line))\n-\t\t\treturn 1;\n-\t}\n-\treturn 0;\n-}\n-\n-static int handle_boundary(struct mailinfo *mi, struct strbuf *line)\n-{\n-\tstruct strbuf newline = STRBUF_INIT;\n-\n-\tstrbuf_addch(&newline, '\\n');\n-again:\n-\tif (line->len >= (*(mi->content_top))->len + 2 &&\n-\t    !memcmp(line->buf + (*(mi->content_top))->len, \"--\", 2)) {\n-\t\t/* we hit an end boundary */\n-\t\t/* pop the current boundary off the stack */\n-\t\tstrbuf_release(*(mi->content_top));\n-\t\tfree(*(mi->content_top));\n-\t\t*(mi->content_top) = NULL;\n-\n-\t\t/* technically won't happen as is_multipart_boundary()\n-\t\t   will fail first.  But just in case..\n-\t\t */\n-\t\tif (--mi->content_top < mi->content) {\n-\t\t\terror(\"Detected mismatched boundaries, can't recover\");\n-\t\t\tmi->input_error = -1;\n-\t\t\tmi->content_top = mi->content;\n-\t\t\treturn 0;\n-\t\t}\n-\t\thandle_filter(mi, &newline);\n-\t\tstrbuf_release(&newline);\n-\t\tif (mi->input_error)\n-\t\t\treturn 0; /* punt to the end */\n-\n-\t\t/* skip to the next boundary */\n-\t\tif (!find_boundary(mi, line))\n-\t\t\treturn 0;\n-\t\tgoto again;\n-\t}\n-\n-\t/* set some defaults */\n-\tmi->transfer_encoding = TE_DONTCARE;\n-\tstrbuf_reset(&mi->charset);\n-\n-\t/* slurp in this section's info */\n-\twhile (read_one_header_line(line, mi->input))\n-\t\tcheck_header(mi, line, mi->p_hdr_data, 0);\n-\n-\tstrbuf_release(&newline);\n-\t/* replenish line */\n-\tif (strbuf_getline(line, mi->input, '\\n'))\n-\t\treturn 0;\n-\tstrbuf_addch(line, '\\n');\n-\treturn 1;\n-}\n-\n-static void handle_body(struct mailinfo *mi, struct strbuf *line)\n-{\n-\tstruct strbuf prev = STRBUF_INIT;\n-\n-\t/* Skip up to the first boundary */\n-\tif (*(mi->content_top)) {\n-\t\tif (!find_boundary(mi, line))\n-\t\t\tgoto handle_body_out;\n-\t}\n-\n-\tdo {\n-\t\t/* process any boundary lines */\n-\t\tif (*(mi->content_top) && is_multipart_boundary(mi, line)) {\n-\t\t\t/* flush any leftover */\n-\t\t\tif (prev.len) {\n-\t\t\t\thandle_filter(mi, &prev);\n-\t\t\t\tstrbuf_reset(&prev);\n-\t\t\t}\n-\t\t\tif (!handle_boundary(mi, line))\n-\t\t\t\tgoto handle_body_out;\n-\t\t}\n-\n-\t\t/* Unwrap transfer encoding */\n-\t\tdecode_transfer_encoding(mi, line);\n-\n-\t\tswitch (mi->transfer_encoding) {\n-\t\tcase TE_BASE64:\n-\t\tcase TE_QP:\n-\t\t{\n-\t\t\tstruct strbuf **lines, **it, *sb;\n-\n-\t\t\t/* Prepend any previous partial lines */\n-\t\t\tstrbuf_insert(line, 0, prev.buf, prev.len);\n-\t\t\tstrbuf_reset(&prev);\n-\n-\t\t\t/*\n-\t\t\t * This is a decoded line that may contain\n-\t\t\t * multiple new lines.  Pass only one chunk\n-\t\t\t * at a time to handle_filter()\n-\t\t\t */\n-\t\t\tlines = strbuf_split(line, '\\n');\n-\t\t\tfor (it = lines; (sb = *it); it++) {\n-\t\t\t\tif (*(it + 1) == NULL) /* The last line */\n-\t\t\t\t\tif (sb->buf[sb->len - 1] != '\\n') {\n-\t\t\t\t\t\t/* Partial line, save it for later. */\n-\t\t\t\t\t\tstrbuf_addbuf(&prev, sb);\n-\t\t\t\t\t\tbreak;\n-\t\t\t\t\t}\n-\t\t\t\thandle_filter(mi, sb);\n-\t\t\t}\n-\t\t\t/*\n-\t\t\t * The partial chunk is saved in \"prev\" and will be\n-\t\t\t * appended by the next iteration of read_line_with_nul().\n-\t\t\t */\n-\t\t\tstrbuf_list_free(lines);\n-\t\t\tbreak;\n-\t\t}\n-\t\tdefault:\n-\t\t\thandle_filter(mi, line);\n-\t\t}\n-\n-\t\tif (mi->input_error)\n-\t\t\tbreak;\n-\t} while (!strbuf_getwholeline(line, mi->input, '\\n'));\n-\n-handle_body_out:\n-\tstrbuf_release(&prev);\n-}\n-\n-static void output_header_lines(FILE *fout, const char *hdr, const struct strbuf *data)\n-{\n-\tconst char *sp = data->buf;\n-\twhile (1) {\n-\t\tchar *ep = strchr(sp, '\\n');\n-\t\tint len;\n-\t\tif (!ep)\n-\t\t\tlen = strlen(sp);\n-\t\telse\n-\t\t\tlen = ep - sp;\n-\t\tfprintf(fout, \"%s: %.*s\\n\", hdr, len, sp);\n-\t\tif (!ep)\n-\t\t\tbreak;\n-\t\tsp = ep + 1;\n-\t}\n-}\n-\n-static void handle_info(struct mailinfo *mi)\n-{\n-\tstruct strbuf *hdr;\n-\tint i;\n-\n-\tfor (i = 0; header[i]; i++) {\n-\t\t/* only print inbody headers if we output a patch file */\n-\t\tif (mi->patch_lines && mi->s_hdr_data[i])\n-\t\t\thdr = mi->s_hdr_data[i];\n-\t\telse if (mi->p_hdr_data[i])\n-\t\t\thdr = mi->p_hdr_data[i];\n-\t\telse\n-\t\t\tcontinue;\n-\n-\t\tif (!strcmp(header[i], \"Subject\")) {\n-\t\t\tif (!mi->keep_subject) {\n-\t\t\t\tcleanup_subject(mi, hdr);\n-\t\t\t\tcleanup_space(hdr);\n-\t\t\t}\n-\t\t\toutput_header_lines(mi->output, \"Subject\", hdr);\n-\t\t} else if (!strcmp(header[i], \"From\")) {\n-\t\t\tcleanup_space(hdr);\n-\t\t\thandle_from(mi, hdr);\n-\t\t\tfprintf(mi->output, \"Author: %s\\n\", mi->name.buf);\n-\t\t\tfprintf(mi->output, \"Email: %s\\n\", mi->email.buf);\n-\t\t} else {\n-\t\t\tcleanup_space(hdr);\n-\t\t\tfprintf(mi->output, \"%s: %s\\n\", header[i], hdr->buf);\n-\t\t}\n-\t}\n-\tfprintf(mi->output, \"\\n\");\n-}\n-\n-static int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)\n-{\n-\tFILE *cmitmsg;\n-\tint peek;\n-\tstruct strbuf line = STRBUF_INIT;\n-\n-\tcmitmsg = fopen(msg, \"w\");\n-\tif (!cmitmsg) {\n-\t\tperror(msg);\n-\t\treturn -1;\n-\t}\n-\tmi->patchfile = fopen(patch, \"w\");\n-\tif (!mi->patchfile) {\n-\t\tperror(patch);\n-\t\tfclose(cmitmsg);\n-\t\treturn -1;\n-\t}\n-\n-\tmi->p_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*(mi->p_hdr_data)));\n-\tmi->s_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*(mi->s_hdr_data)));\n-\n-\tdo {\n-\t\tpeek = fgetc(mi->input);\n-\t} while (isspace(peek));\n-\tungetc(peek, mi->input);\n-\n-\t/* process the email header */\n-\twhile (read_one_header_line(&line, mi->input))\n-\t\tcheck_header(mi, &line, mi->p_hdr_data, 1);\n-\n-\thandle_body(mi, &line);\n-\tif (!mi->input_error) {\n-\t\thandle_info(mi);\n-\t\tfwrite(mi->log_message.buf, 1, mi->log_message.len, cmitmsg);\n-\t}\n-\tfclose(cmitmsg);\n-\n-\treturn mi->input_error;\n-}\n-\n-static int git_mailinfo_config(const char *var, const char *value, void *mi_)\n-{\n-\tstruct mailinfo *mi = mi_;\n-\n-\tif (!starts_with(var, \"mailinfo.\"))\n-\t\treturn git_default_config(var, value, NULL);\n-\tif (!strcmp(var, \"mailinfo.scissors\")) {\n-\t\tmi->use_scissors = git_config_bool(var, value);\n-\t\treturn 0;\n-\t}\n-\t/* perhaps others here */\n-\treturn 0;\n-}\n-\n-static void setup_mailinfo(struct mailinfo *mi)\n-{\n-\tmemset(mi, 0, sizeof(*mi));\n-\tstrbuf_init(&mi->name, 0);\n-\tstrbuf_init(&mi->email, 0);\n-\tstrbuf_init(&mi->charset, 0);\n-\tstrbuf_init(&mi->log_message, 0);\n-\tmi->header_stage = 1;\n-\tmi->use_inbody_headers = 1;\n-\tmi->content_top = mi->content;\n-\tgit_config(git_mailinfo_config, &mi);\n-}\n-\n-static void clear_mailinfo(struct mailinfo *mi)\n-{\n-\tstrbuf_release(&mi->name);\n-\tstrbuf_release(&mi->email);\n-\tstrbuf_release(&mi->charset);\n-\tstrbuf_release(&mi->log_message);\n-\n-\twhile (mi->content < mi->content_top) {\n-\t\tfree(*(mi->content_top));\n-\t\tmi->content_top--;\n-\t}\n-}\n+#include \"mailinfo.h\"\n \n static const char mailinfo_usage[] =\n \t\"git mailinfo [-k | -b] [-m | --message-id] [-u | --encoding=<encoding> | -n] [--scissors | --no-scissors] <msg> <patch> < mail >info\";\ndiff --git a/mailinfo.c b/mailinfo.c\nnew file mode 100644\nindex 0000000..ca40030\n--- /dev/null\n+++ b/mailinfo.c\n@@ -0,0 +1,1058 @@\n+#include \"cache.h\"\n+#include \"builtin.h\"\n+#include \"utf8.h\"\n+#include \"strbuf.h\"\n+#include \"mailinfo.h\"\n+\n+static void cleanup_space(struct strbuf *sb)\n+{\n+\tsize_t pos, cnt;\n+\tfor (pos = 0; pos < sb->len; pos++) {\n+\t\tif (isspace(sb->buf[pos])) {\n+\t\t\tsb->buf[pos] = ' ';\n+\t\t\tfor (cnt = 0; isspace(sb->buf[pos + cnt + 1]); cnt++);\n+\t\t\tstrbuf_remove(sb, pos + 1, cnt);\n+\t\t}\n+\t}\n+}\n+\n+static void get_sane_name(struct strbuf *out, struct strbuf *name, struct strbuf *email)\n+{\n+\tstruct strbuf *src = name;\n+\tif (name->len < 3 || 60 < name->len || strchr(name->buf, '@') ||\n+\t\tstrchr(name->buf, '<') || strchr(name->buf, '>'))\n+\t\tsrc = email;\n+\telse if (name == out)\n+\t\treturn;\n+\tstrbuf_reset(out);\n+\tstrbuf_addbuf(out, src);\n+}\n+\n+static void parse_bogus_from(struct mailinfo *mi, const struct strbuf *line)\n+{\n+\t/* John Doe <johndoe> */\n+\n+\tchar *bra, *ket;\n+\t/* This is fallback, so do not bother if we already have an\n+\t * e-mail address.\n+\t */\n+\tif (mi->email.len)\n+\t\treturn;\n+\n+\tbra = strchr(line->buf, '<');\n+\tif (!bra)\n+\t\treturn;\n+\tket = strchr(bra, '>');\n+\tif (!ket)\n+\t\treturn;\n+\n+\tstrbuf_reset(&mi->email);\n+\tstrbuf_add(&mi->email, bra + 1, ket - bra - 1);\n+\n+\tstrbuf_reset(&mi->name);\n+\tstrbuf_add(&mi->name, line->buf, bra - line->buf);\n+\tstrbuf_trim(&mi->name);\n+\tget_sane_name(&mi->name, &mi->name, &mi->email);\n+}\n+\n+static void handle_from(struct mailinfo *mi, const struct strbuf *from)\n+{\n+\tchar *at;\n+\tsize_t el;\n+\tstruct strbuf f;\n+\n+\tstrbuf_init(&f, from->len);\n+\tstrbuf_addbuf(&f, from);\n+\n+\tat = strchr(f.buf, '@');\n+\tif (!at) {\n+\t\tparse_bogus_from(mi, from);\n+\t\treturn;\n+\t}\n+\n+\t/*\n+\t * If we already have one email, don't take any confusing lines\n+\t */\n+\tif (mi->email.len && strchr(at + 1, '@')) {\n+\t\tstrbuf_release(&f);\n+\t\treturn;\n+\t}\n+\n+\t/* Pick up the string around '@', possibly delimited with <>\n+\t * pair; that is the email part.\n+\t */\n+\twhile (at > f.buf) {\n+\t\tchar c = at[-1];\n+\t\tif (isspace(c))\n+\t\t\tbreak;\n+\t\tif (c == '<') {\n+\t\t\tat[-1] = ' ';\n+\t\t\tbreak;\n+\t\t}\n+\t\tat--;\n+\t}\n+\tel = strcspn(at, \" \\n\\t\\r\\v\\f>\");\n+\tstrbuf_reset(&mi->email);\n+\tstrbuf_add(&mi->email, at, el);\n+\tstrbuf_remove(&f, at - f.buf, el + (at[el] ? 1 : 0));\n+\n+\t/* The remainder is name.  It could be\n+\t *\n+\t * - \"John Doe <john.doe@xz>\"\t\t\t(a), or\n+\t * - \"john.doe@xz (John Doe)\"\t\t\t(b), or\n+\t * - \"John (zzz) Doe <john.doe@xz> (Comment)\"\t(c)\n+\t *\n+\t * but we have removed the email part, so\n+\t *\n+\t * - remove extra spaces which could stay after email (case 'c'), and\n+\t * - trim from both ends, possibly removing the () pair at the end\n+\t *   (cases 'a' and 'b').\n+\t */\n+\tcleanup_space(&f);\n+\tstrbuf_trim(&f);\n+\tif (f.buf[0] == '(' && f.len && f.buf[f.len - 1] == ')') {\n+\t\tstrbuf_remove(&f, 0, 1);\n+\t\tstrbuf_setlen(&f, f.len - 1);\n+\t}\n+\n+\tget_sane_name(&mi->name, &f, &mi->email);\n+\tstrbuf_release(&f);\n+}\n+\n+static void handle_header(struct strbuf **out, const struct strbuf *line)\n+{\n+\tif (!*out) {\n+\t\t*out = xmalloc(sizeof(struct strbuf));\n+\t\tstrbuf_init(*out, line->len);\n+\t} else\n+\t\tstrbuf_reset(*out);\n+\n+\tstrbuf_addbuf(*out, line);\n+}\n+\n+/* NOTE NOTE NOTE.  We do not claim we do full MIME.  We just attempt\n+ * to have enough heuristics to grok MIME encoded patches often found\n+ * on our mailing lists.  For example, we do not even treat header lines\n+ * case insensitively.\n+ */\n+\n+static int slurp_attr(const char *line, const char *name, struct strbuf *attr)\n+{\n+\tconst char *ends, *ap = strcasestr(line, name);\n+\tsize_t sz;\n+\n+\tstrbuf_setlen(attr, 0);\n+\tif (!ap)\n+\t\treturn 0;\n+\tap += strlen(name);\n+\tif (*ap == '\"') {\n+\t\tap++;\n+\t\tends = \"\\\"\";\n+\t}\n+\telse\n+\t\tends = \"; \\t\";\n+\tsz = strcspn(ap, ends);\n+\tstrbuf_add(attr, ap, sz);\n+\treturn 1;\n+}\n+\n+static void handle_content_type(struct mailinfo *mi, struct strbuf *line)\n+{\n+\tstruct strbuf *boundary = xmalloc(sizeof(struct strbuf));\n+\tstrbuf_init(boundary, line->len);\n+\n+\tif (slurp_attr(line->buf, \"boundary=\", boundary)) {\n+\t\tstrbuf_insert(boundary, 0, \"--\", 2);\n+\t\tif (++mi->content_top >= &mi->content[MAX_BOUNDARIES]) {\n+\t\t\terror(\"Too many boundaries to handle\");\n+\t\t\tmi->input_error = -1;\n+\t\t\tmi->content_top = mi->content + MAX_BOUNDARIES - 1;\n+\t\t\treturn;\n+\t\t}\n+\t\t*(mi->content_top) = boundary;\n+\t\tboundary = NULL;\n+\t}\n+\tslurp_attr(line->buf, \"charset=\", &mi->charset);\n+\n+\tif (boundary) {\n+\t\tstrbuf_release(boundary);\n+\t\tfree(boundary);\n+\t}\n+}\n+\n+static void handle_message_id(struct mailinfo *mi, const struct strbuf *line)\n+{\n+\tif (mi->add_message_id)\n+\t\tmi->message_id = strdup(line->buf);\n+}\n+\n+static void handle_content_transfer_encoding(struct mailinfo *mi,\n+\t\t\t\t\t     const struct strbuf *line)\n+{\n+\tif (strcasestr(line->buf, \"base64\"))\n+\t\tmi->transfer_encoding = TE_BASE64;\n+\telse if (strcasestr(line->buf, \"quoted-printable\"))\n+\t\tmi->transfer_encoding = TE_QP;\n+\telse\n+\t\tmi->transfer_encoding = TE_DONTCARE;\n+}\n+\n+static int is_multipart_boundary(struct mailinfo *mi, const struct strbuf *line)\n+{\n+\tstruct strbuf *content_top = *(mi->content_top);\n+\n+\treturn ((content_top->len <= line->len) &&\n+\t\t!memcmp(line->buf, content_top->buf, content_top->len));\n+}\n+\n+static void cleanup_subject(struct mailinfo *mi, struct strbuf *subject)\n+{\n+\tsize_t at = 0;\n+\n+\twhile (at < subject->len) {\n+\t\tchar *pos;\n+\t\tsize_t remove;\n+\n+\t\tswitch (subject->buf[at]) {\n+\t\tcase 'r': case 'R':\n+\t\t\tif (subject->len <= at + 3)\n+\t\t\t\tbreak;\n+\t\t\tif ((subject->buf[at + 1] == 'e' ||\n+\t\t\t     subject->buf[at + 1] == 'E') &&\n+\t\t\t    subject->buf[at + 2] == ':') {\n+\t\t\t\tstrbuf_remove(subject, at, 3);\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\tat++;\n+\t\t\tbreak;\n+\t\tcase ' ': case '\\t': case ':':\n+\t\t\tstrbuf_remove(subject, at, 1);\n+\t\t\tcontinue;\n+\t\tcase '[':\n+\t\t\tpos = strchr(subject->buf + at, ']');\n+\t\t\tif (!pos)\n+\t\t\t\tbreak;\n+\t\t\tremove = pos - subject->buf + at + 1;\n+\t\t\tif (!mi->keep_non_patch_brackets_in_subject ||\n+\t\t\t    (7 <= remove &&\n+\t\t\t     memmem(subject->buf + at, remove, \"PATCH\", 5)))\n+\t\t\t\tstrbuf_remove(subject, at, remove);\n+\t\t\telse {\n+\t\t\t\tat += remove;\n+\t\t\t\t/*\n+\t\t\t\t * If the input had a space after the ], keep\n+\t\t\t\t * it.  We don't bother with finding the end of\n+\t\t\t\t * the space, since we later normalize it\n+\t\t\t\t * anyway.\n+\t\t\t\t */\n+\t\t\t\tif (isspace(subject->buf[at]))\n+\t\t\t\t\tat += 1;\n+\t\t\t}\n+\t\t\tcontinue;\n+\t\t}\n+\t\tbreak;\n+\t}\n+\tstrbuf_trim(subject);\n+}\n+\n+#define MAX_HDR_PARSED 10\n+\n+static const char *header[MAX_HDR_PARSED] = {\n+\t\"From\",\"Subject\",\"Date\",\n+};\n+\n+static inline int cmp_header(const struct strbuf *line, const char *hdr)\n+{\n+\tint len = strlen(hdr);\n+\treturn !strncasecmp(line->buf, hdr, len) && line->len > len &&\n+\t\t\tline->buf[len] == ':' && isspace(line->buf[len + 1]);\n+}\n+\n+static int is_format_patch_separator(const char *line, int len)\n+{\n+\tstatic const char SAMPLE[] =\n+\t\t\"From e6807f3efca28b30decfecb1732a56c7db1137ee Mon Sep 17 00:00:00 2001\\n\";\n+\tconst char *cp;\n+\n+\tif (len != strlen(SAMPLE))\n+\t\treturn 0;\n+\tif (!skip_prefix(line, \"From \", &cp))\n+\t\treturn 0;\n+\tif (strspn(cp, \"0123456789abcdef\") != 40)\n+\t\treturn 0;\n+\tcp += 40;\n+\treturn !memcmp(SAMPLE + (cp - line), cp, strlen(SAMPLE) - (cp - line));\n+}\n+\n+static int is_rfc2822_header(const struct strbuf *line)\n+{\n+\t/*\n+\t * The section that defines the loosest possible\n+\t * field name is \"3.6.8 Optional fields\".\n+\t *\n+\t * optional-field = field-name \":\" unstructured CRLF\n+\t * field-name = 1*ftext\n+\t * ftext = %d33-57 / %59-126\n+\t */\n+\tint ch;\n+\tchar *cp = line->buf;\n+\n+\t/* Count mbox From headers as headers */\n+\tif (starts_with(cp, \"From \") || starts_with(cp, \">From \"))\n+\t\treturn 1;\n+\n+\twhile ((ch = *cp++)) {\n+\t\tif (ch == ':')\n+\t\t\treturn 1;\n+\t\tif ((33 <= ch && ch <= 57) ||\n+\t\t    (59 <= ch && ch <= 126))\n+\t\t\tcontinue;\n+\t\tbreak;\n+\t}\n+\treturn 0;\n+}\n+\n+static int read_one_header_line(struct strbuf *line, FILE *in)\n+{\n+\t/* Get the first part of the line. */\n+\tif (strbuf_getline(line, in, '\\n'))\n+\t\treturn 0;\n+\n+\t/*\n+\t * Is it an empty line or not a valid rfc2822 header?\n+\t * If so, stop here, and return false (\"not a header\")\n+\t */\n+\tstrbuf_rtrim(line);\n+\tif (!line->len || !is_rfc2822_header(line)) {\n+\t\t/* Re-add the newline */\n+\t\tstrbuf_addch(line, '\\n');\n+\t\treturn 0;\n+\t}\n+\n+\t/*\n+\t * Now we need to eat all the continuation lines..\n+\t * Yuck, 2822 header \"folding\"\n+\t */\n+\tfor (;;) {\n+\t\tint peek;\n+\t\tstruct strbuf continuation = STRBUF_INIT;\n+\n+\t\tpeek = fgetc(in); ungetc(peek, in);\n+\t\tif (peek != ' ' && peek != '\\t')\n+\t\t\tbreak;\n+\t\tif (strbuf_getline(&continuation, in, '\\n'))\n+\t\t\tbreak;\n+\t\tcontinuation.buf[0] = ' ';\n+\t\tstrbuf_rtrim(&continuation);\n+\t\tstrbuf_addbuf(line, &continuation);\n+\t}\n+\n+\treturn 1;\n+}\n+\n+static struct strbuf *decode_q_segment(const struct strbuf *q_seg, int rfc2047)\n+{\n+\tconst char *in = q_seg->buf;\n+\tint c;\n+\tstruct strbuf *out = xmalloc(sizeof(struct strbuf));\n+\tstrbuf_init(out, q_seg->len);\n+\n+\twhile ((c = *in++) != 0) {\n+\t\tif (c == '=') {\n+\t\t\tint d = *in++;\n+\t\t\tif (d == '\\n' || !d)\n+\t\t\t\tbreak; /* drop trailing newline */\n+\t\t\tstrbuf_addch(out, (hexval(d) << 4) | hexval(*in++));\n+\t\t\tcontinue;\n+\t\t}\n+\t\tif (rfc2047 && c == '_') /* rfc2047 4.2 (2) */\n+\t\t\tc = 0x20;\n+\t\tstrbuf_addch(out, c);\n+\t}\n+\treturn out;\n+}\n+\n+static struct strbuf *decode_b_segment(const struct strbuf *b_seg)\n+{\n+\t/* Decode in..ep, possibly in-place to ot */\n+\tint c, pos = 0, acc = 0;\n+\tconst char *in = b_seg->buf;\n+\tstruct strbuf *out = xmalloc(sizeof(struct strbuf));\n+\tstrbuf_init(out, b_seg->len);\n+\n+\twhile ((c = *in++) != 0) {\n+\t\tif (c == '+')\n+\t\t\tc = 62;\n+\t\telse if (c == '/')\n+\t\t\tc = 63;\n+\t\telse if ('A' <= c && c <= 'Z')\n+\t\t\tc -= 'A';\n+\t\telse if ('a' <= c && c <= 'z')\n+\t\t\tc -= 'a' - 26;\n+\t\telse if ('0' <= c && c <= '9')\n+\t\t\tc -= '0' - 52;\n+\t\telse\n+\t\t\tcontinue; /* garbage */\n+\t\tswitch (pos++) {\n+\t\tcase 0:\n+\t\t\tacc = (c << 2);\n+\t\t\tbreak;\n+\t\tcase 1:\n+\t\t\tstrbuf_addch(out, (acc | (c >> 4)));\n+\t\t\tacc = (c & 15) << 4;\n+\t\t\tbreak;\n+\t\tcase 2:\n+\t\t\tstrbuf_addch(out, (acc | (c >> 2)));\n+\t\t\tacc = (c & 3) << 6;\n+\t\t\tbreak;\n+\t\tcase 3:\n+\t\t\tstrbuf_addch(out, (acc | c));\n+\t\t\tacc = pos = 0;\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\treturn out;\n+}\n+\n+static int convert_to_utf8(struct mailinfo *mi,\n+\t\t\t   struct strbuf *line, const char *charset)\n+{\n+\tchar *out;\n+\n+\tif (!mi->metainfo_charset || !charset || !*charset)\n+\t\treturn 0;\n+\n+\tif (same_encoding(mi->metainfo_charset, charset))\n+\t\treturn 0;\n+\tout = reencode_string(line->buf, mi->metainfo_charset, charset);\n+\tif (!out) {\n+\t\tmi->input_error = -1;\n+\t\treturn error(\"cannot convert from %s to %s\",\n+\t\t\t     charset, mi->metainfo_charset);\n+\t}\n+\tstrbuf_attach(line, out, strlen(out), strlen(out));\n+\treturn 0;\n+}\n+\n+static int decode_header(struct mailinfo *mi, struct strbuf *it)\n+{\n+\tchar *in, *ep, *cp;\n+\tstruct strbuf outbuf = STRBUF_INIT, *dec;\n+\tstruct strbuf charset_q = STRBUF_INIT, piecebuf = STRBUF_INIT;\n+\tint found_error = -1; /* pessimism */\n+\n+\tin = it->buf;\n+\twhile (in - it->buf <= it->len && (ep = strstr(in, \"=?\")) != NULL) {\n+\t\tint encoding;\n+\t\tstrbuf_reset(&charset_q);\n+\t\tstrbuf_reset(&piecebuf);\n+\n+\t\tif (in != ep) {\n+\t\t\t/*\n+\t\t\t * We are about to process an encoded-word\n+\t\t\t * that begins at ep, but there is something\n+\t\t\t * before the encoded word.\n+\t\t\t */\n+\t\t\tchar *scan;\n+\t\t\tfor (scan = in; scan < ep; scan++)\n+\t\t\t\tif (!isspace(*scan))\n+\t\t\t\t\tbreak;\n+\n+\t\t\tif (scan != ep || in == it->buf) {\n+\t\t\t\t/*\n+\t\t\t\t * We should not lose that \"something\",\n+\t\t\t\t * unless we have just processed an\n+\t\t\t\t * encoded-word, and there is only LWS\n+\t\t\t\t * before the one we are about to process.\n+\t\t\t\t */\n+\t\t\t\tstrbuf_add(&outbuf, in, ep - in);\n+\t\t\t}\n+\t\t}\n+\t\t/* E.g.\n+\t\t * ep : \"=?iso-2022-jp?B?GyR...?= foo\"\n+\t\t * ep : \"=?ISO-8859-1?Q?Foo=FCbar?= baz\"\n+\t\t */\n+\t\tep += 2;\n+\n+\t\tif (ep - it->buf >= it->len || !(cp = strchr(ep, '?')))\n+\t\t\tgoto release_return;\n+\n+\t\tif (cp + 3 - it->buf > it->len)\n+\t\t\tgoto release_return;\n+\t\tstrbuf_add(&charset_q, ep, cp - ep);\n+\n+\t\tencoding = cp[1];\n+\t\tif (!encoding || cp[2] != '?')\n+\t\t\tgoto release_return;\n+\t\tep = strstr(cp + 3, \"?=\");\n+\t\tif (!ep)\n+\t\t\tgoto release_return;\n+\t\tstrbuf_add(&piecebuf, cp + 3, ep - cp - 3);\n+\t\tswitch (tolower(encoding)) {\n+\t\tdefault:\n+\t\t\tgoto release_return;\n+\t\tcase 'b':\n+\t\t\tdec = decode_b_segment(&piecebuf);\n+\t\t\tbreak;\n+\t\tcase 'q':\n+\t\t\tdec = decode_q_segment(&piecebuf, 1);\n+\t\t\tbreak;\n+\t\t}\n+\t\tif (convert_to_utf8(mi, dec, charset_q.buf))\n+\t\t\tgoto release_return;\n+\n+\t\tstrbuf_addbuf(&outbuf, dec);\n+\t\tstrbuf_release(dec);\n+\t\tfree(dec);\n+\t\tin = ep + 2;\n+\t}\n+\tstrbuf_addstr(&outbuf, in);\n+\tstrbuf_reset(it);\n+\tstrbuf_addbuf(it, &outbuf);\n+\tfound_error = 0;\n+release_return:\n+\tstrbuf_release(&outbuf);\n+\tstrbuf_release(&charset_q);\n+\tstrbuf_release(&piecebuf);\n+\n+\treturn found_error;\n+}\n+\n+static int check_header(struct mailinfo *mi,\n+\t\t\tconst struct strbuf *line,\n+\t\t\tstruct strbuf *hdr_data[], int overwrite)\n+{\n+\tint i, ret = 0, len;\n+\tstruct strbuf sb = STRBUF_INIT;\n+\n+\t/* search for the interesting parts */\n+\tfor (i = 0; header[i]; i++) {\n+\t\tint len = strlen(header[i]);\n+\t\tif ((!hdr_data[i] || overwrite) && cmp_header(line, header[i])) {\n+\t\t\t/* Unwrap inline B and Q encoding, and optionally\n+\t\t\t * normalize the meta information to utf8.\n+\t\t\t */\n+\t\t\tstrbuf_add(&sb, line->buf + len + 2, line->len - len - 2);\n+\t\t\tif (!decode_header(mi, &sb))\n+\t\t\t\thandle_header(&hdr_data[i], &sb);\n+\t\t\tret = 1;\n+\t\t\tgoto check_header_out;\n+\t\t}\n+\t}\n+\n+\t/* Content stuff */\n+\tif (cmp_header(line, \"Content-Type\")) {\n+\t\tlen = strlen(\"Content-Type: \");\n+\t\tstrbuf_add(&sb, line->buf + len, line->len - len);\n+\t\tif (!decode_header(mi, &sb)) {\n+\t\t\tstrbuf_insert(&sb, 0, \"Content-Type: \", len);\n+\t\t\thandle_content_type(mi, &sb);\n+\t\t}\n+\t\tret = 1;\n+\t\tgoto check_header_out;\n+\t}\n+\tif (cmp_header(line, \"Content-Transfer-Encoding\")) {\n+\t\tlen = strlen(\"Content-Transfer-Encoding: \");\n+\t\tstrbuf_add(&sb, line->buf + len, line->len - len);\n+\t\tif (!decode_header(mi, &sb))\n+\t\t\thandle_content_transfer_encoding(mi, &sb);\n+\t\tret = 1;\n+\t\tgoto check_header_out;\n+\t}\n+\tif (cmp_header(line, \"Message-Id\")) {\n+\t\tlen = strlen(\"Message-Id: \");\n+\t\tstrbuf_add(&sb, line->buf + len, line->len - len);\n+\t\tif (!decode_header(mi, &sb))\n+\t\t\thandle_message_id(mi, &sb);\n+\t\tret = 1;\n+\t\tgoto check_header_out;\n+\t}\n+\n+\t/* for inbody stuff */\n+\tif (starts_with(line->buf, \">From\") && isspace(line->buf[5])) {\n+\t\tret = is_format_patch_separator(line->buf + 1, line->len - 1);\n+\t\tgoto check_header_out;\n+\t}\n+\tif (starts_with(line->buf, \"[PATCH]\") && isspace(line->buf[7])) {\n+\t\tfor (i = 0; header[i]; i++) {\n+\t\t\tif (!strcmp(\"Subject\", header[i])) {\n+\t\t\t\thandle_header(&hdr_data[i], line);\n+\t\t\t\tret = 1;\n+\t\t\t\tgoto check_header_out;\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+check_header_out:\n+\tstrbuf_release(&sb);\n+\treturn ret;\n+}\n+\n+static void decode_transfer_encoding(struct mailinfo *mi, struct strbuf *line)\n+{\n+\tstruct strbuf *ret;\n+\n+\tswitch (mi->transfer_encoding) {\n+\tcase TE_QP:\n+\t\tret = decode_q_segment(line, 0);\n+\t\tbreak;\n+\tcase TE_BASE64:\n+\t\tret = decode_b_segment(line);\n+\t\tbreak;\n+\tcase TE_DONTCARE:\n+\tdefault:\n+\t\treturn;\n+\t}\n+\tstrbuf_reset(line);\n+\tstrbuf_addbuf(line, ret);\n+\tstrbuf_release(ret);\n+\tfree(ret);\n+}\n+\n+static inline int patchbreak(const struct strbuf *line)\n+{\n+\tsize_t i;\n+\n+\t/* Beginning of a \"diff -\" header? */\n+\tif (starts_with(line->buf, \"diff -\"))\n+\t\treturn 1;\n+\n+\t/* CVS \"Index: \" line? */\n+\tif (starts_with(line->buf, \"Index: \"))\n+\t\treturn 1;\n+\n+\t/*\n+\t * \"--- <filename>\" starts patches without headers\n+\t * \"---<sp>*\" is a manual separator\n+\t */\n+\tif (line->len < 4)\n+\t\treturn 0;\n+\n+\tif (starts_with(line->buf, \"---\")) {\n+\t\t/* space followed by a filename? */\n+\t\tif (line->buf[3] == ' ' && !isspace(line->buf[4]))\n+\t\t\treturn 1;\n+\t\t/* Just whitespace? */\n+\t\tfor (i = 3; i < line->len; i++) {\n+\t\t\tunsigned char c = line->buf[i];\n+\t\t\tif (c == '\\n')\n+\t\t\t\treturn 1;\n+\t\t\tif (!isspace(c))\n+\t\t\t\tbreak;\n+\t\t}\n+\t\treturn 0;\n+\t}\n+\treturn 0;\n+}\n+\n+static int is_scissors_line(const struct strbuf *line)\n+{\n+\tsize_t i, len = line->len;\n+\tint scissors = 0, gap = 0;\n+\tint first_nonblank = -1;\n+\tint last_nonblank = 0, visible, perforation = 0, in_perforation = 0;\n+\tconst char *buf = line->buf;\n+\n+\tfor (i = 0; i < len; i++) {\n+\t\tif (isspace(buf[i])) {\n+\t\t\tif (in_perforation) {\n+\t\t\t\tperforation++;\n+\t\t\t\tgap++;\n+\t\t\t}\n+\t\t\tcontinue;\n+\t\t}\n+\t\tlast_nonblank = i;\n+\t\tif (first_nonblank < 0)\n+\t\t\tfirst_nonblank = i;\n+\t\tif (buf[i] == '-') {\n+\t\t\tin_perforation = 1;\n+\t\t\tperforation++;\n+\t\t\tcontinue;\n+\t\t}\n+\t\tif (i + 1 < len &&\n+\t\t    (!memcmp(buf + i, \">8\", 2) || !memcmp(buf + i, \"8<\", 2) ||\n+\t\t     !memcmp(buf + i, \">%\", 2) || !memcmp(buf + i, \"%<\", 2))) {\n+\t\t\tin_perforation = 1;\n+\t\t\tperforation += 2;\n+\t\t\tscissors += 2;\n+\t\t\ti++;\n+\t\t\tcontinue;\n+\t\t}\n+\t\tin_perforation = 0;\n+\t}\n+\n+\t/*\n+\t * The mark must be at least 8 bytes long (e.g. \"-- >8 --\").\n+\t * Even though there can be arbitrary cruft on the same line\n+\t * (e.g. \"cut here\"), in order to avoid misidentification, the\n+\t * perforation must occupy more than a third of the visible\n+\t * width of the line, and dashes and scissors must occupy more\n+\t * than half of the perforation.\n+\t */\n+\n+\tvisible = last_nonblank - first_nonblank + 1;\n+\treturn (scissors && 8 <= visible &&\n+\t\tvisible < perforation * 3 &&\n+\t\tgap * 2 < perforation);\n+}\n+\n+static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n+{\n+\t/*\n+\t * Are we still scanning and discarding in-body headers?\n+\t * It is initially set to 1, set to 2 when we do see a\n+\t * valid in-body header.\n+\t */\n+\tint is_empty_line;\n+\n+\tassert(!mi->filter_stage);\n+\n+\tis_empty_line = (!line->len || (line->len == 1 && line->buf[0] == '\\n'));\n+\tif (mi->header_stage == 1) {\n+\t\t/*\n+\t\t * Haven't seen a known in-body header; discard an empty line.\n+\t\t */\n+\t\tif (is_empty_line)\n+\t\t\treturn 0;\n+\t}\n+\n+\tif (mi->use_inbody_headers && mi->header_stage) {\n+\t\tint is_known_header = check_header(mi, line, mi->s_hdr_data, 0);\n+\n+\t\tif (mi->header_stage == 2) {\n+\t\t\t/*\n+\t\t\t * an empty line after the in-body header block,\n+\t\t\t * or a line obviously not an attempt to invent\n+\t\t\t * an unsupported in-body header.\n+\t\t\t */\n+\t\t\tif (is_empty_line || !is_rfc2822_header(line))\n+\t\t\t\tmi->header_stage = 0;\n+\t\t\tif (is_empty_line)\n+\t\t\t\treturn 0;\n+\t\t\t/* otherwise do not discard the line, but keep going */\n+\t\t} else if (is_known_header) {\n+\t\t\tmi->header_stage = 2;\n+\t\t} else if (mi->header_stage != 2) {\n+\t\t\tmi->header_stage = 0;\n+\t\t}\n+\n+\t\tif (mi->header_stage)\n+\t\t\treturn 0;\n+\t} else\n+\t\t/* Only trim the first (blank) line of the commit message\n+\t\t * when ignoring in-body headers.\n+\t\t */\n+\t\tmi->header_stage = 0;\n+\n+\t/* normalize the log message to UTF-8. */\n+\tif (convert_to_utf8(mi, line, mi->charset.buf))\n+\t\treturn 0; /* the caller will reject this input */\n+\n+\tif (mi->use_scissors && is_scissors_line(line)) {\n+\t\tint i;\n+\n+\t\tstrbuf_setlen(&mi->log_message, 0);\n+\t\tmi->header_stage = 1;\n+\n+\t\t/*\n+\t\t * We may have already read \"secondary headers\"; purge\n+\t\t * them to give ourselves a clean restart.\n+\t\t */\n+\t\tfor (i = 0; header[i]; i++) {\n+\t\t\tif (mi->s_hdr_data[i])\n+\t\t\t\tstrbuf_release(mi->s_hdr_data[i]);\n+\t\t\tmi->s_hdr_data[i] = NULL;\n+\t\t}\n+\t\treturn 0;\n+\t}\n+\n+\tif (patchbreak(line)) {\n+\t\tif (mi->message_id)\n+\t\t\tstrbuf_addf(&mi->log_message,\n+\t\t\t\t    \"Message-Id: %s\\n\", mi->message_id);\n+\t\treturn 1;\n+\t}\n+\n+\tstrbuf_addbuf(&mi->log_message, line);\n+\treturn 0;\n+}\n+\n+static void handle_patch(struct mailinfo *mi, const struct strbuf *line)\n+{\n+\tfwrite(line->buf, 1, line->len, mi->patchfile);\n+\tmi->patch_lines++;\n+}\n+\n+static void handle_filter(struct mailinfo *mi, struct strbuf *line)\n+{\n+\tif (mi->input_error)\n+\t\treturn;\n+\n+\tswitch (mi->filter_stage) {\n+\tcase 0:\n+\t\tif (!handle_commit_msg(mi, line))\n+\t\t\tbreak;\n+\t\tmi->filter_stage++;\n+\tcase 1:\n+\t\thandle_patch(mi, line);\n+\t\tbreak;\n+\t}\n+}\n+\n+static int find_boundary(struct mailinfo *mi, struct strbuf *line)\n+{\n+\twhile (!strbuf_getline(line, mi->input, '\\n')) {\n+\t\tif (*(mi->content_top) && is_multipart_boundary(mi, line))\n+\t\t\treturn 1;\n+\t}\n+\treturn 0;\n+}\n+\n+static int handle_boundary(struct mailinfo *mi, struct strbuf *line)\n+{\n+\tstruct strbuf newline = STRBUF_INIT;\n+\n+\tstrbuf_addch(&newline, '\\n');\n+again:\n+\tif (line->len >= (*(mi->content_top))->len + 2 &&\n+\t    !memcmp(line->buf + (*(mi->content_top))->len, \"--\", 2)) {\n+\t\t/* we hit an end boundary */\n+\t\t/* pop the current boundary off the stack */\n+\t\tstrbuf_release(*(mi->content_top));\n+\t\tfree(*(mi->content_top));\n+\t\t*(mi->content_top) = NULL;\n+\n+\t\t/* technically won't happen as is_multipart_boundary()\n+\t\t   will fail first.  But just in case..\n+\t\t */\n+\t\tif (--mi->content_top < mi->content) {\n+\t\t\terror(\"Detected mismatched boundaries, can't recover\");\n+\t\t\tmi->input_error = -1;\n+\t\t\tmi->content_top = mi->content;\n+\t\t\treturn 0;\n+\t\t}\n+\t\thandle_filter(mi, &newline);\n+\t\tstrbuf_release(&newline);\n+\t\tif (mi->input_error)\n+\t\t\treturn 0; /* punt to the end */\n+\n+\t\t/* skip to the next boundary */\n+\t\tif (!find_boundary(mi, line))\n+\t\t\treturn 0;\n+\t\tgoto again;\n+\t}\n+\n+\t/* set some defaults */\n+\tmi->transfer_encoding = TE_DONTCARE;\n+\tstrbuf_reset(&mi->charset);\n+\n+\t/* slurp in this section's info */\n+\twhile (read_one_header_line(line, mi->input))\n+\t\tcheck_header(mi, line, mi->p_hdr_data, 0);\n+\n+\tstrbuf_release(&newline);\n+\t/* replenish line */\n+\tif (strbuf_getline(line, mi->input, '\\n'))\n+\t\treturn 0;\n+\tstrbuf_addch(line, '\\n');\n+\treturn 1;\n+}\n+\n+static void handle_body(struct mailinfo *mi, struct strbuf *line)\n+{\n+\tstruct strbuf prev = STRBUF_INIT;\n+\n+\t/* Skip up to the first boundary */\n+\tif (*(mi->content_top)) {\n+\t\tif (!find_boundary(mi, line))\n+\t\t\tgoto handle_body_out;\n+\t}\n+\n+\tdo {\n+\t\t/* process any boundary lines */\n+\t\tif (*(mi->content_top) && is_multipart_boundary(mi, line)) {\n+\t\t\t/* flush any leftover */\n+\t\t\tif (prev.len) {\n+\t\t\t\thandle_filter(mi, &prev);\n+\t\t\t\tstrbuf_reset(&prev);\n+\t\t\t}\n+\t\t\tif (!handle_boundary(mi, line))\n+\t\t\t\tgoto handle_body_out;\n+\t\t}\n+\n+\t\t/* Unwrap transfer encoding */\n+\t\tdecode_transfer_encoding(mi, line);\n+\n+\t\tswitch (mi->transfer_encoding) {\n+\t\tcase TE_BASE64:\n+\t\tcase TE_QP:\n+\t\t{\n+\t\t\tstruct strbuf **lines, **it, *sb;\n+\n+\t\t\t/* Prepend any previous partial lines */\n+\t\t\tstrbuf_insert(line, 0, prev.buf, prev.len);\n+\t\t\tstrbuf_reset(&prev);\n+\n+\t\t\t/*\n+\t\t\t * This is a decoded line that may contain\n+\t\t\t * multiple new lines.  Pass only one chunk\n+\t\t\t * at a time to handle_filter()\n+\t\t\t */\n+\t\t\tlines = strbuf_split(line, '\\n');\n+\t\t\tfor (it = lines; (sb = *it); it++) {\n+\t\t\t\tif (*(it + 1) == NULL) /* The last line */\n+\t\t\t\t\tif (sb->buf[sb->len - 1] != '\\n') {\n+\t\t\t\t\t\t/* Partial line, save it for later. */\n+\t\t\t\t\t\tstrbuf_addbuf(&prev, sb);\n+\t\t\t\t\t\tbreak;\n+\t\t\t\t\t}\n+\t\t\t\thandle_filter(mi, sb);\n+\t\t\t}\n+\t\t\t/*\n+\t\t\t * The partial chunk is saved in \"prev\" and will be\n+\t\t\t * appended by the next iteration of read_line_with_nul().\n+\t\t\t */\n+\t\t\tstrbuf_list_free(lines);\n+\t\t\tbreak;\n+\t\t}\n+\t\tdefault:\n+\t\t\thandle_filter(mi, line);\n+\t\t}\n+\n+\t\tif (mi->input_error)\n+\t\t\tbreak;\n+\t} while (!strbuf_getwholeline(line, mi->input, '\\n'));\n+\n+handle_body_out:\n+\tstrbuf_release(&prev);\n+}\n+\n+static void output_header_lines(FILE *fout, const char *hdr, const struct strbuf *data)\n+{\n+\tconst char *sp = data->buf;\n+\twhile (1) {\n+\t\tchar *ep = strchr(sp, '\\n');\n+\t\tint len;\n+\t\tif (!ep)\n+\t\t\tlen = strlen(sp);\n+\t\telse\n+\t\t\tlen = ep - sp;\n+\t\tfprintf(fout, \"%s: %.*s\\n\", hdr, len, sp);\n+\t\tif (!ep)\n+\t\t\tbreak;\n+\t\tsp = ep + 1;\n+\t}\n+}\n+\n+static void handle_info(struct mailinfo *mi)\n+{\n+\tstruct strbuf *hdr;\n+\tint i;\n+\n+\tfor (i = 0; header[i]; i++) {\n+\t\t/* only print inbody headers if we output a patch file */\n+\t\tif (mi->patch_lines && mi->s_hdr_data[i])\n+\t\t\thdr = mi->s_hdr_data[i];\n+\t\telse if (mi->p_hdr_data[i])\n+\t\t\thdr = mi->p_hdr_data[i];\n+\t\telse\n+\t\t\tcontinue;\n+\n+\t\tif (!strcmp(header[i], \"Subject\")) {\n+\t\t\tif (!mi->keep_subject) {\n+\t\t\t\tcleanup_subject(mi, hdr);\n+\t\t\t\tcleanup_space(hdr);\n+\t\t\t}\n+\t\t\toutput_header_lines(mi->output, \"Subject\", hdr);\n+\t\t} else if (!strcmp(header[i], \"From\")) {\n+\t\t\tcleanup_space(hdr);\n+\t\t\thandle_from(mi, hdr);\n+\t\t\tfprintf(mi->output, \"Author: %s\\n\", mi->name.buf);\n+\t\t\tfprintf(mi->output, \"Email: %s\\n\", mi->email.buf);\n+\t\t} else {\n+\t\t\tcleanup_space(hdr);\n+\t\t\tfprintf(mi->output, \"%s: %s\\n\", header[i], hdr->buf);\n+\t\t}\n+\t}\n+\tfprintf(mi->output, \"\\n\");\n+}\n+\n+int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)\n+{\n+\tFILE *cmitmsg;\n+\tint peek;\n+\tstruct strbuf line = STRBUF_INIT;\n+\n+\tcmitmsg = fopen(msg, \"w\");\n+\tif (!cmitmsg) {\n+\t\tperror(msg);\n+\t\treturn -1;\n+\t}\n+\tmi->patchfile = fopen(patch, \"w\");\n+\tif (!mi->patchfile) {\n+\t\tperror(patch);\n+\t\tfclose(cmitmsg);\n+\t\treturn -1;\n+\t}\n+\n+\tmi->p_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*(mi->p_hdr_data)));\n+\tmi->s_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*(mi->s_hdr_data)));\n+\n+\tdo {\n+\t\tpeek = fgetc(mi->input);\n+\t} while (isspace(peek));\n+\tungetc(peek, mi->input);\n+\n+\t/* process the email header */\n+\twhile (read_one_header_line(&line, mi->input))\n+\t\tcheck_header(mi, &line, mi->p_hdr_data, 1);\n+\n+\thandle_body(mi, &line);\n+\tif (!mi->input_error) {\n+\t\thandle_info(mi);\n+\t\tfwrite(mi->log_message.buf, 1, mi->log_message.len, cmitmsg);\n+\t}\n+\tfclose(cmitmsg);\n+\n+\treturn mi->input_error;\n+}\n+\n+static int git_mailinfo_config(const char *var, const char *value, void *mi_)\n+{\n+\tstruct mailinfo *mi = mi_;\n+\n+\tif (!starts_with(var, \"mailinfo.\"))\n+\t\treturn git_default_config(var, value, NULL);\n+\tif (!strcmp(var, \"mailinfo.scissors\")) {\n+\t\tmi->use_scissors = git_config_bool(var, value);\n+\t\treturn 0;\n+\t}\n+\t/* perhaps others here */\n+\treturn 0;\n+}\n+\n+void setup_mailinfo(struct mailinfo *mi)\n+{\n+\tmemset(mi, 0, sizeof(*mi));\n+\tstrbuf_init(&mi->name, 0);\n+\tstrbuf_init(&mi->email, 0);\n+\tstrbuf_init(&mi->charset, 0);\n+\tstrbuf_init(&mi->log_message, 0);\n+\tmi->header_stage = 1;\n+\tmi->use_inbody_headers = 1;\n+\tmi->content_top = mi->content;\n+\tgit_config(git_mailinfo_config, &mi);\n+}\n+\n+void clear_mailinfo(struct mailinfo *mi)\n+{\n+\tstrbuf_release(&mi->name);\n+\tstrbuf_release(&mi->email);\n+\tstrbuf_release(&mi->charset);\n+\tstrbuf_release(&mi->log_message);\n+\n+\twhile (mi->content < mi->content_top) {\n+\t\tfree(*(mi->content_top));\n+\t\tmi->content_top--;\n+\t}\n+}\ndiff --git a/mailinfo.h b/mailinfo.h\nnew file mode 100644\nindex 0000000..e15e0de\n--- /dev/null\n+++ b/mailinfo.h\n@@ -0,0 +1,41 @@\n+#ifndef MAILINFO_H\n+#define MAILINFO_H\n+\n+#define MAX_BOUNDARIES 5\n+\n+struct mailinfo {\n+\tFILE *input;\n+\tFILE *output;\n+\tFILE *patchfile;\n+\n+\tstruct strbuf name;\n+\tstruct strbuf email;\n+\tint keep_subject;\n+\tint keep_non_patch_brackets_in_subject;\n+\tint add_message_id;\n+\tint use_scissors;\n+\tint use_inbody_headers; /* defaults to 1 */\n+\tconst char *metainfo_charset;\n+\n+\tstruct strbuf *content[MAX_BOUNDARIES];\n+\tstruct strbuf **content_top;\n+\tstruct strbuf charset;\n+\tchar *message_id;\n+\tenum  {\n+\t\tTE_DONTCARE, TE_QP, TE_BASE64\n+\t} transfer_encoding;\n+\tint patch_lines;\n+\tint filter_stage; /* still reading log or are we copying patch? */\n+\tint header_stage; /* still checking in-body headers? */\n+\tstruct strbuf **p_hdr_data;\n+\tstruct strbuf **s_hdr_data;\n+\n+\tstruct strbuf log_message;\n+\tint input_error;\n+};\n+\n+extern void setup_mailinfo(struct mailinfo *);\n+extern void clear_mailinfo(struct mailinfo *);\n+extern int mailinfo(struct mailinfo *, const char *msg, const char *patch);\n+\n+#endif /* MAILINFO_H */\n-- \n2.6.1-320-g86a1181\n"},{"id":"271632","messageId":"xmqq4mhu9qmn.fsf_-_@gitster.mtv.corp.google.com","threadId":"40552","inReplyTo":"1444778207-859-20-git-send-email-gitster@pobox.com","subject":"[PATCH 27/26] mailinfo: close patchfile","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-14T01:37:52Z","receivedAt":"2015-10-14T01:37:52Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"git mailinfo\" itself did not need this, as open file handles are\nflushed and closed upon process exit, but the libified version needs\nto clean up after itself when it is done.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n mailinfo.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/mailinfo.c b/mailinfo.c\nindex ca40030..00e2ea4 100644\n--- a/mailinfo.c\n+++ b/mailinfo.c\n@@ -1013,7 +1013,7 @@ int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)\n \t\tfwrite(mi->log_message.buf, 1, mi->log_message.len, cmitmsg);\n \t}\n \tfclose(cmitmsg);\n-\n+\tfclose(mi->patchfile);\n \treturn mi->input_error;\n }\n \n-- \n2.6.1-320-g86a1181\n"},{"id":"271633","messageId":"xmqqsi5e8boh.fsf_-_@gitster.mtv.corp.google.com","threadId":"40552","inReplyTo":"xmqq4mhu9qmn.fsf_-_@gitster.mtv.corp.google.com","subject":"[PATCH 28/26] am: make direct call to mailinfo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-14T01:46:06Z","receivedAt":"2015-10-14T01:46:06Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"And finally the endgame.  Instead of spawning \"git mailinfo\" via the\nrun_command() API the same number of times as there are incoming\npatches, make direct internal call to the libified mailinfo() from\n\"git am\" to reduce the spawning overhead, which would matter on some\nplatforms.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n\n This is to be applied on top of a merge across\n\n  - jc/am-3-fallback-regression-fix\n  - jc/mailinfo-lib (i.e. the 27-patch series)\n\n As I do not have ready access to such a platform with slow\n run_command(), it would be nice to see some numbers produced on\n such platform by other people.\n\n Thanks.\n\n builtin/am.c | 38 +++++++++++++++++++-------------------\n 1 file changed, 19 insertions(+), 19 deletions(-)\n\ndiff --git a/builtin/am.c b/builtin/am.c\nindex c869796..0471355 100644\n--- a/builtin/am.c\n+++ b/builtin/am.c\n@@ -27,6 +27,7 @@\n #include \"notes-utils.h\"\n #include \"rerere.h\"\n #include \"prompt.h\"\n+#include \"mailinfo.h\"\n \n /**\n  * Returns 1 if the file is empty or does not exist, 0 otherwise.\n@@ -1258,58 +1259,57 @@ static void am_append_signoff(struct am_state *state)\n static int parse_mail(struct am_state *state, const char *mail)\n {\n \tFILE *fp;\n-\tstruct child_process cp = CHILD_PROCESS_INIT;\n \tstruct strbuf sb = STRBUF_INIT;\n \tstruct strbuf msg = STRBUF_INIT;\n \tstruct strbuf author_name = STRBUF_INIT;\n \tstruct strbuf author_date = STRBUF_INIT;\n \tstruct strbuf author_email = STRBUF_INIT;\n \tint ret = 0;\n+\tstruct mailinfo mi;\n \n-\tcp.git_cmd = 1;\n-\tcp.in = xopen(mail, O_RDONLY, 0);\n-\tcp.out = xopen(am_path(state, \"info\"), O_WRONLY | O_CREAT, 0777);\n+\tsetup_mailinfo(&mi);\n \n-\targv_array_push(&cp.args, \"mailinfo\");\n-\targv_array_push(&cp.args, state->utf8 ? \"-u\" : \"-n\");\n+\tif (state->utf8)\n+\t\tmi.metainfo_charset = get_commit_output_encoding();\n+\telse\n+\t\tmi.metainfo_charset = NULL;\n \n \tswitch (state->keep) {\n \tcase KEEP_FALSE:\n \t\tbreak;\n \tcase KEEP_TRUE:\n-\t\targv_array_push(&cp.args, \"-k\");\n+\t\tmi.keep_subject = 1;\n \t\tbreak;\n \tcase KEEP_NON_PATCH:\n-\t\targv_array_push(&cp.args, \"-b\");\n+\t\tmi.keep_non_patch_brackets_in_subject = 1;\n \t\tbreak;\n \tdefault:\n \t\tdie(\"BUG: invalid value for state->keep\");\n \t}\n-\n \tif (state->message_id)\n-\t\targv_array_push(&cp.args, \"-m\");\n+\t\tmi.add_message_id = 1;\n \n \tswitch (state->scissors) {\n \tcase SCISSORS_UNSET:\n \t\tbreak;\n \tcase SCISSORS_FALSE:\n-\t\targv_array_push(&cp.args, \"--no-scissors\");\n+\t\tmi.use_scissors = 0;\n \t\tbreak;\n \tcase SCISSORS_TRUE:\n-\t\targv_array_push(&cp.args, \"--scissors\");\n+\t\tmi.use_scissors = 1;\n \t\tbreak;\n \tdefault:\n \t\tdie(\"BUG: invalid value for state->scissors\");\n \t}\n \n-\targv_array_push(&cp.args, am_path(state, \"msg\"));\n-\targv_array_push(&cp.args, am_path(state, \"patch\"));\n+\tmi.input = fopen(mail, \"r\");\n+\tmi.output = fopen(am_path(state, \"info\"), \"w\");\n \n-\tif (run_command(&cp) < 0)\n+\tif (mailinfo(&mi, am_path(state, \"msg\"), am_path(state, \"patch\")))\n \t\tdie(\"could not parse patch\");\n \n-\tclose(cp.in);\n-\tclose(cp.out);\n+\tfclose(mi.input);\n+\tfclose(mi.output);\n \n \t/* Extract message and author information */\n \tfp = xfopen(am_path(state, \"info\"), \"r\");\n@@ -1341,8 +1341,7 @@ static int parse_mail(struct am_state *state, const char *mail)\n \t}\n \n \tstrbuf_addstr(&msg, \"\\n\\n\");\n-\tif (strbuf_read_file(&msg, am_path(state, \"msg\"), 0) < 0)\n-\t\tdie_errno(_(\"could not read '%s'\"), am_path(state, \"msg\"));\n+\tstrbuf_addbuf(&msg, &mi.log_message);\n \tstripspace(&msg, 0);\n \n \tif (state->signoff)\n@@ -1366,6 +1365,7 @@ finish:\n \tstrbuf_release(&author_email);\n \tstrbuf_release(&author_name);\n \tstrbuf_release(&sb);\n+\tclear_mailinfo(&mi);\n \treturn ret;\n }\n \n-- \n2.6.1-320-g86a1181\n"},{"id":"271660","messageId":"CAGZ79kYGB8QOio7dqKNPjsQg6xeCSEkvC_8_a3=h9sHxbn-6uw@mail.gmail.com","threadId":"40552","inReplyTo":"1444778207-859-3-git-send-email-gitster@pobox.com","subject":"Re: [PATCH 02/26] mailinfo: fix for off-by-one error in boundary stack","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2015-10-14T20:12:58Z","receivedAt":"2015-10-14T20:12:58Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Tue, Oct 13, 2015 at 4:16 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> We pre-increment the pointer that we will use to store something at,\n> so the pointer is already beyond the end of the array if it points\n> at content[MAX_BOUNDARIES].\n>\n> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n> ---\n>\n>  As always, I am very bad at checking and fixing off-by-one errors.\n>  A few extra sets of eyeballs are very much appreciated.\n\nsome relevant lines from the file:\n    #define MAX_BOUNDARIES 5\n    static struct strbuf *content[MAX_BOUNDARIES];\n    static struct strbuf **content_top = content;\n\ncontent has slots 0..4, so checking content[5] is out of range,\nbut was allowed in the original code.\n\nSo this patch looks good to me, though looking at\n289796dd29dd656734cfd59b657deb943a71cf6a,\nmakes me wonder if we forget the other spot where it's\ndecremented in that patch.\n\nAlso looking at the patch, makes we wonder if we rather want to change\n-    static struct strbuf *content[MAX_BOUNDARIES];\n+    static struct strbuf *content[MAX_BOUNDARIES + 1];\n\ninstead? That would actually increase the allocated memory,\nand allow to write one more content line, but reading the code is\neasier as we don't need to reason about > or >=.\n\nAnother way would be to rewrite this part to use an index instead\nof content_top being a pointer. And the index could be compared\nto strictly less than MAX_BOUNDARIES.\n\n> ---\n>  builtin/mailinfo.c | 2 +-\n>  1 file changed, 1 insertion(+), 1 deletion(-)\n>\n> diff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\n> index 330bef4..2742d0d 100644\n> --- a/builtin/mailinfo.c\n> +++ b/builtin/mailinfo.c\n> @@ -185,7 +185,7 @@ static void handle_content_type(struct strbuf *line)\n>\n>         if (slurp_attr(line->buf, \"boundary=\", boundary)) {\n>                 strbuf_insert(boundary, 0, \"--\", 2);\n> -               if (++content_top > &content[MAX_BOUNDARIES]) {\n> +               if (++content_top >= &content[MAX_BOUNDARIES]) {\n>                         fprintf(stderr, \"Too many boundaries to handle\\n\");\n>                         exit(1);\n>                 }\n> --\n> 2.6.1-320-g86a1181\n>\n> --\n> To unsubscribe from this list: send the line \"unsubscribe git\" in\n> the body of a message to majordomo@vger.kernel.org\n> More majordomo info at  http://vger.kernel.org/majordomo-info.html\n"},{"id":"271661","messageId":"CAGZ79kaTPGCzKooBjhk2+=njagFfFir6d5C40zpscuoweQgyiA@mail.gmail.com","threadId":"40552","inReplyTo":"1444778207-859-7-git-send-email-gitster@pobox.com","subject":"Re: [PATCH 06/26] mailinfo: always pass \"line\" as an argument","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2015-10-14T20:22:06Z","receivedAt":"2015-10-14T20:22:06Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Tue, Oct 13, 2015 at 4:16 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Some functions in this module accessed the global \"struct strbuf\n> line\" while many others used a strbuf passed as an argument.\n> Convert the former to ensure that nobody deeper in the callchains\n> relies on the global one.\n>\n> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n> ---\n>  builtin/mailinfo.c | 48 ++++++++++++++++++++++++------------------------\n>  1 file changed, 24 insertions(+), 24 deletions(-)\n>\n> diff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\n> index 5a74811..c3c7d67 100644\n> --- a/builtin/mailinfo.c\n> +++ b/builtin/mailinfo.c\n> @@ -12,7 +12,7 @@ static FILE *cmitmsg, *patchfile, *fin, *fout;\n>  static int keep_subject;\n>  static int keep_non_patch_brackets_in_subject;\n>  static const char *metainfo_charset;\n> -static struct strbuf line = STRBUF_INIT;\n> +static struct strbuf line_global = STRBUF_INIT;\n>  static struct strbuf name = STRBUF_INIT;\n>  static struct strbuf email = STRBUF_INIT;\n>  static char *message_id;\n> @@ -817,23 +817,23 @@ static void handle_filter(struct strbuf *line, int *filter_stage, int *header_st\n>         }\n>  }\n>\n> -static int find_boundary(void)\n> +static int find_boundary(struct strbuf *line)\n>  {\n> -       while (!strbuf_getline(&line, fin, '\\n')) {\n> -               if (*content_top && is_multipart_boundary(&line))\n> +       while (!strbuf_getline(line, fin, '\\n')) {\n> +               if (*content_top && is_multipart_boundary(line))\n>                         return 1;\n>         }\n>         return 0;\n>  }\n>\n> -static int handle_boundary(int *filter_stage, int *header_stage)\n> +static int handle_boundary(struct strbuf *line, int *filter_stage, int *header_stage)\n>  {\n>         struct strbuf newline = STRBUF_INIT;\n>\n>         strbuf_addch(&newline, '\\n');\n>  again:\n> -       if (line.len >= (*content_top)->len + 2 &&\n> -           !memcmp(line.buf + (*content_top)->len, \"--\", 2)) {\n> +       if (line->len >= (*content_top)->len + 2 &&\n> +           !memcmp(line->buf + (*content_top)->len, \"--\", 2)) {\n>                 /* we hit an end boundary */\n>                 /* pop the current boundary off the stack */\n>                 strbuf_release(*content_top);\n> @@ -852,7 +852,7 @@ again:\n>                 strbuf_release(&newline);\n>\n>                 /* skip to the next boundary */\n> -               if (!find_boundary())\n> +               if (!find_boundary(line))\n>                         return 0;\n>                 goto again;\n>         }\n> @@ -862,18 +862,18 @@ again:\n>         strbuf_reset(&charset);\n>\n>         /* slurp in this section's info */\n> -       while (read_one_header_line(&line, fin))\n> -               check_header(&line, p_hdr_data, 0);\n> +       while (read_one_header_line(line, fin))\n> +               check_header(line, p_hdr_data, 0);\n>\n>         strbuf_release(&newline);\n>         /* replenish line */\n> -       if (strbuf_getline(&line, fin, '\\n'))\n> +       if (strbuf_getline(line, fin, '\\n'))\n>                 return 0;\n> -       strbuf_addch(&line, '\\n');\n> +       strbuf_addch(line, '\\n');\n>         return 1;\n>  }\n>\n> -static void handle_body(void)\n> +static void handle_body(struct strbuf *line)\n>  {\n>         struct strbuf prev = STRBUF_INIT;\n>         int filter_stage = 0;\n> @@ -881,24 +881,24 @@ static void handle_body(void)\n>\n>         /* Skip up to the first boundary */\n>         if (*content_top) {\n> -               if (!find_boundary())\n> +               if (!find_boundary(line))\n>                         goto handle_body_out;\n>         }\n>\n>         do {\n>                 /* process any boundary lines */\n> -               if (*content_top && is_multipart_boundary(&line)) {\n> +               if (*content_top && is_multipart_boundary(line)) {\n>                         /* flush any leftover */\n>                         if (prev.len) {\n>                                 handle_filter(&prev, &filter_stage, &header_stage);\n>                                 strbuf_reset(&prev);\n>                         }\n> -                       if (!handle_boundary(&filter_stage, &header_stage))\n> +                       if (!handle_boundary(line, &filter_stage, &header_stage))\n>                                 goto handle_body_out;\n>                 }\n>\n>                 /* Unwrap transfer encoding */\n> -               decode_transfer_encoding(&line);\n> +               decode_transfer_encoding(line);\n>\n>                 switch (transfer_encoding) {\n>                 case TE_BASE64:\n> @@ -907,7 +907,7 @@ static void handle_body(void)\n>                         struct strbuf **lines, **it, *sb;\n>\n>                         /* Prepend any previous partial lines */\n> -                       strbuf_insert(&line, 0, prev.buf, prev.len);\n> +                       strbuf_insert(line, 0, prev.buf, prev.len);\n>                         strbuf_reset(&prev);\n>\n>                         /*\n> @@ -915,7 +915,7 @@ static void handle_body(void)\n>                          * multiple new lines.  Pass only one chunk\n>                          * at a time to handle_filter()\n>                          */\n> -                       lines = strbuf_split(&line, '\\n');\n> +                       lines = strbuf_split(line, '\\n');\n>                         for (it = lines; (sb = *it); it++) {\n>                                 if (*(it + 1) == NULL) /* The last line */\n>                                         if (sb->buf[sb->len - 1] != '\\n') {\n> @@ -933,10 +933,10 @@ static void handle_body(void)\n>                         break;\n>                 }\n>                 default:\n> -                       handle_filter(&line, &filter_stage, &header_stage);\n> +                       handle_filter(line, &filter_stage, &header_stage);\n>                 }\n>\n> -       } while (!strbuf_getwholeline(&line, fin, '\\n'));\n> +       } while (!strbuf_getwholeline(line, fin, '\\n'));\n>\n>  handle_body_out:\n>         strbuf_release(&prev);\n> @@ -1019,10 +1019,10 @@ static int mailinfo(FILE *in, FILE *out, const char *msg, const char *patch)\n>         ungetc(peek, in);\n>\n>         /* process the email header */\n> -       while (read_one_header_line(&line, fin))\n> -               check_header(&line, p_hdr_data, 1);\n> +       while (read_one_header_line(&line_global, fin))\n> +               check_header(&line_global, p_hdr_data, 1);\n\nThis is the only function to use line_global if I see correctly.\nThe function is called only once, so no need to preserve state\noutside the function. Would it make sense to remove line_global\ncompletely and have a local variable in this function instead?\n\n>\n> -       handle_body();\n> +       handle_body(&line_global);\n>         handle_info();\n>\n>         return 0;\n> --\n> 2.6.1-320-g86a1181\n>\n> --\n> To unsubscribe from this list: send the line \"unsubscribe git\" in\n> the body of a message to majordomo@vger.kernel.org\n> More majordomo info at  http://vger.kernel.org/majordomo-info.html\n"},{"id":"271662","messageId":"xmqq37xd8ac5.fsf@gitster.mtv.corp.google.com","threadId":"40552","inReplyTo":"CAGZ79kaTPGCzKooBjhk2+=njagFfFir6d5C40zpscuoweQgyiA@mail.gmail.com","subject":"Re: [PATCH 06/26] mailinfo: always pass \"line\" as an argument","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-14T20:27:22Z","receivedAt":"2015-10-14T20:27:22Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Stefan Beller <sbeller@google.com> writes:\n\n>> @@ -1019,10 +1019,10 @@ static int mailinfo(FILE *in, FILE *out, const char *msg, const char *patch)\n>>         ungetc(peek, in);\n>>\n>>         /* process the email header */\n>> -       while (read_one_header_line(&line, fin))\n>> -               check_header(&line, p_hdr_data, 1);\n>> +       while (read_one_header_line(&line_global, fin))\n>> +               check_header(&line_global, p_hdr_data, 1);\n>\n> This is the only function to use line_global if I see correctly.\n> The function is called only once, so no need to preserve state\n> outside the function. Would it make sense to remove line_global\n> completely and have a local variable in this function instead?\n\nThat is exactly the step that comes after it does, but if you squash\n06 and 07 into one patch (i.e. take diff between the state after 05\nand after 07), that realization will not easily come (well, at least\nit didn't come to me and I wasn't convinced that the conversion is\ncorrect myself until I split 06 and 07 into two separate steps).\n"},{"id":"271663","messageId":"CAGZ79kYuvV68P4HWpr+XCnp3DJufAGnWc7HugddkNToSiRm5XQ@mail.gmail.com","threadId":"40552","inReplyTo":"1444778207-859-8-git-send-email-gitster@pobox.com","subject":"Re: [PATCH 07/26] mailinfo: move global \"line\" into mailinfo() function","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2015-10-14T20:27:38Z","receivedAt":"2015-10-14T20:27:38Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Tue, Oct 13, 2015 at 4:16 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> The mailinfo() function is the only one that wants the \"line_global\"\n> to be directly touchable.  Note that handle_body() has to be passed\n> this strbuf so that it sees the \"first line of the input\" after the\n> loop in this function processes the headers.  It feels a bit dirty\n> that handle_body() then keeps reusing this strbuf to read more lines\n> and does its processing, but that is how the code is structured now.\n>\n> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n\nOk, that is exactly what I thought about squashing into patch 6.\nA separate patch will do too.\n"},{"id":"271664","messageId":"xmqqy4f56vpo.fsf@gitster.mtv.corp.google.com","threadId":"40552","inReplyTo":"CAGZ79kYGB8QOio7dqKNPjsQg6xeCSEkvC_8_a3=h9sHxbn-6uw@mail.gmail.com","subject":"Re: [PATCH 02/26] mailinfo: fix for off-by-one error in boundary stack","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-14T20:28:35Z","receivedAt":"2015-10-14T20:28:35Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"I'll be sending out v2 very soon, so you might want to hold off for\na few minutes.\n"},{"id":"271696","messageId":"1444855557-2127-1-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444778207-859-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 00/31] libify mailinfo and call it directly from am","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-14T20:45:26Z","receivedAt":"2015-10-14T20:45:26Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"During the discussion on the recent \"git am\" regression, I noticed\nthat the command reimplemented in C spawns one \"mailsplit\" and then\nspawns \"mailinfo\" followed by \"apply --index\" to commit the changes\ndescribed in each message.  As there are platforms where spawning\nsubprocess via run_command() interface is heavy-weight, something\nthat is conceptually very simple like \"mailinfo\" is better called\ndirectly inside the process---something that is lightweight and\nfrequently used is where the overhead of run_command() would be felt\nmost.\n\nAnd here is that topic, slightly reordered and polished up, since\nyesterday's version.\n\n - The series no longer depends on an unrelated \"how about this\" patch\n   to mailinfo.\n\n - Fixes are moved to earlier spots in the series.\n\n - Error checking in the endgame patch has been tightened.\n\nJunio C Hamano (31):\n  mailinfo: remove a no-op call convert_to_utf8(it, \"\")\n  mailinfo: fix for off-by-one error in boundary stack\n  mailinfo: explicitly close file handle to the patch output\n  mailinfo: fold decode_header_bq() into decode_header()\n  mailinfo: move handle_boundary() lower\n  mailinfo: get rid of function-local static states\n  mailinfo: always pass \"line\" as an argument\n  mailinfo: move global \"line\" into mailinfo() function\n  mailinfo: introduce \"struct mailinfo\" to hold globals\n  mailinfo: move keep_subject & keep_non_patch_bracket to struct mailinfo\n  mailinfo: move global \"FILE *fin, *fout\" to struct mailinfo\n  mailinfo: move filter/header stage to struct mailinfo\n  mailinfo: move patch_lines to struct mailinfo\n  mailinfo: move add_message_id and message_id to struct mailinfo\n  mailinfo: move use_scissors and use_inbody_headers to struct mailinfo\n  mailinfo: move metainfo_charset to struct mailinfo\n  mailinfo: move transfer_encoding to struct mailinfo\n  mailinfo: move charset to struct mailinfo\n  mailinfo: handle_commit_msg() shouldn't be called after finding patchbreak\n  mailinfo: move cmitmsg and patchfile to struct mailinfo\n  mailinfo: move [ps]_hdr_data to struct mailinfo\n  mailinfo: keep the parsed log message in a strbuf\n  mailinfo: move content/content_top to struct mailinfo\n  mailinfo: move read_one_header_line() closer to its callers\n  mailinfo: move check_header() after the helpers it uses\n  mailinfo: move cleanup_space() before its users\n  mailinfo: move definition of MAX_HDR_PARSED to closer to its use\n  mailinfo: libify\n  mailinfo: handle charset conversion errors in the caller\n  mailinfo: remove calls to exit() and die() deep in the callchain\n  am: make direct call to mailinfo\n\n Makefile           |    1 +\n builtin/am.c       |   42 ++-\n builtin/mailinfo.c | 1055 +---------------------------------------------------\n mailinfo.c         | 1024 ++++++++++++++++++++++++++++++++++++++++++++++++++\n mailinfo.h         |   41 ++\n 5 files changed, 1109 insertions(+), 1054 deletions(-)\n create mode 100644 mailinfo.c\n create mode 100644 mailinfo.h\n\n-- \n2.6.1-320-g86a1181\n"},{"id":"271694","messageId":"1444855557-2127-2-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444855557-2127-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 01/31] mailinfo: remove a no-op call convert_to_utf8(it, \"\")","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-14T20:45:27Z","receivedAt":"2015-10-14T20:45:27Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The called function checks if the second parameter is either a NULL\nor an empty string at the very beginning and returns without doing\nanything.  Remove the useless call.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 5 -----\n 1 file changed, 5 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 999a525..5a4ed75 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -612,11 +612,6 @@ static void decode_header(struct strbuf *it)\n {\n \tif (decode_header_bq(it))\n \t\treturn;\n-\t/* otherwise \"it\" is a straight copy of the input.\n-\t * This can be binary guck but there is no charset specified.\n-\t */\n-\tif (metainfo_charset)\n-\t\tconvert_to_utf8(it, \"\");\n }\n \n static void decode_transfer_encoding(struct strbuf *line)\n-- \n2.6.1-320-g86a1181\n"},{"id":"271689","messageId":"1444855557-2127-3-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444855557-2127-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 02/31] mailinfo: fix for off-by-one error in boundary stack","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-14T20:45:28Z","receivedAt":"2015-10-14T20:45:28Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"We pre-increment the pointer that we will use to store something at,\nso the pointer is already beyond the end of the array if it points\nat content[MAX_BOUNDARIES].\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 5a4ed75..d3756cc 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -185,7 +185,7 @@ static void handle_content_type(struct strbuf *line)\n \n \tif (slurp_attr(line->buf, \"boundary=\", boundary)) {\n \t\tstrbuf_insert(boundary, 0, \"--\", 2);\n-\t\tif (++content_top > &content[MAX_BOUNDARIES]) {\n+\t\tif (++content_top >= &content[MAX_BOUNDARIES]) {\n \t\t\tfprintf(stderr, \"Too many boundaries to handle\\n\");\n \t\t\texit(1);\n \t\t}\n-- \n2.6.1-320-g86a1181\n"},{"id":"271667","messageId":"1444855557-2127-4-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444855557-2127-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 03/31] mailinfo: explicitly close file handle to the patch output","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-14T20:45:29Z","receivedAt":"2015-10-14T20:45:29Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This does not make a difference within the context of \"git mailinfo\"\nthat runs once and exits, as flushing and closing would happen upon\nprocess completion.  It however will matter when we eventually make\nthis function callable as an API function.\n\nBesides, cleaning after yourself once you are done is a good hygiene.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 2 ++\n 1 file changed, 2 insertions(+)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex d3756cc..412a23b 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -1008,6 +1008,8 @@ static int mailinfo(FILE *in, FILE *out, const char *msg, const char *patch)\n \t\tcheck_header(&line, p_hdr_data, 1);\n \n \thandle_body();\n+\tfclose(patchfile);\n+\n \thandle_info();\n \n \treturn 0;\n-- \n2.6.1-320-g86a1181\n"},{"id":"271691","messageId":"1444855557-2127-5-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444855557-2127-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 04/31] mailinfo: fold decode_header_bq() into decode_header()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-14T20:45:30Z","receivedAt":"2015-10-14T20:45:30Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"In olden days we might have wanted to behave differently in\ndecode_header() if the header line was encoded with RFC2047, but we\napparently do not do so, hence this helper function can go, together\nwith its return value.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 23 +++++++----------------\n 1 file changed, 7 insertions(+), 16 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 412a23b..73be47c 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -525,19 +525,17 @@ static void convert_to_utf8(struct strbuf *line, const char *charset)\n \tstrbuf_attach(line, out, strlen(out), strlen(out));\n }\n \n-static int decode_header_bq(struct strbuf *it)\n+static void decode_header(struct strbuf *it)\n {\n \tchar *in, *ep, *cp;\n \tstruct strbuf outbuf = STRBUF_INIT, *dec;\n \tstruct strbuf charset_q = STRBUF_INIT, piecebuf = STRBUF_INIT;\n-\tint rfc2047 = 0;\n \n \tin = it->buf;\n \twhile (in - it->buf <= it->len && (ep = strstr(in, \"=?\")) != NULL) {\n \t\tint encoding;\n \t\tstrbuf_reset(&charset_q);\n \t\tstrbuf_reset(&piecebuf);\n-\t\trfc2047 = 1;\n \n \t\tif (in != ep) {\n \t\t\t/*\n@@ -567,22 +565,22 @@ static int decode_header_bq(struct strbuf *it)\n \t\tep += 2;\n \n \t\tif (ep - it->buf >= it->len || !(cp = strchr(ep, '?')))\n-\t\t\tgoto decode_header_bq_out;\n+\t\t\tgoto release_return;\n \n \t\tif (cp + 3 - it->buf > it->len)\n-\t\t\tgoto decode_header_bq_out;\n+\t\t\tgoto release_return;\n \t\tstrbuf_add(&charset_q, ep, cp - ep);\n \n \t\tencoding = cp[1];\n \t\tif (!encoding || cp[2] != '?')\n-\t\t\tgoto decode_header_bq_out;\n+\t\t\tgoto release_return;\n \t\tep = strstr(cp + 3, \"?=\");\n \t\tif (!ep)\n-\t\t\tgoto decode_header_bq_out;\n+\t\t\tgoto release_return;\n \t\tstrbuf_add(&piecebuf, cp + 3, ep - cp - 3);\n \t\tswitch (tolower(encoding)) {\n \t\tdefault:\n-\t\t\tgoto decode_header_bq_out;\n+\t\t\tgoto release_return;\n \t\tcase 'b':\n \t\t\tdec = decode_b_segment(&piecebuf);\n \t\t\tbreak;\n@@ -601,17 +599,10 @@ static int decode_header_bq(struct strbuf *it)\n \tstrbuf_addstr(&outbuf, in);\n \tstrbuf_reset(it);\n \tstrbuf_addbuf(it, &outbuf);\n-decode_header_bq_out:\n+release_return:\n \tstrbuf_release(&outbuf);\n \tstrbuf_release(&charset_q);\n \tstrbuf_release(&piecebuf);\n-\treturn rfc2047;\n-}\n-\n-static void decode_header(struct strbuf *it)\n-{\n-\tif (decode_header_bq(it))\n-\t\treturn;\n }\n \n static void decode_transfer_encoding(struct strbuf *line)\n-- \n2.6.1-320-g86a1181\n"},{"id":"271690","messageId":"1444855557-2127-6-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444855557-2127-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 05/31] mailinfo: move handle_boundary() lower","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-14T20:45:31Z","receivedAt":"2015-10-14T20:45:31Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This function wants to call find_boundary() and is called only from\none place without any recursing, so it becomes easier to read if it\nappears after the called function.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 114 ++++++++++++++++++++++++++---------------------------\n 1 file changed, 56 insertions(+), 58 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 73be47c..2b7f97b 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -626,64 +626,6 @@ static void decode_transfer_encoding(struct strbuf *line)\n \tfree(ret);\n }\n \n-static void handle_filter(struct strbuf *line);\n-\n-static int find_boundary(void)\n-{\n-\twhile (!strbuf_getline(&line, fin, '\\n')) {\n-\t\tif (*content_top && is_multipart_boundary(&line))\n-\t\t\treturn 1;\n-\t}\n-\treturn 0;\n-}\n-\n-static int handle_boundary(void)\n-{\n-\tstruct strbuf newline = STRBUF_INIT;\n-\n-\tstrbuf_addch(&newline, '\\n');\n-again:\n-\tif (line.len >= (*content_top)->len + 2 &&\n-\t    !memcmp(line.buf + (*content_top)->len, \"--\", 2)) {\n-\t\t/* we hit an end boundary */\n-\t\t/* pop the current boundary off the stack */\n-\t\tstrbuf_release(*content_top);\n-\t\tfree(*content_top);\n-\t\t*content_top = NULL;\n-\n-\t\t/* technically won't happen as is_multipart_boundary()\n-\t\t   will fail first.  But just in case..\n-\t\t */\n-\t\tif (--content_top < content) {\n-\t\t\tfprintf(stderr, \"Detected mismatched boundaries, \"\n-\t\t\t\t\t\"can't recover\\n\");\n-\t\t\texit(1);\n-\t\t}\n-\t\thandle_filter(&newline);\n-\t\tstrbuf_release(&newline);\n-\n-\t\t/* skip to the next boundary */\n-\t\tif (!find_boundary())\n-\t\t\treturn 0;\n-\t\tgoto again;\n-\t}\n-\n-\t/* set some defaults */\n-\ttransfer_encoding = TE_DONTCARE;\n-\tstrbuf_reset(&charset);\n-\n-\t/* slurp in this section's info */\n-\twhile (read_one_header_line(&line, fin))\n-\t\tcheck_header(&line, p_hdr_data, 0);\n-\n-\tstrbuf_release(&newline);\n-\t/* replenish line */\n-\tif (strbuf_getline(&line, fin, '\\n'))\n-\t\treturn 0;\n-\tstrbuf_addch(&line, '\\n');\n-\treturn 1;\n-}\n-\n static inline int patchbreak(const struct strbuf *line)\n {\n \tsize_t i;\n@@ -851,6 +793,62 @@ static void handle_filter(struct strbuf *line)\n \t}\n }\n \n+static int find_boundary(void)\n+{\n+\twhile (!strbuf_getline(&line, fin, '\\n')) {\n+\t\tif (*content_top && is_multipart_boundary(&line))\n+\t\t\treturn 1;\n+\t}\n+\treturn 0;\n+}\n+\n+static int handle_boundary(void)\n+{\n+\tstruct strbuf newline = STRBUF_INIT;\n+\n+\tstrbuf_addch(&newline, '\\n');\n+again:\n+\tif (line.len >= (*content_top)->len + 2 &&\n+\t    !memcmp(line.buf + (*content_top)->len, \"--\", 2)) {\n+\t\t/* we hit an end boundary */\n+\t\t/* pop the current boundary off the stack */\n+\t\tstrbuf_release(*content_top);\n+\t\tfree(*content_top);\n+\t\t*content_top = NULL;\n+\n+\t\t/* technically won't happen as is_multipart_boundary()\n+\t\t   will fail first.  But just in case..\n+\t\t */\n+\t\tif (--content_top < content) {\n+\t\t\tfprintf(stderr, \"Detected mismatched boundaries, \"\n+\t\t\t\t\t\"can't recover\\n\");\n+\t\t\texit(1);\n+\t\t}\n+\t\thandle_filter(&newline);\n+\t\tstrbuf_release(&newline);\n+\n+\t\t/* skip to the next boundary */\n+\t\tif (!find_boundary())\n+\t\t\treturn 0;\n+\t\tgoto again;\n+\t}\n+\n+\t/* set some defaults */\n+\ttransfer_encoding = TE_DONTCARE;\n+\tstrbuf_reset(&charset);\n+\n+\t/* slurp in this section's info */\n+\twhile (read_one_header_line(&line, fin))\n+\t\tcheck_header(&line, p_hdr_data, 0);\n+\n+\tstrbuf_release(&newline);\n+\t/* replenish line */\n+\tif (strbuf_getline(&line, fin, '\\n'))\n+\t\treturn 0;\n+\tstrbuf_addch(&line, '\\n');\n+\treturn 1;\n+}\n+\n static void handle_body(void)\n {\n \tstruct strbuf prev = STRBUF_INIT;\n-- \n2.6.1-320-g86a1181\n"},{"id":"271684","messageId":"1444855557-2127-7-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444855557-2127-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 06/31] mailinfo: get rid of function-local static states","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-14T20:45:32Z","receivedAt":"2015-10-14T20:45:32Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Two helper functions use \"static int\" in their scope to keep track\nof the state while repeatedly getting called once for each input\nline.  Move these state variables their ultimate caller and pass\ndown pointers to them, as a small step in preparation for making\nthis entire callchain more reentrant.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 41 +++++++++++++++++++----------------------\n 1 file changed, 19 insertions(+), 22 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 2b7f97b..1518708 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -713,27 +713,25 @@ static int is_scissors_line(const struct strbuf *line)\n \t\tgap * 2 < perforation);\n }\n \n-static int handle_commit_msg(struct strbuf *line)\n+static int handle_commit_msg(struct strbuf *line, int *still_looking)\n {\n-\tstatic int still_looking = 1;\n-\n \tif (!cmitmsg)\n \t\treturn 0;\n \n-\tif (still_looking) {\n+\tif (*still_looking) {\n \t\tif (!line->len || (line->len == 1 && line->buf[0] == '\\n'))\n \t\t\treturn 0;\n \t}\n \n-\tif (use_inbody_headers && still_looking) {\n-\t\tstill_looking = check_header(line, s_hdr_data, 0);\n-\t\tif (still_looking)\n+\tif (use_inbody_headers && *still_looking) {\n+\t\t*still_looking = check_header(line, s_hdr_data, 0);\n+\t\tif (*still_looking)\n \t\t\treturn 0;\n \t} else\n \t\t/* Only trim the first (blank) line of the commit message\n \t\t * when ignoring in-body headers.\n \t\t */\n-\t\tstill_looking = 0;\n+\t\t*still_looking = 0;\n \n \t/* normalize the log message to UTF-8. */\n \tif (metainfo_charset)\n@@ -745,7 +743,7 @@ static int handle_commit_msg(struct strbuf *line)\n \t\t\tdie_errno(\"Could not rewind output message file\");\n \t\tif (ftruncate(fileno(cmitmsg), 0))\n \t\t\tdie_errno(\"Could not truncate output message file at scissors\");\n-\t\tstill_looking = 1;\n+\t\t*still_looking = 1;\n \n \t\t/*\n \t\t * We may have already read \"secondary headers\"; purge\n@@ -777,16 +775,13 @@ static void handle_patch(const struct strbuf *line)\n \tpatch_lines++;\n }\n \n-static void handle_filter(struct strbuf *line)\n+static void handle_filter(struct strbuf *line, int *filter_stage, int *header_stage)\n {\n-\tstatic int filter = 0;\n-\n-\t/* filter tells us which part we left off on */\n-\tswitch (filter) {\n+\tswitch (*filter_stage) {\n \tcase 0:\n-\t\tif (!handle_commit_msg(line))\n+\t\tif (!handle_commit_msg(line, header_stage))\n \t\t\tbreak;\n-\t\tfilter++;\n+\t\t(*filter_stage)++;\n \tcase 1:\n \t\thandle_patch(line);\n \t\tbreak;\n@@ -802,7 +797,7 @@ static int find_boundary(void)\n \treturn 0;\n }\n \n-static int handle_boundary(void)\n+static int handle_boundary(int *filter_stage, int *header_stage)\n {\n \tstruct strbuf newline = STRBUF_INIT;\n \n@@ -824,7 +819,7 @@ again:\n \t\t\t\t\t\"can't recover\\n\");\n \t\t\texit(1);\n \t\t}\n-\t\thandle_filter(&newline);\n+\t\thandle_filter(&newline, filter_stage, header_stage);\n \t\tstrbuf_release(&newline);\n \n \t\t/* skip to the next boundary */\n@@ -852,6 +847,8 @@ again:\n static void handle_body(void)\n {\n \tstruct strbuf prev = STRBUF_INIT;\n+\tint filter_stage = 0;\n+\tint header_stage = 1;\n \n \t/* Skip up to the first boundary */\n \tif (*content_top) {\n@@ -864,10 +861,10 @@ static void handle_body(void)\n \t\tif (*content_top && is_multipart_boundary(&line)) {\n \t\t\t/* flush any leftover */\n \t\t\tif (prev.len) {\n-\t\t\t\thandle_filter(&prev);\n+\t\t\t\thandle_filter(&prev, &filter_stage, &header_stage);\n \t\t\t\tstrbuf_reset(&prev);\n \t\t\t}\n-\t\t\tif (!handle_boundary())\n+\t\t\tif (!handle_boundary(&filter_stage, &header_stage))\n \t\t\t\tgoto handle_body_out;\n \t\t}\n \n@@ -897,7 +894,7 @@ static void handle_body(void)\n \t\t\t\t\t\tstrbuf_addbuf(&prev, sb);\n \t\t\t\t\t\tbreak;\n \t\t\t\t\t}\n-\t\t\t\thandle_filter(sb);\n+\t\t\t\thandle_filter(sb, &filter_stage, &header_stage);\n \t\t\t}\n \t\t\t/*\n \t\t\t * The partial chunk is saved in \"prev\" and will be\n@@ -907,7 +904,7 @@ static void handle_body(void)\n \t\t\tbreak;\n \t\t}\n \t\tdefault:\n-\t\t\thandle_filter(&line);\n+\t\t\thandle_filter(&line, &filter_stage, &header_stage);\n \t\t}\n \n \t} while (!strbuf_getwholeline(&line, fin, '\\n'));\n-- \n2.6.1-320-g86a1181\n"},{"id":"271686","messageId":"1444855557-2127-8-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444855557-2127-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 07/31] mailinfo: always pass \"line\" as an argument","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-14T20:45:33Z","receivedAt":"2015-10-14T20:45:33Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Some functions in this module accessed the global \"struct strbuf\nline\" while many others used a strbuf passed as an argument.\nConvert the former to ensure that nobody deeper in the callchains\nrelies on the global one.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 48 ++++++++++++++++++++++++------------------------\n 1 file changed, 24 insertions(+), 24 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 1518708..721d999 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -12,7 +12,7 @@ static FILE *cmitmsg, *patchfile, *fin, *fout;\n static int keep_subject;\n static int keep_non_patch_brackets_in_subject;\n static const char *metainfo_charset;\n-static struct strbuf line = STRBUF_INIT;\n+static struct strbuf line_global = STRBUF_INIT;\n static struct strbuf name = STRBUF_INIT;\n static struct strbuf email = STRBUF_INIT;\n static char *message_id;\n@@ -788,23 +788,23 @@ static void handle_filter(struct strbuf *line, int *filter_stage, int *header_st\n \t}\n }\n \n-static int find_boundary(void)\n+static int find_boundary(struct strbuf *line)\n {\n-\twhile (!strbuf_getline(&line, fin, '\\n')) {\n-\t\tif (*content_top && is_multipart_boundary(&line))\n+\twhile (!strbuf_getline(line, fin, '\\n')) {\n+\t\tif (*content_top && is_multipart_boundary(line))\n \t\t\treturn 1;\n \t}\n \treturn 0;\n }\n \n-static int handle_boundary(int *filter_stage, int *header_stage)\n+static int handle_boundary(struct strbuf *line, int *filter_stage, int *header_stage)\n {\n \tstruct strbuf newline = STRBUF_INIT;\n \n \tstrbuf_addch(&newline, '\\n');\n again:\n-\tif (line.len >= (*content_top)->len + 2 &&\n-\t    !memcmp(line.buf + (*content_top)->len, \"--\", 2)) {\n+\tif (line->len >= (*content_top)->len + 2 &&\n+\t    !memcmp(line->buf + (*content_top)->len, \"--\", 2)) {\n \t\t/* we hit an end boundary */\n \t\t/* pop the current boundary off the stack */\n \t\tstrbuf_release(*content_top);\n@@ -823,7 +823,7 @@ again:\n \t\tstrbuf_release(&newline);\n \n \t\t/* skip to the next boundary */\n-\t\tif (!find_boundary())\n+\t\tif (!find_boundary(line))\n \t\t\treturn 0;\n \t\tgoto again;\n \t}\n@@ -833,18 +833,18 @@ again:\n \tstrbuf_reset(&charset);\n \n \t/* slurp in this section's info */\n-\twhile (read_one_header_line(&line, fin))\n-\t\tcheck_header(&line, p_hdr_data, 0);\n+\twhile (read_one_header_line(line, fin))\n+\t\tcheck_header(line, p_hdr_data, 0);\n \n \tstrbuf_release(&newline);\n \t/* replenish line */\n-\tif (strbuf_getline(&line, fin, '\\n'))\n+\tif (strbuf_getline(line, fin, '\\n'))\n \t\treturn 0;\n-\tstrbuf_addch(&line, '\\n');\n+\tstrbuf_addch(line, '\\n');\n \treturn 1;\n }\n \n-static void handle_body(void)\n+static void handle_body(struct strbuf *line)\n {\n \tstruct strbuf prev = STRBUF_INIT;\n \tint filter_stage = 0;\n@@ -852,24 +852,24 @@ static void handle_body(void)\n \n \t/* Skip up to the first boundary */\n \tif (*content_top) {\n-\t\tif (!find_boundary())\n+\t\tif (!find_boundary(line))\n \t\t\tgoto handle_body_out;\n \t}\n \n \tdo {\n \t\t/* process any boundary lines */\n-\t\tif (*content_top && is_multipart_boundary(&line)) {\n+\t\tif (*content_top && is_multipart_boundary(line)) {\n \t\t\t/* flush any leftover */\n \t\t\tif (prev.len) {\n \t\t\t\thandle_filter(&prev, &filter_stage, &header_stage);\n \t\t\t\tstrbuf_reset(&prev);\n \t\t\t}\n-\t\t\tif (!handle_boundary(&filter_stage, &header_stage))\n+\t\t\tif (!handle_boundary(line, &filter_stage, &header_stage))\n \t\t\t\tgoto handle_body_out;\n \t\t}\n \n \t\t/* Unwrap transfer encoding */\n-\t\tdecode_transfer_encoding(&line);\n+\t\tdecode_transfer_encoding(line);\n \n \t\tswitch (transfer_encoding) {\n \t\tcase TE_BASE64:\n@@ -878,7 +878,7 @@ static void handle_body(void)\n \t\t\tstruct strbuf **lines, **it, *sb;\n \n \t\t\t/* Prepend any previous partial lines */\n-\t\t\tstrbuf_insert(&line, 0, prev.buf, prev.len);\n+\t\t\tstrbuf_insert(line, 0, prev.buf, prev.len);\n \t\t\tstrbuf_reset(&prev);\n \n \t\t\t/*\n@@ -886,7 +886,7 @@ static void handle_body(void)\n \t\t\t * multiple new lines.  Pass only one chunk\n \t\t\t * at a time to handle_filter()\n \t\t\t */\n-\t\t\tlines = strbuf_split(&line, '\\n');\n+\t\t\tlines = strbuf_split(line, '\\n');\n \t\t\tfor (it = lines; (sb = *it); it++) {\n \t\t\t\tif (*(it + 1) == NULL) /* The last line */\n \t\t\t\t\tif (sb->buf[sb->len - 1] != '\\n') {\n@@ -904,10 +904,10 @@ static void handle_body(void)\n \t\t\tbreak;\n \t\t}\n \t\tdefault:\n-\t\t\thandle_filter(&line, &filter_stage, &header_stage);\n+\t\t\thandle_filter(line, &filter_stage, &header_stage);\n \t\t}\n \n-\t} while (!strbuf_getwholeline(&line, fin, '\\n'));\n+\t} while (!strbuf_getwholeline(line, fin, '\\n'));\n \n handle_body_out:\n \tstrbuf_release(&prev);\n@@ -990,10 +990,10 @@ static int mailinfo(FILE *in, FILE *out, const char *msg, const char *patch)\n \tungetc(peek, in);\n \n \t/* process the email header */\n-\twhile (read_one_header_line(&line, fin))\n-\t\tcheck_header(&line, p_hdr_data, 1);\n+\twhile (read_one_header_line(&line_global, fin))\n+\t\tcheck_header(&line_global, p_hdr_data, 1);\n \n-\thandle_body();\n+\thandle_body(&line_global);\n \tfclose(patchfile);\n \n \thandle_info();\n-- \n2.6.1-320-g86a1181\n"},{"id":"271673","messageId":"1444855557-2127-9-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444855557-2127-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 08/31] mailinfo: move global \"line\" into mailinfo() function","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-14T20:45:34Z","receivedAt":"2015-10-14T20:45:34Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"With the pregvious step, it becomes clear that the mailinfo()\nfunction is the only one that wants the \"line_global\" to be directly\ntouchable.\n\nLogically, this strbuf belongs to handle_body().  It passes the line\nto its helper functions for processing, and keeps one line at a time\ninto the variable in the loop to drive that process.  It would have\nbeen even nicer looking if we could make the variable local to the\nfunction.  But the function has to be passed its initial value\n(i.e. the first line is read by its caller), and that is why its\nsole caller owns it in the resulting code structure.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 9 +++++----\n 1 file changed, 5 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 721d999..c8dc73f 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -12,7 +12,6 @@ static FILE *cmitmsg, *patchfile, *fin, *fout;\n static int keep_subject;\n static int keep_non_patch_brackets_in_subject;\n static const char *metainfo_charset;\n-static struct strbuf line_global = STRBUF_INIT;\n static struct strbuf name = STRBUF_INIT;\n static struct strbuf email = STRBUF_INIT;\n static char *message_id;\n@@ -966,6 +965,8 @@ static void handle_info(void)\n static int mailinfo(FILE *in, FILE *out, const char *msg, const char *patch)\n {\n \tint peek;\n+\tstruct strbuf line = STRBUF_INIT;\n+\n \tfin = in;\n \tfout = out;\n \n@@ -990,10 +991,10 @@ static int mailinfo(FILE *in, FILE *out, const char *msg, const char *patch)\n \tungetc(peek, in);\n \n \t/* process the email header */\n-\twhile (read_one_header_line(&line_global, fin))\n-\t\tcheck_header(&line_global, p_hdr_data, 1);\n+\twhile (read_one_header_line(&line, fin))\n+\t\tcheck_header(&line, p_hdr_data, 1);\n \n-\thandle_body(&line_global);\n+\thandle_body(&line);\n \tfclose(patchfile);\n \n \thandle_info();\n-- \n2.6.1-320-g86a1181\n"},{"id":"271669","messageId":"1444855557-2127-10-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444855557-2127-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 09/31] mailinfo: introduce \"struct mailinfo\" to hold globals","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-14T20:45:35Z","receivedAt":"2015-10-14T20:45:35Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Initially have only 'email' and 'name' fields in there and remove\nthe corresponding globals.  In subsequent patches, more globals will\nbe moved to this and the structure will be passed around as a new\nparameter to more functions.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 61 +++++++++++++++++++++++++++++++++---------------------\n 1 file changed, 37 insertions(+), 24 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex c8dc73f..9e41a10 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -12,8 +12,11 @@ static FILE *cmitmsg, *patchfile, *fin, *fout;\n static int keep_subject;\n static int keep_non_patch_brackets_in_subject;\n static const char *metainfo_charset;\n-static struct strbuf name = STRBUF_INIT;\n-static struct strbuf email = STRBUF_INIT;\n+\n+struct mailinfo {\n+\tstruct strbuf name;\n+\tstruct strbuf email;\n+};\n static char *message_id;\n \n static enum  {\n@@ -45,7 +48,7 @@ static void get_sane_name(struct strbuf *out, struct strbuf *name, struct strbuf\n \tstrbuf_addbuf(out, src);\n }\n \n-static void parse_bogus_from(const struct strbuf *line)\n+static void parse_bogus_from(struct mailinfo *mi, const struct strbuf *line)\n {\n \t/* John Doe <johndoe> */\n \n@@ -53,7 +56,7 @@ static void parse_bogus_from(const struct strbuf *line)\n \t/* This is fallback, so do not bother if we already have an\n \t * e-mail address.\n \t */\n-\tif (email.len)\n+\tif (mi->email.len)\n \t\treturn;\n \n \tbra = strchr(line->buf, '<');\n@@ -63,16 +66,16 @@ static void parse_bogus_from(const struct strbuf *line)\n \tif (!ket)\n \t\treturn;\n \n-\tstrbuf_reset(&email);\n-\tstrbuf_add(&email, bra + 1, ket - bra - 1);\n+\tstrbuf_reset(&mi->email);\n+\tstrbuf_add(&mi->email, bra + 1, ket - bra - 1);\n \n-\tstrbuf_reset(&name);\n-\tstrbuf_add(&name, line->buf, bra - line->buf);\n-\tstrbuf_trim(&name);\n-\tget_sane_name(&name, &name, &email);\n+\tstrbuf_reset(&mi->name);\n+\tstrbuf_add(&mi->name, line->buf, bra - line->buf);\n+\tstrbuf_trim(&mi->name);\n+\tget_sane_name(&mi->name, &mi->name, &mi->email);\n }\n \n-static void handle_from(const struct strbuf *from)\n+static void handle_from(struct mailinfo *mi, const struct strbuf *from)\n {\n \tchar *at;\n \tsize_t el;\n@@ -83,14 +86,14 @@ static void handle_from(const struct strbuf *from)\n \n \tat = strchr(f.buf, '@');\n \tif (!at) {\n-\t\tparse_bogus_from(from);\n+\t\tparse_bogus_from(mi, from);\n \t\treturn;\n \t}\n \n \t/*\n \t * If we already have one email, don't take any confusing lines\n \t */\n-\tif (email.len && strchr(at + 1, '@')) {\n+\tif (mi->email.len && strchr(at + 1, '@')) {\n \t\tstrbuf_release(&f);\n \t\treturn;\n \t}\n@@ -109,8 +112,8 @@ static void handle_from(const struct strbuf *from)\n \t\tat--;\n \t}\n \tel = strcspn(at, \" \\n\\t\\r\\v\\f>\");\n-\tstrbuf_reset(&email);\n-\tstrbuf_add(&email, at, el);\n+\tstrbuf_reset(&mi->email);\n+\tstrbuf_add(&mi->email, at, el);\n \tstrbuf_remove(&f, at - f.buf, el + (at[el] ? 1 : 0));\n \n \t/* The remainder is name.  It could be\n@@ -132,7 +135,7 @@ static void handle_from(const struct strbuf *from)\n \t\tstrbuf_setlen(&f, f.len - 1);\n \t}\n \n-\tget_sane_name(&name, &f, &email);\n+\tget_sane_name(&mi->name, &f, &mi->email);\n \tstrbuf_release(&f);\n }\n \n@@ -929,7 +932,7 @@ static void output_header_lines(FILE *fout, const char *hdr, const struct strbuf\n \t}\n }\n \n-static void handle_info(void)\n+static void handle_info(struct mailinfo *mi)\n {\n \tstruct strbuf *hdr;\n \tint i;\n@@ -951,9 +954,9 @@ static void handle_info(void)\n \t\t\toutput_header_lines(fout, \"Subject\", hdr);\n \t\t} else if (!strcmp(header[i], \"From\")) {\n \t\t\tcleanup_space(hdr);\n-\t\t\thandle_from(hdr);\n-\t\t\tfprintf(fout, \"Author: %s\\n\", name.buf);\n-\t\t\tfprintf(fout, \"Email: %s\\n\", email.buf);\n+\t\t\thandle_from(mi, hdr);\n+\t\t\tfprintf(fout, \"Author: %s\\n\", mi->name.buf);\n+\t\t\tfprintf(fout, \"Email: %s\\n\", mi->email.buf);\n \t\t} else {\n \t\t\tcleanup_space(hdr);\n \t\t\tfprintf(fout, \"%s: %s\\n\", header[i], hdr->buf);\n@@ -962,7 +965,8 @@ static void handle_info(void)\n \tfprintf(fout, \"\\n\");\n }\n \n-static int mailinfo(FILE *in, FILE *out, const char *msg, const char *patch)\n+static int mailinfo(struct mailinfo *mi,\n+\t\t    FILE *in, FILE *out, const char *msg, const char *patch)\n {\n \tint peek;\n \tstruct strbuf line = STRBUF_INIT;\n@@ -997,7 +1001,7 @@ static int mailinfo(FILE *in, FILE *out, const char *msg, const char *patch)\n \thandle_body(&line);\n \tfclose(patchfile);\n \n-\thandle_info();\n+\thandle_info(mi);\n \n \treturn 0;\n }\n@@ -1014,17 +1018,26 @@ static int git_mailinfo_config(const char *var, const char *value, void *unused)\n \treturn 0;\n }\n \n+static void setup_mailinfo(struct mailinfo *mi)\n+{\n+\tmemset(mi, 0, sizeof(*mi));\n+\tstrbuf_init(&mi->name, 0);\n+\tstrbuf_init(&mi->email, 0);\n+\tgit_config(git_mailinfo_config, &mi);\n+}\n+\n static const char mailinfo_usage[] =\n \t\"git mailinfo [-k | -b] [-m | --message-id] [-u | --encoding=<encoding> | -n] [--scissors | --no-scissors] <msg> <patch> < mail >info\";\n \n int cmd_mailinfo(int argc, const char **argv, const char *prefix)\n {\n \tconst char *def_charset;\n+\tstruct mailinfo mi;\n \n \t/* NEEDSWORK: might want to do the optional .git/ directory\n \t * discovery\n \t */\n-\tgit_config(git_mailinfo_config, NULL);\n+\tsetup_mailinfo(&mi);\n \n \tdef_charset = get_commit_output_encoding();\n \tmetainfo_charset = def_charset;\n@@ -1056,5 +1069,5 @@ int cmd_mailinfo(int argc, const char **argv, const char *prefix)\n \tif (argc != 3)\n \t\tusage(mailinfo_usage);\n \n-\treturn !!mailinfo(stdin, stdout, argv[1], argv[2]);\n+\treturn !!mailinfo(&mi, stdin, stdout, argv[1], argv[2]);\n }\n-- \n2.6.1-320-g86a1181\n"},{"id":"271675","messageId":"1444855557-2127-11-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444855557-2127-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 10/31] mailinfo: move keep_subject & keep_non_patch_bracket to struct mailinfo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-14T20:45:36Z","receivedAt":"2015-10-14T20:45:36Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"These two are the only easy ones that do not require passing the\nstructure around to deep corners of the callchain.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 16 ++++++++--------\n 1 file changed, 8 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 9e41a10..855d813 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -9,13 +9,13 @@\n \n static FILE *cmitmsg, *patchfile, *fin, *fout;\n \n-static int keep_subject;\n-static int keep_non_patch_brackets_in_subject;\n static const char *metainfo_charset;\n \n struct mailinfo {\n \tstruct strbuf name;\n \tstruct strbuf email;\n+\tint keep_subject;\n+\tint keep_non_patch_brackets_in_subject;\n };\n static char *message_id;\n \n@@ -224,7 +224,7 @@ static int is_multipart_boundary(const struct strbuf *line)\n \t\t!memcmp(line->buf, (*content_top)->buf, (*content_top)->len));\n }\n \n-static void cleanup_subject(struct strbuf *subject)\n+static void cleanup_subject(struct mailinfo *mi, struct strbuf *subject)\n {\n \tsize_t at = 0;\n \n@@ -252,7 +252,7 @@ static void cleanup_subject(struct strbuf *subject)\n \t\t\tif (!pos)\n \t\t\t\tbreak;\n \t\t\tremove = pos - subject->buf + at + 1;\n-\t\t\tif (!keep_non_patch_brackets_in_subject ||\n+\t\t\tif (!mi->keep_non_patch_brackets_in_subject ||\n \t\t\t    (7 <= remove &&\n \t\t\t     memmem(subject->buf + at, remove, \"PATCH\", 5)))\n \t\t\t\tstrbuf_remove(subject, at, remove);\n@@ -947,8 +947,8 @@ static void handle_info(struct mailinfo *mi)\n \t\t\tcontinue;\n \n \t\tif (!strcmp(header[i], \"Subject\")) {\n-\t\t\tif (!keep_subject) {\n-\t\t\t\tcleanup_subject(hdr);\n+\t\t\tif (!mi->keep_subject) {\n+\t\t\t\tcleanup_subject(mi, hdr);\n \t\t\t\tcleanup_space(hdr);\n \t\t\t}\n \t\t\toutput_header_lines(fout, \"Subject\", hdr);\n@@ -1044,9 +1044,9 @@ int cmd_mailinfo(int argc, const char **argv, const char *prefix)\n \n \twhile (1 < argc && argv[1][0] == '-') {\n \t\tif (!strcmp(argv[1], \"-k\"))\n-\t\t\tkeep_subject = 1;\n+\t\t\tmi.keep_subject = 1;\n \t\telse if (!strcmp(argv[1], \"-b\"))\n-\t\t\tkeep_non_patch_brackets_in_subject = 1;\n+\t\t\tmi.keep_non_patch_brackets_in_subject = 1;\n \t\telse if (!strcmp(argv[1], \"-m\") || !strcmp(argv[1], \"--message-id\"))\n \t\t\tadd_message_id = 1;\n \t\telse if (!strcmp(argv[1], \"-u\"))\n-- \n2.6.1-320-g86a1181\n"},{"id":"271668","messageId":"1444855557-2127-12-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444855557-2127-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 11/31] mailinfo: move global \"FILE *fin, *fout\" to struct mailinfo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-14T20:45:37Z","receivedAt":"2015-10-14T20:45:37Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This requires us to pass \"struct mailinfo\" to more functions\nthroughout the codepath that read input lines, which makes\nlater steps easier.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 54 ++++++++++++++++++++++++++++--------------------------\n 1 file changed, 28 insertions(+), 26 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 855d813..68a085e 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -7,11 +7,14 @@\n #include \"utf8.h\"\n #include \"strbuf.h\"\n \n-static FILE *cmitmsg, *patchfile, *fin, *fout;\n+static FILE *cmitmsg, *patchfile;\n \n static const char *metainfo_charset;\n \n struct mailinfo {\n+\tFILE *input;\n+\tFILE *output;\n+\n \tstruct strbuf name;\n \tstruct strbuf email;\n \tint keep_subject;\n@@ -790,16 +793,17 @@ static void handle_filter(struct strbuf *line, int *filter_stage, int *header_st\n \t}\n }\n \n-static int find_boundary(struct strbuf *line)\n+static int find_boundary(struct mailinfo *mi, struct strbuf *line)\n {\n-\twhile (!strbuf_getline(line, fin, '\\n')) {\n+\twhile (!strbuf_getline(line, mi->input, '\\n')) {\n \t\tif (*content_top && is_multipart_boundary(line))\n \t\t\treturn 1;\n \t}\n \treturn 0;\n }\n \n-static int handle_boundary(struct strbuf *line, int *filter_stage, int *header_stage)\n+static int handle_boundary(struct mailinfo *mi, struct strbuf *line,\n+\t\t\t   int *filter_stage, int *header_stage)\n {\n \tstruct strbuf newline = STRBUF_INIT;\n \n@@ -825,7 +829,7 @@ again:\n \t\tstrbuf_release(&newline);\n \n \t\t/* skip to the next boundary */\n-\t\tif (!find_boundary(line))\n+\t\tif (!find_boundary(mi, line))\n \t\t\treturn 0;\n \t\tgoto again;\n \t}\n@@ -835,18 +839,18 @@ again:\n \tstrbuf_reset(&charset);\n \n \t/* slurp in this section's info */\n-\twhile (read_one_header_line(line, fin))\n+\twhile (read_one_header_line(line, mi->input))\n \t\tcheck_header(line, p_hdr_data, 0);\n \n \tstrbuf_release(&newline);\n \t/* replenish line */\n-\tif (strbuf_getline(line, fin, '\\n'))\n+\tif (strbuf_getline(line, mi->input, '\\n'))\n \t\treturn 0;\n \tstrbuf_addch(line, '\\n');\n \treturn 1;\n }\n \n-static void handle_body(struct strbuf *line)\n+static void handle_body(struct mailinfo *mi, struct strbuf *line)\n {\n \tstruct strbuf prev = STRBUF_INIT;\n \tint filter_stage = 0;\n@@ -854,7 +858,7 @@ static void handle_body(struct strbuf *line)\n \n \t/* Skip up to the first boundary */\n \tif (*content_top) {\n-\t\tif (!find_boundary(line))\n+\t\tif (!find_boundary(mi, line))\n \t\t\tgoto handle_body_out;\n \t}\n \n@@ -866,7 +870,7 @@ static void handle_body(struct strbuf *line)\n \t\t\t\thandle_filter(&prev, &filter_stage, &header_stage);\n \t\t\t\tstrbuf_reset(&prev);\n \t\t\t}\n-\t\t\tif (!handle_boundary(line, &filter_stage, &header_stage))\n+\t\t\tif (!handle_boundary(mi, line, &filter_stage, &header_stage))\n \t\t\t\tgoto handle_body_out;\n \t\t}\n \n@@ -909,7 +913,7 @@ static void handle_body(struct strbuf *line)\n \t\t\thandle_filter(line, &filter_stage, &header_stage);\n \t\t}\n \n-\t} while (!strbuf_getwholeline(line, fin, '\\n'));\n+\t} while (!strbuf_getwholeline(line, mi->input, '\\n'));\n \n handle_body_out:\n \tstrbuf_release(&prev);\n@@ -951,29 +955,25 @@ static void handle_info(struct mailinfo *mi)\n \t\t\t\tcleanup_subject(mi, hdr);\n \t\t\t\tcleanup_space(hdr);\n \t\t\t}\n-\t\t\toutput_header_lines(fout, \"Subject\", hdr);\n+\t\t\toutput_header_lines(mi->output, \"Subject\", hdr);\n \t\t} else if (!strcmp(header[i], \"From\")) {\n \t\t\tcleanup_space(hdr);\n \t\t\thandle_from(mi, hdr);\n-\t\t\tfprintf(fout, \"Author: %s\\n\", mi->name.buf);\n-\t\t\tfprintf(fout, \"Email: %s\\n\", mi->email.buf);\n+\t\t\tfprintf(mi->output, \"Author: %s\\n\", mi->name.buf);\n+\t\t\tfprintf(mi->output, \"Email: %s\\n\", mi->email.buf);\n \t\t} else {\n \t\t\tcleanup_space(hdr);\n-\t\t\tfprintf(fout, \"%s: %s\\n\", header[i], hdr->buf);\n+\t\t\tfprintf(mi->output, \"%s: %s\\n\", header[i], hdr->buf);\n \t\t}\n \t}\n-\tfprintf(fout, \"\\n\");\n+\tfprintf(mi->output, \"\\n\");\n }\n \n-static int mailinfo(struct mailinfo *mi,\n-\t\t    FILE *in, FILE *out, const char *msg, const char *patch)\n+static int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)\n {\n \tint peek;\n \tstruct strbuf line = STRBUF_INIT;\n \n-\tfin = in;\n-\tfout = out;\n-\n \tcmitmsg = fopen(msg, \"w\");\n \tif (!cmitmsg) {\n \t\tperror(msg);\n@@ -990,15 +990,15 @@ static int mailinfo(struct mailinfo *mi,\n \ts_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*s_hdr_data));\n \n \tdo {\n-\t\tpeek = fgetc(in);\n+\t\tpeek = fgetc(mi->input);\n \t} while (isspace(peek));\n-\tungetc(peek, in);\n+\tungetc(peek, mi->input);\n \n \t/* process the email header */\n-\twhile (read_one_header_line(&line, fin))\n+\twhile (read_one_header_line(&line, mi->input))\n \t\tcheck_header(&line, p_hdr_data, 1);\n \n-\thandle_body(&line);\n+\thandle_body(mi, &line);\n \tfclose(patchfile);\n \n \thandle_info(mi);\n@@ -1069,5 +1069,7 @@ int cmd_mailinfo(int argc, const char **argv, const char *prefix)\n \tif (argc != 3)\n \t\tusage(mailinfo_usage);\n \n-\treturn !!mailinfo(&mi, stdin, stdout, argv[1], argv[2]);\n+\tmi.input = stdin;\n+\tmi.output = stdout;\n+\treturn !!mailinfo(&mi, argv[1], argv[2]);\n }\n-- \n2.6.1-320-g86a1181\n"},{"id":"271676","messageId":"1444855557-2127-13-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444855557-2127-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 12/31] mailinfo: move filter/header stage to struct mailinfo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-14T20:45:38Z","receivedAt":"2015-10-14T20:45:38Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Earlier we got rid of two function-scope static variables that kept\ntrack of the states of helper functions by making them extra arguments\nthat are passed throughout the callchain.  Now we have a convenient\nplace to store and pass them around in the form of \"struct mailinfo\",\nchange them into two fields in the struct.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 42 ++++++++++++++++++++++--------------------\n 1 file changed, 22 insertions(+), 20 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 68a085e..5d2d88a 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -19,6 +19,9 @@ struct mailinfo {\n \tstruct strbuf email;\n \tint keep_subject;\n \tint keep_non_patch_brackets_in_subject;\n+\n+\tint filter_stage; /* still reading log or are we copying patch? */\n+\tint header_stage; /* still checking in-body headers? */\n };\n static char *message_id;\n \n@@ -28,6 +31,7 @@ static enum  {\n \n static struct strbuf charset = STRBUF_INIT;\n static int patch_lines;\n+\n static struct strbuf **p_hdr_data, **s_hdr_data;\n static int use_scissors;\n static int add_message_id;\n@@ -718,25 +722,25 @@ static int is_scissors_line(const struct strbuf *line)\n \t\tgap * 2 < perforation);\n }\n \n-static int handle_commit_msg(struct strbuf *line, int *still_looking)\n+static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n {\n \tif (!cmitmsg)\n \t\treturn 0;\n \n-\tif (*still_looking) {\n+\tif (mi->header_stage) {\n \t\tif (!line->len || (line->len == 1 && line->buf[0] == '\\n'))\n \t\t\treturn 0;\n \t}\n \n-\tif (use_inbody_headers && *still_looking) {\n-\t\t*still_looking = check_header(line, s_hdr_data, 0);\n-\t\tif (*still_looking)\n+\tif (use_inbody_headers && mi->header_stage) {\n+\t\tmi->header_stage = check_header(line, s_hdr_data, 0);\n+\t\tif (mi->header_stage)\n \t\t\treturn 0;\n \t} else\n \t\t/* Only trim the first (blank) line of the commit message\n \t\t * when ignoring in-body headers.\n \t\t */\n-\t\t*still_looking = 0;\n+\t\tmi->header_stage = 0;\n \n \t/* normalize the log message to UTF-8. */\n \tif (metainfo_charset)\n@@ -748,7 +752,7 @@ static int handle_commit_msg(struct strbuf *line, int *still_looking)\n \t\t\tdie_errno(\"Could not rewind output message file\");\n \t\tif (ftruncate(fileno(cmitmsg), 0))\n \t\t\tdie_errno(\"Could not truncate output message file at scissors\");\n-\t\t*still_looking = 1;\n+\t\tmi->header_stage = 1;\n \n \t\t/*\n \t\t * We may have already read \"secondary headers\"; purge\n@@ -780,13 +784,13 @@ static void handle_patch(const struct strbuf *line)\n \tpatch_lines++;\n }\n \n-static void handle_filter(struct strbuf *line, int *filter_stage, int *header_stage)\n+static void handle_filter(struct mailinfo *mi, struct strbuf *line)\n {\n-\tswitch (*filter_stage) {\n+\tswitch (mi->filter_stage) {\n \tcase 0:\n-\t\tif (!handle_commit_msg(line, header_stage))\n+\t\tif (!handle_commit_msg(mi, line))\n \t\t\tbreak;\n-\t\t(*filter_stage)++;\n+\t\tmi->filter_stage++;\n \tcase 1:\n \t\thandle_patch(line);\n \t\tbreak;\n@@ -802,8 +806,7 @@ static int find_boundary(struct mailinfo *mi, struct strbuf *line)\n \treturn 0;\n }\n \n-static int handle_boundary(struct mailinfo *mi, struct strbuf *line,\n-\t\t\t   int *filter_stage, int *header_stage)\n+static int handle_boundary(struct mailinfo *mi, struct strbuf *line)\n {\n \tstruct strbuf newline = STRBUF_INIT;\n \n@@ -825,7 +828,7 @@ again:\n \t\t\t\t\t\"can't recover\\n\");\n \t\t\texit(1);\n \t\t}\n-\t\thandle_filter(&newline, filter_stage, header_stage);\n+\t\thandle_filter(mi, &newline);\n \t\tstrbuf_release(&newline);\n \n \t\t/* skip to the next boundary */\n@@ -853,8 +856,6 @@ again:\n static void handle_body(struct mailinfo *mi, struct strbuf *line)\n {\n \tstruct strbuf prev = STRBUF_INIT;\n-\tint filter_stage = 0;\n-\tint header_stage = 1;\n \n \t/* Skip up to the first boundary */\n \tif (*content_top) {\n@@ -867,10 +868,10 @@ static void handle_body(struct mailinfo *mi, struct strbuf *line)\n \t\tif (*content_top && is_multipart_boundary(line)) {\n \t\t\t/* flush any leftover */\n \t\t\tif (prev.len) {\n-\t\t\t\thandle_filter(&prev, &filter_stage, &header_stage);\n+\t\t\t\thandle_filter(mi, &prev);\n \t\t\t\tstrbuf_reset(&prev);\n \t\t\t}\n-\t\t\tif (!handle_boundary(mi, line, &filter_stage, &header_stage))\n+\t\t\tif (!handle_boundary(mi, line))\n \t\t\t\tgoto handle_body_out;\n \t\t}\n \n@@ -900,7 +901,7 @@ static void handle_body(struct mailinfo *mi, struct strbuf *line)\n \t\t\t\t\t\tstrbuf_addbuf(&prev, sb);\n \t\t\t\t\t\tbreak;\n \t\t\t\t\t}\n-\t\t\t\thandle_filter(sb, &filter_stage, &header_stage);\n+\t\t\t\thandle_filter(mi, sb);\n \t\t\t}\n \t\t\t/*\n \t\t\t * The partial chunk is saved in \"prev\" and will be\n@@ -910,7 +911,7 @@ static void handle_body(struct mailinfo *mi, struct strbuf *line)\n \t\t\tbreak;\n \t\t}\n \t\tdefault:\n-\t\t\thandle_filter(line, &filter_stage, &header_stage);\n+\t\t\thandle_filter(mi, line);\n \t\t}\n \n \t} while (!strbuf_getwholeline(line, mi->input, '\\n'));\n@@ -1023,6 +1024,7 @@ static void setup_mailinfo(struct mailinfo *mi)\n \tmemset(mi, 0, sizeof(*mi));\n \tstrbuf_init(&mi->name, 0);\n \tstrbuf_init(&mi->email, 0);\n+\tmi->header_stage = 1;\n \tgit_config(git_mailinfo_config, &mi);\n }\n \n-- \n2.6.1-320-g86a1181\n"},{"id":"271671","messageId":"1444855557-2127-14-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444855557-2127-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 13/31] mailinfo: move patch_lines to struct mailinfo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-14T20:45:39Z","receivedAt":"2015-10-14T20:45:39Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This one is trivial thanks to previous steps that started passing\nthe structure throughout the input codepaths.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 10 +++++-----\n 1 file changed, 5 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 5d2d88a..f451ba4 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -20,6 +20,7 @@ struct mailinfo {\n \tint keep_subject;\n \tint keep_non_patch_brackets_in_subject;\n \n+\tint patch_lines;\n \tint filter_stage; /* still reading log or are we copying patch? */\n \tint header_stage; /* still checking in-body headers? */\n };\n@@ -30,7 +31,6 @@ static enum  {\n } transfer_encoding;\n \n static struct strbuf charset = STRBUF_INIT;\n-static int patch_lines;\n \n static struct strbuf **p_hdr_data, **s_hdr_data;\n static int use_scissors;\n@@ -778,10 +778,10 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n \treturn 0;\n }\n \n-static void handle_patch(const struct strbuf *line)\n+static void handle_patch(struct mailinfo *mi, const struct strbuf *line)\n {\n \tfwrite(line->buf, 1, line->len, patchfile);\n-\tpatch_lines++;\n+\tmi->patch_lines++;\n }\n \n static void handle_filter(struct mailinfo *mi, struct strbuf *line)\n@@ -792,7 +792,7 @@ static void handle_filter(struct mailinfo *mi, struct strbuf *line)\n \t\t\tbreak;\n \t\tmi->filter_stage++;\n \tcase 1:\n-\t\thandle_patch(line);\n+\t\thandle_patch(mi, line);\n \t\tbreak;\n \t}\n }\n@@ -944,7 +944,7 @@ static void handle_info(struct mailinfo *mi)\n \n \tfor (i = 0; header[i]; i++) {\n \t\t/* only print inbody headers if we output a patch file */\n-\t\tif (patch_lines && s_hdr_data[i])\n+\t\tif (mi->patch_lines && s_hdr_data[i])\n \t\t\thdr = s_hdr_data[i];\n \t\telse if (p_hdr_data[i])\n \t\t\thdr = p_hdr_data[i];\n-- \n2.6.1-320-g86a1181\n"},{"id":"271677","messageId":"1444855557-2127-15-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444855557-2127-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 14/31] mailinfo: move add_message_id and message_id to struct mailinfo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-14T20:45:40Z","receivedAt":"2015-10-14T20:45:40Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This requires us to pass the structure into check_header() codepath.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 30 ++++++++++++++++--------------\n 1 file changed, 16 insertions(+), 14 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex f451ba4..6703453 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -19,12 +19,13 @@ struct mailinfo {\n \tstruct strbuf email;\n \tint keep_subject;\n \tint keep_non_patch_brackets_in_subject;\n+\tint add_message_id;\n \n+\tchar *message_id;\n \tint patch_lines;\n \tint filter_stage; /* still reading log or are we copying patch? */\n \tint header_stage; /* still checking in-body headers? */\n };\n-static char *message_id;\n \n static enum  {\n \tTE_DONTCARE, TE_QP, TE_BASE64\n@@ -34,7 +35,6 @@ static struct strbuf charset = STRBUF_INIT;\n \n static struct strbuf **p_hdr_data, **s_hdr_data;\n static int use_scissors;\n-static int add_message_id;\n static int use_inbody_headers = 1;\n \n #define MAX_HDR_PARSED 10\n@@ -209,10 +209,10 @@ static void handle_content_type(struct strbuf *line)\n \t}\n }\n \n-static void handle_message_id(const struct strbuf *line)\n+static void handle_message_id(struct mailinfo *mi, const struct strbuf *line)\n {\n-\tif (add_message_id)\n-\t\tmessage_id = strdup(line->buf);\n+\tif (mi->add_message_id)\n+\t\tmi->message_id = strdup(line->buf);\n }\n \n static void handle_content_transfer_encoding(const struct strbuf *line)\n@@ -321,11 +321,13 @@ static int is_format_patch_separator(const char *line, int len)\n \treturn !memcmp(SAMPLE + (cp - line), cp, strlen(SAMPLE) - (cp - line));\n }\n \n-static int check_header(const struct strbuf *line,\n-\t\t\t\tstruct strbuf *hdr_data[], int overwrite)\n+static int check_header(struct mailinfo *mi,\n+\t\t\tconst struct strbuf *line,\n+\t\t\tstruct strbuf *hdr_data[], int overwrite)\n {\n \tint i, ret = 0, len;\n \tstruct strbuf sb = STRBUF_INIT;\n+\n \t/* search for the interesting parts */\n \tfor (i = 0; header[i]; i++) {\n \t\tint len = strlen(header[i]);\n@@ -363,7 +365,7 @@ static int check_header(const struct strbuf *line,\n \t\tlen = strlen(\"Message-Id: \");\n \t\tstrbuf_add(&sb, line->buf + len, line->len - len);\n \t\tdecode_header(&sb);\n-\t\thandle_message_id(&sb);\n+\t\thandle_message_id(mi, &sb);\n \t\tret = 1;\n \t\tgoto check_header_out;\n \t}\n@@ -733,7 +735,7 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n \t}\n \n \tif (use_inbody_headers && mi->header_stage) {\n-\t\tmi->header_stage = check_header(line, s_hdr_data, 0);\n+\t\tmi->header_stage = check_header(mi, line, s_hdr_data, 0);\n \t\tif (mi->header_stage)\n \t\t\treturn 0;\n \t} else\n@@ -767,8 +769,8 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n \t}\n \n \tif (patchbreak(line)) {\n-\t\tif (message_id)\n-\t\t\tfprintf(cmitmsg, \"Message-Id: %s\\n\", message_id);\n+\t\tif (mi->message_id)\n+\t\t\tfprintf(cmitmsg, \"Message-Id: %s\\n\", mi->message_id);\n \t\tfclose(cmitmsg);\n \t\tcmitmsg = NULL;\n \t\treturn 1;\n@@ -843,7 +845,7 @@ again:\n \n \t/* slurp in this section's info */\n \twhile (read_one_header_line(line, mi->input))\n-\t\tcheck_header(line, p_hdr_data, 0);\n+\t\tcheck_header(mi, line, p_hdr_data, 0);\n \n \tstrbuf_release(&newline);\n \t/* replenish line */\n@@ -997,7 +999,7 @@ static int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)\n \n \t/* process the email header */\n \twhile (read_one_header_line(&line, mi->input))\n-\t\tcheck_header(&line, p_hdr_data, 1);\n+\t\tcheck_header(mi, &line, p_hdr_data, 1);\n \n \thandle_body(mi, &line);\n \tfclose(patchfile);\n@@ -1050,7 +1052,7 @@ int cmd_mailinfo(int argc, const char **argv, const char *prefix)\n \t\telse if (!strcmp(argv[1], \"-b\"))\n \t\t\tmi.keep_non_patch_brackets_in_subject = 1;\n \t\telse if (!strcmp(argv[1], \"-m\") || !strcmp(argv[1], \"--message-id\"))\n-\t\t\tadd_message_id = 1;\n+\t\t\tmi.add_message_id = 1;\n \t\telse if (!strcmp(argv[1], \"-u\"))\n \t\t\tmetainfo_charset = def_charset;\n \t\telse if (!strcmp(argv[1], \"-n\"))\n-- \n2.6.1-320-g86a1181\n"},{"id":"271678","messageId":"1444855557-2127-16-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444855557-2127-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 15/31] mailinfo: move use_scissors and use_inbody_headers to struct mailinfo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-14T20:45:41Z","receivedAt":"2015-10-14T20:45:41Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Signed-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 23 +++++++++++++----------\n 1 file changed, 13 insertions(+), 10 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 6703453..80034a2 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -20,6 +20,8 @@ struct mailinfo {\n \tint keep_subject;\n \tint keep_non_patch_brackets_in_subject;\n \tint add_message_id;\n+\tint use_scissors;\n+\tint use_inbody_headers; /* defaults to 1 */\n \n \tchar *message_id;\n \tint patch_lines;\n@@ -34,8 +36,6 @@ static enum  {\n static struct strbuf charset = STRBUF_INIT;\n \n static struct strbuf **p_hdr_data, **s_hdr_data;\n-static int use_scissors;\n-static int use_inbody_headers = 1;\n \n #define MAX_HDR_PARSED 10\n #define MAX_BOUNDARIES 5\n@@ -734,7 +734,7 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n \t\t\treturn 0;\n \t}\n \n-\tif (use_inbody_headers && mi->header_stage) {\n+\tif (mi->use_inbody_headers && mi->header_stage) {\n \t\tmi->header_stage = check_header(mi, line, s_hdr_data, 0);\n \t\tif (mi->header_stage)\n \t\t\treturn 0;\n@@ -748,7 +748,7 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n \tif (metainfo_charset)\n \t\tconvert_to_utf8(line, charset.buf);\n \n-\tif (use_scissors && is_scissors_line(line)) {\n+\tif (mi->use_scissors && is_scissors_line(line)) {\n \t\tint i;\n \t\tif (fseek(cmitmsg, 0L, SEEK_SET))\n \t\t\tdie_errno(\"Could not rewind output message file\");\n@@ -1009,12 +1009,14 @@ static int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)\n \treturn 0;\n }\n \n-static int git_mailinfo_config(const char *var, const char *value, void *unused)\n+static int git_mailinfo_config(const char *var, const char *value, void *mi_)\n {\n+\tstruct mailinfo *mi = mi_;\n+\n \tif (!starts_with(var, \"mailinfo.\"))\n-\t\treturn git_default_config(var, value, unused);\n+\t\treturn git_default_config(var, value, NULL);\n \tif (!strcmp(var, \"mailinfo.scissors\")) {\n-\t\tuse_scissors = git_config_bool(var, value);\n+\t\tmi->use_scissors = git_config_bool(var, value);\n \t\treturn 0;\n \t}\n \t/* perhaps others here */\n@@ -1027,6 +1029,7 @@ static void setup_mailinfo(struct mailinfo *mi)\n \tstrbuf_init(&mi->name, 0);\n \tstrbuf_init(&mi->email, 0);\n \tmi->header_stage = 1;\n+\tmi->use_inbody_headers = 1;\n \tgit_config(git_mailinfo_config, &mi);\n }\n \n@@ -1060,11 +1063,11 @@ int cmd_mailinfo(int argc, const char **argv, const char *prefix)\n \t\telse if (starts_with(argv[1], \"--encoding=\"))\n \t\t\tmetainfo_charset = argv[1] + 11;\n \t\telse if (!strcmp(argv[1], \"--scissors\"))\n-\t\t\tuse_scissors = 1;\n+\t\t\tmi.use_scissors = 1;\n \t\telse if (!strcmp(argv[1], \"--no-scissors\"))\n-\t\t\tuse_scissors = 0;\n+\t\t\tmi.use_scissors = 0;\n \t\telse if (!strcmp(argv[1], \"--no-inbody-headers\"))\n-\t\t\tuse_inbody_headers = 0;\n+\t\t\tmi.use_inbody_headers = 0;\n \t\telse\n \t\t\tusage(mailinfo_usage);\n \t\targc--; argv++;\n-- \n2.6.1-320-g86a1181\n"},{"id":"271680","messageId":"1444855557-2127-17-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444855557-2127-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 16/31] mailinfo: move metainfo_charset to struct mailinfo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-14T20:45:42Z","receivedAt":"2015-10-14T20:45:42Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This requires us to pass the struct down to decode_header() and\nconvert_to_utf8() callchain.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 40 +++++++++++++++++++---------------------\n 1 file changed, 19 insertions(+), 21 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 80034a2..00b8b4b 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -9,8 +9,6 @@\n \n static FILE *cmitmsg, *patchfile;\n \n-static const char *metainfo_charset;\n-\n struct mailinfo {\n \tFILE *input;\n \tFILE *output;\n@@ -22,6 +20,7 @@ struct mailinfo {\n \tint add_message_id;\n \tint use_scissors;\n \tint use_inbody_headers; /* defaults to 1 */\n+\tconst char *metainfo_charset;\n \n \tchar *message_id;\n \tint patch_lines;\n@@ -293,7 +292,7 @@ static void cleanup_space(struct strbuf *sb)\n \t}\n }\n \n-static void decode_header(struct strbuf *line);\n+static void decode_header(struct mailinfo *mi, struct strbuf *line);\n static const char *header[MAX_HDR_PARSED] = {\n \t\"From\",\"Subject\",\"Date\",\n };\n@@ -336,7 +335,7 @@ static int check_header(struct mailinfo *mi,\n \t\t\t * normalize the meta information to utf8.\n \t\t\t */\n \t\t\tstrbuf_add(&sb, line->buf + len + 2, line->len - len - 2);\n-\t\t\tdecode_header(&sb);\n+\t\t\tdecode_header(mi, &sb);\n \t\t\thandle_header(&hdr_data[i], &sb);\n \t\t\tret = 1;\n \t\t\tgoto check_header_out;\n@@ -347,7 +346,7 @@ static int check_header(struct mailinfo *mi,\n \tif (cmp_header(line, \"Content-Type\")) {\n \t\tlen = strlen(\"Content-Type: \");\n \t\tstrbuf_add(&sb, line->buf + len, line->len - len);\n-\t\tdecode_header(&sb);\n+\t\tdecode_header(mi, &sb);\n \t\tstrbuf_insert(&sb, 0, \"Content-Type: \", len);\n \t\thandle_content_type(&sb);\n \t\tret = 1;\n@@ -356,7 +355,7 @@ static int check_header(struct mailinfo *mi,\n \tif (cmp_header(line, \"Content-Transfer-Encoding\")) {\n \t\tlen = strlen(\"Content-Transfer-Encoding: \");\n \t\tstrbuf_add(&sb, line->buf + len, line->len - len);\n-\t\tdecode_header(&sb);\n+\t\tdecode_header(mi, &sb);\n \t\thandle_content_transfer_encoding(&sb);\n \t\tret = 1;\n \t\tgoto check_header_out;\n@@ -364,7 +363,7 @@ static int check_header(struct mailinfo *mi,\n \tif (cmp_header(line, \"Message-Id\")) {\n \t\tlen = strlen(\"Message-Id: \");\n \t\tstrbuf_add(&sb, line->buf + len, line->len - len);\n-\t\tdecode_header(&sb);\n+\t\tdecode_header(mi, &sb);\n \t\thandle_message_id(mi, &sb);\n \t\tret = 1;\n \t\tgoto check_header_out;\n@@ -520,23 +519,24 @@ static struct strbuf *decode_b_segment(const struct strbuf *b_seg)\n \treturn out;\n }\n \n-static void convert_to_utf8(struct strbuf *line, const char *charset)\n+static void convert_to_utf8(struct mailinfo *mi,\n+\t\t\t    struct strbuf *line, const char *charset)\n {\n \tchar *out;\n \n-\tif (!charset || !*charset)\n+\tif (!mi->metainfo_charset || !charset || !*charset)\n \t\treturn;\n \n-\tif (same_encoding(metainfo_charset, charset))\n+\tif (same_encoding(mi->metainfo_charset, charset))\n \t\treturn;\n-\tout = reencode_string(line->buf, metainfo_charset, charset);\n+\tout = reencode_string(line->buf, mi->metainfo_charset, charset);\n \tif (!out)\n \t\tdie(\"cannot convert from %s to %s\",\n-\t\t    charset, metainfo_charset);\n+\t\t    charset, mi->metainfo_charset);\n \tstrbuf_attach(line, out, strlen(out), strlen(out));\n }\n \n-static void decode_header(struct strbuf *it)\n+static void decode_header(struct mailinfo *mi, struct strbuf *it)\n {\n \tchar *in, *ep, *cp;\n \tstruct strbuf outbuf = STRBUF_INIT, *dec;\n@@ -599,8 +599,7 @@ static void decode_header(struct strbuf *it)\n \t\t\tdec = decode_q_segment(&piecebuf, 1);\n \t\t\tbreak;\n \t\t}\n-\t\tif (metainfo_charset)\n-\t\t\tconvert_to_utf8(dec, charset_q.buf);\n+\t\tconvert_to_utf8(mi, dec, charset_q.buf);\n \n \t\tstrbuf_addbuf(&outbuf, dec);\n \t\tstrbuf_release(dec);\n@@ -745,8 +744,7 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n \t\tmi->header_stage = 0;\n \n \t/* normalize the log message to UTF-8. */\n-\tif (metainfo_charset)\n-\t\tconvert_to_utf8(line, charset.buf);\n+\tconvert_to_utf8(mi, line, charset.buf);\n \n \tif (mi->use_scissors && is_scissors_line(line)) {\n \t\tint i;\n@@ -1047,7 +1045,7 @@ int cmd_mailinfo(int argc, const char **argv, const char *prefix)\n \tsetup_mailinfo(&mi);\n \n \tdef_charset = get_commit_output_encoding();\n-\tmetainfo_charset = def_charset;\n+\tmi.metainfo_charset = def_charset;\n \n \twhile (1 < argc && argv[1][0] == '-') {\n \t\tif (!strcmp(argv[1], \"-k\"))\n@@ -1057,11 +1055,11 @@ int cmd_mailinfo(int argc, const char **argv, const char *prefix)\n \t\telse if (!strcmp(argv[1], \"-m\") || !strcmp(argv[1], \"--message-id\"))\n \t\t\tmi.add_message_id = 1;\n \t\telse if (!strcmp(argv[1], \"-u\"))\n-\t\t\tmetainfo_charset = def_charset;\n+\t\t\tmi.metainfo_charset = def_charset;\n \t\telse if (!strcmp(argv[1], \"-n\"))\n-\t\t\tmetainfo_charset = NULL;\n+\t\t\tmi.metainfo_charset = NULL;\n \t\telse if (starts_with(argv[1], \"--encoding=\"))\n-\t\t\tmetainfo_charset = argv[1] + 11;\n+\t\t\tmi.metainfo_charset = argv[1] + 11;\n \t\telse if (!strcmp(argv[1], \"--scissors\"))\n \t\t\tmi.use_scissors = 1;\n \t\telse if (!strcmp(argv[1], \"--no-scissors\"))\n-- \n2.6.1-320-g86a1181\n"},{"id":"271666","messageId":"1444855557-2127-18-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444855557-2127-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 17/31] mailinfo: move transfer_encoding to struct mailinfo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-14T20:45:43Z","receivedAt":"2015-10-14T20:45:43Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Signed-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 27 ++++++++++++++-------------\n 1 file changed, 14 insertions(+), 13 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 00b8b4b..140b31ee 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -23,14 +23,14 @@ struct mailinfo {\n \tconst char *metainfo_charset;\n \n \tchar *message_id;\n+\tenum  {\n+\t\tTE_DONTCARE, TE_QP, TE_BASE64\n+\t} transfer_encoding;\n \tint patch_lines;\n \tint filter_stage; /* still reading log or are we copying patch? */\n \tint header_stage; /* still checking in-body headers? */\n };\n \n-static enum  {\n-\tTE_DONTCARE, TE_QP, TE_BASE64\n-} transfer_encoding;\n \n static struct strbuf charset = STRBUF_INIT;\n \n@@ -214,14 +214,15 @@ static void handle_message_id(struct mailinfo *mi, const struct strbuf *line)\n \t\tmi->message_id = strdup(line->buf);\n }\n \n-static void handle_content_transfer_encoding(const struct strbuf *line)\n+static void handle_content_transfer_encoding(struct mailinfo *mi,\n+\t\t\t\t\t     const struct strbuf *line)\n {\n \tif (strcasestr(line->buf, \"base64\"))\n-\t\ttransfer_encoding = TE_BASE64;\n+\t\tmi->transfer_encoding = TE_BASE64;\n \telse if (strcasestr(line->buf, \"quoted-printable\"))\n-\t\ttransfer_encoding = TE_QP;\n+\t\tmi->transfer_encoding = TE_QP;\n \telse\n-\t\ttransfer_encoding = TE_DONTCARE;\n+\t\tmi->transfer_encoding = TE_DONTCARE;\n }\n \n static int is_multipart_boundary(const struct strbuf *line)\n@@ -356,7 +357,7 @@ static int check_header(struct mailinfo *mi,\n \t\tlen = strlen(\"Content-Transfer-Encoding: \");\n \t\tstrbuf_add(&sb, line->buf + len, line->len - len);\n \t\tdecode_header(mi, &sb);\n-\t\thandle_content_transfer_encoding(&sb);\n+\t\thandle_content_transfer_encoding(mi, &sb);\n \t\tret = 1;\n \t\tgoto check_header_out;\n \t}\n@@ -615,11 +616,11 @@ release_return:\n \tstrbuf_release(&piecebuf);\n }\n \n-static void decode_transfer_encoding(struct strbuf *line)\n+static void decode_transfer_encoding(struct mailinfo *mi, struct strbuf *line)\n {\n \tstruct strbuf *ret;\n \n-\tswitch (transfer_encoding) {\n+\tswitch (mi->transfer_encoding) {\n \tcase TE_QP:\n \t\tret = decode_q_segment(line, 0);\n \t\tbreak;\n@@ -838,7 +839,7 @@ again:\n \t}\n \n \t/* set some defaults */\n-\ttransfer_encoding = TE_DONTCARE;\n+\tmi->transfer_encoding = TE_DONTCARE;\n \tstrbuf_reset(&charset);\n \n \t/* slurp in this section's info */\n@@ -876,9 +877,9 @@ static void handle_body(struct mailinfo *mi, struct strbuf *line)\n \t\t}\n \n \t\t/* Unwrap transfer encoding */\n-\t\tdecode_transfer_encoding(line);\n+\t\tdecode_transfer_encoding(mi, line);\n \n-\t\tswitch (transfer_encoding) {\n+\t\tswitch (mi->transfer_encoding) {\n \t\tcase TE_BASE64:\n \t\tcase TE_QP:\n \t\t{\n-- \n2.6.1-320-g86a1181\n"},{"id":"271697","messageId":"1444855557-2127-19-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444855557-2127-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 18/31] mailinfo: move charset to struct mailinfo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-14T20:45:44Z","receivedAt":"2015-10-14T20:45:44Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Signed-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 15 +++++++--------\n 1 file changed, 7 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 140b31ee..41f659d 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -22,6 +22,7 @@ struct mailinfo {\n \tint use_inbody_headers; /* defaults to 1 */\n \tconst char *metainfo_charset;\n \n+\tstruct strbuf charset;\n \tchar *message_id;\n \tenum  {\n \t\tTE_DONTCARE, TE_QP, TE_BASE64\n@@ -31,9 +32,6 @@ struct mailinfo {\n \tint header_stage; /* still checking in-body headers? */\n };\n \n-\n-static struct strbuf charset = STRBUF_INIT;\n-\n static struct strbuf **p_hdr_data, **s_hdr_data;\n \n #define MAX_HDR_PARSED 10\n@@ -186,7 +184,7 @@ static struct strbuf *content[MAX_BOUNDARIES];\n \n static struct strbuf **content_top = content;\n \n-static void handle_content_type(struct strbuf *line)\n+static void handle_content_type(struct mailinfo *mi, struct strbuf *line)\n {\n \tstruct strbuf *boundary = xmalloc(sizeof(struct strbuf));\n \tstrbuf_init(boundary, line->len);\n@@ -200,7 +198,7 @@ static void handle_content_type(struct strbuf *line)\n \t\t*content_top = boundary;\n \t\tboundary = NULL;\n \t}\n-\tslurp_attr(line->buf, \"charset=\", &charset);\n+\tslurp_attr(line->buf, \"charset=\", &mi->charset);\n \n \tif (boundary) {\n \t\tstrbuf_release(boundary);\n@@ -349,7 +347,7 @@ static int check_header(struct mailinfo *mi,\n \t\tstrbuf_add(&sb, line->buf + len, line->len - len);\n \t\tdecode_header(mi, &sb);\n \t\tstrbuf_insert(&sb, 0, \"Content-Type: \", len);\n-\t\thandle_content_type(&sb);\n+\t\thandle_content_type(mi, &sb);\n \t\tret = 1;\n \t\tgoto check_header_out;\n \t}\n@@ -745,7 +743,7 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n \t\tmi->header_stage = 0;\n \n \t/* normalize the log message to UTF-8. */\n-\tconvert_to_utf8(mi, line, charset.buf);\n+\tconvert_to_utf8(mi, line, mi->charset.buf);\n \n \tif (mi->use_scissors && is_scissors_line(line)) {\n \t\tint i;\n@@ -840,7 +838,7 @@ again:\n \n \t/* set some defaults */\n \tmi->transfer_encoding = TE_DONTCARE;\n-\tstrbuf_reset(&charset);\n+\tstrbuf_reset(&mi->charset);\n \n \t/* slurp in this section's info */\n \twhile (read_one_header_line(line, mi->input))\n@@ -1027,6 +1025,7 @@ static void setup_mailinfo(struct mailinfo *mi)\n \tmemset(mi, 0, sizeof(*mi));\n \tstrbuf_init(&mi->name, 0);\n \tstrbuf_init(&mi->email, 0);\n+\tstrbuf_init(&mi->charset, 0);\n \tmi->header_stage = 1;\n \tmi->use_inbody_headers = 1;\n \tgit_config(git_mailinfo_config, &mi);\n-- \n2.6.1-320-g86a1181\n"},{"id":"271695","messageId":"1444855557-2127-20-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444855557-2127-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 19/31] mailinfo: handle_commit_msg() shouldn't be called after finding patchbreak","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-14T20:45:45Z","receivedAt":"2015-10-14T20:45:45Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"There is a strange \"if (!cmitmsg) return 0\" at the very beginning of\nhandle_commit_msg(), but the condition should never trigger,\nbecause:\n\n * The only place cmitmsg is set to NULL is after this function sees\n   a patch break, closes the FILE * to write the commit log message\n   and returns 1.  This function returns non-zero only from that\n   codepath.\n\n * The caller of this function, upon seeing a non-zero return,\n   increments filter_stage, starts treating the input as patch text\n   and will never call handle_commit_msg() again.\n\nReplace it with an assert(!mi->filter_stage).\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 3 +--\n 1 file changed, 1 insertion(+), 2 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 41f659d..f48a260 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -724,8 +724,7 @@ static int is_scissors_line(const struct strbuf *line)\n \n static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n {\n-\tif (!cmitmsg)\n-\t\treturn 0;\n+\tassert(!mi->filter_stage);\n \n \tif (mi->header_stage) {\n \t\tif (!line->len || (line->len == 1 && line->buf[0] == '\\n'))\n-- \n2.6.1-320-g86a1181\n"},{"id":"271692","messageId":"1444855557-2127-21-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444855557-2127-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 20/31] mailinfo: move cmitmsg and patchfile to struct mailinfo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-14T20:45:46Z","receivedAt":"2015-10-14T20:45:46Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Signed-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 28 ++++++++++++++--------------\n 1 file changed, 14 insertions(+), 14 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex f48a260..5809e13 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -7,11 +7,11 @@\n #include \"utf8.h\"\n #include \"strbuf.h\"\n \n-static FILE *cmitmsg, *patchfile;\n-\n struct mailinfo {\n \tFILE *input;\n \tFILE *output;\n+\tFILE *cmitmsg;\n+\tFILE *patchfile;\n \n \tstruct strbuf name;\n \tstruct strbuf email;\n@@ -746,9 +746,9 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n \n \tif (mi->use_scissors && is_scissors_line(line)) {\n \t\tint i;\n-\t\tif (fseek(cmitmsg, 0L, SEEK_SET))\n+\t\tif (fseek(mi->cmitmsg, 0L, SEEK_SET))\n \t\t\tdie_errno(\"Could not rewind output message file\");\n-\t\tif (ftruncate(fileno(cmitmsg), 0))\n+\t\tif (ftruncate(fileno(mi->cmitmsg), 0))\n \t\t\tdie_errno(\"Could not truncate output message file at scissors\");\n \t\tmi->header_stage = 1;\n \n@@ -766,19 +766,19 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n \n \tif (patchbreak(line)) {\n \t\tif (mi->message_id)\n-\t\t\tfprintf(cmitmsg, \"Message-Id: %s\\n\", mi->message_id);\n-\t\tfclose(cmitmsg);\n-\t\tcmitmsg = NULL;\n+\t\t\tfprintf(mi->cmitmsg, \"Message-Id: %s\\n\", mi->message_id);\n+\t\tfclose(mi->cmitmsg);\n+\t\tmi->cmitmsg = NULL;\n \t\treturn 1;\n \t}\n \n-\tfputs(line->buf, cmitmsg);\n+\tfputs(line->buf, mi->cmitmsg);\n \treturn 0;\n }\n \n static void handle_patch(struct mailinfo *mi, const struct strbuf *line)\n {\n-\tfwrite(line->buf, 1, line->len, patchfile);\n+\tfwrite(line->buf, 1, line->len, mi->patchfile);\n \tmi->patch_lines++;\n }\n \n@@ -973,15 +973,15 @@ static int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)\n \tint peek;\n \tstruct strbuf line = STRBUF_INIT;\n \n-\tcmitmsg = fopen(msg, \"w\");\n-\tif (!cmitmsg) {\n+\tmi->cmitmsg = fopen(msg, \"w\");\n+\tif (!mi->cmitmsg) {\n \t\tperror(msg);\n \t\treturn -1;\n \t}\n-\tpatchfile = fopen(patch, \"w\");\n-\tif (!patchfile) {\n+\tmi->patchfile = fopen(patch, \"w\");\n+\tif (!mi->patchfile) {\n \t\tperror(patch);\n-\t\tfclose(cmitmsg);\n+\t\tfclose(mi->cmitmsg);\n \t\treturn -1;\n \t}\n \n-- \n2.6.1-320-g86a1181\n"},{"id":"271688","messageId":"1444855557-2127-22-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444855557-2127-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 21/31] mailinfo: move [ps]_hdr_data to struct mailinfo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-14T20:45:47Z","receivedAt":"2015-10-14T20:45:47Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Signed-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 30 +++++++++++++++---------------\n 1 file changed, 15 insertions(+), 15 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 5809e13..aa17c77 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -30,10 +30,10 @@ struct mailinfo {\n \tint patch_lines;\n \tint filter_stage; /* still reading log or are we copying patch? */\n \tint header_stage; /* still checking in-body headers? */\n+\tstruct strbuf **p_hdr_data;\n+\tstruct strbuf **s_hdr_data;\n };\n \n-static struct strbuf **p_hdr_data, **s_hdr_data;\n-\n #define MAX_HDR_PARSED 10\n #define MAX_BOUNDARIES 5\n \n@@ -732,7 +732,7 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n \t}\n \n \tif (mi->use_inbody_headers && mi->header_stage) {\n-\t\tmi->header_stage = check_header(mi, line, s_hdr_data, 0);\n+\t\tmi->header_stage = check_header(mi, line, mi->s_hdr_data, 0);\n \t\tif (mi->header_stage)\n \t\t\treturn 0;\n \t} else\n@@ -757,9 +757,9 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n \t\t * them to give ourselves a clean restart.\n \t\t */\n \t\tfor (i = 0; header[i]; i++) {\n-\t\t\tif (s_hdr_data[i])\n-\t\t\t\tstrbuf_release(s_hdr_data[i]);\n-\t\t\ts_hdr_data[i] = NULL;\n+\t\t\tif (mi->s_hdr_data[i])\n+\t\t\t\tstrbuf_release(mi->s_hdr_data[i]);\n+\t\t\tmi->s_hdr_data[i] = NULL;\n \t\t}\n \t\treturn 0;\n \t}\n@@ -841,7 +841,7 @@ again:\n \n \t/* slurp in this section's info */\n \twhile (read_one_header_line(line, mi->input))\n-\t\tcheck_header(mi, line, p_hdr_data, 0);\n+\t\tcheck_header(mi, line, mi->p_hdr_data, 0);\n \n \tstrbuf_release(&newline);\n \t/* replenish line */\n@@ -942,10 +942,10 @@ static void handle_info(struct mailinfo *mi)\n \n \tfor (i = 0; header[i]; i++) {\n \t\t/* only print inbody headers if we output a patch file */\n-\t\tif (mi->patch_lines && s_hdr_data[i])\n-\t\t\thdr = s_hdr_data[i];\n-\t\telse if (p_hdr_data[i])\n-\t\t\thdr = p_hdr_data[i];\n+\t\tif (mi->patch_lines && mi->s_hdr_data[i])\n+\t\t\thdr = mi->s_hdr_data[i];\n+\t\telse if (mi->p_hdr_data[i])\n+\t\t\thdr = mi->p_hdr_data[i];\n \t\telse\n \t\t\tcontinue;\n \n@@ -985,8 +985,8 @@ static int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)\n \t\treturn -1;\n \t}\n \n-\tp_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*p_hdr_data));\n-\ts_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*s_hdr_data));\n+\tmi->p_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*(mi->p_hdr_data)));\n+\tmi->s_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*(mi->s_hdr_data)));\n \n \tdo {\n \t\tpeek = fgetc(mi->input);\n@@ -995,10 +995,10 @@ static int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)\n \n \t/* process the email header */\n \twhile (read_one_header_line(&line, mi->input))\n-\t\tcheck_header(mi, &line, p_hdr_data, 1);\n+\t\tcheck_header(mi, &line, mi->p_hdr_data, 1);\n \n \thandle_body(mi, &line);\n-\tfclose(patchfile);\n+\tfclose(mi->patchfile);\n \n \thandle_info(mi);\n \n-- \n2.6.1-320-g86a1181\n"},{"id":"271665","messageId":"1444855557-2127-23-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444855557-2127-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 22/31] mailinfo: keep the parsed log message in a strbuf","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-14T20:45:48Z","receivedAt":"2015-10-14T20:45:48Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"When mailinfo() is eventually libified, the calling \"git am\" still\nwill have to write out the log message in the \"msg\" file for hooks\nand other users of the information, but at least it does not have to\nreopen and reread what was written back if the function kept it in a\nstrbuf so that the caller can read it from there.\n\nThis also removes the need for seeking and truncating the output\nfile when we see a scissors mark in the input, which in turn reduces\ntwo callsites of die_errno().\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 40 +++++++++++++++++++++++++++-------------\n 1 file changed, 27 insertions(+), 13 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex aa17c77..72668c9 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -10,7 +10,6 @@\n struct mailinfo {\n \tFILE *input;\n \tFILE *output;\n-\tFILE *cmitmsg;\n \tFILE *patchfile;\n \n \tstruct strbuf name;\n@@ -32,6 +31,8 @@ struct mailinfo {\n \tint header_stage; /* still checking in-body headers? */\n \tstruct strbuf **p_hdr_data;\n \tstruct strbuf **s_hdr_data;\n+\n+\tstruct strbuf log_message;\n };\n \n #define MAX_HDR_PARSED 10\n@@ -746,10 +747,8 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n \n \tif (mi->use_scissors && is_scissors_line(line)) {\n \t\tint i;\n-\t\tif (fseek(mi->cmitmsg, 0L, SEEK_SET))\n-\t\t\tdie_errno(\"Could not rewind output message file\");\n-\t\tif (ftruncate(fileno(mi->cmitmsg), 0))\n-\t\t\tdie_errno(\"Could not truncate output message file at scissors\");\n+\n+\t\tstrbuf_setlen(&mi->log_message, 0);\n \t\tmi->header_stage = 1;\n \n \t\t/*\n@@ -766,13 +765,12 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n \n \tif (patchbreak(line)) {\n \t\tif (mi->message_id)\n-\t\t\tfprintf(mi->cmitmsg, \"Message-Id: %s\\n\", mi->message_id);\n-\t\tfclose(mi->cmitmsg);\n-\t\tmi->cmitmsg = NULL;\n+\t\t\tstrbuf_addf(&mi->log_message,\n+\t\t\t\t    \"Message-Id: %s\\n\", mi->message_id);\n \t\treturn 1;\n \t}\n \n-\tfputs(line->buf, mi->cmitmsg);\n+\tstrbuf_addbuf(&mi->log_message, line);\n \treturn 0;\n }\n \n@@ -970,18 +968,19 @@ static void handle_info(struct mailinfo *mi)\n \n static int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)\n {\n+\tFILE *cmitmsg;\n \tint peek;\n \tstruct strbuf line = STRBUF_INIT;\n \n-\tmi->cmitmsg = fopen(msg, \"w\");\n-\tif (!mi->cmitmsg) {\n+\tcmitmsg = fopen(msg, \"w\");\n+\tif (!cmitmsg) {\n \t\tperror(msg);\n \t\treturn -1;\n \t}\n \tmi->patchfile = fopen(patch, \"w\");\n \tif (!mi->patchfile) {\n \t\tperror(patch);\n-\t\tfclose(mi->cmitmsg);\n+\t\tfclose(cmitmsg);\n \t\treturn -1;\n \t}\n \n@@ -998,6 +997,8 @@ static int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)\n \t\tcheck_header(mi, &line, mi->p_hdr_data, 1);\n \n \thandle_body(mi, &line);\n+\tfwrite(mi->log_message.buf, 1, mi->log_message.len, cmitmsg);\n+\tfclose(cmitmsg);\n \tfclose(mi->patchfile);\n \n \thandle_info(mi);\n@@ -1025,11 +1026,20 @@ static void setup_mailinfo(struct mailinfo *mi)\n \tstrbuf_init(&mi->name, 0);\n \tstrbuf_init(&mi->email, 0);\n \tstrbuf_init(&mi->charset, 0);\n+\tstrbuf_init(&mi->log_message, 0);\n \tmi->header_stage = 1;\n \tmi->use_inbody_headers = 1;\n \tgit_config(git_mailinfo_config, &mi);\n }\n \n+static void clear_mailinfo(struct mailinfo *mi)\n+{\n+\tstrbuf_release(&mi->name);\n+\tstrbuf_release(&mi->email);\n+\tstrbuf_release(&mi->charset);\n+\tstrbuf_release(&mi->log_message);\n+}\n+\n static const char mailinfo_usage[] =\n \t\"git mailinfo [-k | -b] [-m | --message-id] [-u | --encoding=<encoding> | -n] [--scissors | --no-scissors] <msg> <patch> < mail >info\";\n \n@@ -1037,6 +1047,7 @@ int cmd_mailinfo(int argc, const char **argv, const char *prefix)\n {\n \tconst char *def_charset;\n \tstruct mailinfo mi;\n+\tint status;\n \n \t/* NEEDSWORK: might want to do the optional .git/ directory\n \t * discovery\n@@ -1075,5 +1086,8 @@ int cmd_mailinfo(int argc, const char **argv, const char *prefix)\n \n \tmi.input = stdin;\n \tmi.output = stdout;\n-\treturn !!mailinfo(&mi, argv[1], argv[2]);\n+\tstatus = !!mailinfo(&mi, argv[1], argv[2]);\n+\tclear_mailinfo(&mi);\n+\n+\treturn status;\n }\n-- \n2.6.1-320-g86a1181\n"},{"id":"271687","messageId":"1444855557-2127-24-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444855557-2127-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 23/31] mailinfo: move content/content_top to struct mailinfo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-14T20:45:49Z","receivedAt":"2015-10-14T20:45:49Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Signed-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 45 ++++++++++++++++++++++++++-------------------\n 1 file changed, 26 insertions(+), 19 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 72668c9..138ca3b 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -7,6 +7,8 @@\n #include \"utf8.h\"\n #include \"strbuf.h\"\n \n+#define MAX_BOUNDARIES 5\n+\n struct mailinfo {\n \tFILE *input;\n \tFILE *output;\n@@ -21,6 +23,8 @@ struct mailinfo {\n \tint use_inbody_headers; /* defaults to 1 */\n \tconst char *metainfo_charset;\n \n+\tstruct strbuf *content[MAX_BOUNDARIES];\n+\tstruct strbuf **content_top;\n \tstruct strbuf charset;\n \tchar *message_id;\n \tenum  {\n@@ -36,7 +40,6 @@ struct mailinfo {\n };\n \n #define MAX_HDR_PARSED 10\n-#define MAX_BOUNDARIES 5\n \n static void cleanup_space(struct strbuf *sb);\n \n@@ -181,10 +184,6 @@ static int slurp_attr(const char *line, const char *name, struct strbuf *attr)\n \treturn 1;\n }\n \n-static struct strbuf *content[MAX_BOUNDARIES];\n-\n-static struct strbuf **content_top = content;\n-\n static void handle_content_type(struct mailinfo *mi, struct strbuf *line)\n {\n \tstruct strbuf *boundary = xmalloc(sizeof(struct strbuf));\n@@ -192,11 +191,11 @@ static void handle_content_type(struct mailinfo *mi, struct strbuf *line)\n \n \tif (slurp_attr(line->buf, \"boundary=\", boundary)) {\n \t\tstrbuf_insert(boundary, 0, \"--\", 2);\n-\t\tif (++content_top >= &content[MAX_BOUNDARIES]) {\n+\t\tif (++mi->content_top >= &mi->content[MAX_BOUNDARIES]) {\n \t\t\tfprintf(stderr, \"Too many boundaries to handle\\n\");\n \t\t\texit(1);\n \t\t}\n-\t\t*content_top = boundary;\n+\t\t*(mi->content_top) = boundary;\n \t\tboundary = NULL;\n \t}\n \tslurp_attr(line->buf, \"charset=\", &mi->charset);\n@@ -224,10 +223,12 @@ static void handle_content_transfer_encoding(struct mailinfo *mi,\n \t\tmi->transfer_encoding = TE_DONTCARE;\n }\n \n-static int is_multipart_boundary(const struct strbuf *line)\n+static int is_multipart_boundary(struct mailinfo *mi, const struct strbuf *line)\n {\n-\treturn (((*content_top)->len <= line->len) &&\n-\t\t!memcmp(line->buf, (*content_top)->buf, (*content_top)->len));\n+\tstruct strbuf *content_top = *(mi->content_top);\n+\n+\treturn ((content_top->len <= line->len) &&\n+\t\t!memcmp(line->buf, content_top->buf, content_top->len));\n }\n \n static void cleanup_subject(struct mailinfo *mi, struct strbuf *subject)\n@@ -796,7 +797,7 @@ static void handle_filter(struct mailinfo *mi, struct strbuf *line)\n static int find_boundary(struct mailinfo *mi, struct strbuf *line)\n {\n \twhile (!strbuf_getline(line, mi->input, '\\n')) {\n-\t\tif (*content_top && is_multipart_boundary(line))\n+\t\tif (*(mi->content_top) && is_multipart_boundary(mi, line))\n \t\t\treturn 1;\n \t}\n \treturn 0;\n@@ -808,18 +809,18 @@ static int handle_boundary(struct mailinfo *mi, struct strbuf *line)\n \n \tstrbuf_addch(&newline, '\\n');\n again:\n-\tif (line->len >= (*content_top)->len + 2 &&\n-\t    !memcmp(line->buf + (*content_top)->len, \"--\", 2)) {\n+\tif (line->len >= (*(mi->content_top))->len + 2 &&\n+\t    !memcmp(line->buf + (*(mi->content_top))->len, \"--\", 2)) {\n \t\t/* we hit an end boundary */\n \t\t/* pop the current boundary off the stack */\n-\t\tstrbuf_release(*content_top);\n-\t\tfree(*content_top);\n-\t\t*content_top = NULL;\n+\t\tstrbuf_release(*(mi->content_top));\n+\t\tfree(*(mi->content_top));\n+\t\t*(mi->content_top) = NULL;\n \n \t\t/* technically won't happen as is_multipart_boundary()\n \t\t   will fail first.  But just in case..\n \t\t */\n-\t\tif (--content_top < content) {\n+\t\tif (--mi->content_top < mi->content) {\n \t\t\tfprintf(stderr, \"Detected mismatched boundaries, \"\n \t\t\t\t\t\"can't recover\\n\");\n \t\t\texit(1);\n@@ -854,14 +855,14 @@ static void handle_body(struct mailinfo *mi, struct strbuf *line)\n \tstruct strbuf prev = STRBUF_INIT;\n \n \t/* Skip up to the first boundary */\n-\tif (*content_top) {\n+\tif (*(mi->content_top)) {\n \t\tif (!find_boundary(mi, line))\n \t\t\tgoto handle_body_out;\n \t}\n \n \tdo {\n \t\t/* process any boundary lines */\n-\t\tif (*content_top && is_multipart_boundary(line)) {\n+\t\tif (*(mi->content_top) && is_multipart_boundary(mi, line)) {\n \t\t\t/* flush any leftover */\n \t\t\tif (prev.len) {\n \t\t\t\thandle_filter(mi, &prev);\n@@ -1029,6 +1030,7 @@ static void setup_mailinfo(struct mailinfo *mi)\n \tstrbuf_init(&mi->log_message, 0);\n \tmi->header_stage = 1;\n \tmi->use_inbody_headers = 1;\n+\tmi->content_top = mi->content;\n \tgit_config(git_mailinfo_config, &mi);\n }\n \n@@ -1038,6 +1040,11 @@ static void clear_mailinfo(struct mailinfo *mi)\n \tstrbuf_release(&mi->email);\n \tstrbuf_release(&mi->charset);\n \tstrbuf_release(&mi->log_message);\n+\n+\twhile (mi->content < mi->content_top) {\n+\t\tfree(*(mi->content_top));\n+\t\tmi->content_top--;\n+\t}\n }\n \n static const char mailinfo_usage[] =\n-- \n2.6.1-320-g86a1181\n"},{"id":"271685","messageId":"1444855557-2127-25-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444855557-2127-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 24/31] mailinfo: move read_one_header_line() closer to its callers","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-14T20:45:50Z","receivedAt":"2015-10-14T20:45:50Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Signed-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 132 ++++++++++++++++++++++++++---------------------------\n 1 file changed, 66 insertions(+), 66 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 138ca3b..0b083d0 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -390,72 +390,6 @@ check_header_out:\n \treturn ret;\n }\n \n-static int is_rfc2822_header(const struct strbuf *line)\n-{\n-\t/*\n-\t * The section that defines the loosest possible\n-\t * field name is \"3.6.8 Optional fields\".\n-\t *\n-\t * optional-field = field-name \":\" unstructured CRLF\n-\t * field-name = 1*ftext\n-\t * ftext = %d33-57 / %59-126\n-\t */\n-\tint ch;\n-\tchar *cp = line->buf;\n-\n-\t/* Count mbox From headers as headers */\n-\tif (starts_with(cp, \"From \") || starts_with(cp, \">From \"))\n-\t\treturn 1;\n-\n-\twhile ((ch = *cp++)) {\n-\t\tif (ch == ':')\n-\t\t\treturn 1;\n-\t\tif ((33 <= ch && ch <= 57) ||\n-\t\t    (59 <= ch && ch <= 126))\n-\t\t\tcontinue;\n-\t\tbreak;\n-\t}\n-\treturn 0;\n-}\n-\n-static int read_one_header_line(struct strbuf *line, FILE *in)\n-{\n-\t/* Get the first part of the line. */\n-\tif (strbuf_getline(line, in, '\\n'))\n-\t\treturn 0;\n-\n-\t/*\n-\t * Is it an empty line or not a valid rfc2822 header?\n-\t * If so, stop here, and return false (\"not a header\")\n-\t */\n-\tstrbuf_rtrim(line);\n-\tif (!line->len || !is_rfc2822_header(line)) {\n-\t\t/* Re-add the newline */\n-\t\tstrbuf_addch(line, '\\n');\n-\t\treturn 0;\n-\t}\n-\n-\t/*\n-\t * Now we need to eat all the continuation lines..\n-\t * Yuck, 2822 header \"folding\"\n-\t */\n-\tfor (;;) {\n-\t\tint peek;\n-\t\tstruct strbuf continuation = STRBUF_INIT;\n-\n-\t\tpeek = fgetc(in); ungetc(peek, in);\n-\t\tif (peek != ' ' && peek != '\\t')\n-\t\t\tbreak;\n-\t\tif (strbuf_getline(&continuation, in, '\\n'))\n-\t\t\tbreak;\n-\t\tcontinuation.buf[0] = ' ';\n-\t\tstrbuf_rtrim(&continuation);\n-\t\tstrbuf_addbuf(line, &continuation);\n-\t}\n-\n-\treturn 1;\n-}\n-\n static struct strbuf *decode_q_segment(const struct strbuf *q_seg, int rfc2047)\n {\n \tconst char *in = q_seg->buf;\n@@ -794,6 +728,72 @@ static void handle_filter(struct mailinfo *mi, struct strbuf *line)\n \t}\n }\n \n+static int is_rfc2822_header(const struct strbuf *line)\n+{\n+\t/*\n+\t * The section that defines the loosest possible\n+\t * field name is \"3.6.8 Optional fields\".\n+\t *\n+\t * optional-field = field-name \":\" unstructured CRLF\n+\t * field-name = 1*ftext\n+\t * ftext = %d33-57 / %59-126\n+\t */\n+\tint ch;\n+\tchar *cp = line->buf;\n+\n+\t/* Count mbox From headers as headers */\n+\tif (starts_with(cp, \"From \") || starts_with(cp, \">From \"))\n+\t\treturn 1;\n+\n+\twhile ((ch = *cp++)) {\n+\t\tif (ch == ':')\n+\t\t\treturn 1;\n+\t\tif ((33 <= ch && ch <= 57) ||\n+\t\t    (59 <= ch && ch <= 126))\n+\t\t\tcontinue;\n+\t\tbreak;\n+\t}\n+\treturn 0;\n+}\n+\n+static int read_one_header_line(struct strbuf *line, FILE *in)\n+{\n+\t/* Get the first part of the line. */\n+\tif (strbuf_getline(line, in, '\\n'))\n+\t\treturn 0;\n+\n+\t/*\n+\t * Is it an empty line or not a valid rfc2822 header?\n+\t * If so, stop here, and return false (\"not a header\")\n+\t */\n+\tstrbuf_rtrim(line);\n+\tif (!line->len || !is_rfc2822_header(line)) {\n+\t\t/* Re-add the newline */\n+\t\tstrbuf_addch(line, '\\n');\n+\t\treturn 0;\n+\t}\n+\n+\t/*\n+\t * Now we need to eat all the continuation lines..\n+\t * Yuck, 2822 header \"folding\"\n+\t */\n+\tfor (;;) {\n+\t\tint peek;\n+\t\tstruct strbuf continuation = STRBUF_INIT;\n+\n+\t\tpeek = fgetc(in); ungetc(peek, in);\n+\t\tif (peek != ' ' && peek != '\\t')\n+\t\t\tbreak;\n+\t\tif (strbuf_getline(&continuation, in, '\\n'))\n+\t\t\tbreak;\n+\t\tcontinuation.buf[0] = ' ';\n+\t\tstrbuf_rtrim(&continuation);\n+\t\tstrbuf_addbuf(line, &continuation);\n+\t}\n+\n+\treturn 1;\n+}\n+\n static int find_boundary(struct mailinfo *mi, struct strbuf *line)\n {\n \twhile (!strbuf_getline(line, mi->input, '\\n')) {\n-- \n2.6.1-320-g86a1181\n"},{"id":"271672","messageId":"1444855557-2127-26-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444855557-2127-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 25/31] mailinfo: move check_header() after the helpers it uses","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-14T20:45:51Z","receivedAt":"2015-10-14T20:45:51Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This way, we can lose a forward decl for decode_header().\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 139 ++++++++++++++++++++++++++---------------------------\n 1 file changed, 69 insertions(+), 70 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 0b083d0..ee669b9 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -293,7 +293,6 @@ static void cleanup_space(struct strbuf *sb)\n \t}\n }\n \n-static void decode_header(struct mailinfo *mi, struct strbuf *line);\n static const char *header[MAX_HDR_PARSED] = {\n \t\"From\",\"Subject\",\"Date\",\n };\n@@ -321,75 +320,6 @@ static int is_format_patch_separator(const char *line, int len)\n \treturn !memcmp(SAMPLE + (cp - line), cp, strlen(SAMPLE) - (cp - line));\n }\n \n-static int check_header(struct mailinfo *mi,\n-\t\t\tconst struct strbuf *line,\n-\t\t\tstruct strbuf *hdr_data[], int overwrite)\n-{\n-\tint i, ret = 0, len;\n-\tstruct strbuf sb = STRBUF_INIT;\n-\n-\t/* search for the interesting parts */\n-\tfor (i = 0; header[i]; i++) {\n-\t\tint len = strlen(header[i]);\n-\t\tif ((!hdr_data[i] || overwrite) && cmp_header(line, header[i])) {\n-\t\t\t/* Unwrap inline B and Q encoding, and optionally\n-\t\t\t * normalize the meta information to utf8.\n-\t\t\t */\n-\t\t\tstrbuf_add(&sb, line->buf + len + 2, line->len - len - 2);\n-\t\t\tdecode_header(mi, &sb);\n-\t\t\thandle_header(&hdr_data[i], &sb);\n-\t\t\tret = 1;\n-\t\t\tgoto check_header_out;\n-\t\t}\n-\t}\n-\n-\t/* Content stuff */\n-\tif (cmp_header(line, \"Content-Type\")) {\n-\t\tlen = strlen(\"Content-Type: \");\n-\t\tstrbuf_add(&sb, line->buf + len, line->len - len);\n-\t\tdecode_header(mi, &sb);\n-\t\tstrbuf_insert(&sb, 0, \"Content-Type: \", len);\n-\t\thandle_content_type(mi, &sb);\n-\t\tret = 1;\n-\t\tgoto check_header_out;\n-\t}\n-\tif (cmp_header(line, \"Content-Transfer-Encoding\")) {\n-\t\tlen = strlen(\"Content-Transfer-Encoding: \");\n-\t\tstrbuf_add(&sb, line->buf + len, line->len - len);\n-\t\tdecode_header(mi, &sb);\n-\t\thandle_content_transfer_encoding(mi, &sb);\n-\t\tret = 1;\n-\t\tgoto check_header_out;\n-\t}\n-\tif (cmp_header(line, \"Message-Id\")) {\n-\t\tlen = strlen(\"Message-Id: \");\n-\t\tstrbuf_add(&sb, line->buf + len, line->len - len);\n-\t\tdecode_header(mi, &sb);\n-\t\thandle_message_id(mi, &sb);\n-\t\tret = 1;\n-\t\tgoto check_header_out;\n-\t}\n-\n-\t/* for inbody stuff */\n-\tif (starts_with(line->buf, \">From\") && isspace(line->buf[5])) {\n-\t\tret = is_format_patch_separator(line->buf + 1, line->len - 1);\n-\t\tgoto check_header_out;\n-\t}\n-\tif (starts_with(line->buf, \"[PATCH]\") && isspace(line->buf[7])) {\n-\t\tfor (i = 0; header[i]; i++) {\n-\t\t\tif (!strcmp(\"Subject\", header[i])) {\n-\t\t\t\thandle_header(&hdr_data[i], line);\n-\t\t\t\tret = 1;\n-\t\t\t\tgoto check_header_out;\n-\t\t\t}\n-\t\t}\n-\t}\n-\n-check_header_out:\n-\tstrbuf_release(&sb);\n-\treturn ret;\n-}\n-\n static struct strbuf *decode_q_segment(const struct strbuf *q_seg, int rfc2047)\n {\n \tconst char *in = q_seg->buf;\n@@ -550,6 +480,75 @@ release_return:\n \tstrbuf_release(&piecebuf);\n }\n \n+static int check_header(struct mailinfo *mi,\n+\t\t\tconst struct strbuf *line,\n+\t\t\tstruct strbuf *hdr_data[], int overwrite)\n+{\n+\tint i, ret = 0, len;\n+\tstruct strbuf sb = STRBUF_INIT;\n+\n+\t/* search for the interesting parts */\n+\tfor (i = 0; header[i]; i++) {\n+\t\tint len = strlen(header[i]);\n+\t\tif ((!hdr_data[i] || overwrite) && cmp_header(line, header[i])) {\n+\t\t\t/* Unwrap inline B and Q encoding, and optionally\n+\t\t\t * normalize the meta information to utf8.\n+\t\t\t */\n+\t\t\tstrbuf_add(&sb, line->buf + len + 2, line->len - len - 2);\n+\t\t\tdecode_header(mi, &sb);\n+\t\t\thandle_header(&hdr_data[i], &sb);\n+\t\t\tret = 1;\n+\t\t\tgoto check_header_out;\n+\t\t}\n+\t}\n+\n+\t/* Content stuff */\n+\tif (cmp_header(line, \"Content-Type\")) {\n+\t\tlen = strlen(\"Content-Type: \");\n+\t\tstrbuf_add(&sb, line->buf + len, line->len - len);\n+\t\tdecode_header(mi, &sb);\n+\t\tstrbuf_insert(&sb, 0, \"Content-Type: \", len);\n+\t\thandle_content_type(mi, &sb);\n+\t\tret = 1;\n+\t\tgoto check_header_out;\n+\t}\n+\tif (cmp_header(line, \"Content-Transfer-Encoding\")) {\n+\t\tlen = strlen(\"Content-Transfer-Encoding: \");\n+\t\tstrbuf_add(&sb, line->buf + len, line->len - len);\n+\t\tdecode_header(mi, &sb);\n+\t\thandle_content_transfer_encoding(mi, &sb);\n+\t\tret = 1;\n+\t\tgoto check_header_out;\n+\t}\n+\tif (cmp_header(line, \"Message-Id\")) {\n+\t\tlen = strlen(\"Message-Id: \");\n+\t\tstrbuf_add(&sb, line->buf + len, line->len - len);\n+\t\tdecode_header(mi, &sb);\n+\t\thandle_message_id(mi, &sb);\n+\t\tret = 1;\n+\t\tgoto check_header_out;\n+\t}\n+\n+\t/* for inbody stuff */\n+\tif (starts_with(line->buf, \">From\") && isspace(line->buf[5])) {\n+\t\tret = is_format_patch_separator(line->buf + 1, line->len - 1);\n+\t\tgoto check_header_out;\n+\t}\n+\tif (starts_with(line->buf, \"[PATCH]\") && isspace(line->buf[7])) {\n+\t\tfor (i = 0; header[i]; i++) {\n+\t\t\tif (!strcmp(\"Subject\", header[i])) {\n+\t\t\t\thandle_header(&hdr_data[i], line);\n+\t\t\t\tret = 1;\n+\t\t\t\tgoto check_header_out;\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+check_header_out:\n+\tstrbuf_release(&sb);\n+\treturn ret;\n+}\n+\n static void decode_transfer_encoding(struct mailinfo *mi, struct strbuf *line)\n {\n \tstruct strbuf *ret;\n-- \n2.6.1-320-g86a1181\n"},{"id":"271683","messageId":"1444855557-2127-27-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444855557-2127-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 26/31] mailinfo: move cleanup_space() before its users","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-14T20:45:52Z","receivedAt":"2015-10-14T20:45:52Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Signed-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 25 +++++++++++--------------\n 1 file changed, 11 insertions(+), 14 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex ee669b9..f4771ee 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -41,8 +41,17 @@ struct mailinfo {\n \n #define MAX_HDR_PARSED 10\n \n-static void cleanup_space(struct strbuf *sb);\n-\n+static void cleanup_space(struct strbuf *sb)\n+{\n+\tsize_t pos, cnt;\n+\tfor (pos = 0; pos < sb->len; pos++) {\n+\t\tif (isspace(sb->buf[pos])) {\n+\t\t\tsb->buf[pos] = ' ';\n+\t\t\tfor (cnt = 0; isspace(sb->buf[pos + cnt + 1]); cnt++);\n+\t\t\tstrbuf_remove(sb, pos + 1, cnt);\n+\t\t}\n+\t}\n+}\n \n static void get_sane_name(struct strbuf *out, struct strbuf *name, struct strbuf *email)\n {\n@@ -281,18 +290,6 @@ static void cleanup_subject(struct mailinfo *mi, struct strbuf *subject)\n \tstrbuf_trim(subject);\n }\n \n-static void cleanup_space(struct strbuf *sb)\n-{\n-\tsize_t pos, cnt;\n-\tfor (pos = 0; pos < sb->len; pos++) {\n-\t\tif (isspace(sb->buf[pos])) {\n-\t\t\tsb->buf[pos] = ' ';\n-\t\t\tfor (cnt = 0; isspace(sb->buf[pos + cnt + 1]); cnt++);\n-\t\t\tstrbuf_remove(sb, pos + 1, cnt);\n-\t\t}\n-\t}\n-}\n-\n static const char *header[MAX_HDR_PARSED] = {\n \t\"From\",\"Subject\",\"Date\",\n };\n-- \n2.6.1-320-g86a1181\n"},{"id":"271682","messageId":"1444855557-2127-28-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444855557-2127-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 27/31] mailinfo: move definition of MAX_HDR_PARSED to closer to its use","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-14T20:45:53Z","receivedAt":"2015-10-14T20:45:53Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Signed-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 3 +--\n 1 file changed, 1 insertion(+), 2 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex f4771ee..de446ec 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -39,8 +39,6 @@ struct mailinfo {\n \tstruct strbuf log_message;\n };\n \n-#define MAX_HDR_PARSED 10\n-\n static void cleanup_space(struct strbuf *sb)\n {\n \tsize_t pos, cnt;\n@@ -290,6 +288,7 @@ static void cleanup_subject(struct mailinfo *mi, struct strbuf *subject)\n \tstrbuf_trim(subject);\n }\n \n+#define MAX_HDR_PARSED 10\n static const char *header[MAX_HDR_PARSED] = {\n \t\"From\",\"Subject\",\"Date\",\n };\n-- \n2.6.1-320-g86a1181\n"},{"id":"271681","messageId":"1444855557-2127-29-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444855557-2127-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 28/31] mailinfo: libify","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-14T20:45:54Z","receivedAt":"2015-10-14T20:45:54Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Move the bulk of the code from builtin/mailinfo.c to mailinfo.c\nso that new callers can start calling mailinfo() directly.\n\nNote that a few calls to exit() and die() need to be cleaned up\nfor the API to be truly useful, which will come in later steps.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n Makefile           |    1 +\n builtin/mailinfo.c | 1036 +---------------------------------------------------\n mailinfo.c         | 1007 ++++++++++++++++++++++++++++++++++++++++++++++++++\n mailinfo.h         |   40 ++\n 4 files changed, 1049 insertions(+), 1035 deletions(-)\n create mode 100644 mailinfo.c\n create mode 100644 mailinfo.h\n\ndiff --git a/Makefile b/Makefile\nindex 8d5df7e..7dd3bff 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -726,6 +726,7 @@ LIB_OBJS += list-objects.o\n LIB_OBJS += ll-merge.o\n LIB_OBJS += lockfile.o\n LIB_OBJS += log-tree.o\n+LIB_OBJS += mailinfo.o\n LIB_OBJS += mailmap.o\n LIB_OBJS += match-trees.o\n LIB_OBJS += merge.o\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex de446ec..f6df274 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -6,1041 +6,7 @@\n #include \"builtin.h\"\n #include \"utf8.h\"\n #include \"strbuf.h\"\n-\n-#define MAX_BOUNDARIES 5\n-\n-struct mailinfo {\n-\tFILE *input;\n-\tFILE *output;\n-\tFILE *patchfile;\n-\n-\tstruct strbuf name;\n-\tstruct strbuf email;\n-\tint keep_subject;\n-\tint keep_non_patch_brackets_in_subject;\n-\tint add_message_id;\n-\tint use_scissors;\n-\tint use_inbody_headers; /* defaults to 1 */\n-\tconst char *metainfo_charset;\n-\n-\tstruct strbuf *content[MAX_BOUNDARIES];\n-\tstruct strbuf **content_top;\n-\tstruct strbuf charset;\n-\tchar *message_id;\n-\tenum  {\n-\t\tTE_DONTCARE, TE_QP, TE_BASE64\n-\t} transfer_encoding;\n-\tint patch_lines;\n-\tint filter_stage; /* still reading log or are we copying patch? */\n-\tint header_stage; /* still checking in-body headers? */\n-\tstruct strbuf **p_hdr_data;\n-\tstruct strbuf **s_hdr_data;\n-\n-\tstruct strbuf log_message;\n-};\n-\n-static void cleanup_space(struct strbuf *sb)\n-{\n-\tsize_t pos, cnt;\n-\tfor (pos = 0; pos < sb->len; pos++) {\n-\t\tif (isspace(sb->buf[pos])) {\n-\t\t\tsb->buf[pos] = ' ';\n-\t\t\tfor (cnt = 0; isspace(sb->buf[pos + cnt + 1]); cnt++);\n-\t\t\tstrbuf_remove(sb, pos + 1, cnt);\n-\t\t}\n-\t}\n-}\n-\n-static void get_sane_name(struct strbuf *out, struct strbuf *name, struct strbuf *email)\n-{\n-\tstruct strbuf *src = name;\n-\tif (name->len < 3 || 60 < name->len || strchr(name->buf, '@') ||\n-\t\tstrchr(name->buf, '<') || strchr(name->buf, '>'))\n-\t\tsrc = email;\n-\telse if (name == out)\n-\t\treturn;\n-\tstrbuf_reset(out);\n-\tstrbuf_addbuf(out, src);\n-}\n-\n-static void parse_bogus_from(struct mailinfo *mi, const struct strbuf *line)\n-{\n-\t/* John Doe <johndoe> */\n-\n-\tchar *bra, *ket;\n-\t/* This is fallback, so do not bother if we already have an\n-\t * e-mail address.\n-\t */\n-\tif (mi->email.len)\n-\t\treturn;\n-\n-\tbra = strchr(line->buf, '<');\n-\tif (!bra)\n-\t\treturn;\n-\tket = strchr(bra, '>');\n-\tif (!ket)\n-\t\treturn;\n-\n-\tstrbuf_reset(&mi->email);\n-\tstrbuf_add(&mi->email, bra + 1, ket - bra - 1);\n-\n-\tstrbuf_reset(&mi->name);\n-\tstrbuf_add(&mi->name, line->buf, bra - line->buf);\n-\tstrbuf_trim(&mi->name);\n-\tget_sane_name(&mi->name, &mi->name, &mi->email);\n-}\n-\n-static void handle_from(struct mailinfo *mi, const struct strbuf *from)\n-{\n-\tchar *at;\n-\tsize_t el;\n-\tstruct strbuf f;\n-\n-\tstrbuf_init(&f, from->len);\n-\tstrbuf_addbuf(&f, from);\n-\n-\tat = strchr(f.buf, '@');\n-\tif (!at) {\n-\t\tparse_bogus_from(mi, from);\n-\t\treturn;\n-\t}\n-\n-\t/*\n-\t * If we already have one email, don't take any confusing lines\n-\t */\n-\tif (mi->email.len && strchr(at + 1, '@')) {\n-\t\tstrbuf_release(&f);\n-\t\treturn;\n-\t}\n-\n-\t/* Pick up the string around '@', possibly delimited with <>\n-\t * pair; that is the email part.\n-\t */\n-\twhile (at > f.buf) {\n-\t\tchar c = at[-1];\n-\t\tif (isspace(c))\n-\t\t\tbreak;\n-\t\tif (c == '<') {\n-\t\t\tat[-1] = ' ';\n-\t\t\tbreak;\n-\t\t}\n-\t\tat--;\n-\t}\n-\tel = strcspn(at, \" \\n\\t\\r\\v\\f>\");\n-\tstrbuf_reset(&mi->email);\n-\tstrbuf_add(&mi->email, at, el);\n-\tstrbuf_remove(&f, at - f.buf, el + (at[el] ? 1 : 0));\n-\n-\t/* The remainder is name.  It could be\n-\t *\n-\t * - \"John Doe <john.doe@xz>\"\t\t\t(a), or\n-\t * - \"john.doe@xz (John Doe)\"\t\t\t(b), or\n-\t * - \"John (zzz) Doe <john.doe@xz> (Comment)\"\t(c)\n-\t *\n-\t * but we have removed the email part, so\n-\t *\n-\t * - remove extra spaces which could stay after email (case 'c'), and\n-\t * - trim from both ends, possibly removing the () pair at the end\n-\t *   (cases 'a' and 'b').\n-\t */\n-\tcleanup_space(&f);\n-\tstrbuf_trim(&f);\n-\tif (f.buf[0] == '(' && f.len && f.buf[f.len - 1] == ')') {\n-\t\tstrbuf_remove(&f, 0, 1);\n-\t\tstrbuf_setlen(&f, f.len - 1);\n-\t}\n-\n-\tget_sane_name(&mi->name, &f, &mi->email);\n-\tstrbuf_release(&f);\n-}\n-\n-static void handle_header(struct strbuf **out, const struct strbuf *line)\n-{\n-\tif (!*out) {\n-\t\t*out = xmalloc(sizeof(struct strbuf));\n-\t\tstrbuf_init(*out, line->len);\n-\t} else\n-\t\tstrbuf_reset(*out);\n-\n-\tstrbuf_addbuf(*out, line);\n-}\n-\n-/* NOTE NOTE NOTE.  We do not claim we do full MIME.  We just attempt\n- * to have enough heuristics to grok MIME encoded patches often found\n- * on our mailing lists.  For example, we do not even treat header lines\n- * case insensitively.\n- */\n-\n-static int slurp_attr(const char *line, const char *name, struct strbuf *attr)\n-{\n-\tconst char *ends, *ap = strcasestr(line, name);\n-\tsize_t sz;\n-\n-\tstrbuf_setlen(attr, 0);\n-\tif (!ap)\n-\t\treturn 0;\n-\tap += strlen(name);\n-\tif (*ap == '\"') {\n-\t\tap++;\n-\t\tends = \"\\\"\";\n-\t}\n-\telse\n-\t\tends = \"; \\t\";\n-\tsz = strcspn(ap, ends);\n-\tstrbuf_add(attr, ap, sz);\n-\treturn 1;\n-}\n-\n-static void handle_content_type(struct mailinfo *mi, struct strbuf *line)\n-{\n-\tstruct strbuf *boundary = xmalloc(sizeof(struct strbuf));\n-\tstrbuf_init(boundary, line->len);\n-\n-\tif (slurp_attr(line->buf, \"boundary=\", boundary)) {\n-\t\tstrbuf_insert(boundary, 0, \"--\", 2);\n-\t\tif (++mi->content_top >= &mi->content[MAX_BOUNDARIES]) {\n-\t\t\tfprintf(stderr, \"Too many boundaries to handle\\n\");\n-\t\t\texit(1);\n-\t\t}\n-\t\t*(mi->content_top) = boundary;\n-\t\tboundary = NULL;\n-\t}\n-\tslurp_attr(line->buf, \"charset=\", &mi->charset);\n-\n-\tif (boundary) {\n-\t\tstrbuf_release(boundary);\n-\t\tfree(boundary);\n-\t}\n-}\n-\n-static void handle_message_id(struct mailinfo *mi, const struct strbuf *line)\n-{\n-\tif (mi->add_message_id)\n-\t\tmi->message_id = strdup(line->buf);\n-}\n-\n-static void handle_content_transfer_encoding(struct mailinfo *mi,\n-\t\t\t\t\t     const struct strbuf *line)\n-{\n-\tif (strcasestr(line->buf, \"base64\"))\n-\t\tmi->transfer_encoding = TE_BASE64;\n-\telse if (strcasestr(line->buf, \"quoted-printable\"))\n-\t\tmi->transfer_encoding = TE_QP;\n-\telse\n-\t\tmi->transfer_encoding = TE_DONTCARE;\n-}\n-\n-static int is_multipart_boundary(struct mailinfo *mi, const struct strbuf *line)\n-{\n-\tstruct strbuf *content_top = *(mi->content_top);\n-\n-\treturn ((content_top->len <= line->len) &&\n-\t\t!memcmp(line->buf, content_top->buf, content_top->len));\n-}\n-\n-static void cleanup_subject(struct mailinfo *mi, struct strbuf *subject)\n-{\n-\tsize_t at = 0;\n-\n-\twhile (at < subject->len) {\n-\t\tchar *pos;\n-\t\tsize_t remove;\n-\n-\t\tswitch (subject->buf[at]) {\n-\t\tcase 'r': case 'R':\n-\t\t\tif (subject->len <= at + 3)\n-\t\t\t\tbreak;\n-\t\t\tif ((subject->buf[at + 1] == 'e' ||\n-\t\t\t     subject->buf[at + 1] == 'E') &&\n-\t\t\t    subject->buf[at + 2] == ':') {\n-\t\t\t\tstrbuf_remove(subject, at, 3);\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\t\t\tat++;\n-\t\t\tbreak;\n-\t\tcase ' ': case '\\t': case ':':\n-\t\t\tstrbuf_remove(subject, at, 1);\n-\t\t\tcontinue;\n-\t\tcase '[':\n-\t\t\tpos = strchr(subject->buf + at, ']');\n-\t\t\tif (!pos)\n-\t\t\t\tbreak;\n-\t\t\tremove = pos - subject->buf + at + 1;\n-\t\t\tif (!mi->keep_non_patch_brackets_in_subject ||\n-\t\t\t    (7 <= remove &&\n-\t\t\t     memmem(subject->buf + at, remove, \"PATCH\", 5)))\n-\t\t\t\tstrbuf_remove(subject, at, remove);\n-\t\t\telse {\n-\t\t\t\tat += remove;\n-\t\t\t\t/*\n-\t\t\t\t * If the input had a space after the ], keep\n-\t\t\t\t * it.  We don't bother with finding the end of\n-\t\t\t\t * the space, since we later normalize it\n-\t\t\t\t * anyway.\n-\t\t\t\t */\n-\t\t\t\tif (isspace(subject->buf[at]))\n-\t\t\t\t\tat += 1;\n-\t\t\t}\n-\t\t\tcontinue;\n-\t\t}\n-\t\tbreak;\n-\t}\n-\tstrbuf_trim(subject);\n-}\n-\n-#define MAX_HDR_PARSED 10\n-static const char *header[MAX_HDR_PARSED] = {\n-\t\"From\",\"Subject\",\"Date\",\n-};\n-\n-static inline int cmp_header(const struct strbuf *line, const char *hdr)\n-{\n-\tint len = strlen(hdr);\n-\treturn !strncasecmp(line->buf, hdr, len) && line->len > len &&\n-\t\t\tline->buf[len] == ':' && isspace(line->buf[len + 1]);\n-}\n-\n-static int is_format_patch_separator(const char *line, int len)\n-{\n-\tstatic const char SAMPLE[] =\n-\t\t\"From e6807f3efca28b30decfecb1732a56c7db1137ee Mon Sep 17 00:00:00 2001\\n\";\n-\tconst char *cp;\n-\n-\tif (len != strlen(SAMPLE))\n-\t\treturn 0;\n-\tif (!skip_prefix(line, \"From \", &cp))\n-\t\treturn 0;\n-\tif (strspn(cp, \"0123456789abcdef\") != 40)\n-\t\treturn 0;\n-\tcp += 40;\n-\treturn !memcmp(SAMPLE + (cp - line), cp, strlen(SAMPLE) - (cp - line));\n-}\n-\n-static struct strbuf *decode_q_segment(const struct strbuf *q_seg, int rfc2047)\n-{\n-\tconst char *in = q_seg->buf;\n-\tint c;\n-\tstruct strbuf *out = xmalloc(sizeof(struct strbuf));\n-\tstrbuf_init(out, q_seg->len);\n-\n-\twhile ((c = *in++) != 0) {\n-\t\tif (c == '=') {\n-\t\t\tint d = *in++;\n-\t\t\tif (d == '\\n' || !d)\n-\t\t\t\tbreak; /* drop trailing newline */\n-\t\t\tstrbuf_addch(out, (hexval(d) << 4) | hexval(*in++));\n-\t\t\tcontinue;\n-\t\t}\n-\t\tif (rfc2047 && c == '_') /* rfc2047 4.2 (2) */\n-\t\t\tc = 0x20;\n-\t\tstrbuf_addch(out, c);\n-\t}\n-\treturn out;\n-}\n-\n-static struct strbuf *decode_b_segment(const struct strbuf *b_seg)\n-{\n-\t/* Decode in..ep, possibly in-place to ot */\n-\tint c, pos = 0, acc = 0;\n-\tconst char *in = b_seg->buf;\n-\tstruct strbuf *out = xmalloc(sizeof(struct strbuf));\n-\tstrbuf_init(out, b_seg->len);\n-\n-\twhile ((c = *in++) != 0) {\n-\t\tif (c == '+')\n-\t\t\tc = 62;\n-\t\telse if (c == '/')\n-\t\t\tc = 63;\n-\t\telse if ('A' <= c && c <= 'Z')\n-\t\t\tc -= 'A';\n-\t\telse if ('a' <= c && c <= 'z')\n-\t\t\tc -= 'a' - 26;\n-\t\telse if ('0' <= c && c <= '9')\n-\t\t\tc -= '0' - 52;\n-\t\telse\n-\t\t\tcontinue; /* garbage */\n-\t\tswitch (pos++) {\n-\t\tcase 0:\n-\t\t\tacc = (c << 2);\n-\t\t\tbreak;\n-\t\tcase 1:\n-\t\t\tstrbuf_addch(out, (acc | (c >> 4)));\n-\t\t\tacc = (c & 15) << 4;\n-\t\t\tbreak;\n-\t\tcase 2:\n-\t\t\tstrbuf_addch(out, (acc | (c >> 2)));\n-\t\t\tacc = (c & 3) << 6;\n-\t\t\tbreak;\n-\t\tcase 3:\n-\t\t\tstrbuf_addch(out, (acc | c));\n-\t\t\tacc = pos = 0;\n-\t\t\tbreak;\n-\t\t}\n-\t}\n-\treturn out;\n-}\n-\n-static void convert_to_utf8(struct mailinfo *mi,\n-\t\t\t    struct strbuf *line, const char *charset)\n-{\n-\tchar *out;\n-\n-\tif (!mi->metainfo_charset || !charset || !*charset)\n-\t\treturn;\n-\n-\tif (same_encoding(mi->metainfo_charset, charset))\n-\t\treturn;\n-\tout = reencode_string(line->buf, mi->metainfo_charset, charset);\n-\tif (!out)\n-\t\tdie(\"cannot convert from %s to %s\",\n-\t\t    charset, mi->metainfo_charset);\n-\tstrbuf_attach(line, out, strlen(out), strlen(out));\n-}\n-\n-static void decode_header(struct mailinfo *mi, struct strbuf *it)\n-{\n-\tchar *in, *ep, *cp;\n-\tstruct strbuf outbuf = STRBUF_INIT, *dec;\n-\tstruct strbuf charset_q = STRBUF_INIT, piecebuf = STRBUF_INIT;\n-\n-\tin = it->buf;\n-\twhile (in - it->buf <= it->len && (ep = strstr(in, \"=?\")) != NULL) {\n-\t\tint encoding;\n-\t\tstrbuf_reset(&charset_q);\n-\t\tstrbuf_reset(&piecebuf);\n-\n-\t\tif (in != ep) {\n-\t\t\t/*\n-\t\t\t * We are about to process an encoded-word\n-\t\t\t * that begins at ep, but there is something\n-\t\t\t * before the encoded word.\n-\t\t\t */\n-\t\t\tchar *scan;\n-\t\t\tfor (scan = in; scan < ep; scan++)\n-\t\t\t\tif (!isspace(*scan))\n-\t\t\t\t\tbreak;\n-\n-\t\t\tif (scan != ep || in == it->buf) {\n-\t\t\t\t/*\n-\t\t\t\t * We should not lose that \"something\",\n-\t\t\t\t * unless we have just processed an\n-\t\t\t\t * encoded-word, and there is only LWS\n-\t\t\t\t * before the one we are about to process.\n-\t\t\t\t */\n-\t\t\t\tstrbuf_add(&outbuf, in, ep - in);\n-\t\t\t}\n-\t\t}\n-\t\t/* E.g.\n-\t\t * ep : \"=?iso-2022-jp?B?GyR...?= foo\"\n-\t\t * ep : \"=?ISO-8859-1?Q?Foo=FCbar?= baz\"\n-\t\t */\n-\t\tep += 2;\n-\n-\t\tif (ep - it->buf >= it->len || !(cp = strchr(ep, '?')))\n-\t\t\tgoto release_return;\n-\n-\t\tif (cp + 3 - it->buf > it->len)\n-\t\t\tgoto release_return;\n-\t\tstrbuf_add(&charset_q, ep, cp - ep);\n-\n-\t\tencoding = cp[1];\n-\t\tif (!encoding || cp[2] != '?')\n-\t\t\tgoto release_return;\n-\t\tep = strstr(cp + 3, \"?=\");\n-\t\tif (!ep)\n-\t\t\tgoto release_return;\n-\t\tstrbuf_add(&piecebuf, cp + 3, ep - cp - 3);\n-\t\tswitch (tolower(encoding)) {\n-\t\tdefault:\n-\t\t\tgoto release_return;\n-\t\tcase 'b':\n-\t\t\tdec = decode_b_segment(&piecebuf);\n-\t\t\tbreak;\n-\t\tcase 'q':\n-\t\t\tdec = decode_q_segment(&piecebuf, 1);\n-\t\t\tbreak;\n-\t\t}\n-\t\tconvert_to_utf8(mi, dec, charset_q.buf);\n-\n-\t\tstrbuf_addbuf(&outbuf, dec);\n-\t\tstrbuf_release(dec);\n-\t\tfree(dec);\n-\t\tin = ep + 2;\n-\t}\n-\tstrbuf_addstr(&outbuf, in);\n-\tstrbuf_reset(it);\n-\tstrbuf_addbuf(it, &outbuf);\n-release_return:\n-\tstrbuf_release(&outbuf);\n-\tstrbuf_release(&charset_q);\n-\tstrbuf_release(&piecebuf);\n-}\n-\n-static int check_header(struct mailinfo *mi,\n-\t\t\tconst struct strbuf *line,\n-\t\t\tstruct strbuf *hdr_data[], int overwrite)\n-{\n-\tint i, ret = 0, len;\n-\tstruct strbuf sb = STRBUF_INIT;\n-\n-\t/* search for the interesting parts */\n-\tfor (i = 0; header[i]; i++) {\n-\t\tint len = strlen(header[i]);\n-\t\tif ((!hdr_data[i] || overwrite) && cmp_header(line, header[i])) {\n-\t\t\t/* Unwrap inline B and Q encoding, and optionally\n-\t\t\t * normalize the meta information to utf8.\n-\t\t\t */\n-\t\t\tstrbuf_add(&sb, line->buf + len + 2, line->len - len - 2);\n-\t\t\tdecode_header(mi, &sb);\n-\t\t\thandle_header(&hdr_data[i], &sb);\n-\t\t\tret = 1;\n-\t\t\tgoto check_header_out;\n-\t\t}\n-\t}\n-\n-\t/* Content stuff */\n-\tif (cmp_header(line, \"Content-Type\")) {\n-\t\tlen = strlen(\"Content-Type: \");\n-\t\tstrbuf_add(&sb, line->buf + len, line->len - len);\n-\t\tdecode_header(mi, &sb);\n-\t\tstrbuf_insert(&sb, 0, \"Content-Type: \", len);\n-\t\thandle_content_type(mi, &sb);\n-\t\tret = 1;\n-\t\tgoto check_header_out;\n-\t}\n-\tif (cmp_header(line, \"Content-Transfer-Encoding\")) {\n-\t\tlen = strlen(\"Content-Transfer-Encoding: \");\n-\t\tstrbuf_add(&sb, line->buf + len, line->len - len);\n-\t\tdecode_header(mi, &sb);\n-\t\thandle_content_transfer_encoding(mi, &sb);\n-\t\tret = 1;\n-\t\tgoto check_header_out;\n-\t}\n-\tif (cmp_header(line, \"Message-Id\")) {\n-\t\tlen = strlen(\"Message-Id: \");\n-\t\tstrbuf_add(&sb, line->buf + len, line->len - len);\n-\t\tdecode_header(mi, &sb);\n-\t\thandle_message_id(mi, &sb);\n-\t\tret = 1;\n-\t\tgoto check_header_out;\n-\t}\n-\n-\t/* for inbody stuff */\n-\tif (starts_with(line->buf, \">From\") && isspace(line->buf[5])) {\n-\t\tret = is_format_patch_separator(line->buf + 1, line->len - 1);\n-\t\tgoto check_header_out;\n-\t}\n-\tif (starts_with(line->buf, \"[PATCH]\") && isspace(line->buf[7])) {\n-\t\tfor (i = 0; header[i]; i++) {\n-\t\t\tif (!strcmp(\"Subject\", header[i])) {\n-\t\t\t\thandle_header(&hdr_data[i], line);\n-\t\t\t\tret = 1;\n-\t\t\t\tgoto check_header_out;\n-\t\t\t}\n-\t\t}\n-\t}\n-\n-check_header_out:\n-\tstrbuf_release(&sb);\n-\treturn ret;\n-}\n-\n-static void decode_transfer_encoding(struct mailinfo *mi, struct strbuf *line)\n-{\n-\tstruct strbuf *ret;\n-\n-\tswitch (mi->transfer_encoding) {\n-\tcase TE_QP:\n-\t\tret = decode_q_segment(line, 0);\n-\t\tbreak;\n-\tcase TE_BASE64:\n-\t\tret = decode_b_segment(line);\n-\t\tbreak;\n-\tcase TE_DONTCARE:\n-\tdefault:\n-\t\treturn;\n-\t}\n-\tstrbuf_reset(line);\n-\tstrbuf_addbuf(line, ret);\n-\tstrbuf_release(ret);\n-\tfree(ret);\n-}\n-\n-static inline int patchbreak(const struct strbuf *line)\n-{\n-\tsize_t i;\n-\n-\t/* Beginning of a \"diff -\" header? */\n-\tif (starts_with(line->buf, \"diff -\"))\n-\t\treturn 1;\n-\n-\t/* CVS \"Index: \" line? */\n-\tif (starts_with(line->buf, \"Index: \"))\n-\t\treturn 1;\n-\n-\t/*\n-\t * \"--- <filename>\" starts patches without headers\n-\t * \"---<sp>*\" is a manual separator\n-\t */\n-\tif (line->len < 4)\n-\t\treturn 0;\n-\n-\tif (starts_with(line->buf, \"---\")) {\n-\t\t/* space followed by a filename? */\n-\t\tif (line->buf[3] == ' ' && !isspace(line->buf[4]))\n-\t\t\treturn 1;\n-\t\t/* Just whitespace? */\n-\t\tfor (i = 3; i < line->len; i++) {\n-\t\t\tunsigned char c = line->buf[i];\n-\t\t\tif (c == '\\n')\n-\t\t\t\treturn 1;\n-\t\t\tif (!isspace(c))\n-\t\t\t\tbreak;\n-\t\t}\n-\t\treturn 0;\n-\t}\n-\treturn 0;\n-}\n-\n-static int is_scissors_line(const struct strbuf *line)\n-{\n-\tsize_t i, len = line->len;\n-\tint scissors = 0, gap = 0;\n-\tint first_nonblank = -1;\n-\tint last_nonblank = 0, visible, perforation = 0, in_perforation = 0;\n-\tconst char *buf = line->buf;\n-\n-\tfor (i = 0; i < len; i++) {\n-\t\tif (isspace(buf[i])) {\n-\t\t\tif (in_perforation) {\n-\t\t\t\tperforation++;\n-\t\t\t\tgap++;\n-\t\t\t}\n-\t\t\tcontinue;\n-\t\t}\n-\t\tlast_nonblank = i;\n-\t\tif (first_nonblank < 0)\n-\t\t\tfirst_nonblank = i;\n-\t\tif (buf[i] == '-') {\n-\t\t\tin_perforation = 1;\n-\t\t\tperforation++;\n-\t\t\tcontinue;\n-\t\t}\n-\t\tif (i + 1 < len &&\n-\t\t    (!memcmp(buf + i, \">8\", 2) || !memcmp(buf + i, \"8<\", 2) ||\n-\t\t     !memcmp(buf + i, \">%\", 2) || !memcmp(buf + i, \"%<\", 2))) {\n-\t\t\tin_perforation = 1;\n-\t\t\tperforation += 2;\n-\t\t\tscissors += 2;\n-\t\t\ti++;\n-\t\t\tcontinue;\n-\t\t}\n-\t\tin_perforation = 0;\n-\t}\n-\n-\t/*\n-\t * The mark must be at least 8 bytes long (e.g. \"-- >8 --\").\n-\t * Even though there can be arbitrary cruft on the same line\n-\t * (e.g. \"cut here\"), in order to avoid misidentification, the\n-\t * perforation must occupy more than a third of the visible\n-\t * width of the line, and dashes and scissors must occupy more\n-\t * than half of the perforation.\n-\t */\n-\n-\tvisible = last_nonblank - first_nonblank + 1;\n-\treturn (scissors && 8 <= visible &&\n-\t\tvisible < perforation * 3 &&\n-\t\tgap * 2 < perforation);\n-}\n-\n-static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n-{\n-\tassert(!mi->filter_stage);\n-\n-\tif (mi->header_stage) {\n-\t\tif (!line->len || (line->len == 1 && line->buf[0] == '\\n'))\n-\t\t\treturn 0;\n-\t}\n-\n-\tif (mi->use_inbody_headers && mi->header_stage) {\n-\t\tmi->header_stage = check_header(mi, line, mi->s_hdr_data, 0);\n-\t\tif (mi->header_stage)\n-\t\t\treturn 0;\n-\t} else\n-\t\t/* Only trim the first (blank) line of the commit message\n-\t\t * when ignoring in-body headers.\n-\t\t */\n-\t\tmi->header_stage = 0;\n-\n-\t/* normalize the log message to UTF-8. */\n-\tconvert_to_utf8(mi, line, mi->charset.buf);\n-\n-\tif (mi->use_scissors && is_scissors_line(line)) {\n-\t\tint i;\n-\n-\t\tstrbuf_setlen(&mi->log_message, 0);\n-\t\tmi->header_stage = 1;\n-\n-\t\t/*\n-\t\t * We may have already read \"secondary headers\"; purge\n-\t\t * them to give ourselves a clean restart.\n-\t\t */\n-\t\tfor (i = 0; header[i]; i++) {\n-\t\t\tif (mi->s_hdr_data[i])\n-\t\t\t\tstrbuf_release(mi->s_hdr_data[i]);\n-\t\t\tmi->s_hdr_data[i] = NULL;\n-\t\t}\n-\t\treturn 0;\n-\t}\n-\n-\tif (patchbreak(line)) {\n-\t\tif (mi->message_id)\n-\t\t\tstrbuf_addf(&mi->log_message,\n-\t\t\t\t    \"Message-Id: %s\\n\", mi->message_id);\n-\t\treturn 1;\n-\t}\n-\n-\tstrbuf_addbuf(&mi->log_message, line);\n-\treturn 0;\n-}\n-\n-static void handle_patch(struct mailinfo *mi, const struct strbuf *line)\n-{\n-\tfwrite(line->buf, 1, line->len, mi->patchfile);\n-\tmi->patch_lines++;\n-}\n-\n-static void handle_filter(struct mailinfo *mi, struct strbuf *line)\n-{\n-\tswitch (mi->filter_stage) {\n-\tcase 0:\n-\t\tif (!handle_commit_msg(mi, line))\n-\t\t\tbreak;\n-\t\tmi->filter_stage++;\n-\tcase 1:\n-\t\thandle_patch(mi, line);\n-\t\tbreak;\n-\t}\n-}\n-\n-static int is_rfc2822_header(const struct strbuf *line)\n-{\n-\t/*\n-\t * The section that defines the loosest possible\n-\t * field name is \"3.6.8 Optional fields\".\n-\t *\n-\t * optional-field = field-name \":\" unstructured CRLF\n-\t * field-name = 1*ftext\n-\t * ftext = %d33-57 / %59-126\n-\t */\n-\tint ch;\n-\tchar *cp = line->buf;\n-\n-\t/* Count mbox From headers as headers */\n-\tif (starts_with(cp, \"From \") || starts_with(cp, \">From \"))\n-\t\treturn 1;\n-\n-\twhile ((ch = *cp++)) {\n-\t\tif (ch == ':')\n-\t\t\treturn 1;\n-\t\tif ((33 <= ch && ch <= 57) ||\n-\t\t    (59 <= ch && ch <= 126))\n-\t\t\tcontinue;\n-\t\tbreak;\n-\t}\n-\treturn 0;\n-}\n-\n-static int read_one_header_line(struct strbuf *line, FILE *in)\n-{\n-\t/* Get the first part of the line. */\n-\tif (strbuf_getline(line, in, '\\n'))\n-\t\treturn 0;\n-\n-\t/*\n-\t * Is it an empty line or not a valid rfc2822 header?\n-\t * If so, stop here, and return false (\"not a header\")\n-\t */\n-\tstrbuf_rtrim(line);\n-\tif (!line->len || !is_rfc2822_header(line)) {\n-\t\t/* Re-add the newline */\n-\t\tstrbuf_addch(line, '\\n');\n-\t\treturn 0;\n-\t}\n-\n-\t/*\n-\t * Now we need to eat all the continuation lines..\n-\t * Yuck, 2822 header \"folding\"\n-\t */\n-\tfor (;;) {\n-\t\tint peek;\n-\t\tstruct strbuf continuation = STRBUF_INIT;\n-\n-\t\tpeek = fgetc(in); ungetc(peek, in);\n-\t\tif (peek != ' ' && peek != '\\t')\n-\t\t\tbreak;\n-\t\tif (strbuf_getline(&continuation, in, '\\n'))\n-\t\t\tbreak;\n-\t\tcontinuation.buf[0] = ' ';\n-\t\tstrbuf_rtrim(&continuation);\n-\t\tstrbuf_addbuf(line, &continuation);\n-\t}\n-\n-\treturn 1;\n-}\n-\n-static int find_boundary(struct mailinfo *mi, struct strbuf *line)\n-{\n-\twhile (!strbuf_getline(line, mi->input, '\\n')) {\n-\t\tif (*(mi->content_top) && is_multipart_boundary(mi, line))\n-\t\t\treturn 1;\n-\t}\n-\treturn 0;\n-}\n-\n-static int handle_boundary(struct mailinfo *mi, struct strbuf *line)\n-{\n-\tstruct strbuf newline = STRBUF_INIT;\n-\n-\tstrbuf_addch(&newline, '\\n');\n-again:\n-\tif (line->len >= (*(mi->content_top))->len + 2 &&\n-\t    !memcmp(line->buf + (*(mi->content_top))->len, \"--\", 2)) {\n-\t\t/* we hit an end boundary */\n-\t\t/* pop the current boundary off the stack */\n-\t\tstrbuf_release(*(mi->content_top));\n-\t\tfree(*(mi->content_top));\n-\t\t*(mi->content_top) = NULL;\n-\n-\t\t/* technically won't happen as is_multipart_boundary()\n-\t\t   will fail first.  But just in case..\n-\t\t */\n-\t\tif (--mi->content_top < mi->content) {\n-\t\t\tfprintf(stderr, \"Detected mismatched boundaries, \"\n-\t\t\t\t\t\"can't recover\\n\");\n-\t\t\texit(1);\n-\t\t}\n-\t\thandle_filter(mi, &newline);\n-\t\tstrbuf_release(&newline);\n-\n-\t\t/* skip to the next boundary */\n-\t\tif (!find_boundary(mi, line))\n-\t\t\treturn 0;\n-\t\tgoto again;\n-\t}\n-\n-\t/* set some defaults */\n-\tmi->transfer_encoding = TE_DONTCARE;\n-\tstrbuf_reset(&mi->charset);\n-\n-\t/* slurp in this section's info */\n-\twhile (read_one_header_line(line, mi->input))\n-\t\tcheck_header(mi, line, mi->p_hdr_data, 0);\n-\n-\tstrbuf_release(&newline);\n-\t/* replenish line */\n-\tif (strbuf_getline(line, mi->input, '\\n'))\n-\t\treturn 0;\n-\tstrbuf_addch(line, '\\n');\n-\treturn 1;\n-}\n-\n-static void handle_body(struct mailinfo *mi, struct strbuf *line)\n-{\n-\tstruct strbuf prev = STRBUF_INIT;\n-\n-\t/* Skip up to the first boundary */\n-\tif (*(mi->content_top)) {\n-\t\tif (!find_boundary(mi, line))\n-\t\t\tgoto handle_body_out;\n-\t}\n-\n-\tdo {\n-\t\t/* process any boundary lines */\n-\t\tif (*(mi->content_top) && is_multipart_boundary(mi, line)) {\n-\t\t\t/* flush any leftover */\n-\t\t\tif (prev.len) {\n-\t\t\t\thandle_filter(mi, &prev);\n-\t\t\t\tstrbuf_reset(&prev);\n-\t\t\t}\n-\t\t\tif (!handle_boundary(mi, line))\n-\t\t\t\tgoto handle_body_out;\n-\t\t}\n-\n-\t\t/* Unwrap transfer encoding */\n-\t\tdecode_transfer_encoding(mi, line);\n-\n-\t\tswitch (mi->transfer_encoding) {\n-\t\tcase TE_BASE64:\n-\t\tcase TE_QP:\n-\t\t{\n-\t\t\tstruct strbuf **lines, **it, *sb;\n-\n-\t\t\t/* Prepend any previous partial lines */\n-\t\t\tstrbuf_insert(line, 0, prev.buf, prev.len);\n-\t\t\tstrbuf_reset(&prev);\n-\n-\t\t\t/*\n-\t\t\t * This is a decoded line that may contain\n-\t\t\t * multiple new lines.  Pass only one chunk\n-\t\t\t * at a time to handle_filter()\n-\t\t\t */\n-\t\t\tlines = strbuf_split(line, '\\n');\n-\t\t\tfor (it = lines; (sb = *it); it++) {\n-\t\t\t\tif (*(it + 1) == NULL) /* The last line */\n-\t\t\t\t\tif (sb->buf[sb->len - 1] != '\\n') {\n-\t\t\t\t\t\t/* Partial line, save it for later. */\n-\t\t\t\t\t\tstrbuf_addbuf(&prev, sb);\n-\t\t\t\t\t\tbreak;\n-\t\t\t\t\t}\n-\t\t\t\thandle_filter(mi, sb);\n-\t\t\t}\n-\t\t\t/*\n-\t\t\t * The partial chunk is saved in \"prev\" and will be\n-\t\t\t * appended by the next iteration of read_line_with_nul().\n-\t\t\t */\n-\t\t\tstrbuf_list_free(lines);\n-\t\t\tbreak;\n-\t\t}\n-\t\tdefault:\n-\t\t\thandle_filter(mi, line);\n-\t\t}\n-\n-\t} while (!strbuf_getwholeline(line, mi->input, '\\n'));\n-\n-handle_body_out:\n-\tstrbuf_release(&prev);\n-}\n-\n-static void output_header_lines(FILE *fout, const char *hdr, const struct strbuf *data)\n-{\n-\tconst char *sp = data->buf;\n-\twhile (1) {\n-\t\tchar *ep = strchr(sp, '\\n');\n-\t\tint len;\n-\t\tif (!ep)\n-\t\t\tlen = strlen(sp);\n-\t\telse\n-\t\t\tlen = ep - sp;\n-\t\tfprintf(fout, \"%s: %.*s\\n\", hdr, len, sp);\n-\t\tif (!ep)\n-\t\t\tbreak;\n-\t\tsp = ep + 1;\n-\t}\n-}\n-\n-static void handle_info(struct mailinfo *mi)\n-{\n-\tstruct strbuf *hdr;\n-\tint i;\n-\n-\tfor (i = 0; header[i]; i++) {\n-\t\t/* only print inbody headers if we output a patch file */\n-\t\tif (mi->patch_lines && mi->s_hdr_data[i])\n-\t\t\thdr = mi->s_hdr_data[i];\n-\t\telse if (mi->p_hdr_data[i])\n-\t\t\thdr = mi->p_hdr_data[i];\n-\t\telse\n-\t\t\tcontinue;\n-\n-\t\tif (!strcmp(header[i], \"Subject\")) {\n-\t\t\tif (!mi->keep_subject) {\n-\t\t\t\tcleanup_subject(mi, hdr);\n-\t\t\t\tcleanup_space(hdr);\n-\t\t\t}\n-\t\t\toutput_header_lines(mi->output, \"Subject\", hdr);\n-\t\t} else if (!strcmp(header[i], \"From\")) {\n-\t\t\tcleanup_space(hdr);\n-\t\t\thandle_from(mi, hdr);\n-\t\t\tfprintf(mi->output, \"Author: %s\\n\", mi->name.buf);\n-\t\t\tfprintf(mi->output, \"Email: %s\\n\", mi->email.buf);\n-\t\t} else {\n-\t\t\tcleanup_space(hdr);\n-\t\t\tfprintf(mi->output, \"%s: %s\\n\", header[i], hdr->buf);\n-\t\t}\n-\t}\n-\tfprintf(mi->output, \"\\n\");\n-}\n-\n-static int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)\n-{\n-\tFILE *cmitmsg;\n-\tint peek;\n-\tstruct strbuf line = STRBUF_INIT;\n-\n-\tcmitmsg = fopen(msg, \"w\");\n-\tif (!cmitmsg) {\n-\t\tperror(msg);\n-\t\treturn -1;\n-\t}\n-\tmi->patchfile = fopen(patch, \"w\");\n-\tif (!mi->patchfile) {\n-\t\tperror(patch);\n-\t\tfclose(cmitmsg);\n-\t\treturn -1;\n-\t}\n-\n-\tmi->p_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*(mi->p_hdr_data)));\n-\tmi->s_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*(mi->s_hdr_data)));\n-\n-\tdo {\n-\t\tpeek = fgetc(mi->input);\n-\t} while (isspace(peek));\n-\tungetc(peek, mi->input);\n-\n-\t/* process the email header */\n-\twhile (read_one_header_line(&line, mi->input))\n-\t\tcheck_header(mi, &line, mi->p_hdr_data, 1);\n-\n-\thandle_body(mi, &line);\n-\tfwrite(mi->log_message.buf, 1, mi->log_message.len, cmitmsg);\n-\tfclose(cmitmsg);\n-\tfclose(mi->patchfile);\n-\n-\thandle_info(mi);\n-\n-\treturn 0;\n-}\n-\n-static int git_mailinfo_config(const char *var, const char *value, void *mi_)\n-{\n-\tstruct mailinfo *mi = mi_;\n-\n-\tif (!starts_with(var, \"mailinfo.\"))\n-\t\treturn git_default_config(var, value, NULL);\n-\tif (!strcmp(var, \"mailinfo.scissors\")) {\n-\t\tmi->use_scissors = git_config_bool(var, value);\n-\t\treturn 0;\n-\t}\n-\t/* perhaps others here */\n-\treturn 0;\n-}\n-\n-static void setup_mailinfo(struct mailinfo *mi)\n-{\n-\tmemset(mi, 0, sizeof(*mi));\n-\tstrbuf_init(&mi->name, 0);\n-\tstrbuf_init(&mi->email, 0);\n-\tstrbuf_init(&mi->charset, 0);\n-\tstrbuf_init(&mi->log_message, 0);\n-\tmi->header_stage = 1;\n-\tmi->use_inbody_headers = 1;\n-\tmi->content_top = mi->content;\n-\tgit_config(git_mailinfo_config, &mi);\n-}\n-\n-static void clear_mailinfo(struct mailinfo *mi)\n-{\n-\tstrbuf_release(&mi->name);\n-\tstrbuf_release(&mi->email);\n-\tstrbuf_release(&mi->charset);\n-\tstrbuf_release(&mi->log_message);\n-\n-\twhile (mi->content < mi->content_top) {\n-\t\tfree(*(mi->content_top));\n-\t\tmi->content_top--;\n-\t}\n-}\n+#include \"mailinfo.h\"\n \n static const char mailinfo_usage[] =\n \t\"git mailinfo [-k | -b] [-m | --message-id] [-u | --encoding=<encoding> | -n] [--scissors | --no-scissors] <msg> <patch> < mail >info\";\ndiff --git a/mailinfo.c b/mailinfo.c\nnew file mode 100644\nindex 0000000..59479f6\n--- /dev/null\n+++ b/mailinfo.c\n@@ -0,0 +1,1007 @@\n+#include \"cache.h\"\n+#include \"utf8.h\"\n+#include \"strbuf.h\"\n+#include \"mailinfo.h\"\n+\n+static void cleanup_space(struct strbuf *sb)\n+{\n+\tsize_t pos, cnt;\n+\tfor (pos = 0; pos < sb->len; pos++) {\n+\t\tif (isspace(sb->buf[pos])) {\n+\t\t\tsb->buf[pos] = ' ';\n+\t\t\tfor (cnt = 0; isspace(sb->buf[pos + cnt + 1]); cnt++);\n+\t\t\tstrbuf_remove(sb, pos + 1, cnt);\n+\t\t}\n+\t}\n+}\n+\n+static void get_sane_name(struct strbuf *out, struct strbuf *name, struct strbuf *email)\n+{\n+\tstruct strbuf *src = name;\n+\tif (name->len < 3 || 60 < name->len || strchr(name->buf, '@') ||\n+\t\tstrchr(name->buf, '<') || strchr(name->buf, '>'))\n+\t\tsrc = email;\n+\telse if (name == out)\n+\t\treturn;\n+\tstrbuf_reset(out);\n+\tstrbuf_addbuf(out, src);\n+}\n+\n+static void parse_bogus_from(struct mailinfo *mi, const struct strbuf *line)\n+{\n+\t/* John Doe <johndoe> */\n+\n+\tchar *bra, *ket;\n+\t/* This is fallback, so do not bother if we already have an\n+\t * e-mail address.\n+\t */\n+\tif (mi->email.len)\n+\t\treturn;\n+\n+\tbra = strchr(line->buf, '<');\n+\tif (!bra)\n+\t\treturn;\n+\tket = strchr(bra, '>');\n+\tif (!ket)\n+\t\treturn;\n+\n+\tstrbuf_reset(&mi->email);\n+\tstrbuf_add(&mi->email, bra + 1, ket - bra - 1);\n+\n+\tstrbuf_reset(&mi->name);\n+\tstrbuf_add(&mi->name, line->buf, bra - line->buf);\n+\tstrbuf_trim(&mi->name);\n+\tget_sane_name(&mi->name, &mi->name, &mi->email);\n+}\n+\n+static void handle_from(struct mailinfo *mi, const struct strbuf *from)\n+{\n+\tchar *at;\n+\tsize_t el;\n+\tstruct strbuf f;\n+\n+\tstrbuf_init(&f, from->len);\n+\tstrbuf_addbuf(&f, from);\n+\n+\tat = strchr(f.buf, '@');\n+\tif (!at) {\n+\t\tparse_bogus_from(mi, from);\n+\t\treturn;\n+\t}\n+\n+\t/*\n+\t * If we already have one email, don't take any confusing lines\n+\t */\n+\tif (mi->email.len && strchr(at + 1, '@')) {\n+\t\tstrbuf_release(&f);\n+\t\treturn;\n+\t}\n+\n+\t/* Pick up the string around '@', possibly delimited with <>\n+\t * pair; that is the email part.\n+\t */\n+\twhile (at > f.buf) {\n+\t\tchar c = at[-1];\n+\t\tif (isspace(c))\n+\t\t\tbreak;\n+\t\tif (c == '<') {\n+\t\t\tat[-1] = ' ';\n+\t\t\tbreak;\n+\t\t}\n+\t\tat--;\n+\t}\n+\tel = strcspn(at, \" \\n\\t\\r\\v\\f>\");\n+\tstrbuf_reset(&mi->email);\n+\tstrbuf_add(&mi->email, at, el);\n+\tstrbuf_remove(&f, at - f.buf, el + (at[el] ? 1 : 0));\n+\n+\t/* The remainder is name.  It could be\n+\t *\n+\t * - \"John Doe <john.doe@xz>\"\t\t\t(a), or\n+\t * - \"john.doe@xz (John Doe)\"\t\t\t(b), or\n+\t * - \"John (zzz) Doe <john.doe@xz> (Comment)\"\t(c)\n+\t *\n+\t * but we have removed the email part, so\n+\t *\n+\t * - remove extra spaces which could stay after email (case 'c'), and\n+\t * - trim from both ends, possibly removing the () pair at the end\n+\t *   (cases 'a' and 'b').\n+\t */\n+\tcleanup_space(&f);\n+\tstrbuf_trim(&f);\n+\tif (f.buf[0] == '(' && f.len && f.buf[f.len - 1] == ')') {\n+\t\tstrbuf_remove(&f, 0, 1);\n+\t\tstrbuf_setlen(&f, f.len - 1);\n+\t}\n+\n+\tget_sane_name(&mi->name, &f, &mi->email);\n+\tstrbuf_release(&f);\n+}\n+\n+static void handle_header(struct strbuf **out, const struct strbuf *line)\n+{\n+\tif (!*out) {\n+\t\t*out = xmalloc(sizeof(struct strbuf));\n+\t\tstrbuf_init(*out, line->len);\n+\t} else\n+\t\tstrbuf_reset(*out);\n+\n+\tstrbuf_addbuf(*out, line);\n+}\n+\n+/* NOTE NOTE NOTE.  We do not claim we do full MIME.  We just attempt\n+ * to have enough heuristics to grok MIME encoded patches often found\n+ * on our mailing lists.  For example, we do not even treat header lines\n+ * case insensitively.\n+ */\n+\n+static int slurp_attr(const char *line, const char *name, struct strbuf *attr)\n+{\n+\tconst char *ends, *ap = strcasestr(line, name);\n+\tsize_t sz;\n+\n+\tstrbuf_setlen(attr, 0);\n+\tif (!ap)\n+\t\treturn 0;\n+\tap += strlen(name);\n+\tif (*ap == '\"') {\n+\t\tap++;\n+\t\tends = \"\\\"\";\n+\t}\n+\telse\n+\t\tends = \"; \\t\";\n+\tsz = strcspn(ap, ends);\n+\tstrbuf_add(attr, ap, sz);\n+\treturn 1;\n+}\n+\n+static void handle_content_type(struct mailinfo *mi, struct strbuf *line)\n+{\n+\tstruct strbuf *boundary = xmalloc(sizeof(struct strbuf));\n+\tstrbuf_init(boundary, line->len);\n+\n+\tif (slurp_attr(line->buf, \"boundary=\", boundary)) {\n+\t\tstrbuf_insert(boundary, 0, \"--\", 2);\n+\t\tif (++mi->content_top >= &mi->content[MAX_BOUNDARIES]) {\n+\t\t\tfprintf(stderr, \"Too many boundaries to handle\\n\");\n+\t\t\texit(1);\n+\t\t}\n+\t\t*(mi->content_top) = boundary;\n+\t\tboundary = NULL;\n+\t}\n+\tslurp_attr(line->buf, \"charset=\", &mi->charset);\n+\n+\tif (boundary) {\n+\t\tstrbuf_release(boundary);\n+\t\tfree(boundary);\n+\t}\n+}\n+\n+static void handle_message_id(struct mailinfo *mi, const struct strbuf *line)\n+{\n+\tif (mi->add_message_id)\n+\t\tmi->message_id = strdup(line->buf);\n+}\n+\n+static void handle_content_transfer_encoding(struct mailinfo *mi,\n+\t\t\t\t\t     const struct strbuf *line)\n+{\n+\tif (strcasestr(line->buf, \"base64\"))\n+\t\tmi->transfer_encoding = TE_BASE64;\n+\telse if (strcasestr(line->buf, \"quoted-printable\"))\n+\t\tmi->transfer_encoding = TE_QP;\n+\telse\n+\t\tmi->transfer_encoding = TE_DONTCARE;\n+}\n+\n+static int is_multipart_boundary(struct mailinfo *mi, const struct strbuf *line)\n+{\n+\tstruct strbuf *content_top = *(mi->content_top);\n+\n+\treturn ((content_top->len <= line->len) &&\n+\t\t!memcmp(line->buf, content_top->buf, content_top->len));\n+}\n+\n+static void cleanup_subject(struct mailinfo *mi, struct strbuf *subject)\n+{\n+\tsize_t at = 0;\n+\n+\twhile (at < subject->len) {\n+\t\tchar *pos;\n+\t\tsize_t remove;\n+\n+\t\tswitch (subject->buf[at]) {\n+\t\tcase 'r': case 'R':\n+\t\t\tif (subject->len <= at + 3)\n+\t\t\t\tbreak;\n+\t\t\tif ((subject->buf[at + 1] == 'e' ||\n+\t\t\t     subject->buf[at + 1] == 'E') &&\n+\t\t\t    subject->buf[at + 2] == ':') {\n+\t\t\t\tstrbuf_remove(subject, at, 3);\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\tat++;\n+\t\t\tbreak;\n+\t\tcase ' ': case '\\t': case ':':\n+\t\t\tstrbuf_remove(subject, at, 1);\n+\t\t\tcontinue;\n+\t\tcase '[':\n+\t\t\tpos = strchr(subject->buf + at, ']');\n+\t\t\tif (!pos)\n+\t\t\t\tbreak;\n+\t\t\tremove = pos - subject->buf + at + 1;\n+\t\t\tif (!mi->keep_non_patch_brackets_in_subject ||\n+\t\t\t    (7 <= remove &&\n+\t\t\t     memmem(subject->buf + at, remove, \"PATCH\", 5)))\n+\t\t\t\tstrbuf_remove(subject, at, remove);\n+\t\t\telse {\n+\t\t\t\tat += remove;\n+\t\t\t\t/*\n+\t\t\t\t * If the input had a space after the ], keep\n+\t\t\t\t * it.  We don't bother with finding the end of\n+\t\t\t\t * the space, since we later normalize it\n+\t\t\t\t * anyway.\n+\t\t\t\t */\n+\t\t\t\tif (isspace(subject->buf[at]))\n+\t\t\t\t\tat += 1;\n+\t\t\t}\n+\t\t\tcontinue;\n+\t\t}\n+\t\tbreak;\n+\t}\n+\tstrbuf_trim(subject);\n+}\n+\n+#define MAX_HDR_PARSED 10\n+static const char *header[MAX_HDR_PARSED] = {\n+\t\"From\",\"Subject\",\"Date\",\n+};\n+\n+static inline int cmp_header(const struct strbuf *line, const char *hdr)\n+{\n+\tint len = strlen(hdr);\n+\treturn !strncasecmp(line->buf, hdr, len) && line->len > len &&\n+\t\t\tline->buf[len] == ':' && isspace(line->buf[len + 1]);\n+}\n+\n+static int is_format_patch_separator(const char *line, int len)\n+{\n+\tstatic const char SAMPLE[] =\n+\t\t\"From e6807f3efca28b30decfecb1732a56c7db1137ee Mon Sep 17 00:00:00 2001\\n\";\n+\tconst char *cp;\n+\n+\tif (len != strlen(SAMPLE))\n+\t\treturn 0;\n+\tif (!skip_prefix(line, \"From \", &cp))\n+\t\treturn 0;\n+\tif (strspn(cp, \"0123456789abcdef\") != 40)\n+\t\treturn 0;\n+\tcp += 40;\n+\treturn !memcmp(SAMPLE + (cp - line), cp, strlen(SAMPLE) - (cp - line));\n+}\n+\n+static struct strbuf *decode_q_segment(const struct strbuf *q_seg, int rfc2047)\n+{\n+\tconst char *in = q_seg->buf;\n+\tint c;\n+\tstruct strbuf *out = xmalloc(sizeof(struct strbuf));\n+\tstrbuf_init(out, q_seg->len);\n+\n+\twhile ((c = *in++) != 0) {\n+\t\tif (c == '=') {\n+\t\t\tint d = *in++;\n+\t\t\tif (d == '\\n' || !d)\n+\t\t\t\tbreak; /* drop trailing newline */\n+\t\t\tstrbuf_addch(out, (hexval(d) << 4) | hexval(*in++));\n+\t\t\tcontinue;\n+\t\t}\n+\t\tif (rfc2047 && c == '_') /* rfc2047 4.2 (2) */\n+\t\t\tc = 0x20;\n+\t\tstrbuf_addch(out, c);\n+\t}\n+\treturn out;\n+}\n+\n+static struct strbuf *decode_b_segment(const struct strbuf *b_seg)\n+{\n+\t/* Decode in..ep, possibly in-place to ot */\n+\tint c, pos = 0, acc = 0;\n+\tconst char *in = b_seg->buf;\n+\tstruct strbuf *out = xmalloc(sizeof(struct strbuf));\n+\tstrbuf_init(out, b_seg->len);\n+\n+\twhile ((c = *in++) != 0) {\n+\t\tif (c == '+')\n+\t\t\tc = 62;\n+\t\telse if (c == '/')\n+\t\t\tc = 63;\n+\t\telse if ('A' <= c && c <= 'Z')\n+\t\t\tc -= 'A';\n+\t\telse if ('a' <= c && c <= 'z')\n+\t\t\tc -= 'a' - 26;\n+\t\telse if ('0' <= c && c <= '9')\n+\t\t\tc -= '0' - 52;\n+\t\telse\n+\t\t\tcontinue; /* garbage */\n+\t\tswitch (pos++) {\n+\t\tcase 0:\n+\t\t\tacc = (c << 2);\n+\t\t\tbreak;\n+\t\tcase 1:\n+\t\t\tstrbuf_addch(out, (acc | (c >> 4)));\n+\t\t\tacc = (c & 15) << 4;\n+\t\t\tbreak;\n+\t\tcase 2:\n+\t\t\tstrbuf_addch(out, (acc | (c >> 2)));\n+\t\t\tacc = (c & 3) << 6;\n+\t\t\tbreak;\n+\t\tcase 3:\n+\t\t\tstrbuf_addch(out, (acc | c));\n+\t\t\tacc = pos = 0;\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\treturn out;\n+}\n+\n+static void convert_to_utf8(struct mailinfo *mi,\n+\t\t\t    struct strbuf *line, const char *charset)\n+{\n+\tchar *out;\n+\n+\tif (!mi->metainfo_charset || !charset || !*charset)\n+\t\treturn;\n+\n+\tif (same_encoding(mi->metainfo_charset, charset))\n+\t\treturn;\n+\tout = reencode_string(line->buf, mi->metainfo_charset, charset);\n+\tif (!out)\n+\t\tdie(\"cannot convert from %s to %s\",\n+\t\t    charset, mi->metainfo_charset);\n+\tstrbuf_attach(line, out, strlen(out), strlen(out));\n+}\n+\n+static void decode_header(struct mailinfo *mi, struct strbuf *it)\n+{\n+\tchar *in, *ep, *cp;\n+\tstruct strbuf outbuf = STRBUF_INIT, *dec;\n+\tstruct strbuf charset_q = STRBUF_INIT, piecebuf = STRBUF_INIT;\n+\n+\tin = it->buf;\n+\twhile (in - it->buf <= it->len && (ep = strstr(in, \"=?\")) != NULL) {\n+\t\tint encoding;\n+\t\tstrbuf_reset(&charset_q);\n+\t\tstrbuf_reset(&piecebuf);\n+\n+\t\tif (in != ep) {\n+\t\t\t/*\n+\t\t\t * We are about to process an encoded-word\n+\t\t\t * that begins at ep, but there is something\n+\t\t\t * before the encoded word.\n+\t\t\t */\n+\t\t\tchar *scan;\n+\t\t\tfor (scan = in; scan < ep; scan++)\n+\t\t\t\tif (!isspace(*scan))\n+\t\t\t\t\tbreak;\n+\n+\t\t\tif (scan != ep || in == it->buf) {\n+\t\t\t\t/*\n+\t\t\t\t * We should not lose that \"something\",\n+\t\t\t\t * unless we have just processed an\n+\t\t\t\t * encoded-word, and there is only LWS\n+\t\t\t\t * before the one we are about to process.\n+\t\t\t\t */\n+\t\t\t\tstrbuf_add(&outbuf, in, ep - in);\n+\t\t\t}\n+\t\t}\n+\t\t/* E.g.\n+\t\t * ep : \"=?iso-2022-jp?B?GyR...?= foo\"\n+\t\t * ep : \"=?ISO-8859-1?Q?Foo=FCbar?= baz\"\n+\t\t */\n+\t\tep += 2;\n+\n+\t\tif (ep - it->buf >= it->len || !(cp = strchr(ep, '?')))\n+\t\t\tgoto release_return;\n+\n+\t\tif (cp + 3 - it->buf > it->len)\n+\t\t\tgoto release_return;\n+\t\tstrbuf_add(&charset_q, ep, cp - ep);\n+\n+\t\tencoding = cp[1];\n+\t\tif (!encoding || cp[2] != '?')\n+\t\t\tgoto release_return;\n+\t\tep = strstr(cp + 3, \"?=\");\n+\t\tif (!ep)\n+\t\t\tgoto release_return;\n+\t\tstrbuf_add(&piecebuf, cp + 3, ep - cp - 3);\n+\t\tswitch (tolower(encoding)) {\n+\t\tdefault:\n+\t\t\tgoto release_return;\n+\t\tcase 'b':\n+\t\t\tdec = decode_b_segment(&piecebuf);\n+\t\t\tbreak;\n+\t\tcase 'q':\n+\t\t\tdec = decode_q_segment(&piecebuf, 1);\n+\t\t\tbreak;\n+\t\t}\n+\t\tconvert_to_utf8(mi, dec, charset_q.buf);\n+\n+\t\tstrbuf_addbuf(&outbuf, dec);\n+\t\tstrbuf_release(dec);\n+\t\tfree(dec);\n+\t\tin = ep + 2;\n+\t}\n+\tstrbuf_addstr(&outbuf, in);\n+\tstrbuf_reset(it);\n+\tstrbuf_addbuf(it, &outbuf);\n+release_return:\n+\tstrbuf_release(&outbuf);\n+\tstrbuf_release(&charset_q);\n+\tstrbuf_release(&piecebuf);\n+}\n+\n+static int check_header(struct mailinfo *mi,\n+\t\t\tconst struct strbuf *line,\n+\t\t\tstruct strbuf *hdr_data[], int overwrite)\n+{\n+\tint i, ret = 0, len;\n+\tstruct strbuf sb = STRBUF_INIT;\n+\n+\t/* search for the interesting parts */\n+\tfor (i = 0; header[i]; i++) {\n+\t\tint len = strlen(header[i]);\n+\t\tif ((!hdr_data[i] || overwrite) && cmp_header(line, header[i])) {\n+\t\t\t/* Unwrap inline B and Q encoding, and optionally\n+\t\t\t * normalize the meta information to utf8.\n+\t\t\t */\n+\t\t\tstrbuf_add(&sb, line->buf + len + 2, line->len - len - 2);\n+\t\t\tdecode_header(mi, &sb);\n+\t\t\thandle_header(&hdr_data[i], &sb);\n+\t\t\tret = 1;\n+\t\t\tgoto check_header_out;\n+\t\t}\n+\t}\n+\n+\t/* Content stuff */\n+\tif (cmp_header(line, \"Content-Type\")) {\n+\t\tlen = strlen(\"Content-Type: \");\n+\t\tstrbuf_add(&sb, line->buf + len, line->len - len);\n+\t\tdecode_header(mi, &sb);\n+\t\tstrbuf_insert(&sb, 0, \"Content-Type: \", len);\n+\t\thandle_content_type(mi, &sb);\n+\t\tret = 1;\n+\t\tgoto check_header_out;\n+\t}\n+\tif (cmp_header(line, \"Content-Transfer-Encoding\")) {\n+\t\tlen = strlen(\"Content-Transfer-Encoding: \");\n+\t\tstrbuf_add(&sb, line->buf + len, line->len - len);\n+\t\tdecode_header(mi, &sb);\n+\t\thandle_content_transfer_encoding(mi, &sb);\n+\t\tret = 1;\n+\t\tgoto check_header_out;\n+\t}\n+\tif (cmp_header(line, \"Message-Id\")) {\n+\t\tlen = strlen(\"Message-Id: \");\n+\t\tstrbuf_add(&sb, line->buf + len, line->len - len);\n+\t\tdecode_header(mi, &sb);\n+\t\thandle_message_id(mi, &sb);\n+\t\tret = 1;\n+\t\tgoto check_header_out;\n+\t}\n+\n+\t/* for inbody stuff */\n+\tif (starts_with(line->buf, \">From\") && isspace(line->buf[5])) {\n+\t\tret = is_format_patch_separator(line->buf + 1, line->len - 1);\n+\t\tgoto check_header_out;\n+\t}\n+\tif (starts_with(line->buf, \"[PATCH]\") && isspace(line->buf[7])) {\n+\t\tfor (i = 0; header[i]; i++) {\n+\t\t\tif (!strcmp(\"Subject\", header[i])) {\n+\t\t\t\thandle_header(&hdr_data[i], line);\n+\t\t\t\tret = 1;\n+\t\t\t\tgoto check_header_out;\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+check_header_out:\n+\tstrbuf_release(&sb);\n+\treturn ret;\n+}\n+\n+static void decode_transfer_encoding(struct mailinfo *mi, struct strbuf *line)\n+{\n+\tstruct strbuf *ret;\n+\n+\tswitch (mi->transfer_encoding) {\n+\tcase TE_QP:\n+\t\tret = decode_q_segment(line, 0);\n+\t\tbreak;\n+\tcase TE_BASE64:\n+\t\tret = decode_b_segment(line);\n+\t\tbreak;\n+\tcase TE_DONTCARE:\n+\tdefault:\n+\t\treturn;\n+\t}\n+\tstrbuf_reset(line);\n+\tstrbuf_addbuf(line, ret);\n+\tstrbuf_release(ret);\n+\tfree(ret);\n+}\n+\n+static inline int patchbreak(const struct strbuf *line)\n+{\n+\tsize_t i;\n+\n+\t/* Beginning of a \"diff -\" header? */\n+\tif (starts_with(line->buf, \"diff -\"))\n+\t\treturn 1;\n+\n+\t/* CVS \"Index: \" line? */\n+\tif (starts_with(line->buf, \"Index: \"))\n+\t\treturn 1;\n+\n+\t/*\n+\t * \"--- <filename>\" starts patches without headers\n+\t * \"---<sp>*\" is a manual separator\n+\t */\n+\tif (line->len < 4)\n+\t\treturn 0;\n+\n+\tif (starts_with(line->buf, \"---\")) {\n+\t\t/* space followed by a filename? */\n+\t\tif (line->buf[3] == ' ' && !isspace(line->buf[4]))\n+\t\t\treturn 1;\n+\t\t/* Just whitespace? */\n+\t\tfor (i = 3; i < line->len; i++) {\n+\t\t\tunsigned char c = line->buf[i];\n+\t\t\tif (c == '\\n')\n+\t\t\t\treturn 1;\n+\t\t\tif (!isspace(c))\n+\t\t\t\tbreak;\n+\t\t}\n+\t\treturn 0;\n+\t}\n+\treturn 0;\n+}\n+\n+static int is_scissors_line(const struct strbuf *line)\n+{\n+\tsize_t i, len = line->len;\n+\tint scissors = 0, gap = 0;\n+\tint first_nonblank = -1;\n+\tint last_nonblank = 0, visible, perforation = 0, in_perforation = 0;\n+\tconst char *buf = line->buf;\n+\n+\tfor (i = 0; i < len; i++) {\n+\t\tif (isspace(buf[i])) {\n+\t\t\tif (in_perforation) {\n+\t\t\t\tperforation++;\n+\t\t\t\tgap++;\n+\t\t\t}\n+\t\t\tcontinue;\n+\t\t}\n+\t\tlast_nonblank = i;\n+\t\tif (first_nonblank < 0)\n+\t\t\tfirst_nonblank = i;\n+\t\tif (buf[i] == '-') {\n+\t\t\tin_perforation = 1;\n+\t\t\tperforation++;\n+\t\t\tcontinue;\n+\t\t}\n+\t\tif (i + 1 < len &&\n+\t\t    (!memcmp(buf + i, \">8\", 2) || !memcmp(buf + i, \"8<\", 2) ||\n+\t\t     !memcmp(buf + i, \">%\", 2) || !memcmp(buf + i, \"%<\", 2))) {\n+\t\t\tin_perforation = 1;\n+\t\t\tperforation += 2;\n+\t\t\tscissors += 2;\n+\t\t\ti++;\n+\t\t\tcontinue;\n+\t\t}\n+\t\tin_perforation = 0;\n+\t}\n+\n+\t/*\n+\t * The mark must be at least 8 bytes long (e.g. \"-- >8 --\").\n+\t * Even though there can be arbitrary cruft on the same line\n+\t * (e.g. \"cut here\"), in order to avoid misidentification, the\n+\t * perforation must occupy more than a third of the visible\n+\t * width of the line, and dashes and scissors must occupy more\n+\t * than half of the perforation.\n+\t */\n+\n+\tvisible = last_nonblank - first_nonblank + 1;\n+\treturn (scissors && 8 <= visible &&\n+\t\tvisible < perforation * 3 &&\n+\t\tgap * 2 < perforation);\n+}\n+\n+static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n+{\n+\tassert(!mi->filter_stage);\n+\n+\tif (mi->header_stage) {\n+\t\tif (!line->len || (line->len == 1 && line->buf[0] == '\\n'))\n+\t\t\treturn 0;\n+\t}\n+\n+\tif (mi->use_inbody_headers && mi->header_stage) {\n+\t\tmi->header_stage = check_header(mi, line, mi->s_hdr_data, 0);\n+\t\tif (mi->header_stage)\n+\t\t\treturn 0;\n+\t} else\n+\t\t/* Only trim the first (blank) line of the commit message\n+\t\t * when ignoring in-body headers.\n+\t\t */\n+\t\tmi->header_stage = 0;\n+\n+\t/* normalize the log message to UTF-8. */\n+\tconvert_to_utf8(mi, line, mi->charset.buf);\n+\n+\tif (mi->use_scissors && is_scissors_line(line)) {\n+\t\tint i;\n+\n+\t\tstrbuf_setlen(&mi->log_message, 0);\n+\t\tmi->header_stage = 1;\n+\n+\t\t/*\n+\t\t * We may have already read \"secondary headers\"; purge\n+\t\t * them to give ourselves a clean restart.\n+\t\t */\n+\t\tfor (i = 0; header[i]; i++) {\n+\t\t\tif (mi->s_hdr_data[i])\n+\t\t\t\tstrbuf_release(mi->s_hdr_data[i]);\n+\t\t\tmi->s_hdr_data[i] = NULL;\n+\t\t}\n+\t\treturn 0;\n+\t}\n+\n+\tif (patchbreak(line)) {\n+\t\tif (mi->message_id)\n+\t\t\tstrbuf_addf(&mi->log_message,\n+\t\t\t\t    \"Message-Id: %s\\n\", mi->message_id);\n+\t\treturn 1;\n+\t}\n+\n+\tstrbuf_addbuf(&mi->log_message, line);\n+\treturn 0;\n+}\n+\n+static void handle_patch(struct mailinfo *mi, const struct strbuf *line)\n+{\n+\tfwrite(line->buf, 1, line->len, mi->patchfile);\n+\tmi->patch_lines++;\n+}\n+\n+static void handle_filter(struct mailinfo *mi, struct strbuf *line)\n+{\n+\tswitch (mi->filter_stage) {\n+\tcase 0:\n+\t\tif (!handle_commit_msg(mi, line))\n+\t\t\tbreak;\n+\t\tmi->filter_stage++;\n+\tcase 1:\n+\t\thandle_patch(mi, line);\n+\t\tbreak;\n+\t}\n+}\n+\n+static int is_rfc2822_header(const struct strbuf *line)\n+{\n+\t/*\n+\t * The section that defines the loosest possible\n+\t * field name is \"3.6.8 Optional fields\".\n+\t *\n+\t * optional-field = field-name \":\" unstructured CRLF\n+\t * field-name = 1*ftext\n+\t * ftext = %d33-57 / %59-126\n+\t */\n+\tint ch;\n+\tchar *cp = line->buf;\n+\n+\t/* Count mbox From headers as headers */\n+\tif (starts_with(cp, \"From \") || starts_with(cp, \">From \"))\n+\t\treturn 1;\n+\n+\twhile ((ch = *cp++)) {\n+\t\tif (ch == ':')\n+\t\t\treturn 1;\n+\t\tif ((33 <= ch && ch <= 57) ||\n+\t\t    (59 <= ch && ch <= 126))\n+\t\t\tcontinue;\n+\t\tbreak;\n+\t}\n+\treturn 0;\n+}\n+\n+static int read_one_header_line(struct strbuf *line, FILE *in)\n+{\n+\t/* Get the first part of the line. */\n+\tif (strbuf_getline(line, in, '\\n'))\n+\t\treturn 0;\n+\n+\t/*\n+\t * Is it an empty line or not a valid rfc2822 header?\n+\t * If so, stop here, and return false (\"not a header\")\n+\t */\n+\tstrbuf_rtrim(line);\n+\tif (!line->len || !is_rfc2822_header(line)) {\n+\t\t/* Re-add the newline */\n+\t\tstrbuf_addch(line, '\\n');\n+\t\treturn 0;\n+\t}\n+\n+\t/*\n+\t * Now we need to eat all the continuation lines..\n+\t * Yuck, 2822 header \"folding\"\n+\t */\n+\tfor (;;) {\n+\t\tint peek;\n+\t\tstruct strbuf continuation = STRBUF_INIT;\n+\n+\t\tpeek = fgetc(in); ungetc(peek, in);\n+\t\tif (peek != ' ' && peek != '\\t')\n+\t\t\tbreak;\n+\t\tif (strbuf_getline(&continuation, in, '\\n'))\n+\t\t\tbreak;\n+\t\tcontinuation.buf[0] = ' ';\n+\t\tstrbuf_rtrim(&continuation);\n+\t\tstrbuf_addbuf(line, &continuation);\n+\t}\n+\n+\treturn 1;\n+}\n+\n+static int find_boundary(struct mailinfo *mi, struct strbuf *line)\n+{\n+\twhile (!strbuf_getline(line, mi->input, '\\n')) {\n+\t\tif (*(mi->content_top) && is_multipart_boundary(mi, line))\n+\t\t\treturn 1;\n+\t}\n+\treturn 0;\n+}\n+\n+static int handle_boundary(struct mailinfo *mi, struct strbuf *line)\n+{\n+\tstruct strbuf newline = STRBUF_INIT;\n+\n+\tstrbuf_addch(&newline, '\\n');\n+again:\n+\tif (line->len >= (*(mi->content_top))->len + 2 &&\n+\t    !memcmp(line->buf + (*(mi->content_top))->len, \"--\", 2)) {\n+\t\t/* we hit an end boundary */\n+\t\t/* pop the current boundary off the stack */\n+\t\tstrbuf_release(*(mi->content_top));\n+\t\tfree(*(mi->content_top));\n+\t\t*(mi->content_top) = NULL;\n+\n+\t\t/* technically won't happen as is_multipart_boundary()\n+\t\t   will fail first.  But just in case..\n+\t\t */\n+\t\tif (--mi->content_top < mi->content) {\n+\t\t\tfprintf(stderr, \"Detected mismatched boundaries, \"\n+\t\t\t\t\t\"can't recover\\n\");\n+\t\t\texit(1);\n+\t\t}\n+\t\thandle_filter(mi, &newline);\n+\t\tstrbuf_release(&newline);\n+\n+\t\t/* skip to the next boundary */\n+\t\tif (!find_boundary(mi, line))\n+\t\t\treturn 0;\n+\t\tgoto again;\n+\t}\n+\n+\t/* set some defaults */\n+\tmi->transfer_encoding = TE_DONTCARE;\n+\tstrbuf_reset(&mi->charset);\n+\n+\t/* slurp in this section's info */\n+\twhile (read_one_header_line(line, mi->input))\n+\t\tcheck_header(mi, line, mi->p_hdr_data, 0);\n+\n+\tstrbuf_release(&newline);\n+\t/* replenish line */\n+\tif (strbuf_getline(line, mi->input, '\\n'))\n+\t\treturn 0;\n+\tstrbuf_addch(line, '\\n');\n+\treturn 1;\n+}\n+\n+static void handle_body(struct mailinfo *mi, struct strbuf *line)\n+{\n+\tstruct strbuf prev = STRBUF_INIT;\n+\n+\t/* Skip up to the first boundary */\n+\tif (*(mi->content_top)) {\n+\t\tif (!find_boundary(mi, line))\n+\t\t\tgoto handle_body_out;\n+\t}\n+\n+\tdo {\n+\t\t/* process any boundary lines */\n+\t\tif (*(mi->content_top) && is_multipart_boundary(mi, line)) {\n+\t\t\t/* flush any leftover */\n+\t\t\tif (prev.len) {\n+\t\t\t\thandle_filter(mi, &prev);\n+\t\t\t\tstrbuf_reset(&prev);\n+\t\t\t}\n+\t\t\tif (!handle_boundary(mi, line))\n+\t\t\t\tgoto handle_body_out;\n+\t\t}\n+\n+\t\t/* Unwrap transfer encoding */\n+\t\tdecode_transfer_encoding(mi, line);\n+\n+\t\tswitch (mi->transfer_encoding) {\n+\t\tcase TE_BASE64:\n+\t\tcase TE_QP:\n+\t\t{\n+\t\t\tstruct strbuf **lines, **it, *sb;\n+\n+\t\t\t/* Prepend any previous partial lines */\n+\t\t\tstrbuf_insert(line, 0, prev.buf, prev.len);\n+\t\t\tstrbuf_reset(&prev);\n+\n+\t\t\t/*\n+\t\t\t * This is a decoded line that may contain\n+\t\t\t * multiple new lines.  Pass only one chunk\n+\t\t\t * at a time to handle_filter()\n+\t\t\t */\n+\t\t\tlines = strbuf_split(line, '\\n');\n+\t\t\tfor (it = lines; (sb = *it); it++) {\n+\t\t\t\tif (*(it + 1) == NULL) /* The last line */\n+\t\t\t\t\tif (sb->buf[sb->len - 1] != '\\n') {\n+\t\t\t\t\t\t/* Partial line, save it for later. */\n+\t\t\t\t\t\tstrbuf_addbuf(&prev, sb);\n+\t\t\t\t\t\tbreak;\n+\t\t\t\t\t}\n+\t\t\t\thandle_filter(mi, sb);\n+\t\t\t}\n+\t\t\t/*\n+\t\t\t * The partial chunk is saved in \"prev\" and will be\n+\t\t\t * appended by the next iteration of read_line_with_nul().\n+\t\t\t */\n+\t\t\tstrbuf_list_free(lines);\n+\t\t\tbreak;\n+\t\t}\n+\t\tdefault:\n+\t\t\thandle_filter(mi, line);\n+\t\t}\n+\n+\t} while (!strbuf_getwholeline(line, mi->input, '\\n'));\n+\n+handle_body_out:\n+\tstrbuf_release(&prev);\n+}\n+\n+static void output_header_lines(FILE *fout, const char *hdr, const struct strbuf *data)\n+{\n+\tconst char *sp = data->buf;\n+\twhile (1) {\n+\t\tchar *ep = strchr(sp, '\\n');\n+\t\tint len;\n+\t\tif (!ep)\n+\t\t\tlen = strlen(sp);\n+\t\telse\n+\t\t\tlen = ep - sp;\n+\t\tfprintf(fout, \"%s: %.*s\\n\", hdr, len, sp);\n+\t\tif (!ep)\n+\t\t\tbreak;\n+\t\tsp = ep + 1;\n+\t}\n+}\n+\n+static void handle_info(struct mailinfo *mi)\n+{\n+\tstruct strbuf *hdr;\n+\tint i;\n+\n+\tfor (i = 0; header[i]; i++) {\n+\t\t/* only print inbody headers if we output a patch file */\n+\t\tif (mi->patch_lines && mi->s_hdr_data[i])\n+\t\t\thdr = mi->s_hdr_data[i];\n+\t\telse if (mi->p_hdr_data[i])\n+\t\t\thdr = mi->p_hdr_data[i];\n+\t\telse\n+\t\t\tcontinue;\n+\n+\t\tif (!strcmp(header[i], \"Subject\")) {\n+\t\t\tif (!mi->keep_subject) {\n+\t\t\t\tcleanup_subject(mi, hdr);\n+\t\t\t\tcleanup_space(hdr);\n+\t\t\t}\n+\t\t\toutput_header_lines(mi->output, \"Subject\", hdr);\n+\t\t} else if (!strcmp(header[i], \"From\")) {\n+\t\t\tcleanup_space(hdr);\n+\t\t\thandle_from(mi, hdr);\n+\t\t\tfprintf(mi->output, \"Author: %s\\n\", mi->name.buf);\n+\t\t\tfprintf(mi->output, \"Email: %s\\n\", mi->email.buf);\n+\t\t} else {\n+\t\t\tcleanup_space(hdr);\n+\t\t\tfprintf(mi->output, \"%s: %s\\n\", header[i], hdr->buf);\n+\t\t}\n+\t}\n+\tfprintf(mi->output, \"\\n\");\n+}\n+\n+int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)\n+{\n+\tFILE *cmitmsg;\n+\tint peek;\n+\tstruct strbuf line = STRBUF_INIT;\n+\n+\tcmitmsg = fopen(msg, \"w\");\n+\tif (!cmitmsg) {\n+\t\tperror(msg);\n+\t\treturn -1;\n+\t}\n+\tmi->patchfile = fopen(patch, \"w\");\n+\tif (!mi->patchfile) {\n+\t\tperror(patch);\n+\t\tfclose(cmitmsg);\n+\t\treturn -1;\n+\t}\n+\n+\tmi->p_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*(mi->p_hdr_data)));\n+\tmi->s_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*(mi->s_hdr_data)));\n+\n+\tdo {\n+\t\tpeek = fgetc(mi->input);\n+\t} while (isspace(peek));\n+\tungetc(peek, mi->input);\n+\n+\t/* process the email header */\n+\twhile (read_one_header_line(&line, mi->input))\n+\t\tcheck_header(mi, &line, mi->p_hdr_data, 1);\n+\n+\thandle_body(mi, &line);\n+\tfwrite(mi->log_message.buf, 1, mi->log_message.len, cmitmsg);\n+\tfclose(cmitmsg);\n+\tfclose(mi->patchfile);\n+\n+\thandle_info(mi);\n+\n+\treturn 0;\n+}\n+\n+static int git_mailinfo_config(const char *var, const char *value, void *mi_)\n+{\n+\tstruct mailinfo *mi = mi_;\n+\n+\tif (!starts_with(var, \"mailinfo.\"))\n+\t\treturn git_default_config(var, value, NULL);\n+\tif (!strcmp(var, \"mailinfo.scissors\")) {\n+\t\tmi->use_scissors = git_config_bool(var, value);\n+\t\treturn 0;\n+\t}\n+\t/* perhaps others here */\n+\treturn 0;\n+}\n+\n+void setup_mailinfo(struct mailinfo *mi)\n+{\n+\tmemset(mi, 0, sizeof(*mi));\n+\tstrbuf_init(&mi->name, 0);\n+\tstrbuf_init(&mi->email, 0);\n+\tstrbuf_init(&mi->charset, 0);\n+\tstrbuf_init(&mi->log_message, 0);\n+\tmi->header_stage = 1;\n+\tmi->use_inbody_headers = 1;\n+\tmi->content_top = mi->content;\n+\tgit_config(git_mailinfo_config, &mi);\n+}\n+\n+void clear_mailinfo(struct mailinfo *mi)\n+{\n+\tstrbuf_release(&mi->name);\n+\tstrbuf_release(&mi->email);\n+\tstrbuf_release(&mi->charset);\n+\tstrbuf_release(&mi->log_message);\n+\n+\twhile (mi->content < mi->content_top) {\n+\t\tfree(*(mi->content_top));\n+\t\tmi->content_top--;\n+\t}\n+}\ndiff --git a/mailinfo.h b/mailinfo.h\nnew file mode 100644\nindex 0000000..27841be\n--- /dev/null\n+++ b/mailinfo.h\n@@ -0,0 +1,40 @@\n+#ifndef MAILINFO_H\n+#define MAILINFO_H\n+\n+#define MAX_BOUNDARIES 5\n+\n+struct mailinfo {\n+\tFILE *input;\n+\tFILE *output;\n+\tFILE *patchfile;\n+\n+\tstruct strbuf name;\n+\tstruct strbuf email;\n+\tint keep_subject;\n+\tint keep_non_patch_brackets_in_subject;\n+\tint add_message_id;\n+\tint use_scissors;\n+\tint use_inbody_headers; /* defaults to 1 */\n+\tconst char *metainfo_charset;\n+\n+\tstruct strbuf *content[MAX_BOUNDARIES];\n+\tstruct strbuf **content_top;\n+\tstruct strbuf charset;\n+\tchar *message_id;\n+\tenum  {\n+\t\tTE_DONTCARE, TE_QP, TE_BASE64\n+\t} transfer_encoding;\n+\tint patch_lines;\n+\tint filter_stage; /* still reading log or are we copying patch? */\n+\tint header_stage; /* still checking in-body headers? */\n+\tstruct strbuf **p_hdr_data;\n+\tstruct strbuf **s_hdr_data;\n+\n+\tstruct strbuf log_message;\n+};\n+\n+extern void setup_mailinfo(struct mailinfo *);\n+extern int mailinfo(struct mailinfo *, const char *msg, const char *patch);\n+extern void clear_mailinfo(struct mailinfo *);\n+\n+#endif /* MAILINFO_H */\n-- \n2.6.1-320-g86a1181\n"},{"id":"271679","messageId":"1444855557-2127-30-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444855557-2127-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 29/31] mailinfo: handle charset conversion errors in the caller","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-14T20:45:55Z","receivedAt":"2015-10-14T20:45:55Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Instead of dying in convert_to_utf8(), just report an error and let\nthe callers handle it.  Between the two callers:\n\n - decode_header() silently punts when it cannot parse a broken\n   RFC2047 encoded text (e.g. when it sees anything other than B or\n   Q after it sees \"=?<charset>\") by jumping to release_return,\n   returning the string it successfully parsed out so far, to the\n   caller.  A piece of string that convert_to_utf8() cannot handle\n   can be treated the same way.\n\n - handle_commit_msg() doesn't cope with a malformed line well, so\n   die there for now.  We'll lift this even higher in later changes\n   in this series.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n mailinfo.c | 19 +++++++++++--------\n 1 file changed, 11 insertions(+), 8 deletions(-)\n\ndiff --git a/mailinfo.c b/mailinfo.c\nindex 59479f6..7969bf4 100644\n--- a/mailinfo.c\n+++ b/mailinfo.c\n@@ -344,21 +344,22 @@ static struct strbuf *decode_b_segment(const struct strbuf *b_seg)\n \treturn out;\n }\n \n-static void convert_to_utf8(struct mailinfo *mi,\n-\t\t\t    struct strbuf *line, const char *charset)\n+static int convert_to_utf8(struct mailinfo *mi,\n+\t\t\t   struct strbuf *line, const char *charset)\n {\n \tchar *out;\n \n \tif (!mi->metainfo_charset || !charset || !*charset)\n-\t\treturn;\n+\t\treturn 0;\n \n \tif (same_encoding(mi->metainfo_charset, charset))\n-\t\treturn;\n+\t\treturn 0;\n \tout = reencode_string(line->buf, mi->metainfo_charset, charset);\n \tif (!out)\n-\t\tdie(\"cannot convert from %s to %s\",\n-\t\t    charset, mi->metainfo_charset);\n+\t\treturn error(\"cannot convert from %s to %s\",\n+\t\t\t     charset, mi->metainfo_charset);\n \tstrbuf_attach(line, out, strlen(out), strlen(out));\n+\treturn 0;\n }\n \n static void decode_header(struct mailinfo *mi, struct strbuf *it)\n@@ -424,7 +425,8 @@ static void decode_header(struct mailinfo *mi, struct strbuf *it)\n \t\t\tdec = decode_q_segment(&piecebuf, 1);\n \t\t\tbreak;\n \t\t}\n-\t\tconvert_to_utf8(mi, dec, charset_q.buf);\n+\t\tif (convert_to_utf8(mi, dec, charset_q.buf))\n+\t\t\tgoto release_return;\n \n \t\tstrbuf_addbuf(&outbuf, dec);\n \t\tstrbuf_release(dec);\n@@ -637,7 +639,8 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n \t\tmi->header_stage = 0;\n \n \t/* normalize the log message to UTF-8. */\n-\tconvert_to_utf8(mi, line, mi->charset.buf);\n+\tif (convert_to_utf8(mi, line, mi->charset.buf))\n+\t\texit(128);\n \n \tif (mi->use_scissors && is_scissors_line(line)) {\n \t\tint i;\n-- \n2.6.1-320-g86a1181\n"},{"id":"271674","messageId":"1444855557-2127-31-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444855557-2127-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 30/31] mailinfo: remove calls to exit() and die() deep in the callchain","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-14T20:45:56Z","receivedAt":"2015-10-14T20:45:56Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The top-level mailinfo() would instead punt when the code in the\ndeeper part of the callchain detects an unrecoverable error in the\ninput.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n mailinfo.c | 30 ++++++++++++++++++++++--------\n mailinfo.h |  1 +\n 2 files changed, 23 insertions(+), 8 deletions(-)\n\ndiff --git a/mailinfo.c b/mailinfo.c\nindex 7969bf4..cb39c6d 100644\n--- a/mailinfo.c\n+++ b/mailinfo.c\n@@ -163,8 +163,10 @@ static void handle_content_type(struct mailinfo *mi, struct strbuf *line)\n \tif (slurp_attr(line->buf, \"boundary=\", boundary)) {\n \t\tstrbuf_insert(boundary, 0, \"--\", 2);\n \t\tif (++mi->content_top >= &mi->content[MAX_BOUNDARIES]) {\n-\t\t\tfprintf(stderr, \"Too many boundaries to handle\\n\");\n-\t\t\texit(1);\n+\t\t\terror(\"Too many boundaries to handle\");\n+\t\t\tmi->input_error = -1;\n+\t\t\tmi->content_top = &mi->content[MAX_BOUNDARIES] - 1;\n+\t\t\treturn;\n \t\t}\n \t\t*(mi->content_top) = boundary;\n \t\tboundary = NULL;\n@@ -355,9 +357,11 @@ static int convert_to_utf8(struct mailinfo *mi,\n \tif (same_encoding(mi->metainfo_charset, charset))\n \t\treturn 0;\n \tout = reencode_string(line->buf, mi->metainfo_charset, charset);\n-\tif (!out)\n+\tif (!out) {\n+\t\tmi->input_error = -1;\n \t\treturn error(\"cannot convert from %s to %s\",\n \t\t\t     charset, mi->metainfo_charset);\n+\t}\n \tstrbuf_attach(line, out, strlen(out), strlen(out));\n \treturn 0;\n }\n@@ -367,6 +371,7 @@ static void decode_header(struct mailinfo *mi, struct strbuf *it)\n \tchar *in, *ep, *cp;\n \tstruct strbuf outbuf = STRBUF_INIT, *dec;\n \tstruct strbuf charset_q = STRBUF_INIT, piecebuf = STRBUF_INIT;\n+\tint found_error = 1; /* pessimism */\n \n \tin = it->buf;\n \twhile (in - it->buf <= it->len && (ep = strstr(in, \"=?\")) != NULL) {\n@@ -436,10 +441,14 @@ static void decode_header(struct mailinfo *mi, struct strbuf *it)\n \tstrbuf_addstr(&outbuf, in);\n \tstrbuf_reset(it);\n \tstrbuf_addbuf(it, &outbuf);\n+\tfound_error = 0;\n release_return:\n \tstrbuf_release(&outbuf);\n \tstrbuf_release(&charset_q);\n \tstrbuf_release(&piecebuf);\n+\n+\tif (found_error)\n+\t\tmi->input_error = -1;\n }\n \n static int check_header(struct mailinfo *mi,\n@@ -640,7 +649,7 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n \n \t/* normalize the log message to UTF-8. */\n \tif (convert_to_utf8(mi, line, mi->charset.buf))\n-\t\texit(128);\n+\t\treturn 0; /* mi->input_error already set */\n \n \tif (mi->use_scissors && is_scissors_line(line)) {\n \t\tint i;\n@@ -783,12 +792,15 @@ again:\n \t\t   will fail first.  But just in case..\n \t\t */\n \t\tif (--mi->content_top < mi->content) {\n-\t\t\tfprintf(stderr, \"Detected mismatched boundaries, \"\n-\t\t\t\t\t\"can't recover\\n\");\n-\t\t\texit(1);\n+\t\t\terror(\"Detected mismatched boundaries, can't recover\");\n+\t\t\tmi->input_error = -1;\n+\t\t\tmi->content_top = mi->content;\n+\t\t\treturn 0;\n \t\t}\n \t\thandle_filter(mi, &newline);\n \t\tstrbuf_release(&newline);\n+\t\tif (mi->input_error)\n+\t\t\treturn 0;\n \n \t\t/* skip to the next boundary */\n \t\tif (!find_boundary(mi, line))\n@@ -873,6 +885,8 @@ static void handle_body(struct mailinfo *mi, struct strbuf *line)\n \t\t\thandle_filter(mi, line);\n \t\t}\n \n+\t\tif (mi->input_error)\n+\t\t\tbreak;\n \t} while (!strbuf_getwholeline(line, mi->input, '\\n'));\n \n handle_body_out:\n@@ -966,7 +980,7 @@ int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)\n \n \thandle_info(mi);\n \n-\treturn 0;\n+\treturn mi->input_error;\n }\n \n static int git_mailinfo_config(const char *var, const char *value, void *mi_)\ndiff --git a/mailinfo.h b/mailinfo.h\nindex 27841be..5bf257d 100644\n--- a/mailinfo.h\n+++ b/mailinfo.h\n@@ -31,6 +31,7 @@ struct mailinfo {\n \tstruct strbuf **s_hdr_data;\n \n \tstruct strbuf log_message;\n+\tint input_error;\n };\n \n extern void setup_mailinfo(struct mailinfo *);\n-- \n2.6.1-320-g86a1181\n"},{"id":"271670","messageId":"1444855557-2127-32-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444855557-2127-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 31/31] am: make direct call to mailinfo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-14T20:45:57Z","receivedAt":"2015-10-14T20:45:57Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"And finally the endgame.  Instead of spawning \"git mailinfo\" via the\nrun_command() API the same number of times as there are incoming\npatches, make direct internal call to the libified mailinfo() from\n\"git am\" to reduce the spawning overhead, which would matter on some\nplatforms.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/am.c | 42 +++++++++++++++++++++++-------------------\n 1 file changed, 23 insertions(+), 19 deletions(-)\n\ndiff --git a/builtin/am.c b/builtin/am.c\nindex 4f77e07..1873307 100644\n--- a/builtin/am.c\n+++ b/builtin/am.c\n@@ -27,6 +27,7 @@\n #include \"notes-utils.h\"\n #include \"rerere.h\"\n #include \"prompt.h\"\n+#include \"mailinfo.h\"\n \n /**\n  * Returns 1 if the file is empty or does not exist, 0 otherwise.\n@@ -1258,58 +1259,61 @@ static void am_append_signoff(struct am_state *state)\n static int parse_mail(struct am_state *state, const char *mail)\n {\n \tFILE *fp;\n-\tstruct child_process cp = CHILD_PROCESS_INIT;\n \tstruct strbuf sb = STRBUF_INIT;\n \tstruct strbuf msg = STRBUF_INIT;\n \tstruct strbuf author_name = STRBUF_INIT;\n \tstruct strbuf author_date = STRBUF_INIT;\n \tstruct strbuf author_email = STRBUF_INIT;\n \tint ret = 0;\n+\tstruct mailinfo mi;\n \n-\tcp.git_cmd = 1;\n-\tcp.in = xopen(mail, O_RDONLY, 0);\n-\tcp.out = xopen(am_path(state, \"info\"), O_WRONLY | O_CREAT, 0777);\n+\tsetup_mailinfo(&mi);\n \n-\targv_array_push(&cp.args, \"mailinfo\");\n-\targv_array_push(&cp.args, state->utf8 ? \"-u\" : \"-n\");\n+\tif (state->utf8)\n+\t\tmi.metainfo_charset = get_commit_output_encoding();\n+\telse\n+\t\tmi.metainfo_charset = NULL;\n \n \tswitch (state->keep) {\n \tcase KEEP_FALSE:\n \t\tbreak;\n \tcase KEEP_TRUE:\n-\t\targv_array_push(&cp.args, \"-k\");\n+\t\tmi.keep_subject = 1;\n \t\tbreak;\n \tcase KEEP_NON_PATCH:\n-\t\targv_array_push(&cp.args, \"-b\");\n+\t\tmi.keep_non_patch_brackets_in_subject = 1;\n \t\tbreak;\n \tdefault:\n \t\tdie(\"BUG: invalid value for state->keep\");\n \t}\n \n \tif (state->message_id)\n-\t\targv_array_push(&cp.args, \"-m\");\n+\t\tmi.add_message_id = 1;\n \n \tswitch (state->scissors) {\n \tcase SCISSORS_UNSET:\n \t\tbreak;\n \tcase SCISSORS_FALSE:\n-\t\targv_array_push(&cp.args, \"--no-scissors\");\n+\t\tmi.use_scissors = 0;\n \t\tbreak;\n \tcase SCISSORS_TRUE:\n-\t\targv_array_push(&cp.args, \"--scissors\");\n+\t\tmi.use_scissors = 1;\n \t\tbreak;\n \tdefault:\n \t\tdie(\"BUG: invalid value for state->scissors\");\n \t}\n \n-\targv_array_push(&cp.args, am_path(state, \"msg\"));\n-\targv_array_push(&cp.args, am_path(state, \"patch\"));\n-\n-\tif (run_command(&cp) < 0)\n+\tmi.input = fopen(mail, \"r\");\n+\tif (!mi.input)\n+\t\tdie(\"could not open input\");\n+\tmi.output = fopen(am_path(state, \"info\"), \"w\");\n+\tif (!mi.output)\n+\t\tdie(\"could not open output 'info'\");\n+\tif (mailinfo(&mi, am_path(state, \"msg\"), am_path(state, \"patch\")))\n \t\tdie(\"could not parse patch\");\n \n-\tclose(cp.in);\n-\tclose(cp.out);\n+\tfclose(mi.input);\n+\tfclose(mi.output);\n \n \t/* Extract message and author information */\n \tfp = xfopen(am_path(state, \"info\"), \"r\");\n@@ -1341,8 +1345,7 @@ static int parse_mail(struct am_state *state, const char *mail)\n \t}\n \n \tstrbuf_addstr(&msg, \"\\n\\n\");\n-\tif (strbuf_read_file(&msg, am_path(state, \"msg\"), 0) < 0)\n-\t\tdie_errno(_(\"could not read '%s'\"), am_path(state, \"msg\"));\n+\tstrbuf_addbuf(&msg, &mi.log_message);\n \tstripspace(&msg, 0);\n \n \tif (state->signoff)\n@@ -1366,6 +1369,7 @@ finish:\n \tstrbuf_release(&author_email);\n \tstrbuf_release(&author_name);\n \tstrbuf_release(&sb);\n+\tclear_mailinfo(&mi);\n \treturn ret;\n }\n \n-- \n2.6.1-320-g86a1181\n"},{"id":"271707","messageId":"xmqq7fmphxft.fsf@gitster.mtv.corp.google.com","threadId":"40552","inReplyTo":"1444855557-2127-21-git-send-email-gitster@pobox.com","subject":"Re: [PATCH v2 20/31] mailinfo: move cmitmsg and patchfile to struct mailinfo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-14T22:55:50Z","receivedAt":"2015-10-14T22:55:50Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This step does not compile correctly; will be fixed in v3.\n"},{"id":"271708","messageId":"xmqq37xdhxcx.fsf@gitster.mtv.corp.google.com","threadId":"40552","inReplyTo":"1444855557-2127-22-git-send-email-gitster@pobox.com","subject":"Re: [PATCH v2 21/31] mailinfo: move [ps]_hdr_data to struct mailinfo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-14T22:57:34Z","receivedAt":"2015-10-14T22:57:34Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> @@ -995,10 +995,10 @@ static int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)\n>  \n>  \t/* process the email header */\n>  \twhile (read_one_header_line(&line, mi->input))\n> -\t\tcheck_header(mi, &line, p_hdr_data, 1);\n> +\t\tcheck_header(mi, &line, mi->p_hdr_data, 1);\n>  \n>  \thandle_body(mi, &line);\n> -\tfclose(patchfile);\n> +\tfclose(mi->patchfile);\n\n... this is the bit that should have be in 20/31.\n"},{"id":"271776","messageId":"CAPig+cSnPT=oEB7bxFufaZ8JtDTxtrkiaUDcz4K+hu4wM-wOmg@mail.gmail.com","threadId":"40552","inReplyTo":"1444855557-2127-17-git-send-email-gitster@pobox.com","subject":"Re: [PATCH v2 16/31] mailinfo: move metainfo_charset to struct mailinfo","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2015-10-15T20:47:19Z","receivedAt":"2015-10-15T20:47:19Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Wed, Oct 14, 2015 at 4:45 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> This requires us to pass the struct down to decode_header() and\n> convert_to_utf8() callchain.\n>\n> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n> ---\n> @@ -520,23 +519,24 @@ static struct strbuf *decode_b_segment(const struct strbuf *b_seg)\n> -static void convert_to_utf8(struct strbuf *line, const char *charset)\n> +static void convert_to_utf8(struct mailinfo *mi,\n> +                           struct strbuf *line, const char *charset)\n>  {\n>         char *out;\n>\n> -       if (!charset || !*charset)\n> +       if (!mi->metainfo_charset || !charset || !*charset)\n>                 return;\n\nMental note: convert_to_utf8() is updated to return early when\nmetainfo_charset==NULL.\n\n> -       if (same_encoding(metainfo_charset, charset))\n> +       if (same_encoding(mi->metainfo_charset, charset))\n>                 return;\n> -       out = reencode_string(line->buf, metainfo_charset, charset);\n> +       out = reencode_string(line->buf, mi->metainfo_charset, charset);\n>         if (!out)\n>                 die(\"cannot convert from %s to %s\",\n> -                   charset, metainfo_charset);\n> +                   charset, mi->metainfo_charset);\n>         strbuf_attach(line, out, strlen(out), strlen(out));\n>  }\n>\n> -static void decode_header(struct strbuf *it)\n> +static void decode_header(struct mailinfo *mi, struct strbuf *it)\n>  {\n>         char *in, *ep, *cp;\n>         struct strbuf outbuf = STRBUF_INIT, *dec;\n> @@ -599,8 +599,7 @@ static void decode_header(struct strbuf *it)\n>                         dec = decode_q_segment(&piecebuf, 1);\n>                         break;\n>                 }\n> -               if (metainfo_charset)\n> -                       convert_to_utf8(dec, charset_q.buf);\n> +               convert_to_utf8(mi, dec, charset_q.buf);\n\nIt's safe to drop the conditional here since convert_to_utf8() now\nchecks metainfo_charset. Okay.\n\n>                 strbuf_addbuf(&outbuf, dec);\n>                 strbuf_release(dec);\n> @@ -745,8 +744,7 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n>                 mi->header_stage = 0;\n>\n>         /* normalize the log message to UTF-8. */\n> -       if (metainfo_charset)\n> -               convert_to_utf8(line, charset.buf);\n> +       convert_to_utf8(mi, line, charset.buf);\n\nDitto.\n\n>         if (mi->use_scissors && is_scissors_line(line)) {\n>                 int i;\n"},{"id":"271895","messageId":"1445239731-10677-1-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1444855557-2127-1-git-send-email-gitster@pobox.com","subject":"[PATCH v3 00/34] libify mailinfo and call it directly from am","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-19T07:28:17Z","receivedAt":"2015-10-19T07:28:17Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"During the discussion on the recent \"git am\" regression, I noticed\nthat the command reimplemented in C spawns one \"mailsplit\" and then\nspawns \"mailinfo\" followed by \"apply --index\" to commit the changes\ndescribed in each message.  As there are platforms where spawning\nsubprocess via run_command() interface is heavy-weight, something\nthat is conceptually very simple like \"mailinfo\" is better called\ndirectly inside the process---something that is lightweight and\nfrequently used is where the overhead of run_command() would be felt\nmost.\n\nI think this round is ready for 'next'.  Relative to the previous\nround, the changes are:\n\n * Editorial fixes on log messages.\n\n * The previous round leaked some fields in struct mailinfo upon\n   completion (of course, inherited from the original that let the\n   system clean them up upon process termination).  clear_mailinfo()\n   has been enhanced to clear them.\n\n * The step to remove the global \"line\" variable has been split into\n   multiple steps.\n\n * The step to move metainfo_charset to the struct has been split\n   into two.\n\nAnd here are the patches.\n\n  mailinfo: remove a no-op call convert_to_utf8(it, \"\")\n  mailinfo: fold decode_header_bq() into decode_header()\n  mailinfo: fix an off-by-one error in the boundary stack\n  mailinfo: explicitly close file handle to the patch output\n  mailinfo: move handle_boundary() lower\n  mailinfo: get rid of function-local static states\n\nMostly unchanged other than editorial fixes on their log messages.\n\n  mailinfo: do not let handle_body() touch global \"line\" directly\n  mailinfo: do not let handle_boundary() touch global \"line\" directly\n  mailinfo: do not let find_boundary() touch global \"line\" directly\n  mailinfo: move global \"line\" into mailinfo() function\n\nAfter Stefan's review comments, I wanted to be really sure that this\nconversion was correct.  Blindingly replacing the reference to the\nglobal with a pointer passed from the callern is not sufficient to\nensure that the change is a no-op; the patches needed to show that\nthe pointer passed from the caller is always the global \"line\".  For\nthat, the patch [v2 7/31] needed to be split further into 3 patches\nto convert three functions, each of which always is called with the\npointer that points at the global \"line\", in separate steps.\n\n  mailinfo: introduce \"struct mailinfo\" to hold globals\n\nThe previous round was lazy and did not introduce clear_mailinfo()\nuntil later, leaking the two strbuf moved into the struct.  The\noriginal was leaking the global anyway, so it is not a big deal, but\nthis round adds corresponding clean-up as the patches move global\nvariables to the struct, which should make it harder to miss\nforgotten clean-up.\n\n  mailinfo: move keep_subject & keep_non_patch_bracket to struct mailinfo\n  mailinfo: move global \"FILE *fin, *fout\" to struct mailinfo\n  mailinfo: move filter/header stage to struct mailinfo\n  mailinfo: move patch_lines to struct mailinfo\n  mailinfo: move add_message_id and message_id to struct mailinfo\n  mailinfo: move use_scissors and use_inbody_headers to struct mailinfo\n  mailinfo: move metainfo_charset to struct mailinfo\n\nMostly unchanged, except for the clean-up in clear_mailinfo().\n\n  mailinfo: move check for metainfo_charset to convert_to_utf8()\n\nEric's review noticed that the previous round conflated this step\nin the previous step.  Separated the change to its own commit.\n\n  mailinfo: move transfer_encoding to struct mailinfo\n  mailinfo: move charset to struct mailinfo\n  mailinfo: move cmitmsg and patchfile to struct mailinfo\n  mailinfo: move [ps]_hdr_data to struct mailinfo\n  mailinfo: move content/content_top to struct mailinfo\n\nMostly unchanged, except for the clean-up in clear_mailinfo().\n\n  mailinfo: handle_commit_msg() shouldn't be called after finding patchbreak\n  mailinfo: keep the parsed log message in a strbuf\n\nThese two were placed earlier in the series in the previous round,\nbut are not about moving globals to struct.  This round finishes\nmoving the globals to struct mailinfo before doing these two steps.\n\n  mailinfo: move read_one_header_line() closer to its callers\n  mailinfo: move check_header() after the helpers it uses\n  mailinfo: move cleanup_space() before its users\n  mailinfo: move definition of MAX_HDR_PARSED closer to its use\n\nMostly unchanged.  These are pure shuffling of functions and\nvariables to lose forward declarations and to allow easier reading\nby grouping related things together.\n\n  mailinfo: libify\n\nMostly pure code movement that is unchanged since v2.\n\n  mailinfo: handle charset conversion errors in the caller\n  mailinfo: remove calls to exit() and die() deep in the callchain\n  am: make direct call to mailinfo\n\n Makefile                         |    1 +\n builtin/am.c                     |   42 +-\n builtin/mailinfo.c               | 1137 ++------------------------------------\n builtin/mailinfo.c => mailinfo.c |  799 +++++++++++++--------------\n mailinfo.h                       |   41 ++\n 5 files changed, 505 insertions(+), 1515 deletions(-)\n rewrite builtin/mailinfo.c (95%)\n copy builtin/mailinfo.c => mailinfo.c (67%)\n create mode 100644 mailinfo.h\n\n-- \n2.6.2-383-g144b2e6\n"},{"id":"271896","messageId":"1445239731-10677-2-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1445239731-10677-1-git-send-email-gitster@pobox.com","subject":"[PATCH v3 01/34] mailinfo: remove a no-op call convert_to_utf8(it, \"\")","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-19T07:28:18Z","receivedAt":"2015-10-19T07:28:18Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The called function checks if the second parameter is either a NULL\nor an empty string at the very beginning and returns without doing\nanything.  Remove the useless call.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 5 -----\n 1 file changed, 5 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 999a525..5a4ed75 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -612,11 +612,6 @@ static void decode_header(struct strbuf *it)\n {\n \tif (decode_header_bq(it))\n \t\treturn;\n-\t/* otherwise \"it\" is a straight copy of the input.\n-\t * This can be binary guck but there is no charset specified.\n-\t */\n-\tif (metainfo_charset)\n-\t\tconvert_to_utf8(it, \"\");\n }\n \n static void decode_transfer_encoding(struct strbuf *line)\n-- \n2.6.2-383-g144b2e6\n"},{"id":"271929","messageId":"1445239731-10677-3-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1445239731-10677-1-git-send-email-gitster@pobox.com","subject":"[PATCH v3 02/34] mailinfo: fold decode_header_bq() into decode_header()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-19T07:28:19Z","receivedAt":"2015-10-19T07:28:19Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"In olden days we might have wanted to behave differently in\ndecode_header() if the header line was encoded with RFC2047, but we\napparently do not do so, hence this helper function can go, together\nwith its return value.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 23 +++++++----------------\n 1 file changed, 7 insertions(+), 16 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 5a4ed75..addc0e0 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -525,19 +525,17 @@ static void convert_to_utf8(struct strbuf *line, const char *charset)\n \tstrbuf_attach(line, out, strlen(out), strlen(out));\n }\n \n-static int decode_header_bq(struct strbuf *it)\n+static void decode_header(struct strbuf *it)\n {\n \tchar *in, *ep, *cp;\n \tstruct strbuf outbuf = STRBUF_INIT, *dec;\n \tstruct strbuf charset_q = STRBUF_INIT, piecebuf = STRBUF_INIT;\n-\tint rfc2047 = 0;\n \n \tin = it->buf;\n \twhile (in - it->buf <= it->len && (ep = strstr(in, \"=?\")) != NULL) {\n \t\tint encoding;\n \t\tstrbuf_reset(&charset_q);\n \t\tstrbuf_reset(&piecebuf);\n-\t\trfc2047 = 1;\n \n \t\tif (in != ep) {\n \t\t\t/*\n@@ -567,22 +565,22 @@ static int decode_header_bq(struct strbuf *it)\n \t\tep += 2;\n \n \t\tif (ep - it->buf >= it->len || !(cp = strchr(ep, '?')))\n-\t\t\tgoto decode_header_bq_out;\n+\t\t\tgoto release_return;\n \n \t\tif (cp + 3 - it->buf > it->len)\n-\t\t\tgoto decode_header_bq_out;\n+\t\t\tgoto release_return;\n \t\tstrbuf_add(&charset_q, ep, cp - ep);\n \n \t\tencoding = cp[1];\n \t\tif (!encoding || cp[2] != '?')\n-\t\t\tgoto decode_header_bq_out;\n+\t\t\tgoto release_return;\n \t\tep = strstr(cp + 3, \"?=\");\n \t\tif (!ep)\n-\t\t\tgoto decode_header_bq_out;\n+\t\t\tgoto release_return;\n \t\tstrbuf_add(&piecebuf, cp + 3, ep - cp - 3);\n \t\tswitch (tolower(encoding)) {\n \t\tdefault:\n-\t\t\tgoto decode_header_bq_out;\n+\t\t\tgoto release_return;\n \t\tcase 'b':\n \t\t\tdec = decode_b_segment(&piecebuf);\n \t\t\tbreak;\n@@ -601,17 +599,10 @@ static int decode_header_bq(struct strbuf *it)\n \tstrbuf_addstr(&outbuf, in);\n \tstrbuf_reset(it);\n \tstrbuf_addbuf(it, &outbuf);\n-decode_header_bq_out:\n+release_return:\n \tstrbuf_release(&outbuf);\n \tstrbuf_release(&charset_q);\n \tstrbuf_release(&piecebuf);\n-\treturn rfc2047;\n-}\n-\n-static void decode_header(struct strbuf *it)\n-{\n-\tif (decode_header_bq(it))\n-\t\treturn;\n }\n \n static void decode_transfer_encoding(struct strbuf *line)\n-- \n2.6.2-383-g144b2e6\n"},{"id":"271897","messageId":"1445239731-10677-4-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1445239731-10677-1-git-send-email-gitster@pobox.com","subject":"[PATCH v3 03/34] mailinfo: fix an off-by-one error in the boundary stack","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-19T07:28:20Z","receivedAt":"2015-10-19T07:28:20Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"We pre-increment the pointer that we will use to store something at,\nso the pointer is already beyond the end of the array if it points\nat content[MAX_BOUNDARIES].\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex addc0e0..1566c19 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -185,7 +185,7 @@ static void handle_content_type(struct strbuf *line)\n \n \tif (slurp_attr(line->buf, \"boundary=\", boundary)) {\n \t\tstrbuf_insert(boundary, 0, \"--\", 2);\n-\t\tif (++content_top > &content[MAX_BOUNDARIES]) {\n+\t\tif (++content_top >= &content[MAX_BOUNDARIES]) {\n \t\t\tfprintf(stderr, \"Too many boundaries to handle\\n\");\n \t\t\texit(1);\n \t\t}\n-- \n2.6.2-383-g144b2e6\n"},{"id":"271901","messageId":"1445239731-10677-5-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1445239731-10677-1-git-send-email-gitster@pobox.com","subject":"[PATCH v3 04/34] mailinfo: explicitly close file handle to the patch output","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-19T07:28:21Z","receivedAt":"2015-10-19T07:28:21Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This does not make a difference within the context of \"git mailinfo\"\nthat runs once and exits, as flushing and closing would happen upon\nprocess termination.  It however will matter when we eventually make\nit callable as an API function.\n\nBesides, cleaning after yourself once you are done is a good hygiene.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 2 ++\n 1 file changed, 2 insertions(+)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 1566c19..73be47c 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -999,6 +999,8 @@ static int mailinfo(FILE *in, FILE *out, const char *msg, const char *patch)\n \t\tcheck_header(&line, p_hdr_data, 1);\n \n \thandle_body();\n+\tfclose(patchfile);\n+\n \thandle_info();\n \n \treturn 0;\n-- \n2.6.2-383-g144b2e6\n"},{"id":"271898","messageId":"1445239731-10677-6-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1445239731-10677-1-git-send-email-gitster@pobox.com","subject":"[PATCH v3 05/34] mailinfo: move handle_boundary() lower","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-19T07:28:22Z","receivedAt":"2015-10-19T07:28:22Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This function wants to call find_boundary() and is called only from\none place without any recursing, so it becomes easier to read if it\nappears after the called function.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 114 ++++++++++++++++++++++++++---------------------------\n 1 file changed, 56 insertions(+), 58 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 73be47c..2b7f97b 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -626,64 +626,6 @@ static void decode_transfer_encoding(struct strbuf *line)\n \tfree(ret);\n }\n \n-static void handle_filter(struct strbuf *line);\n-\n-static int find_boundary(void)\n-{\n-\twhile (!strbuf_getline(&line, fin, '\\n')) {\n-\t\tif (*content_top && is_multipart_boundary(&line))\n-\t\t\treturn 1;\n-\t}\n-\treturn 0;\n-}\n-\n-static int handle_boundary(void)\n-{\n-\tstruct strbuf newline = STRBUF_INIT;\n-\n-\tstrbuf_addch(&newline, '\\n');\n-again:\n-\tif (line.len >= (*content_top)->len + 2 &&\n-\t    !memcmp(line.buf + (*content_top)->len, \"--\", 2)) {\n-\t\t/* we hit an end boundary */\n-\t\t/* pop the current boundary off the stack */\n-\t\tstrbuf_release(*content_top);\n-\t\tfree(*content_top);\n-\t\t*content_top = NULL;\n-\n-\t\t/* technically won't happen as is_multipart_boundary()\n-\t\t   will fail first.  But just in case..\n-\t\t */\n-\t\tif (--content_top < content) {\n-\t\t\tfprintf(stderr, \"Detected mismatched boundaries, \"\n-\t\t\t\t\t\"can't recover\\n\");\n-\t\t\texit(1);\n-\t\t}\n-\t\thandle_filter(&newline);\n-\t\tstrbuf_release(&newline);\n-\n-\t\t/* skip to the next boundary */\n-\t\tif (!find_boundary())\n-\t\t\treturn 0;\n-\t\tgoto again;\n-\t}\n-\n-\t/* set some defaults */\n-\ttransfer_encoding = TE_DONTCARE;\n-\tstrbuf_reset(&charset);\n-\n-\t/* slurp in this section's info */\n-\twhile (read_one_header_line(&line, fin))\n-\t\tcheck_header(&line, p_hdr_data, 0);\n-\n-\tstrbuf_release(&newline);\n-\t/* replenish line */\n-\tif (strbuf_getline(&line, fin, '\\n'))\n-\t\treturn 0;\n-\tstrbuf_addch(&line, '\\n');\n-\treturn 1;\n-}\n-\n static inline int patchbreak(const struct strbuf *line)\n {\n \tsize_t i;\n@@ -851,6 +793,62 @@ static void handle_filter(struct strbuf *line)\n \t}\n }\n \n+static int find_boundary(void)\n+{\n+\twhile (!strbuf_getline(&line, fin, '\\n')) {\n+\t\tif (*content_top && is_multipart_boundary(&line))\n+\t\t\treturn 1;\n+\t}\n+\treturn 0;\n+}\n+\n+static int handle_boundary(void)\n+{\n+\tstruct strbuf newline = STRBUF_INIT;\n+\n+\tstrbuf_addch(&newline, '\\n');\n+again:\n+\tif (line.len >= (*content_top)->len + 2 &&\n+\t    !memcmp(line.buf + (*content_top)->len, \"--\", 2)) {\n+\t\t/* we hit an end boundary */\n+\t\t/* pop the current boundary off the stack */\n+\t\tstrbuf_release(*content_top);\n+\t\tfree(*content_top);\n+\t\t*content_top = NULL;\n+\n+\t\t/* technically won't happen as is_multipart_boundary()\n+\t\t   will fail first.  But just in case..\n+\t\t */\n+\t\tif (--content_top < content) {\n+\t\t\tfprintf(stderr, \"Detected mismatched boundaries, \"\n+\t\t\t\t\t\"can't recover\\n\");\n+\t\t\texit(1);\n+\t\t}\n+\t\thandle_filter(&newline);\n+\t\tstrbuf_release(&newline);\n+\n+\t\t/* skip to the next boundary */\n+\t\tif (!find_boundary())\n+\t\t\treturn 0;\n+\t\tgoto again;\n+\t}\n+\n+\t/* set some defaults */\n+\ttransfer_encoding = TE_DONTCARE;\n+\tstrbuf_reset(&charset);\n+\n+\t/* slurp in this section's info */\n+\twhile (read_one_header_line(&line, fin))\n+\t\tcheck_header(&line, p_hdr_data, 0);\n+\n+\tstrbuf_release(&newline);\n+\t/* replenish line */\n+\tif (strbuf_getline(&line, fin, '\\n'))\n+\t\treturn 0;\n+\tstrbuf_addch(&line, '\\n');\n+\treturn 1;\n+}\n+\n static void handle_body(void)\n {\n \tstruct strbuf prev = STRBUF_INIT;\n-- \n2.6.2-383-g144b2e6\n"},{"id":"271899","messageId":"1445239731-10677-7-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1445239731-10677-1-git-send-email-gitster@pobox.com","subject":"[PATCH v3 06/34] mailinfo: get rid of function-local static states","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-19T07:28:23Z","receivedAt":"2015-10-19T07:28:23Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Two helper functions use \"static int\" in their scope to keep track\nof the state while repeatedly getting called once for each input\nline.  Move these state variables to their ultimate caller and pass\ndown pointers to them along the callchain, as a small step in\npreparation for making this entire callchain more reentrant.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 41 +++++++++++++++++++----------------------\n 1 file changed, 19 insertions(+), 22 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 2b7f97b..1518708 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -713,27 +713,25 @@ static int is_scissors_line(const struct strbuf *line)\n \t\tgap * 2 < perforation);\n }\n \n-static int handle_commit_msg(struct strbuf *line)\n+static int handle_commit_msg(struct strbuf *line, int *still_looking)\n {\n-\tstatic int still_looking = 1;\n-\n \tif (!cmitmsg)\n \t\treturn 0;\n \n-\tif (still_looking) {\n+\tif (*still_looking) {\n \t\tif (!line->len || (line->len == 1 && line->buf[0] == '\\n'))\n \t\t\treturn 0;\n \t}\n \n-\tif (use_inbody_headers && still_looking) {\n-\t\tstill_looking = check_header(line, s_hdr_data, 0);\n-\t\tif (still_looking)\n+\tif (use_inbody_headers && *still_looking) {\n+\t\t*still_looking = check_header(line, s_hdr_data, 0);\n+\t\tif (*still_looking)\n \t\t\treturn 0;\n \t} else\n \t\t/* Only trim the first (blank) line of the commit message\n \t\t * when ignoring in-body headers.\n \t\t */\n-\t\tstill_looking = 0;\n+\t\t*still_looking = 0;\n \n \t/* normalize the log message to UTF-8. */\n \tif (metainfo_charset)\n@@ -745,7 +743,7 @@ static int handle_commit_msg(struct strbuf *line)\n \t\t\tdie_errno(\"Could not rewind output message file\");\n \t\tif (ftruncate(fileno(cmitmsg), 0))\n \t\t\tdie_errno(\"Could not truncate output message file at scissors\");\n-\t\tstill_looking = 1;\n+\t\t*still_looking = 1;\n \n \t\t/*\n \t\t * We may have already read \"secondary headers\"; purge\n@@ -777,16 +775,13 @@ static void handle_patch(const struct strbuf *line)\n \tpatch_lines++;\n }\n \n-static void handle_filter(struct strbuf *line)\n+static void handle_filter(struct strbuf *line, int *filter_stage, int *header_stage)\n {\n-\tstatic int filter = 0;\n-\n-\t/* filter tells us which part we left off on */\n-\tswitch (filter) {\n+\tswitch (*filter_stage) {\n \tcase 0:\n-\t\tif (!handle_commit_msg(line))\n+\t\tif (!handle_commit_msg(line, header_stage))\n \t\t\tbreak;\n-\t\tfilter++;\n+\t\t(*filter_stage)++;\n \tcase 1:\n \t\thandle_patch(line);\n \t\tbreak;\n@@ -802,7 +797,7 @@ static int find_boundary(void)\n \treturn 0;\n }\n \n-static int handle_boundary(void)\n+static int handle_boundary(int *filter_stage, int *header_stage)\n {\n \tstruct strbuf newline = STRBUF_INIT;\n \n@@ -824,7 +819,7 @@ again:\n \t\t\t\t\t\"can't recover\\n\");\n \t\t\texit(1);\n \t\t}\n-\t\thandle_filter(&newline);\n+\t\thandle_filter(&newline, filter_stage, header_stage);\n \t\tstrbuf_release(&newline);\n \n \t\t/* skip to the next boundary */\n@@ -852,6 +847,8 @@ again:\n static void handle_body(void)\n {\n \tstruct strbuf prev = STRBUF_INIT;\n+\tint filter_stage = 0;\n+\tint header_stage = 1;\n \n \t/* Skip up to the first boundary */\n \tif (*content_top) {\n@@ -864,10 +861,10 @@ static void handle_body(void)\n \t\tif (*content_top && is_multipart_boundary(&line)) {\n \t\t\t/* flush any leftover */\n \t\t\tif (prev.len) {\n-\t\t\t\thandle_filter(&prev);\n+\t\t\t\thandle_filter(&prev, &filter_stage, &header_stage);\n \t\t\t\tstrbuf_reset(&prev);\n \t\t\t}\n-\t\t\tif (!handle_boundary())\n+\t\t\tif (!handle_boundary(&filter_stage, &header_stage))\n \t\t\t\tgoto handle_body_out;\n \t\t}\n \n@@ -897,7 +894,7 @@ static void handle_body(void)\n \t\t\t\t\t\tstrbuf_addbuf(&prev, sb);\n \t\t\t\t\t\tbreak;\n \t\t\t\t\t}\n-\t\t\t\thandle_filter(sb);\n+\t\t\t\thandle_filter(sb, &filter_stage, &header_stage);\n \t\t\t}\n \t\t\t/*\n \t\t\t * The partial chunk is saved in \"prev\" and will be\n@@ -907,7 +904,7 @@ static void handle_body(void)\n \t\t\tbreak;\n \t\t}\n \t\tdefault:\n-\t\t\thandle_filter(&line);\n+\t\t\thandle_filter(&line, &filter_stage, &header_stage);\n \t\t}\n \n \t} while (!strbuf_getwholeline(&line, fin, '\\n'));\n-- \n2.6.2-383-g144b2e6\n"},{"id":"271925","messageId":"1445239731-10677-8-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1445239731-10677-1-git-send-email-gitster@pobox.com","subject":"[PATCH v3 07/34] mailinfo: do not let handle_body() touch global \"line\" directly","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-19T07:28:24Z","receivedAt":"2015-10-19T07:28:24Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This function has a single caller, and called with the global \"line\"\nholding the first line of the e-mail body after the caller finished\nprocessing the e-mail headers.  The function then goes into a loop\nto process each line of the input, starting from what was given by\nits caller, and fills the same global \"line\" variable from the input\nas it needs to process more lines.\n\nLet the caller explicitly pass a pointer to this global \"line\"\nvariable as an argument, and have the function itself use that\nstrbuf throughout, instead of referring to the global \"line\" itself.\n\nThere are helper functions that this function calls that still touch\nthe global directly; they will be updated as the series progresses.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 16 ++++++++--------\n 1 file changed, 8 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 1518708..52be7db 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -844,7 +844,7 @@ again:\n \treturn 1;\n }\n \n-static void handle_body(void)\n+static void handle_body(struct strbuf *line)\n {\n \tstruct strbuf prev = STRBUF_INIT;\n \tint filter_stage = 0;\n@@ -858,7 +858,7 @@ static void handle_body(void)\n \n \tdo {\n \t\t/* process any boundary lines */\n-\t\tif (*content_top && is_multipart_boundary(&line)) {\n+\t\tif (*content_top && is_multipart_boundary(line)) {\n \t\t\t/* flush any leftover */\n \t\t\tif (prev.len) {\n \t\t\t\thandle_filter(&prev, &filter_stage, &header_stage);\n@@ -869,7 +869,7 @@ static void handle_body(void)\n \t\t}\n \n \t\t/* Unwrap transfer encoding */\n-\t\tdecode_transfer_encoding(&line);\n+\t\tdecode_transfer_encoding(line);\n \n \t\tswitch (transfer_encoding) {\n \t\tcase TE_BASE64:\n@@ -878,7 +878,7 @@ static void handle_body(void)\n \t\t\tstruct strbuf **lines, **it, *sb;\n \n \t\t\t/* Prepend any previous partial lines */\n-\t\t\tstrbuf_insert(&line, 0, prev.buf, prev.len);\n+\t\t\tstrbuf_insert(line, 0, prev.buf, prev.len);\n \t\t\tstrbuf_reset(&prev);\n \n \t\t\t/*\n@@ -886,7 +886,7 @@ static void handle_body(void)\n \t\t\t * multiple new lines.  Pass only one chunk\n \t\t\t * at a time to handle_filter()\n \t\t\t */\n-\t\t\tlines = strbuf_split(&line, '\\n');\n+\t\t\tlines = strbuf_split(line, '\\n');\n \t\t\tfor (it = lines; (sb = *it); it++) {\n \t\t\t\tif (*(it + 1) == NULL) /* The last line */\n \t\t\t\t\tif (sb->buf[sb->len - 1] != '\\n') {\n@@ -904,10 +904,10 @@ static void handle_body(void)\n \t\t\tbreak;\n \t\t}\n \t\tdefault:\n-\t\t\thandle_filter(&line, &filter_stage, &header_stage);\n+\t\t\thandle_filter(line, &filter_stage, &header_stage);\n \t\t}\n \n-\t} while (!strbuf_getwholeline(&line, fin, '\\n'));\n+\t} while (!strbuf_getwholeline(line, fin, '\\n'));\n \n handle_body_out:\n \tstrbuf_release(&prev);\n@@ -993,7 +993,7 @@ static int mailinfo(FILE *in, FILE *out, const char *msg, const char *patch)\n \twhile (read_one_header_line(&line, fin))\n \t\tcheck_header(&line, p_hdr_data, 1);\n \n-\thandle_body();\n+\thandle_body(&line);\n \tfclose(patchfile);\n \n \thandle_info();\n-- \n2.6.2-383-g144b2e6\n"},{"id":"271924","messageId":"1445239731-10677-9-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1445239731-10677-1-git-send-email-gitster@pobox.com","subject":"[PATCH v3 08/34] mailinfo: do not let handle_boundary() touch global \"line\" directly","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-19T07:28:25Z","receivedAt":"2015-10-19T07:28:25Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This function has a single caller, and called with the global \"line\"\nholding the multi-part boundary line the caller saw while processing\nthe e-mail body.  The function then goes into a loop to process each\nline of the input, and fills the same global \"line\" variable from\nthe input as it needs to read more lines to process the multi-part\nheaders.\n\nLet the caller explicitly pass a pointer to this global \"line\"\nvariable as an argument, and have the function itself use that\nstrbuf throughout, instead of referring to the global \"line\" itself.\n\nThere still is a helper function that this function calls that still\ntouches the global directly; it will be updated as the series progresses.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 16 ++++++++--------\n 1 file changed, 8 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 52be7db..cab1235 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -797,14 +797,14 @@ static int find_boundary(void)\n \treturn 0;\n }\n \n-static int handle_boundary(int *filter_stage, int *header_stage)\n+static int handle_boundary(struct strbuf *line, int *filter_stage, int *header_stage)\n {\n \tstruct strbuf newline = STRBUF_INIT;\n \n \tstrbuf_addch(&newline, '\\n');\n again:\n-\tif (line.len >= (*content_top)->len + 2 &&\n-\t    !memcmp(line.buf + (*content_top)->len, \"--\", 2)) {\n+\tif (line->len >= (*content_top)->len + 2 &&\n+\t    !memcmp(line->buf + (*content_top)->len, \"--\", 2)) {\n \t\t/* we hit an end boundary */\n \t\t/* pop the current boundary off the stack */\n \t\tstrbuf_release(*content_top);\n@@ -833,14 +833,14 @@ again:\n \tstrbuf_reset(&charset);\n \n \t/* slurp in this section's info */\n-\twhile (read_one_header_line(&line, fin))\n-\t\tcheck_header(&line, p_hdr_data, 0);\n+\twhile (read_one_header_line(line, fin))\n+\t\tcheck_header(line, p_hdr_data, 0);\n \n \tstrbuf_release(&newline);\n \t/* replenish line */\n-\tif (strbuf_getline(&line, fin, '\\n'))\n+\tif (strbuf_getline(line, fin, '\\n'))\n \t\treturn 0;\n-\tstrbuf_addch(&line, '\\n');\n+\tstrbuf_addch(line, '\\n');\n \treturn 1;\n }\n \n@@ -864,7 +864,7 @@ static void handle_body(struct strbuf *line)\n \t\t\t\thandle_filter(&prev, &filter_stage, &header_stage);\n \t\t\t\tstrbuf_reset(&prev);\n \t\t\t}\n-\t\t\tif (!handle_boundary(&filter_stage, &header_stage))\n+\t\t\tif (!handle_boundary(line, &filter_stage, &header_stage))\n \t\t\t\tgoto handle_body_out;\n \t\t}\n \n-- \n2.6.2-383-g144b2e6\n"},{"id":"271926","messageId":"1445239731-10677-10-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1445239731-10677-1-git-send-email-gitster@pobox.com","subject":"[PATCH v3 09/34] mailinfo: do not let find_boundary() touch global \"line\" directly","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-19T07:28:26Z","receivedAt":"2015-10-19T07:28:26Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"With the previous two commits, we established that the local\nvariable \"line\" in handle_body() and handle_boundary() functions\nalways refer to the global \"line\" that is used as the common and\nshared \"current line from the input\".  They are the only callers of\nthe last function that refers to the global line directly, i.e.\nfind_boundary().  Pass \"line\" as a parameter to this leaf function\nto complete the clean-up.  Now the only function that directly refers\nto the global \"line\" is the caller of handle_body() at the very\nbeginning of this whole callchain.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 10 +++++-----\n 1 file changed, 5 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex cab1235..12d1eda 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -788,10 +788,10 @@ static void handle_filter(struct strbuf *line, int *filter_stage, int *header_st\n \t}\n }\n \n-static int find_boundary(void)\n+static int find_boundary(struct strbuf *line)\n {\n-\twhile (!strbuf_getline(&line, fin, '\\n')) {\n-\t\tif (*content_top && is_multipart_boundary(&line))\n+\twhile (!strbuf_getline(line, fin, '\\n')) {\n+\t\tif (*content_top && is_multipart_boundary(line))\n \t\t\treturn 1;\n \t}\n \treturn 0;\n@@ -823,7 +823,7 @@ again:\n \t\tstrbuf_release(&newline);\n \n \t\t/* skip to the next boundary */\n-\t\tif (!find_boundary())\n+\t\tif (!find_boundary(line))\n \t\t\treturn 0;\n \t\tgoto again;\n \t}\n@@ -852,7 +852,7 @@ static void handle_body(struct strbuf *line)\n \n \t/* Skip up to the first boundary */\n \tif (*content_top) {\n-\t\tif (!find_boundary())\n+\t\tif (!find_boundary(line))\n \t\t\tgoto handle_body_out;\n \t}\n \n-- \n2.6.2-383-g144b2e6\n"},{"id":"271927","messageId":"1445239731-10677-11-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1445239731-10677-1-git-send-email-gitster@pobox.com","subject":"[PATCH v3 10/34] mailinfo: move global \"line\" into mailinfo() function","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-19T07:28:27Z","receivedAt":"2015-10-19T07:28:27Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"With the previous steps, it becomes clear that the mailinfo()\nfunction is the only one that wants the \"line\" to be directly\ntouchable.  Move it to the function scope of this function.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 3 ++-\n 1 file changed, 2 insertions(+), 1 deletion(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 12d1eda..c8dc73f 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -12,7 +12,6 @@ static FILE *cmitmsg, *patchfile, *fin, *fout;\n static int keep_subject;\n static int keep_non_patch_brackets_in_subject;\n static const char *metainfo_charset;\n-static struct strbuf line = STRBUF_INIT;\n static struct strbuf name = STRBUF_INIT;\n static struct strbuf email = STRBUF_INIT;\n static char *message_id;\n@@ -966,6 +965,8 @@ static void handle_info(void)\n static int mailinfo(FILE *in, FILE *out, const char *msg, const char *patch)\n {\n \tint peek;\n+\tstruct strbuf line = STRBUF_INIT;\n+\n \tfin = in;\n \tfout = out;\n \n-- \n2.6.2-383-g144b2e6\n"},{"id":"271928","messageId":"1445239731-10677-12-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1445239731-10677-1-git-send-email-gitster@pobox.com","subject":"[PATCH v3 11/34] mailinfo: introduce \"struct mailinfo\" to hold globals","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-19T07:28:28Z","receivedAt":"2015-10-19T07:28:28Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"In this first step, move only 'email' and 'name' fields in there and\nremove the corresponding globals.  In subsequent patches, more\nglobals will be moved to this and the structure will be passed\naround as a new parameter to more functions.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 71 ++++++++++++++++++++++++++++++++++++------------------\n 1 file changed, 47 insertions(+), 24 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex c8dc73f..e3c0c31 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -12,8 +12,11 @@ static FILE *cmitmsg, *patchfile, *fin, *fout;\n static int keep_subject;\n static int keep_non_patch_brackets_in_subject;\n static const char *metainfo_charset;\n-static struct strbuf name = STRBUF_INIT;\n-static struct strbuf email = STRBUF_INIT;\n+\n+struct mailinfo {\n+\tstruct strbuf name;\n+\tstruct strbuf email;\n+};\n static char *message_id;\n \n static enum  {\n@@ -45,7 +48,7 @@ static void get_sane_name(struct strbuf *out, struct strbuf *name, struct strbuf\n \tstrbuf_addbuf(out, src);\n }\n \n-static void parse_bogus_from(const struct strbuf *line)\n+static void parse_bogus_from(struct mailinfo *mi, const struct strbuf *line)\n {\n \t/* John Doe <johndoe> */\n \n@@ -53,7 +56,7 @@ static void parse_bogus_from(const struct strbuf *line)\n \t/* This is fallback, so do not bother if we already have an\n \t * e-mail address.\n \t */\n-\tif (email.len)\n+\tif (mi->email.len)\n \t\treturn;\n \n \tbra = strchr(line->buf, '<');\n@@ -63,16 +66,16 @@ static void parse_bogus_from(const struct strbuf *line)\n \tif (!ket)\n \t\treturn;\n \n-\tstrbuf_reset(&email);\n-\tstrbuf_add(&email, bra + 1, ket - bra - 1);\n+\tstrbuf_reset(&mi->email);\n+\tstrbuf_add(&mi->email, bra + 1, ket - bra - 1);\n \n-\tstrbuf_reset(&name);\n-\tstrbuf_add(&name, line->buf, bra - line->buf);\n-\tstrbuf_trim(&name);\n-\tget_sane_name(&name, &name, &email);\n+\tstrbuf_reset(&mi->name);\n+\tstrbuf_add(&mi->name, line->buf, bra - line->buf);\n+\tstrbuf_trim(&mi->name);\n+\tget_sane_name(&mi->name, &mi->name, &mi->email);\n }\n \n-static void handle_from(const struct strbuf *from)\n+static void handle_from(struct mailinfo *mi, const struct strbuf *from)\n {\n \tchar *at;\n \tsize_t el;\n@@ -83,14 +86,14 @@ static void handle_from(const struct strbuf *from)\n \n \tat = strchr(f.buf, '@');\n \tif (!at) {\n-\t\tparse_bogus_from(from);\n+\t\tparse_bogus_from(mi, from);\n \t\treturn;\n \t}\n \n \t/*\n \t * If we already have one email, don't take any confusing lines\n \t */\n-\tif (email.len && strchr(at + 1, '@')) {\n+\tif (mi->email.len && strchr(at + 1, '@')) {\n \t\tstrbuf_release(&f);\n \t\treturn;\n \t}\n@@ -109,8 +112,8 @@ static void handle_from(const struct strbuf *from)\n \t\tat--;\n \t}\n \tel = strcspn(at, \" \\n\\t\\r\\v\\f>\");\n-\tstrbuf_reset(&email);\n-\tstrbuf_add(&email, at, el);\n+\tstrbuf_reset(&mi->email);\n+\tstrbuf_add(&mi->email, at, el);\n \tstrbuf_remove(&f, at - f.buf, el + (at[el] ? 1 : 0));\n \n \t/* The remainder is name.  It could be\n@@ -132,7 +135,7 @@ static void handle_from(const struct strbuf *from)\n \t\tstrbuf_setlen(&f, f.len - 1);\n \t}\n \n-\tget_sane_name(&name, &f, &email);\n+\tget_sane_name(&mi->name, &f, &mi->email);\n \tstrbuf_release(&f);\n }\n \n@@ -929,7 +932,7 @@ static void output_header_lines(FILE *fout, const char *hdr, const struct strbuf\n \t}\n }\n \n-static void handle_info(void)\n+static void handle_info(struct mailinfo *mi)\n {\n \tstruct strbuf *hdr;\n \tint i;\n@@ -951,9 +954,9 @@ static void handle_info(void)\n \t\t\toutput_header_lines(fout, \"Subject\", hdr);\n \t\t} else if (!strcmp(header[i], \"From\")) {\n \t\t\tcleanup_space(hdr);\n-\t\t\thandle_from(hdr);\n-\t\t\tfprintf(fout, \"Author: %s\\n\", name.buf);\n-\t\t\tfprintf(fout, \"Email: %s\\n\", email.buf);\n+\t\t\thandle_from(mi, hdr);\n+\t\t\tfprintf(fout, \"Author: %s\\n\", mi->name.buf);\n+\t\t\tfprintf(fout, \"Email: %s\\n\", mi->email.buf);\n \t\t} else {\n \t\t\tcleanup_space(hdr);\n \t\t\tfprintf(fout, \"%s: %s\\n\", header[i], hdr->buf);\n@@ -962,7 +965,8 @@ static void handle_info(void)\n \tfprintf(fout, \"\\n\");\n }\n \n-static int mailinfo(FILE *in, FILE *out, const char *msg, const char *patch)\n+static int mailinfo(struct mailinfo *mi,\n+\t\t    FILE *in, FILE *out, const char *msg, const char *patch)\n {\n \tint peek;\n \tstruct strbuf line = STRBUF_INIT;\n@@ -997,7 +1001,7 @@ static int mailinfo(FILE *in, FILE *out, const char *msg, const char *patch)\n \thandle_body(&line);\n \tfclose(patchfile);\n \n-\thandle_info();\n+\thandle_info(mi);\n \n \treturn 0;\n }\n@@ -1014,17 +1018,33 @@ static int git_mailinfo_config(const char *var, const char *value, void *unused)\n \treturn 0;\n }\n \n+static void setup_mailinfo(struct mailinfo *mi)\n+{\n+\tmemset(mi, 0, sizeof(*mi));\n+\tstrbuf_init(&mi->name, 0);\n+\tstrbuf_init(&mi->email, 0);\n+\tgit_config(git_mailinfo_config, &mi);\n+}\n+\n+static void clear_mailinfo(struct mailinfo *mi)\n+{\n+\tstrbuf_release(&mi->name);\n+\tstrbuf_release(&mi->email);\n+}\n+\n static const char mailinfo_usage[] =\n \t\"git mailinfo [-k | -b] [-m | --message-id] [-u | --encoding=<encoding> | -n] [--scissors | --no-scissors] <msg> <patch> < mail >info\";\n \n int cmd_mailinfo(int argc, const char **argv, const char *prefix)\n {\n \tconst char *def_charset;\n+\tstruct mailinfo mi;\n+\tint status;\n \n \t/* NEEDSWORK: might want to do the optional .git/ directory\n \t * discovery\n \t */\n-\tgit_config(git_mailinfo_config, NULL);\n+\tsetup_mailinfo(&mi);\n \n \tdef_charset = get_commit_output_encoding();\n \tmetainfo_charset = def_charset;\n@@ -1056,5 +1076,8 @@ int cmd_mailinfo(int argc, const char **argv, const char *prefix)\n \tif (argc != 3)\n \t\tusage(mailinfo_usage);\n \n-\treturn !!mailinfo(stdin, stdout, argv[1], argv[2]);\n+\tstatus = !!mailinfo(&mi, stdin, stdout, argv[1], argv[2]);\n+\tclear_mailinfo(&mi);\n+\n+\treturn status;\n }\n-- \n2.6.2-383-g144b2e6\n"},{"id":"271900","messageId":"1445239731-10677-13-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1445239731-10677-1-git-send-email-gitster@pobox.com","subject":"[PATCH v3 12/34] mailinfo: move keep_subject & keep_non_patch_bracket to struct mailinfo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-19T07:28:29Z","receivedAt":"2015-10-19T07:28:29Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"These two are the only easy ones that do not require passing the\nstructure around to deep corners of the callchain.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 16 ++++++++--------\n 1 file changed, 8 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex e3c0c31..08c67f5 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -9,13 +9,13 @@\n \n static FILE *cmitmsg, *patchfile, *fin, *fout;\n \n-static int keep_subject;\n-static int keep_non_patch_brackets_in_subject;\n static const char *metainfo_charset;\n \n struct mailinfo {\n \tstruct strbuf name;\n \tstruct strbuf email;\n+\tint keep_subject;\n+\tint keep_non_patch_brackets_in_subject;\n };\n static char *message_id;\n \n@@ -224,7 +224,7 @@ static int is_multipart_boundary(const struct strbuf *line)\n \t\t!memcmp(line->buf, (*content_top)->buf, (*content_top)->len));\n }\n \n-static void cleanup_subject(struct strbuf *subject)\n+static void cleanup_subject(struct mailinfo *mi, struct strbuf *subject)\n {\n \tsize_t at = 0;\n \n@@ -252,7 +252,7 @@ static void cleanup_subject(struct strbuf *subject)\n \t\t\tif (!pos)\n \t\t\t\tbreak;\n \t\t\tremove = pos - subject->buf + at + 1;\n-\t\t\tif (!keep_non_patch_brackets_in_subject ||\n+\t\t\tif (!mi->keep_non_patch_brackets_in_subject ||\n \t\t\t    (7 <= remove &&\n \t\t\t     memmem(subject->buf + at, remove, \"PATCH\", 5)))\n \t\t\t\tstrbuf_remove(subject, at, remove);\n@@ -947,8 +947,8 @@ static void handle_info(struct mailinfo *mi)\n \t\t\tcontinue;\n \n \t\tif (!strcmp(header[i], \"Subject\")) {\n-\t\t\tif (!keep_subject) {\n-\t\t\t\tcleanup_subject(hdr);\n+\t\t\tif (!mi->keep_subject) {\n+\t\t\t\tcleanup_subject(mi, hdr);\n \t\t\t\tcleanup_space(hdr);\n \t\t\t}\n \t\t\toutput_header_lines(fout, \"Subject\", hdr);\n@@ -1051,9 +1051,9 @@ int cmd_mailinfo(int argc, const char **argv, const char *prefix)\n \n \twhile (1 < argc && argv[1][0] == '-') {\n \t\tif (!strcmp(argv[1], \"-k\"))\n-\t\t\tkeep_subject = 1;\n+\t\t\tmi.keep_subject = 1;\n \t\telse if (!strcmp(argv[1], \"-b\"))\n-\t\t\tkeep_non_patch_brackets_in_subject = 1;\n+\t\t\tmi.keep_non_patch_brackets_in_subject = 1;\n \t\telse if (!strcmp(argv[1], \"-m\") || !strcmp(argv[1], \"--message-id\"))\n \t\t\tadd_message_id = 1;\n \t\telse if (!strcmp(argv[1], \"-u\"))\n-- \n2.6.2-383-g144b2e6\n"},{"id":"271902","messageId":"1445239731-10677-14-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1445239731-10677-1-git-send-email-gitster@pobox.com","subject":"[PATCH v3 13/34] mailinfo: move global \"FILE *fin, *fout\" to struct mailinfo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-19T07:28:30Z","receivedAt":"2015-10-19T07:28:30Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This requires us to pass \"struct mailinfo\" to more functions\nthroughout the codepath that read input lines.  Incidentally,\nlater steps are helped by this patch passing the struct to\nmore callchains.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 54 ++++++++++++++++++++++++++++--------------------------\n 1 file changed, 28 insertions(+), 26 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 08c67f5..b150936 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -7,11 +7,14 @@\n #include \"utf8.h\"\n #include \"strbuf.h\"\n \n-static FILE *cmitmsg, *patchfile, *fin, *fout;\n+static FILE *cmitmsg, *patchfile;\n \n static const char *metainfo_charset;\n \n struct mailinfo {\n+\tFILE *input;\n+\tFILE *output;\n+\n \tstruct strbuf name;\n \tstruct strbuf email;\n \tint keep_subject;\n@@ -790,16 +793,17 @@ static void handle_filter(struct strbuf *line, int *filter_stage, int *header_st\n \t}\n }\n \n-static int find_boundary(struct strbuf *line)\n+static int find_boundary(struct mailinfo *mi, struct strbuf *line)\n {\n-\twhile (!strbuf_getline(line, fin, '\\n')) {\n+\twhile (!strbuf_getline(line, mi->input, '\\n')) {\n \t\tif (*content_top && is_multipart_boundary(line))\n \t\t\treturn 1;\n \t}\n \treturn 0;\n }\n \n-static int handle_boundary(struct strbuf *line, int *filter_stage, int *header_stage)\n+static int handle_boundary(struct mailinfo *mi, struct strbuf *line,\n+\t\t\t   int *filter_stage, int *header_stage)\n {\n \tstruct strbuf newline = STRBUF_INIT;\n \n@@ -825,7 +829,7 @@ again:\n \t\tstrbuf_release(&newline);\n \n \t\t/* skip to the next boundary */\n-\t\tif (!find_boundary(line))\n+\t\tif (!find_boundary(mi, line))\n \t\t\treturn 0;\n \t\tgoto again;\n \t}\n@@ -835,18 +839,18 @@ again:\n \tstrbuf_reset(&charset);\n \n \t/* slurp in this section's info */\n-\twhile (read_one_header_line(line, fin))\n+\twhile (read_one_header_line(line, mi->input))\n \t\tcheck_header(line, p_hdr_data, 0);\n \n \tstrbuf_release(&newline);\n \t/* replenish line */\n-\tif (strbuf_getline(line, fin, '\\n'))\n+\tif (strbuf_getline(line, mi->input, '\\n'))\n \t\treturn 0;\n \tstrbuf_addch(line, '\\n');\n \treturn 1;\n }\n \n-static void handle_body(struct strbuf *line)\n+static void handle_body(struct mailinfo *mi, struct strbuf *line)\n {\n \tstruct strbuf prev = STRBUF_INIT;\n \tint filter_stage = 0;\n@@ -854,7 +858,7 @@ static void handle_body(struct strbuf *line)\n \n \t/* Skip up to the first boundary */\n \tif (*content_top) {\n-\t\tif (!find_boundary(line))\n+\t\tif (!find_boundary(mi, line))\n \t\t\tgoto handle_body_out;\n \t}\n \n@@ -866,7 +870,7 @@ static void handle_body(struct strbuf *line)\n \t\t\t\thandle_filter(&prev, &filter_stage, &header_stage);\n \t\t\t\tstrbuf_reset(&prev);\n \t\t\t}\n-\t\t\tif (!handle_boundary(line, &filter_stage, &header_stage))\n+\t\t\tif (!handle_boundary(mi, line, &filter_stage, &header_stage))\n \t\t\t\tgoto handle_body_out;\n \t\t}\n \n@@ -909,7 +913,7 @@ static void handle_body(struct strbuf *line)\n \t\t\thandle_filter(line, &filter_stage, &header_stage);\n \t\t}\n \n-\t} while (!strbuf_getwholeline(line, fin, '\\n'));\n+\t} while (!strbuf_getwholeline(line, mi->input, '\\n'));\n \n handle_body_out:\n \tstrbuf_release(&prev);\n@@ -951,29 +955,25 @@ static void handle_info(struct mailinfo *mi)\n \t\t\t\tcleanup_subject(mi, hdr);\n \t\t\t\tcleanup_space(hdr);\n \t\t\t}\n-\t\t\toutput_header_lines(fout, \"Subject\", hdr);\n+\t\t\toutput_header_lines(mi->output, \"Subject\", hdr);\n \t\t} else if (!strcmp(header[i], \"From\")) {\n \t\t\tcleanup_space(hdr);\n \t\t\thandle_from(mi, hdr);\n-\t\t\tfprintf(fout, \"Author: %s\\n\", mi->name.buf);\n-\t\t\tfprintf(fout, \"Email: %s\\n\", mi->email.buf);\n+\t\t\tfprintf(mi->output, \"Author: %s\\n\", mi->name.buf);\n+\t\t\tfprintf(mi->output, \"Email: %s\\n\", mi->email.buf);\n \t\t} else {\n \t\t\tcleanup_space(hdr);\n-\t\t\tfprintf(fout, \"%s: %s\\n\", header[i], hdr->buf);\n+\t\t\tfprintf(mi->output, \"%s: %s\\n\", header[i], hdr->buf);\n \t\t}\n \t}\n-\tfprintf(fout, \"\\n\");\n+\tfprintf(mi->output, \"\\n\");\n }\n \n-static int mailinfo(struct mailinfo *mi,\n-\t\t    FILE *in, FILE *out, const char *msg, const char *patch)\n+static int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)\n {\n \tint peek;\n \tstruct strbuf line = STRBUF_INIT;\n \n-\tfin = in;\n-\tfout = out;\n-\n \tcmitmsg = fopen(msg, \"w\");\n \tif (!cmitmsg) {\n \t\tperror(msg);\n@@ -990,15 +990,15 @@ static int mailinfo(struct mailinfo *mi,\n \ts_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*s_hdr_data));\n \n \tdo {\n-\t\tpeek = fgetc(in);\n+\t\tpeek = fgetc(mi->input);\n \t} while (isspace(peek));\n-\tungetc(peek, in);\n+\tungetc(peek, mi->input);\n \n \t/* process the email header */\n-\twhile (read_one_header_line(&line, fin))\n+\twhile (read_one_header_line(&line, mi->input))\n \t\tcheck_header(&line, p_hdr_data, 1);\n \n-\thandle_body(&line);\n+\thandle_body(mi, &line);\n \tfclose(patchfile);\n \n \thandle_info(mi);\n@@ -1076,7 +1076,9 @@ int cmd_mailinfo(int argc, const char **argv, const char *prefix)\n \tif (argc != 3)\n \t\tusage(mailinfo_usage);\n \n-\tstatus = !!mailinfo(&mi, stdin, stdout, argv[1], argv[2]);\n+\tmi.input = stdin;\n+\tmi.output = stdout;\n+\tstatus = !!mailinfo(&mi, argv[1], argv[2]);\n \tclear_mailinfo(&mi);\n \n \treturn status;\n-- \n2.6.2-383-g144b2e6\n"},{"id":"271922","messageId":"1445239731-10677-15-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1445239731-10677-1-git-send-email-gitster@pobox.com","subject":"[PATCH v3 14/34] mailinfo: move filter/header stage to struct mailinfo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-19T07:28:31Z","receivedAt":"2015-10-19T07:28:31Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Earlier we got rid of two function-scope static variables that kept\ntrack of the states of helper functions by making them extra arguments\nthat are passed throughout the callchain.  Now we have a convenient\nplace to store and pass them around in the form of \"struct mailinfo\",\nchange them into two fields in the struct.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 42 ++++++++++++++++++++++--------------------\n 1 file changed, 22 insertions(+), 20 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex b150936..5823ae5 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -19,6 +19,9 @@ struct mailinfo {\n \tstruct strbuf email;\n \tint keep_subject;\n \tint keep_non_patch_brackets_in_subject;\n+\n+\tint filter_stage; /* still reading log or are we copying patch? */\n+\tint header_stage; /* still checking in-body headers? */\n };\n static char *message_id;\n \n@@ -28,6 +31,7 @@ static enum  {\n \n static struct strbuf charset = STRBUF_INIT;\n static int patch_lines;\n+\n static struct strbuf **p_hdr_data, **s_hdr_data;\n static int use_scissors;\n static int add_message_id;\n@@ -718,25 +722,25 @@ static int is_scissors_line(const struct strbuf *line)\n \t\tgap * 2 < perforation);\n }\n \n-static int handle_commit_msg(struct strbuf *line, int *still_looking)\n+static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n {\n \tif (!cmitmsg)\n \t\treturn 0;\n \n-\tif (*still_looking) {\n+\tif (mi->header_stage) {\n \t\tif (!line->len || (line->len == 1 && line->buf[0] == '\\n'))\n \t\t\treturn 0;\n \t}\n \n-\tif (use_inbody_headers && *still_looking) {\n-\t\t*still_looking = check_header(line, s_hdr_data, 0);\n-\t\tif (*still_looking)\n+\tif (use_inbody_headers && mi->header_stage) {\n+\t\tmi->header_stage = check_header(line, s_hdr_data, 0);\n+\t\tif (mi->header_stage)\n \t\t\treturn 0;\n \t} else\n \t\t/* Only trim the first (blank) line of the commit message\n \t\t * when ignoring in-body headers.\n \t\t */\n-\t\t*still_looking = 0;\n+\t\tmi->header_stage = 0;\n \n \t/* normalize the log message to UTF-8. */\n \tif (metainfo_charset)\n@@ -748,7 +752,7 @@ static int handle_commit_msg(struct strbuf *line, int *still_looking)\n \t\t\tdie_errno(\"Could not rewind output message file\");\n \t\tif (ftruncate(fileno(cmitmsg), 0))\n \t\t\tdie_errno(\"Could not truncate output message file at scissors\");\n-\t\t*still_looking = 1;\n+\t\tmi->header_stage = 1;\n \n \t\t/*\n \t\t * We may have already read \"secondary headers\"; purge\n@@ -780,13 +784,13 @@ static void handle_patch(const struct strbuf *line)\n \tpatch_lines++;\n }\n \n-static void handle_filter(struct strbuf *line, int *filter_stage, int *header_stage)\n+static void handle_filter(struct mailinfo *mi, struct strbuf *line)\n {\n-\tswitch (*filter_stage) {\n+\tswitch (mi->filter_stage) {\n \tcase 0:\n-\t\tif (!handle_commit_msg(line, header_stage))\n+\t\tif (!handle_commit_msg(mi, line))\n \t\t\tbreak;\n-\t\t(*filter_stage)++;\n+\t\tmi->filter_stage++;\n \tcase 1:\n \t\thandle_patch(line);\n \t\tbreak;\n@@ -802,8 +806,7 @@ static int find_boundary(struct mailinfo *mi, struct strbuf *line)\n \treturn 0;\n }\n \n-static int handle_boundary(struct mailinfo *mi, struct strbuf *line,\n-\t\t\t   int *filter_stage, int *header_stage)\n+static int handle_boundary(struct mailinfo *mi, struct strbuf *line)\n {\n \tstruct strbuf newline = STRBUF_INIT;\n \n@@ -825,7 +828,7 @@ again:\n \t\t\t\t\t\"can't recover\\n\");\n \t\t\texit(1);\n \t\t}\n-\t\thandle_filter(&newline, filter_stage, header_stage);\n+\t\thandle_filter(mi, &newline);\n \t\tstrbuf_release(&newline);\n \n \t\t/* skip to the next boundary */\n@@ -853,8 +856,6 @@ again:\n static void handle_body(struct mailinfo *mi, struct strbuf *line)\n {\n \tstruct strbuf prev = STRBUF_INIT;\n-\tint filter_stage = 0;\n-\tint header_stage = 1;\n \n \t/* Skip up to the first boundary */\n \tif (*content_top) {\n@@ -867,10 +868,10 @@ static void handle_body(struct mailinfo *mi, struct strbuf *line)\n \t\tif (*content_top && is_multipart_boundary(line)) {\n \t\t\t/* flush any leftover */\n \t\t\tif (prev.len) {\n-\t\t\t\thandle_filter(&prev, &filter_stage, &header_stage);\n+\t\t\t\thandle_filter(mi, &prev);\n \t\t\t\tstrbuf_reset(&prev);\n \t\t\t}\n-\t\t\tif (!handle_boundary(mi, line, &filter_stage, &header_stage))\n+\t\t\tif (!handle_boundary(mi, line))\n \t\t\t\tgoto handle_body_out;\n \t\t}\n \n@@ -900,7 +901,7 @@ static void handle_body(struct mailinfo *mi, struct strbuf *line)\n \t\t\t\t\t\tstrbuf_addbuf(&prev, sb);\n \t\t\t\t\t\tbreak;\n \t\t\t\t\t}\n-\t\t\t\thandle_filter(sb, &filter_stage, &header_stage);\n+\t\t\t\thandle_filter(mi, sb);\n \t\t\t}\n \t\t\t/*\n \t\t\t * The partial chunk is saved in \"prev\" and will be\n@@ -910,7 +911,7 @@ static void handle_body(struct mailinfo *mi, struct strbuf *line)\n \t\t\tbreak;\n \t\t}\n \t\tdefault:\n-\t\t\thandle_filter(line, &filter_stage, &header_stage);\n+\t\t\thandle_filter(mi, line);\n \t\t}\n \n \t} while (!strbuf_getwholeline(line, mi->input, '\\n'));\n@@ -1023,6 +1024,7 @@ static void setup_mailinfo(struct mailinfo *mi)\n \tmemset(mi, 0, sizeof(*mi));\n \tstrbuf_init(&mi->name, 0);\n \tstrbuf_init(&mi->email, 0);\n+\tmi->header_stage = 1;\n \tgit_config(git_mailinfo_config, &mi);\n }\n \n-- \n2.6.2-383-g144b2e6\n"},{"id":"271923","messageId":"1445239731-10677-16-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1445239731-10677-1-git-send-email-gitster@pobox.com","subject":"[PATCH v3 15/34] mailinfo: move patch_lines to struct mailinfo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-19T07:28:32Z","receivedAt":"2015-10-19T07:28:32Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This one is trivial thanks to previous steps that started passing\nthe structure throughout the input codepaths.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 10 +++++-----\n 1 file changed, 5 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 5823ae5..8bd76c6 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -20,6 +20,7 @@ struct mailinfo {\n \tint keep_subject;\n \tint keep_non_patch_brackets_in_subject;\n \n+\tint patch_lines;\n \tint filter_stage; /* still reading log or are we copying patch? */\n \tint header_stage; /* still checking in-body headers? */\n };\n@@ -30,7 +31,6 @@ static enum  {\n } transfer_encoding;\n \n static struct strbuf charset = STRBUF_INIT;\n-static int patch_lines;\n \n static struct strbuf **p_hdr_data, **s_hdr_data;\n static int use_scissors;\n@@ -778,10 +778,10 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n \treturn 0;\n }\n \n-static void handle_patch(const struct strbuf *line)\n+static void handle_patch(struct mailinfo *mi, const struct strbuf *line)\n {\n \tfwrite(line->buf, 1, line->len, patchfile);\n-\tpatch_lines++;\n+\tmi->patch_lines++;\n }\n \n static void handle_filter(struct mailinfo *mi, struct strbuf *line)\n@@ -792,7 +792,7 @@ static void handle_filter(struct mailinfo *mi, struct strbuf *line)\n \t\t\tbreak;\n \t\tmi->filter_stage++;\n \tcase 1:\n-\t\thandle_patch(line);\n+\t\thandle_patch(mi, line);\n \t\tbreak;\n \t}\n }\n@@ -944,7 +944,7 @@ static void handle_info(struct mailinfo *mi)\n \n \tfor (i = 0; header[i]; i++) {\n \t\t/* only print inbody headers if we output a patch file */\n-\t\tif (patch_lines && s_hdr_data[i])\n+\t\tif (mi->patch_lines && s_hdr_data[i])\n \t\t\thdr = s_hdr_data[i];\n \t\telse if (p_hdr_data[i])\n \t\t\thdr = p_hdr_data[i];\n-- \n2.6.2-383-g144b2e6\n"},{"id":"271903","messageId":"1445239731-10677-17-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1445239731-10677-1-git-send-email-gitster@pobox.com","subject":"[PATCH v3 16/34] mailinfo: move add_message_id and message_id to struct mailinfo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-19T07:28:33Z","receivedAt":"2015-10-19T07:28:33Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This requires us to pass the structure into check_header() codepath.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 31 +++++++++++++++++--------------\n 1 file changed, 17 insertions(+), 14 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 8bd76c6..c0522f2 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -19,12 +19,13 @@ struct mailinfo {\n \tstruct strbuf email;\n \tint keep_subject;\n \tint keep_non_patch_brackets_in_subject;\n+\tint add_message_id;\n \n+\tchar *message_id;\n \tint patch_lines;\n \tint filter_stage; /* still reading log or are we copying patch? */\n \tint header_stage; /* still checking in-body headers? */\n };\n-static char *message_id;\n \n static enum  {\n \tTE_DONTCARE, TE_QP, TE_BASE64\n@@ -34,7 +35,6 @@ static struct strbuf charset = STRBUF_INIT;\n \n static struct strbuf **p_hdr_data, **s_hdr_data;\n static int use_scissors;\n-static int add_message_id;\n static int use_inbody_headers = 1;\n \n #define MAX_HDR_PARSED 10\n@@ -209,10 +209,10 @@ static void handle_content_type(struct strbuf *line)\n \t}\n }\n \n-static void handle_message_id(const struct strbuf *line)\n+static void handle_message_id(struct mailinfo *mi, const struct strbuf *line)\n {\n-\tif (add_message_id)\n-\t\tmessage_id = strdup(line->buf);\n+\tif (mi->add_message_id)\n+\t\tmi->message_id = strdup(line->buf);\n }\n \n static void handle_content_transfer_encoding(const struct strbuf *line)\n@@ -321,11 +321,13 @@ static int is_format_patch_separator(const char *line, int len)\n \treturn !memcmp(SAMPLE + (cp - line), cp, strlen(SAMPLE) - (cp - line));\n }\n \n-static int check_header(const struct strbuf *line,\n-\t\t\t\tstruct strbuf *hdr_data[], int overwrite)\n+static int check_header(struct mailinfo *mi,\n+\t\t\tconst struct strbuf *line,\n+\t\t\tstruct strbuf *hdr_data[], int overwrite)\n {\n \tint i, ret = 0, len;\n \tstruct strbuf sb = STRBUF_INIT;\n+\n \t/* search for the interesting parts */\n \tfor (i = 0; header[i]; i++) {\n \t\tint len = strlen(header[i]);\n@@ -363,7 +365,7 @@ static int check_header(const struct strbuf *line,\n \t\tlen = strlen(\"Message-Id: \");\n \t\tstrbuf_add(&sb, line->buf + len, line->len - len);\n \t\tdecode_header(&sb);\n-\t\thandle_message_id(&sb);\n+\t\thandle_message_id(mi, &sb);\n \t\tret = 1;\n \t\tgoto check_header_out;\n \t}\n@@ -733,7 +735,7 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n \t}\n \n \tif (use_inbody_headers && mi->header_stage) {\n-\t\tmi->header_stage = check_header(line, s_hdr_data, 0);\n+\t\tmi->header_stage = check_header(mi, line, s_hdr_data, 0);\n \t\tif (mi->header_stage)\n \t\t\treturn 0;\n \t} else\n@@ -767,8 +769,8 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n \t}\n \n \tif (patchbreak(line)) {\n-\t\tif (message_id)\n-\t\t\tfprintf(cmitmsg, \"Message-Id: %s\\n\", message_id);\n+\t\tif (mi->message_id)\n+\t\t\tfprintf(cmitmsg, \"Message-Id: %s\\n\", mi->message_id);\n \t\tfclose(cmitmsg);\n \t\tcmitmsg = NULL;\n \t\treturn 1;\n@@ -843,7 +845,7 @@ again:\n \n \t/* slurp in this section's info */\n \twhile (read_one_header_line(line, mi->input))\n-\t\tcheck_header(line, p_hdr_data, 0);\n+\t\tcheck_header(mi, line, p_hdr_data, 0);\n \n \tstrbuf_release(&newline);\n \t/* replenish line */\n@@ -997,7 +999,7 @@ static int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)\n \n \t/* process the email header */\n \twhile (read_one_header_line(&line, mi->input))\n-\t\tcheck_header(&line, p_hdr_data, 1);\n+\t\tcheck_header(mi, &line, p_hdr_data, 1);\n \n \thandle_body(mi, &line);\n \tfclose(patchfile);\n@@ -1032,6 +1034,7 @@ static void clear_mailinfo(struct mailinfo *mi)\n {\n \tstrbuf_release(&mi->name);\n \tstrbuf_release(&mi->email);\n+\tfree(mi->message_id);\n }\n \n static const char mailinfo_usage[] =\n@@ -1057,7 +1060,7 @@ int cmd_mailinfo(int argc, const char **argv, const char *prefix)\n \t\telse if (!strcmp(argv[1], \"-b\"))\n \t\t\tmi.keep_non_patch_brackets_in_subject = 1;\n \t\telse if (!strcmp(argv[1], \"-m\") || !strcmp(argv[1], \"--message-id\"))\n-\t\t\tadd_message_id = 1;\n+\t\t\tmi.add_message_id = 1;\n \t\telse if (!strcmp(argv[1], \"-u\"))\n \t\t\tmetainfo_charset = def_charset;\n \t\telse if (!strcmp(argv[1], \"-n\"))\n-- \n2.6.2-383-g144b2e6\n"},{"id":"271919","messageId":"1445239731-10677-18-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1445239731-10677-1-git-send-email-gitster@pobox.com","subject":"[PATCH v3 17/34] mailinfo: move use_scissors and use_inbody_headers to struct mailinfo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-19T07:28:34Z","receivedAt":"2015-10-19T07:28:34Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Signed-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 23 +++++++++++++----------\n 1 file changed, 13 insertions(+), 10 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex c0522f2..2c8f249 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -20,6 +20,8 @@ struct mailinfo {\n \tint keep_subject;\n \tint keep_non_patch_brackets_in_subject;\n \tint add_message_id;\n+\tint use_scissors;\n+\tint use_inbody_headers; /* defaults to 1 */\n \n \tchar *message_id;\n \tint patch_lines;\n@@ -34,8 +36,6 @@ static enum  {\n static struct strbuf charset = STRBUF_INIT;\n \n static struct strbuf **p_hdr_data, **s_hdr_data;\n-static int use_scissors;\n-static int use_inbody_headers = 1;\n \n #define MAX_HDR_PARSED 10\n #define MAX_BOUNDARIES 5\n@@ -734,7 +734,7 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n \t\t\treturn 0;\n \t}\n \n-\tif (use_inbody_headers && mi->header_stage) {\n+\tif (mi->use_inbody_headers && mi->header_stage) {\n \t\tmi->header_stage = check_header(mi, line, s_hdr_data, 0);\n \t\tif (mi->header_stage)\n \t\t\treturn 0;\n@@ -748,7 +748,7 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n \tif (metainfo_charset)\n \t\tconvert_to_utf8(line, charset.buf);\n \n-\tif (use_scissors && is_scissors_line(line)) {\n+\tif (mi->use_scissors && is_scissors_line(line)) {\n \t\tint i;\n \t\tif (fseek(cmitmsg, 0L, SEEK_SET))\n \t\t\tdie_errno(\"Could not rewind output message file\");\n@@ -1009,12 +1009,14 @@ static int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)\n \treturn 0;\n }\n \n-static int git_mailinfo_config(const char *var, const char *value, void *unused)\n+static int git_mailinfo_config(const char *var, const char *value, void *mi_)\n {\n+\tstruct mailinfo *mi = mi_;\n+\n \tif (!starts_with(var, \"mailinfo.\"))\n-\t\treturn git_default_config(var, value, unused);\n+\t\treturn git_default_config(var, value, NULL);\n \tif (!strcmp(var, \"mailinfo.scissors\")) {\n-\t\tuse_scissors = git_config_bool(var, value);\n+\t\tmi->use_scissors = git_config_bool(var, value);\n \t\treturn 0;\n \t}\n \t/* perhaps others here */\n@@ -1027,6 +1029,7 @@ static void setup_mailinfo(struct mailinfo *mi)\n \tstrbuf_init(&mi->name, 0);\n \tstrbuf_init(&mi->email, 0);\n \tmi->header_stage = 1;\n+\tmi->use_inbody_headers = 1;\n \tgit_config(git_mailinfo_config, &mi);\n }\n \n@@ -1068,11 +1071,11 @@ int cmd_mailinfo(int argc, const char **argv, const char *prefix)\n \t\telse if (starts_with(argv[1], \"--encoding=\"))\n \t\t\tmetainfo_charset = argv[1] + 11;\n \t\telse if (!strcmp(argv[1], \"--scissors\"))\n-\t\t\tuse_scissors = 1;\n+\t\t\tmi.use_scissors = 1;\n \t\telse if (!strcmp(argv[1], \"--no-scissors\"))\n-\t\t\tuse_scissors = 0;\n+\t\t\tmi.use_scissors = 0;\n \t\telse if (!strcmp(argv[1], \"--no-inbody-headers\"))\n-\t\t\tuse_inbody_headers = 0;\n+\t\t\tmi.use_inbody_headers = 0;\n \t\telse\n \t\t\tusage(mailinfo_usage);\n \t\targc--; argv++;\n-- \n2.6.2-383-g144b2e6\n"},{"id":"271921","messageId":"1445239731-10677-19-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1445239731-10677-1-git-send-email-gitster@pobox.com","subject":"[PATCH v3 18/34] mailinfo: move metainfo_charset to struct mailinfo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-19T07:28:35Z","receivedAt":"2015-10-19T07:28:35Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This requires us to pass the struct down to decode_header() and\nconvert_to_utf8() callchain.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 40 ++++++++++++++++++++--------------------\n 1 file changed, 20 insertions(+), 20 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 2c8f249..26fd9b1 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -9,8 +9,6 @@\n \n static FILE *cmitmsg, *patchfile;\n \n-static const char *metainfo_charset;\n-\n struct mailinfo {\n \tFILE *input;\n \tFILE *output;\n@@ -22,6 +20,7 @@ struct mailinfo {\n \tint add_message_id;\n \tint use_scissors;\n \tint use_inbody_headers; /* defaults to 1 */\n+\tconst char *metainfo_charset;\n \n \tchar *message_id;\n \tint patch_lines;\n@@ -293,7 +292,7 @@ static void cleanup_space(struct strbuf *sb)\n \t}\n }\n \n-static void decode_header(struct strbuf *line);\n+static void decode_header(struct mailinfo *mi, struct strbuf *line);\n static const char *header[MAX_HDR_PARSED] = {\n \t\"From\",\"Subject\",\"Date\",\n };\n@@ -336,7 +335,7 @@ static int check_header(struct mailinfo *mi,\n \t\t\t * normalize the meta information to utf8.\n \t\t\t */\n \t\t\tstrbuf_add(&sb, line->buf + len + 2, line->len - len - 2);\n-\t\t\tdecode_header(&sb);\n+\t\t\tdecode_header(mi, &sb);\n \t\t\thandle_header(&hdr_data[i], &sb);\n \t\t\tret = 1;\n \t\t\tgoto check_header_out;\n@@ -347,7 +346,7 @@ static int check_header(struct mailinfo *mi,\n \tif (cmp_header(line, \"Content-Type\")) {\n \t\tlen = strlen(\"Content-Type: \");\n \t\tstrbuf_add(&sb, line->buf + len, line->len - len);\n-\t\tdecode_header(&sb);\n+\t\tdecode_header(mi, &sb);\n \t\tstrbuf_insert(&sb, 0, \"Content-Type: \", len);\n \t\thandle_content_type(&sb);\n \t\tret = 1;\n@@ -356,7 +355,7 @@ static int check_header(struct mailinfo *mi,\n \tif (cmp_header(line, \"Content-Transfer-Encoding\")) {\n \t\tlen = strlen(\"Content-Transfer-Encoding: \");\n \t\tstrbuf_add(&sb, line->buf + len, line->len - len);\n-\t\tdecode_header(&sb);\n+\t\tdecode_header(mi, &sb);\n \t\thandle_content_transfer_encoding(&sb);\n \t\tret = 1;\n \t\tgoto check_header_out;\n@@ -364,7 +363,7 @@ static int check_header(struct mailinfo *mi,\n \tif (cmp_header(line, \"Message-Id\")) {\n \t\tlen = strlen(\"Message-Id: \");\n \t\tstrbuf_add(&sb, line->buf + len, line->len - len);\n-\t\tdecode_header(&sb);\n+\t\tdecode_header(mi, &sb);\n \t\thandle_message_id(mi, &sb);\n \t\tret = 1;\n \t\tgoto check_header_out;\n@@ -520,23 +519,24 @@ static struct strbuf *decode_b_segment(const struct strbuf *b_seg)\n \treturn out;\n }\n \n-static void convert_to_utf8(struct strbuf *line, const char *charset)\n+static void convert_to_utf8(struct mailinfo *mi,\n+\t\t\t    struct strbuf *line, const char *charset)\n {\n \tchar *out;\n \n \tif (!charset || !*charset)\n \t\treturn;\n \n-\tif (same_encoding(metainfo_charset, charset))\n+\tif (same_encoding(mi->metainfo_charset, charset))\n \t\treturn;\n-\tout = reencode_string(line->buf, metainfo_charset, charset);\n+\tout = reencode_string(line->buf, mi->metainfo_charset, charset);\n \tif (!out)\n \t\tdie(\"cannot convert from %s to %s\",\n-\t\t    charset, metainfo_charset);\n+\t\t    charset, mi->metainfo_charset);\n \tstrbuf_attach(line, out, strlen(out), strlen(out));\n }\n \n-static void decode_header(struct strbuf *it)\n+static void decode_header(struct mailinfo *mi, struct strbuf *it)\n {\n \tchar *in, *ep, *cp;\n \tstruct strbuf outbuf = STRBUF_INIT, *dec;\n@@ -599,8 +599,8 @@ static void decode_header(struct strbuf *it)\n \t\t\tdec = decode_q_segment(&piecebuf, 1);\n \t\t\tbreak;\n \t\t}\n-\t\tif (metainfo_charset)\n-\t\t\tconvert_to_utf8(dec, charset_q.buf);\n+\t\tif (mi->metainfo_charset)\n+\t\t\tconvert_to_utf8(mi, dec, charset_q.buf);\n \n \t\tstrbuf_addbuf(&outbuf, dec);\n \t\tstrbuf_release(dec);\n@@ -745,8 +745,8 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n \t\tmi->header_stage = 0;\n \n \t/* normalize the log message to UTF-8. */\n-\tif (metainfo_charset)\n-\t\tconvert_to_utf8(line, charset.buf);\n+\tif (mi->metainfo_charset)\n+\t\tconvert_to_utf8(mi, line, charset.buf);\n \n \tif (mi->use_scissors && is_scissors_line(line)) {\n \t\tint i;\n@@ -1055,7 +1055,7 @@ int cmd_mailinfo(int argc, const char **argv, const char *prefix)\n \tsetup_mailinfo(&mi);\n \n \tdef_charset = get_commit_output_encoding();\n-\tmetainfo_charset = def_charset;\n+\tmi.metainfo_charset = def_charset;\n \n \twhile (1 < argc && argv[1][0] == '-') {\n \t\tif (!strcmp(argv[1], \"-k\"))\n@@ -1065,11 +1065,11 @@ int cmd_mailinfo(int argc, const char **argv, const char *prefix)\n \t\telse if (!strcmp(argv[1], \"-m\") || !strcmp(argv[1], \"--message-id\"))\n \t\t\tmi.add_message_id = 1;\n \t\telse if (!strcmp(argv[1], \"-u\"))\n-\t\t\tmetainfo_charset = def_charset;\n+\t\t\tmi.metainfo_charset = def_charset;\n \t\telse if (!strcmp(argv[1], \"-n\"))\n-\t\t\tmetainfo_charset = NULL;\n+\t\t\tmi.metainfo_charset = NULL;\n \t\telse if (starts_with(argv[1], \"--encoding=\"))\n-\t\t\tmetainfo_charset = argv[1] + 11;\n+\t\t\tmi.metainfo_charset = argv[1] + 11;\n \t\telse if (!strcmp(argv[1], \"--scissors\"))\n \t\t\tmi.use_scissors = 1;\n \t\telse if (!strcmp(argv[1], \"--no-scissors\"))\n-- \n2.6.2-383-g144b2e6\n"},{"id":"271905","messageId":"1445239731-10677-20-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1445239731-10677-1-git-send-email-gitster@pobox.com","subject":"[PATCH v3 19/34] mailinfo: move check for metainfo_charset to convert_to_utf8()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-19T07:28:36Z","receivedAt":"2015-10-19T07:28:36Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"All callers of this function refrains from calling it when\nmi->metainfo_charset is NULL; move the check to the callee,\nas it already has a few conditions at its beginning to turn\nit into a no-op.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 8 +++-----\n 1 file changed, 3 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 26fd9b1..737d0fc 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -524,7 +524,7 @@ static void convert_to_utf8(struct mailinfo *mi,\n {\n \tchar *out;\n \n-\tif (!charset || !*charset)\n+\tif (!mi->metainfo_charset || !charset || !*charset)\n \t\treturn;\n \n \tif (same_encoding(mi->metainfo_charset, charset))\n@@ -599,8 +599,7 @@ static void decode_header(struct mailinfo *mi, struct strbuf *it)\n \t\t\tdec = decode_q_segment(&piecebuf, 1);\n \t\t\tbreak;\n \t\t}\n-\t\tif (mi->metainfo_charset)\n-\t\t\tconvert_to_utf8(mi, dec, charset_q.buf);\n+\t\tconvert_to_utf8(mi, dec, charset_q.buf);\n \n \t\tstrbuf_addbuf(&outbuf, dec);\n \t\tstrbuf_release(dec);\n@@ -745,8 +744,7 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n \t\tmi->header_stage = 0;\n \n \t/* normalize the log message to UTF-8. */\n-\tif (mi->metainfo_charset)\n-\t\tconvert_to_utf8(mi, line, charset.buf);\n+\tconvert_to_utf8(mi, line, charset.buf);\n \n \tif (mi->use_scissors && is_scissors_line(line)) {\n \t\tint i;\n-- \n2.6.2-383-g144b2e6\n"},{"id":"271915","messageId":"1445239731-10677-21-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1445239731-10677-1-git-send-email-gitster@pobox.com","subject":"[PATCH v3 20/34] mailinfo: move transfer_encoding to struct mailinfo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-19T07:28:37Z","receivedAt":"2015-10-19T07:28:37Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Signed-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 27 ++++++++++++++-------------\n 1 file changed, 14 insertions(+), 13 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 737d0fc..18781b7 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -23,14 +23,14 @@ struct mailinfo {\n \tconst char *metainfo_charset;\n \n \tchar *message_id;\n+\tenum  {\n+\t\tTE_DONTCARE, TE_QP, TE_BASE64\n+\t} transfer_encoding;\n \tint patch_lines;\n \tint filter_stage; /* still reading log or are we copying patch? */\n \tint header_stage; /* still checking in-body headers? */\n };\n \n-static enum  {\n-\tTE_DONTCARE, TE_QP, TE_BASE64\n-} transfer_encoding;\n \n static struct strbuf charset = STRBUF_INIT;\n \n@@ -214,14 +214,15 @@ static void handle_message_id(struct mailinfo *mi, const struct strbuf *line)\n \t\tmi->message_id = strdup(line->buf);\n }\n \n-static void handle_content_transfer_encoding(const struct strbuf *line)\n+static void handle_content_transfer_encoding(struct mailinfo *mi,\n+\t\t\t\t\t     const struct strbuf *line)\n {\n \tif (strcasestr(line->buf, \"base64\"))\n-\t\ttransfer_encoding = TE_BASE64;\n+\t\tmi->transfer_encoding = TE_BASE64;\n \telse if (strcasestr(line->buf, \"quoted-printable\"))\n-\t\ttransfer_encoding = TE_QP;\n+\t\tmi->transfer_encoding = TE_QP;\n \telse\n-\t\ttransfer_encoding = TE_DONTCARE;\n+\t\tmi->transfer_encoding = TE_DONTCARE;\n }\n \n static int is_multipart_boundary(const struct strbuf *line)\n@@ -356,7 +357,7 @@ static int check_header(struct mailinfo *mi,\n \t\tlen = strlen(\"Content-Transfer-Encoding: \");\n \t\tstrbuf_add(&sb, line->buf + len, line->len - len);\n \t\tdecode_header(mi, &sb);\n-\t\thandle_content_transfer_encoding(&sb);\n+\t\thandle_content_transfer_encoding(mi, &sb);\n \t\tret = 1;\n \t\tgoto check_header_out;\n \t}\n@@ -615,11 +616,11 @@ release_return:\n \tstrbuf_release(&piecebuf);\n }\n \n-static void decode_transfer_encoding(struct strbuf *line)\n+static void decode_transfer_encoding(struct mailinfo *mi, struct strbuf *line)\n {\n \tstruct strbuf *ret;\n \n-\tswitch (transfer_encoding) {\n+\tswitch (mi->transfer_encoding) {\n \tcase TE_QP:\n \t\tret = decode_q_segment(line, 0);\n \t\tbreak;\n@@ -838,7 +839,7 @@ again:\n \t}\n \n \t/* set some defaults */\n-\ttransfer_encoding = TE_DONTCARE;\n+\tmi->transfer_encoding = TE_DONTCARE;\n \tstrbuf_reset(&charset);\n \n \t/* slurp in this section's info */\n@@ -876,9 +877,9 @@ static void handle_body(struct mailinfo *mi, struct strbuf *line)\n \t\t}\n \n \t\t/* Unwrap transfer encoding */\n-\t\tdecode_transfer_encoding(line);\n+\t\tdecode_transfer_encoding(mi, line);\n \n-\t\tswitch (transfer_encoding) {\n+\t\tswitch (mi->transfer_encoding) {\n \t\tcase TE_BASE64:\n \t\tcase TE_QP:\n \t\t{\n-- \n2.6.2-383-g144b2e6\n"},{"id":"271916","messageId":"1445239731-10677-22-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1445239731-10677-1-git-send-email-gitster@pobox.com","subject":"[PATCH v3 21/34] mailinfo: move charset to struct mailinfo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-19T07:28:38Z","receivedAt":"2015-10-19T07:28:38Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Signed-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 16 ++++++++--------\n 1 file changed, 8 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 18781b7..810d132 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -22,6 +22,7 @@ struct mailinfo {\n \tint use_inbody_headers; /* defaults to 1 */\n \tconst char *metainfo_charset;\n \n+\tstruct strbuf charset;\n \tchar *message_id;\n \tenum  {\n \t\tTE_DONTCARE, TE_QP, TE_BASE64\n@@ -31,9 +32,6 @@ struct mailinfo {\n \tint header_stage; /* still checking in-body headers? */\n };\n \n-\n-static struct strbuf charset = STRBUF_INIT;\n-\n static struct strbuf **p_hdr_data, **s_hdr_data;\n \n #define MAX_HDR_PARSED 10\n@@ -186,7 +184,7 @@ static struct strbuf *content[MAX_BOUNDARIES];\n \n static struct strbuf **content_top = content;\n \n-static void handle_content_type(struct strbuf *line)\n+static void handle_content_type(struct mailinfo *mi, struct strbuf *line)\n {\n \tstruct strbuf *boundary = xmalloc(sizeof(struct strbuf));\n \tstrbuf_init(boundary, line->len);\n@@ -200,7 +198,7 @@ static void handle_content_type(struct strbuf *line)\n \t\t*content_top = boundary;\n \t\tboundary = NULL;\n \t}\n-\tslurp_attr(line->buf, \"charset=\", &charset);\n+\tslurp_attr(line->buf, \"charset=\", &mi->charset);\n \n \tif (boundary) {\n \t\tstrbuf_release(boundary);\n@@ -349,7 +347,7 @@ static int check_header(struct mailinfo *mi,\n \t\tstrbuf_add(&sb, line->buf + len, line->len - len);\n \t\tdecode_header(mi, &sb);\n \t\tstrbuf_insert(&sb, 0, \"Content-Type: \", len);\n-\t\thandle_content_type(&sb);\n+\t\thandle_content_type(mi, &sb);\n \t\tret = 1;\n \t\tgoto check_header_out;\n \t}\n@@ -745,7 +743,7 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n \t\tmi->header_stage = 0;\n \n \t/* normalize the log message to UTF-8. */\n-\tconvert_to_utf8(mi, line, charset.buf);\n+\tconvert_to_utf8(mi, line, mi->charset.buf);\n \n \tif (mi->use_scissors && is_scissors_line(line)) {\n \t\tint i;\n@@ -840,7 +838,7 @@ again:\n \n \t/* set some defaults */\n \tmi->transfer_encoding = TE_DONTCARE;\n-\tstrbuf_reset(&charset);\n+\tstrbuf_reset(&mi->charset);\n \n \t/* slurp in this section's info */\n \twhile (read_one_header_line(line, mi->input))\n@@ -1027,6 +1025,7 @@ static void setup_mailinfo(struct mailinfo *mi)\n \tmemset(mi, 0, sizeof(*mi));\n \tstrbuf_init(&mi->name, 0);\n \tstrbuf_init(&mi->email, 0);\n+\tstrbuf_init(&mi->charset, 0);\n \tmi->header_stage = 1;\n \tmi->use_inbody_headers = 1;\n \tgit_config(git_mailinfo_config, &mi);\n@@ -1036,6 +1035,7 @@ static void clear_mailinfo(struct mailinfo *mi)\n {\n \tstrbuf_release(&mi->name);\n \tstrbuf_release(&mi->email);\n+\tstrbuf_release(&mi->charset);\n \tfree(mi->message_id);\n }\n \n-- \n2.6.2-383-g144b2e6\n"},{"id":"271917","messageId":"1445239731-10677-23-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1445239731-10677-1-git-send-email-gitster@pobox.com","subject":"[PATCH v3 22/34] mailinfo: move cmitmsg and patchfile to struct mailinfo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-19T07:28:39Z","receivedAt":"2015-10-19T07:28:39Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Signed-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 32 ++++++++++++++++----------------\n 1 file changed, 16 insertions(+), 16 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 810d132..b8b94d6 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -7,11 +7,11 @@\n #include \"utf8.h\"\n #include \"strbuf.h\"\n \n-static FILE *cmitmsg, *patchfile;\n-\n struct mailinfo {\n \tFILE *input;\n \tFILE *output;\n+\tFILE *cmitmsg;\n+\tFILE *patchfile;\n \n \tstruct strbuf name;\n \tstruct strbuf email;\n@@ -724,7 +724,7 @@ static int is_scissors_line(const struct strbuf *line)\n \n static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n {\n-\tif (!cmitmsg)\n+\tif (!mi->cmitmsg)\n \t\treturn 0;\n \n \tif (mi->header_stage) {\n@@ -747,9 +747,9 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n \n \tif (mi->use_scissors && is_scissors_line(line)) {\n \t\tint i;\n-\t\tif (fseek(cmitmsg, 0L, SEEK_SET))\n+\t\tif (fseek(mi->cmitmsg, 0L, SEEK_SET))\n \t\t\tdie_errno(\"Could not rewind output message file\");\n-\t\tif (ftruncate(fileno(cmitmsg), 0))\n+\t\tif (ftruncate(fileno(mi->cmitmsg), 0))\n \t\t\tdie_errno(\"Could not truncate output message file at scissors\");\n \t\tmi->header_stage = 1;\n \n@@ -767,19 +767,19 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n \n \tif (patchbreak(line)) {\n \t\tif (mi->message_id)\n-\t\t\tfprintf(cmitmsg, \"Message-Id: %s\\n\", mi->message_id);\n-\t\tfclose(cmitmsg);\n-\t\tcmitmsg = NULL;\n+\t\t\tfprintf(mi->cmitmsg, \"Message-Id: %s\\n\", mi->message_id);\n+\t\tfclose(mi->cmitmsg);\n+\t\tmi->cmitmsg = NULL;\n \t\treturn 1;\n \t}\n \n-\tfputs(line->buf, cmitmsg);\n+\tfputs(line->buf, mi->cmitmsg);\n \treturn 0;\n }\n \n static void handle_patch(struct mailinfo *mi, const struct strbuf *line)\n {\n-\tfwrite(line->buf, 1, line->len, patchfile);\n+\tfwrite(line->buf, 1, line->len, mi->patchfile);\n \tmi->patch_lines++;\n }\n \n@@ -974,15 +974,15 @@ static int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)\n \tint peek;\n \tstruct strbuf line = STRBUF_INIT;\n \n-\tcmitmsg = fopen(msg, \"w\");\n-\tif (!cmitmsg) {\n+\tmi->cmitmsg = fopen(msg, \"w\");\n+\tif (!mi->cmitmsg) {\n \t\tperror(msg);\n \t\treturn -1;\n \t}\n-\tpatchfile = fopen(patch, \"w\");\n-\tif (!patchfile) {\n+\tmi->patchfile = fopen(patch, \"w\");\n+\tif (!mi->patchfile) {\n \t\tperror(patch);\n-\t\tfclose(cmitmsg);\n+\t\tfclose(mi->cmitmsg);\n \t\treturn -1;\n \t}\n \n@@ -999,7 +999,7 @@ static int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)\n \t\tcheck_header(mi, &line, p_hdr_data, 1);\n \n \thandle_body(mi, &line);\n-\tfclose(patchfile);\n+\tfclose(mi->patchfile);\n \n \thandle_info(mi);\n \n-- \n2.6.2-383-g144b2e6\n"},{"id":"271920","messageId":"1445239731-10677-24-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1445239731-10677-1-git-send-email-gitster@pobox.com","subject":"[PATCH v3 23/34] mailinfo: move [ps]_hdr_data to struct mailinfo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-19T07:28:40Z","receivedAt":"2015-10-19T07:28:40Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Signed-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 37 +++++++++++++++++++++++--------------\n 1 file changed, 23 insertions(+), 14 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex b8b94d6..2c194da 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -30,10 +30,10 @@ struct mailinfo {\n \tint patch_lines;\n \tint filter_stage; /* still reading log or are we copying patch? */\n \tint header_stage; /* still checking in-body headers? */\n+\tstruct strbuf **p_hdr_data;\n+\tstruct strbuf **s_hdr_data;\n };\n \n-static struct strbuf **p_hdr_data, **s_hdr_data;\n-\n #define MAX_HDR_PARSED 10\n #define MAX_BOUNDARIES 5\n \n@@ -733,7 +733,7 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n \t}\n \n \tif (mi->use_inbody_headers && mi->header_stage) {\n-\t\tmi->header_stage = check_header(mi, line, s_hdr_data, 0);\n+\t\tmi->header_stage = check_header(mi, line, mi->s_hdr_data, 0);\n \t\tif (mi->header_stage)\n \t\t\treturn 0;\n \t} else\n@@ -758,9 +758,9 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n \t\t * them to give ourselves a clean restart.\n \t\t */\n \t\tfor (i = 0; header[i]; i++) {\n-\t\t\tif (s_hdr_data[i])\n-\t\t\t\tstrbuf_release(s_hdr_data[i]);\n-\t\t\ts_hdr_data[i] = NULL;\n+\t\t\tif (mi->s_hdr_data[i])\n+\t\t\t\tstrbuf_release(mi->s_hdr_data[i]);\n+\t\t\tmi->s_hdr_data[i] = NULL;\n \t\t}\n \t\treturn 0;\n \t}\n@@ -842,7 +842,7 @@ again:\n \n \t/* slurp in this section's info */\n \twhile (read_one_header_line(line, mi->input))\n-\t\tcheck_header(mi, line, p_hdr_data, 0);\n+\t\tcheck_header(mi, line, mi->p_hdr_data, 0);\n \n \tstrbuf_release(&newline);\n \t/* replenish line */\n@@ -943,10 +943,10 @@ static void handle_info(struct mailinfo *mi)\n \n \tfor (i = 0; header[i]; i++) {\n \t\t/* only print inbody headers if we output a patch file */\n-\t\tif (mi->patch_lines && s_hdr_data[i])\n-\t\t\thdr = s_hdr_data[i];\n-\t\telse if (p_hdr_data[i])\n-\t\t\thdr = p_hdr_data[i];\n+\t\tif (mi->patch_lines && mi->s_hdr_data[i])\n+\t\t\thdr = mi->s_hdr_data[i];\n+\t\telse if (mi->p_hdr_data[i])\n+\t\t\thdr = mi->p_hdr_data[i];\n \t\telse\n \t\t\tcontinue;\n \n@@ -986,8 +986,8 @@ static int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)\n \t\treturn -1;\n \t}\n \n-\tp_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*p_hdr_data));\n-\ts_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*s_hdr_data));\n+\tmi->p_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*(mi->p_hdr_data)));\n+\tmi->s_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*(mi->s_hdr_data)));\n \n \tdo {\n \t\tpeek = fgetc(mi->input);\n@@ -996,7 +996,7 @@ static int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)\n \n \t/* process the email header */\n \twhile (read_one_header_line(&line, mi->input))\n-\t\tcheck_header(mi, &line, p_hdr_data, 1);\n+\t\tcheck_header(mi, &line, mi->p_hdr_data, 1);\n \n \thandle_body(mi, &line);\n \tfclose(mi->patchfile);\n@@ -1033,10 +1033,19 @@ static void setup_mailinfo(struct mailinfo *mi)\n \n static void clear_mailinfo(struct mailinfo *mi)\n {\n+\tint i;\n+\n \tstrbuf_release(&mi->name);\n \tstrbuf_release(&mi->email);\n \tstrbuf_release(&mi->charset);\n \tfree(mi->message_id);\n+\n+\tfor (i = 0; mi->p_hdr_data[i]; i++)\n+\t\tstrbuf_release(mi->p_hdr_data[i]);\n+\tfree(mi->p_hdr_data);\n+\tfor (i = 0; mi->s_hdr_data[i]; i++)\n+\t\tstrbuf_release(mi->s_hdr_data[i]);\n+\tfree(mi->s_hdr_data);\n }\n \n static const char mailinfo_usage[] =\n-- \n2.6.2-383-g144b2e6\n"},{"id":"271918","messageId":"1445239731-10677-25-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1445239731-10677-1-git-send-email-gitster@pobox.com","subject":"[PATCH v3 24/34] mailinfo: move content/content_top to struct mailinfo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-19T07:28:41Z","receivedAt":"2015-10-19T07:28:41Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Signed-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 45 ++++++++++++++++++++++++++-------------------\n 1 file changed, 26 insertions(+), 19 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 2c194da..ec65805 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -7,6 +7,8 @@\n #include \"utf8.h\"\n #include \"strbuf.h\"\n \n+#define MAX_BOUNDARIES 5\n+\n struct mailinfo {\n \tFILE *input;\n \tFILE *output;\n@@ -22,6 +24,8 @@ struct mailinfo {\n \tint use_inbody_headers; /* defaults to 1 */\n \tconst char *metainfo_charset;\n \n+\tstruct strbuf *content[MAX_BOUNDARIES];\n+\tstruct strbuf **content_top;\n \tstruct strbuf charset;\n \tchar *message_id;\n \tenum  {\n@@ -35,7 +39,6 @@ struct mailinfo {\n };\n \n #define MAX_HDR_PARSED 10\n-#define MAX_BOUNDARIES 5\n \n static void cleanup_space(struct strbuf *sb);\n \n@@ -180,10 +183,6 @@ static int slurp_attr(const char *line, const char *name, struct strbuf *attr)\n \treturn 1;\n }\n \n-static struct strbuf *content[MAX_BOUNDARIES];\n-\n-static struct strbuf **content_top = content;\n-\n static void handle_content_type(struct mailinfo *mi, struct strbuf *line)\n {\n \tstruct strbuf *boundary = xmalloc(sizeof(struct strbuf));\n@@ -191,11 +190,11 @@ static void handle_content_type(struct mailinfo *mi, struct strbuf *line)\n \n \tif (slurp_attr(line->buf, \"boundary=\", boundary)) {\n \t\tstrbuf_insert(boundary, 0, \"--\", 2);\n-\t\tif (++content_top >= &content[MAX_BOUNDARIES]) {\n+\t\tif (++mi->content_top >= &mi->content[MAX_BOUNDARIES]) {\n \t\t\tfprintf(stderr, \"Too many boundaries to handle\\n\");\n \t\t\texit(1);\n \t\t}\n-\t\t*content_top = boundary;\n+\t\t*(mi->content_top) = boundary;\n \t\tboundary = NULL;\n \t}\n \tslurp_attr(line->buf, \"charset=\", &mi->charset);\n@@ -223,10 +222,12 @@ static void handle_content_transfer_encoding(struct mailinfo *mi,\n \t\tmi->transfer_encoding = TE_DONTCARE;\n }\n \n-static int is_multipart_boundary(const struct strbuf *line)\n+static int is_multipart_boundary(struct mailinfo *mi, const struct strbuf *line)\n {\n-\treturn (((*content_top)->len <= line->len) &&\n-\t\t!memcmp(line->buf, (*content_top)->buf, (*content_top)->len));\n+\tstruct strbuf *content_top = *(mi->content_top);\n+\n+\treturn ((content_top->len <= line->len) &&\n+\t\t!memcmp(line->buf, content_top->buf, content_top->len));\n }\n \n static void cleanup_subject(struct mailinfo *mi, struct strbuf *subject)\n@@ -799,7 +800,7 @@ static void handle_filter(struct mailinfo *mi, struct strbuf *line)\n static int find_boundary(struct mailinfo *mi, struct strbuf *line)\n {\n \twhile (!strbuf_getline(line, mi->input, '\\n')) {\n-\t\tif (*content_top && is_multipart_boundary(line))\n+\t\tif (*(mi->content_top) && is_multipart_boundary(mi, line))\n \t\t\treturn 1;\n \t}\n \treturn 0;\n@@ -811,18 +812,18 @@ static int handle_boundary(struct mailinfo *mi, struct strbuf *line)\n \n \tstrbuf_addch(&newline, '\\n');\n again:\n-\tif (line->len >= (*content_top)->len + 2 &&\n-\t    !memcmp(line->buf + (*content_top)->len, \"--\", 2)) {\n+\tif (line->len >= (*(mi->content_top))->len + 2 &&\n+\t    !memcmp(line->buf + (*(mi->content_top))->len, \"--\", 2)) {\n \t\t/* we hit an end boundary */\n \t\t/* pop the current boundary off the stack */\n-\t\tstrbuf_release(*content_top);\n-\t\tfree(*content_top);\n-\t\t*content_top = NULL;\n+\t\tstrbuf_release(*(mi->content_top));\n+\t\tfree(*(mi->content_top));\n+\t\t*(mi->content_top) = NULL;\n \n \t\t/* technically won't happen as is_multipart_boundary()\n \t\t   will fail first.  But just in case..\n \t\t */\n-\t\tif (--content_top < content) {\n+\t\tif (--mi->content_top < mi->content) {\n \t\t\tfprintf(stderr, \"Detected mismatched boundaries, \"\n \t\t\t\t\t\"can't recover\\n\");\n \t\t\texit(1);\n@@ -857,14 +858,14 @@ static void handle_body(struct mailinfo *mi, struct strbuf *line)\n \tstruct strbuf prev = STRBUF_INIT;\n \n \t/* Skip up to the first boundary */\n-\tif (*content_top) {\n+\tif (*(mi->content_top)) {\n \t\tif (!find_boundary(mi, line))\n \t\t\tgoto handle_body_out;\n \t}\n \n \tdo {\n \t\t/* process any boundary lines */\n-\t\tif (*content_top && is_multipart_boundary(line)) {\n+\t\tif (*(mi->content_top) && is_multipart_boundary(mi, line)) {\n \t\t\t/* flush any leftover */\n \t\t\tif (prev.len) {\n \t\t\t\thandle_filter(mi, &prev);\n@@ -1028,6 +1029,7 @@ static void setup_mailinfo(struct mailinfo *mi)\n \tstrbuf_init(&mi->charset, 0);\n \tmi->header_stage = 1;\n \tmi->use_inbody_headers = 1;\n+\tmi->content_top = mi->content;\n \tgit_config(git_mailinfo_config, &mi);\n }\n \n@@ -1046,6 +1048,11 @@ static void clear_mailinfo(struct mailinfo *mi)\n \tfor (i = 0; mi->s_hdr_data[i]; i++)\n \t\tstrbuf_release(mi->s_hdr_data[i]);\n \tfree(mi->s_hdr_data);\n+\n+\twhile (mi->content < mi->content_top) {\n+\t\tfree(*(mi->content_top));\n+\t\tmi->content_top--;\n+\t}\n }\n \n static const char mailinfo_usage[] =\n-- \n2.6.2-383-g144b2e6\n"},{"id":"271904","messageId":"1445239731-10677-26-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1445239731-10677-1-git-send-email-gitster@pobox.com","subject":"[PATCH v3 25/34] mailinfo: handle_commit_msg() shouldn't be called after finding patchbreak","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-19T07:28:42Z","receivedAt":"2015-10-19T07:28:42Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"There is a strange \"if (!mi->cmitmsg) return 0\" at the very beginning\nof handle_commit_msg(), but the condition should never trigger, because:\n\n * The only place cmitmsg is set to NULL is after this function sees\n   a patch break, closes the FILE * to write the commit log message\n   and returns 1.  This function returns non-zero only from that\n   codepath.\n\n * The caller of this function, upon seeing a non-zero return,\n   increments filter_stage, starts treating the input as patch text\n   and will never call handle_commit_msg() again.\n\nReplace it with an assert(!mi->filter_stage) to ensure the above\nobservation will stay to be true.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 3 +--\n 1 file changed, 1 insertion(+), 2 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex ec65805..286eda0 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -725,8 +725,7 @@ static int is_scissors_line(const struct strbuf *line)\n \n static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n {\n-\tif (!mi->cmitmsg)\n-\t\treturn 0;\n+\tassert(!mi->filter_stage);\n \n \tif (mi->header_stage) {\n \t\tif (!line->len || (line->len == 1 && line->buf[0] == '\\n'))\n-- \n2.6.2-383-g144b2e6\n"},{"id":"271913","messageId":"1445239731-10677-27-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1445239731-10677-1-git-send-email-gitster@pobox.com","subject":"[PATCH v3 26/34] mailinfo: keep the parsed log message in a strbuf","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-19T07:28:43Z","receivedAt":"2015-10-19T07:28:43Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"When mailinfo() is eventually libified, the calling \"git am\" still\nwill have to write out the log message in the \"msg\" file for hooks\nand other users of the information, but it does not have to reopen\nand reread what it wrote earlier if the function kept it in a strbuf.\n\nThis also removes the need for seeking and truncating the output\nfile when we see a scissors mark in the input, which in turn allows\nus to lose two callsites of die_errno().\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 28 ++++++++++++++++------------\n 1 file changed, 16 insertions(+), 12 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 286eda0..81bb3c7 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -12,7 +12,6 @@\n struct mailinfo {\n \tFILE *input;\n \tFILE *output;\n-\tFILE *cmitmsg;\n \tFILE *patchfile;\n \n \tstruct strbuf name;\n@@ -36,6 +35,8 @@ struct mailinfo {\n \tint header_stage; /* still checking in-body headers? */\n \tstruct strbuf **p_hdr_data;\n \tstruct strbuf **s_hdr_data;\n+\n+\tstruct strbuf log_message;\n };\n \n #define MAX_HDR_PARSED 10\n@@ -747,10 +748,8 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n \n \tif (mi->use_scissors && is_scissors_line(line)) {\n \t\tint i;\n-\t\tif (fseek(mi->cmitmsg, 0L, SEEK_SET))\n-\t\t\tdie_errno(\"Could not rewind output message file\");\n-\t\tif (ftruncate(fileno(mi->cmitmsg), 0))\n-\t\t\tdie_errno(\"Could not truncate output message file at scissors\");\n+\n+\t\tstrbuf_setlen(&mi->log_message, 0);\n \t\tmi->header_stage = 1;\n \n \t\t/*\n@@ -767,13 +766,12 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n \n \tif (patchbreak(line)) {\n \t\tif (mi->message_id)\n-\t\t\tfprintf(mi->cmitmsg, \"Message-Id: %s\\n\", mi->message_id);\n-\t\tfclose(mi->cmitmsg);\n-\t\tmi->cmitmsg = NULL;\n+\t\t\tstrbuf_addf(&mi->log_message,\n+\t\t\t\t    \"Message-Id: %s\\n\", mi->message_id);\n \t\treturn 1;\n \t}\n \n-\tfputs(line->buf, mi->cmitmsg);\n+\tstrbuf_addbuf(&mi->log_message, line);\n \treturn 0;\n }\n \n@@ -971,18 +969,19 @@ static void handle_info(struct mailinfo *mi)\n \n static int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)\n {\n+\tFILE *cmitmsg;\n \tint peek;\n \tstruct strbuf line = STRBUF_INIT;\n \n-\tmi->cmitmsg = fopen(msg, \"w\");\n-\tif (!mi->cmitmsg) {\n+\tcmitmsg = fopen(msg, \"w\");\n+\tif (!cmitmsg) {\n \t\tperror(msg);\n \t\treturn -1;\n \t}\n \tmi->patchfile = fopen(patch, \"w\");\n \tif (!mi->patchfile) {\n \t\tperror(patch);\n-\t\tfclose(mi->cmitmsg);\n+\t\tfclose(cmitmsg);\n \t\treturn -1;\n \t}\n \n@@ -999,6 +998,8 @@ static int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)\n \t\tcheck_header(mi, &line, mi->p_hdr_data, 1);\n \n \thandle_body(mi, &line);\n+\tfwrite(mi->log_message.buf, 1, mi->log_message.len, cmitmsg);\n+\tfclose(cmitmsg);\n \tfclose(mi->patchfile);\n \n \thandle_info(mi);\n@@ -1026,6 +1027,7 @@ static void setup_mailinfo(struct mailinfo *mi)\n \tstrbuf_init(&mi->name, 0);\n \tstrbuf_init(&mi->email, 0);\n \tstrbuf_init(&mi->charset, 0);\n+\tstrbuf_init(&mi->log_message, 0);\n \tmi->header_stage = 1;\n \tmi->use_inbody_headers = 1;\n \tmi->content_top = mi->content;\n@@ -1052,6 +1054,8 @@ static void clear_mailinfo(struct mailinfo *mi)\n \t\tfree(*(mi->content_top));\n \t\tmi->content_top--;\n \t}\n+\n+\tstrbuf_release(&mi->log_message);\n }\n \n static const char mailinfo_usage[] =\n-- \n2.6.2-383-g144b2e6\n"},{"id":"271909","messageId":"1445239731-10677-28-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1445239731-10677-1-git-send-email-gitster@pobox.com","subject":"[PATCH v3 27/34] mailinfo: move read_one_header_line() closer to its callers","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-19T07:28:44Z","receivedAt":"2015-10-19T07:28:44Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Signed-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 132 ++++++++++++++++++++++++++---------------------------\n 1 file changed, 66 insertions(+), 66 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 81bb3c7..5a21d93 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -390,72 +390,6 @@ check_header_out:\n \treturn ret;\n }\n \n-static int is_rfc2822_header(const struct strbuf *line)\n-{\n-\t/*\n-\t * The section that defines the loosest possible\n-\t * field name is \"3.6.8 Optional fields\".\n-\t *\n-\t * optional-field = field-name \":\" unstructured CRLF\n-\t * field-name = 1*ftext\n-\t * ftext = %d33-57 / %59-126\n-\t */\n-\tint ch;\n-\tchar *cp = line->buf;\n-\n-\t/* Count mbox From headers as headers */\n-\tif (starts_with(cp, \"From \") || starts_with(cp, \">From \"))\n-\t\treturn 1;\n-\n-\twhile ((ch = *cp++)) {\n-\t\tif (ch == ':')\n-\t\t\treturn 1;\n-\t\tif ((33 <= ch && ch <= 57) ||\n-\t\t    (59 <= ch && ch <= 126))\n-\t\t\tcontinue;\n-\t\tbreak;\n-\t}\n-\treturn 0;\n-}\n-\n-static int read_one_header_line(struct strbuf *line, FILE *in)\n-{\n-\t/* Get the first part of the line. */\n-\tif (strbuf_getline(line, in, '\\n'))\n-\t\treturn 0;\n-\n-\t/*\n-\t * Is it an empty line or not a valid rfc2822 header?\n-\t * If so, stop here, and return false (\"not a header\")\n-\t */\n-\tstrbuf_rtrim(line);\n-\tif (!line->len || !is_rfc2822_header(line)) {\n-\t\t/* Re-add the newline */\n-\t\tstrbuf_addch(line, '\\n');\n-\t\treturn 0;\n-\t}\n-\n-\t/*\n-\t * Now we need to eat all the continuation lines..\n-\t * Yuck, 2822 header \"folding\"\n-\t */\n-\tfor (;;) {\n-\t\tint peek;\n-\t\tstruct strbuf continuation = STRBUF_INIT;\n-\n-\t\tpeek = fgetc(in); ungetc(peek, in);\n-\t\tif (peek != ' ' && peek != '\\t')\n-\t\t\tbreak;\n-\t\tif (strbuf_getline(&continuation, in, '\\n'))\n-\t\t\tbreak;\n-\t\tcontinuation.buf[0] = ' ';\n-\t\tstrbuf_rtrim(&continuation);\n-\t\tstrbuf_addbuf(line, &continuation);\n-\t}\n-\n-\treturn 1;\n-}\n-\n static struct strbuf *decode_q_segment(const struct strbuf *q_seg, int rfc2047)\n {\n \tconst char *in = q_seg->buf;\n@@ -794,6 +728,72 @@ static void handle_filter(struct mailinfo *mi, struct strbuf *line)\n \t}\n }\n \n+static int is_rfc2822_header(const struct strbuf *line)\n+{\n+\t/*\n+\t * The section that defines the loosest possible\n+\t * field name is \"3.6.8 Optional fields\".\n+\t *\n+\t * optional-field = field-name \":\" unstructured CRLF\n+\t * field-name = 1*ftext\n+\t * ftext = %d33-57 / %59-126\n+\t */\n+\tint ch;\n+\tchar *cp = line->buf;\n+\n+\t/* Count mbox From headers as headers */\n+\tif (starts_with(cp, \"From \") || starts_with(cp, \">From \"))\n+\t\treturn 1;\n+\n+\twhile ((ch = *cp++)) {\n+\t\tif (ch == ':')\n+\t\t\treturn 1;\n+\t\tif ((33 <= ch && ch <= 57) ||\n+\t\t    (59 <= ch && ch <= 126))\n+\t\t\tcontinue;\n+\t\tbreak;\n+\t}\n+\treturn 0;\n+}\n+\n+static int read_one_header_line(struct strbuf *line, FILE *in)\n+{\n+\t/* Get the first part of the line. */\n+\tif (strbuf_getline(line, in, '\\n'))\n+\t\treturn 0;\n+\n+\t/*\n+\t * Is it an empty line or not a valid rfc2822 header?\n+\t * If so, stop here, and return false (\"not a header\")\n+\t */\n+\tstrbuf_rtrim(line);\n+\tif (!line->len || !is_rfc2822_header(line)) {\n+\t\t/* Re-add the newline */\n+\t\tstrbuf_addch(line, '\\n');\n+\t\treturn 0;\n+\t}\n+\n+\t/*\n+\t * Now we need to eat all the continuation lines..\n+\t * Yuck, 2822 header \"folding\"\n+\t */\n+\tfor (;;) {\n+\t\tint peek;\n+\t\tstruct strbuf continuation = STRBUF_INIT;\n+\n+\t\tpeek = fgetc(in); ungetc(peek, in);\n+\t\tif (peek != ' ' && peek != '\\t')\n+\t\t\tbreak;\n+\t\tif (strbuf_getline(&continuation, in, '\\n'))\n+\t\t\tbreak;\n+\t\tcontinuation.buf[0] = ' ';\n+\t\tstrbuf_rtrim(&continuation);\n+\t\tstrbuf_addbuf(line, &continuation);\n+\t}\n+\n+\treturn 1;\n+}\n+\n static int find_boundary(struct mailinfo *mi, struct strbuf *line)\n {\n \twhile (!strbuf_getline(line, mi->input, '\\n')) {\n-- \n2.6.2-383-g144b2e6\n"},{"id":"271907","messageId":"1445239731-10677-29-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1445239731-10677-1-git-send-email-gitster@pobox.com","subject":"[PATCH v3 28/34] mailinfo: move check_header() after the helpers it uses","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-19T07:28:45Z","receivedAt":"2015-10-19T07:28:45Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This way, we can lose a forward decl for decode_header().\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 139 ++++++++++++++++++++++++++---------------------------\n 1 file changed, 69 insertions(+), 70 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 5a21d93..6fc6aa8 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -293,7 +293,6 @@ static void cleanup_space(struct strbuf *sb)\n \t}\n }\n \n-static void decode_header(struct mailinfo *mi, struct strbuf *line);\n static const char *header[MAX_HDR_PARSED] = {\n \t\"From\",\"Subject\",\"Date\",\n };\n@@ -321,75 +320,6 @@ static int is_format_patch_separator(const char *line, int len)\n \treturn !memcmp(SAMPLE + (cp - line), cp, strlen(SAMPLE) - (cp - line));\n }\n \n-static int check_header(struct mailinfo *mi,\n-\t\t\tconst struct strbuf *line,\n-\t\t\tstruct strbuf *hdr_data[], int overwrite)\n-{\n-\tint i, ret = 0, len;\n-\tstruct strbuf sb = STRBUF_INIT;\n-\n-\t/* search for the interesting parts */\n-\tfor (i = 0; header[i]; i++) {\n-\t\tint len = strlen(header[i]);\n-\t\tif ((!hdr_data[i] || overwrite) && cmp_header(line, header[i])) {\n-\t\t\t/* Unwrap inline B and Q encoding, and optionally\n-\t\t\t * normalize the meta information to utf8.\n-\t\t\t */\n-\t\t\tstrbuf_add(&sb, line->buf + len + 2, line->len - len - 2);\n-\t\t\tdecode_header(mi, &sb);\n-\t\t\thandle_header(&hdr_data[i], &sb);\n-\t\t\tret = 1;\n-\t\t\tgoto check_header_out;\n-\t\t}\n-\t}\n-\n-\t/* Content stuff */\n-\tif (cmp_header(line, \"Content-Type\")) {\n-\t\tlen = strlen(\"Content-Type: \");\n-\t\tstrbuf_add(&sb, line->buf + len, line->len - len);\n-\t\tdecode_header(mi, &sb);\n-\t\tstrbuf_insert(&sb, 0, \"Content-Type: \", len);\n-\t\thandle_content_type(mi, &sb);\n-\t\tret = 1;\n-\t\tgoto check_header_out;\n-\t}\n-\tif (cmp_header(line, \"Content-Transfer-Encoding\")) {\n-\t\tlen = strlen(\"Content-Transfer-Encoding: \");\n-\t\tstrbuf_add(&sb, line->buf + len, line->len - len);\n-\t\tdecode_header(mi, &sb);\n-\t\thandle_content_transfer_encoding(mi, &sb);\n-\t\tret = 1;\n-\t\tgoto check_header_out;\n-\t}\n-\tif (cmp_header(line, \"Message-Id\")) {\n-\t\tlen = strlen(\"Message-Id: \");\n-\t\tstrbuf_add(&sb, line->buf + len, line->len - len);\n-\t\tdecode_header(mi, &sb);\n-\t\thandle_message_id(mi, &sb);\n-\t\tret = 1;\n-\t\tgoto check_header_out;\n-\t}\n-\n-\t/* for inbody stuff */\n-\tif (starts_with(line->buf, \">From\") && isspace(line->buf[5])) {\n-\t\tret = is_format_patch_separator(line->buf + 1, line->len - 1);\n-\t\tgoto check_header_out;\n-\t}\n-\tif (starts_with(line->buf, \"[PATCH]\") && isspace(line->buf[7])) {\n-\t\tfor (i = 0; header[i]; i++) {\n-\t\t\tif (!strcmp(\"Subject\", header[i])) {\n-\t\t\t\thandle_header(&hdr_data[i], line);\n-\t\t\t\tret = 1;\n-\t\t\t\tgoto check_header_out;\n-\t\t\t}\n-\t\t}\n-\t}\n-\n-check_header_out:\n-\tstrbuf_release(&sb);\n-\treturn ret;\n-}\n-\n static struct strbuf *decode_q_segment(const struct strbuf *q_seg, int rfc2047)\n {\n \tconst char *in = q_seg->buf;\n@@ -550,6 +480,75 @@ release_return:\n \tstrbuf_release(&piecebuf);\n }\n \n+static int check_header(struct mailinfo *mi,\n+\t\t\tconst struct strbuf *line,\n+\t\t\tstruct strbuf *hdr_data[], int overwrite)\n+{\n+\tint i, ret = 0, len;\n+\tstruct strbuf sb = STRBUF_INIT;\n+\n+\t/* search for the interesting parts */\n+\tfor (i = 0; header[i]; i++) {\n+\t\tint len = strlen(header[i]);\n+\t\tif ((!hdr_data[i] || overwrite) && cmp_header(line, header[i])) {\n+\t\t\t/* Unwrap inline B and Q encoding, and optionally\n+\t\t\t * normalize the meta information to utf8.\n+\t\t\t */\n+\t\t\tstrbuf_add(&sb, line->buf + len + 2, line->len - len - 2);\n+\t\t\tdecode_header(mi, &sb);\n+\t\t\thandle_header(&hdr_data[i], &sb);\n+\t\t\tret = 1;\n+\t\t\tgoto check_header_out;\n+\t\t}\n+\t}\n+\n+\t/* Content stuff */\n+\tif (cmp_header(line, \"Content-Type\")) {\n+\t\tlen = strlen(\"Content-Type: \");\n+\t\tstrbuf_add(&sb, line->buf + len, line->len - len);\n+\t\tdecode_header(mi, &sb);\n+\t\tstrbuf_insert(&sb, 0, \"Content-Type: \", len);\n+\t\thandle_content_type(mi, &sb);\n+\t\tret = 1;\n+\t\tgoto check_header_out;\n+\t}\n+\tif (cmp_header(line, \"Content-Transfer-Encoding\")) {\n+\t\tlen = strlen(\"Content-Transfer-Encoding: \");\n+\t\tstrbuf_add(&sb, line->buf + len, line->len - len);\n+\t\tdecode_header(mi, &sb);\n+\t\thandle_content_transfer_encoding(mi, &sb);\n+\t\tret = 1;\n+\t\tgoto check_header_out;\n+\t}\n+\tif (cmp_header(line, \"Message-Id\")) {\n+\t\tlen = strlen(\"Message-Id: \");\n+\t\tstrbuf_add(&sb, line->buf + len, line->len - len);\n+\t\tdecode_header(mi, &sb);\n+\t\thandle_message_id(mi, &sb);\n+\t\tret = 1;\n+\t\tgoto check_header_out;\n+\t}\n+\n+\t/* for inbody stuff */\n+\tif (starts_with(line->buf, \">From\") && isspace(line->buf[5])) {\n+\t\tret = is_format_patch_separator(line->buf + 1, line->len - 1);\n+\t\tgoto check_header_out;\n+\t}\n+\tif (starts_with(line->buf, \"[PATCH]\") && isspace(line->buf[7])) {\n+\t\tfor (i = 0; header[i]; i++) {\n+\t\t\tif (!strcmp(\"Subject\", header[i])) {\n+\t\t\t\thandle_header(&hdr_data[i], line);\n+\t\t\t\tret = 1;\n+\t\t\t\tgoto check_header_out;\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+check_header_out:\n+\tstrbuf_release(&sb);\n+\treturn ret;\n+}\n+\n static void decode_transfer_encoding(struct mailinfo *mi, struct strbuf *line)\n {\n \tstruct strbuf *ret;\n-- \n2.6.2-383-g144b2e6\n"},{"id":"271914","messageId":"1445239731-10677-30-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1445239731-10677-1-git-send-email-gitster@pobox.com","subject":"[PATCH v3 29/34] mailinfo: move cleanup_space() before its users","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-19T07:28:46Z","receivedAt":"2015-10-19T07:28:46Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Signed-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 25 +++++++++++--------------\n 1 file changed, 11 insertions(+), 14 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 6fc6aa8..104d3d9 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -41,8 +41,17 @@ struct mailinfo {\n \n #define MAX_HDR_PARSED 10\n \n-static void cleanup_space(struct strbuf *sb);\n-\n+static void cleanup_space(struct strbuf *sb)\n+{\n+\tsize_t pos, cnt;\n+\tfor (pos = 0; pos < sb->len; pos++) {\n+\t\tif (isspace(sb->buf[pos])) {\n+\t\t\tsb->buf[pos] = ' ';\n+\t\t\tfor (cnt = 0; isspace(sb->buf[pos + cnt + 1]); cnt++);\n+\t\t\tstrbuf_remove(sb, pos + 1, cnt);\n+\t\t}\n+\t}\n+}\n \n static void get_sane_name(struct strbuf *out, struct strbuf *name, struct strbuf *email)\n {\n@@ -281,18 +290,6 @@ static void cleanup_subject(struct mailinfo *mi, struct strbuf *subject)\n \tstrbuf_trim(subject);\n }\n \n-static void cleanup_space(struct strbuf *sb)\n-{\n-\tsize_t pos, cnt;\n-\tfor (pos = 0; pos < sb->len; pos++) {\n-\t\tif (isspace(sb->buf[pos])) {\n-\t\t\tsb->buf[pos] = ' ';\n-\t\t\tfor (cnt = 0; isspace(sb->buf[pos + cnt + 1]); cnt++);\n-\t\t\tstrbuf_remove(sb, pos + 1, cnt);\n-\t\t}\n-\t}\n-}\n-\n static const char *header[MAX_HDR_PARSED] = {\n \t\"From\",\"Subject\",\"Date\",\n };\n-- \n2.6.2-383-g144b2e6\n"},{"id":"271910","messageId":"1445239731-10677-31-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1445239731-10677-1-git-send-email-gitster@pobox.com","subject":"[PATCH v3 30/34] mailinfo: move definition of MAX_HDR_PARSED closer to its use","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-19T07:28:47Z","receivedAt":"2015-10-19T07:28:47Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Signed-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mailinfo.c | 3 +--\n 1 file changed, 1 insertion(+), 2 deletions(-)\n\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 104d3d9..4eabc11 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -39,8 +39,6 @@ struct mailinfo {\n \tstruct strbuf log_message;\n };\n \n-#define MAX_HDR_PARSED 10\n-\n static void cleanup_space(struct strbuf *sb)\n {\n \tsize_t pos, cnt;\n@@ -290,6 +288,7 @@ static void cleanup_subject(struct mailinfo *mi, struct strbuf *subject)\n \tstrbuf_trim(subject);\n }\n \n+#define MAX_HDR_PARSED 10\n static const char *header[MAX_HDR_PARSED] = {\n \t\"From\",\"Subject\",\"Date\",\n };\n-- \n2.6.2-383-g144b2e6\n"},{"id":"271908","messageId":"1445239731-10677-32-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1445239731-10677-1-git-send-email-gitster@pobox.com","subject":"[PATCH v3 31/34] mailinfo: libify","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-19T07:28:48Z","receivedAt":"2015-10-19T07:28:48Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Move the bulk of the code from builtin/mailinfo.c to mailinfo.c\nso that new callers can start calling mailinfo() directly.\n\nNote that a few calls to exit() and die() need to be cleaned up\nfor the API to be truly useful, which will come in later steps.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n Makefile                         |    1 +\n builtin/mailinfo.c               | 1167 ++------------------------------------\n builtin/mailinfo.c => mailinfo.c |   96 +---\n mailinfo.h                       |   40 ++\n 4 files changed, 106 insertions(+), 1198 deletions(-)\n rewrite builtin/mailinfo.c (93%)\n copy builtin/mailinfo.c => mailinfo.c (90%)\n create mode 100644 mailinfo.h\n\ndiff --git a/Makefile b/Makefile\nindex 8d5df7e..7dd3bff 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -726,6 +726,7 @@ LIB_OBJS += list-objects.o\n LIB_OBJS += ll-merge.o\n LIB_OBJS += lockfile.o\n LIB_OBJS += log-tree.o\n+LIB_OBJS += mailinfo.o\n LIB_OBJS += mailmap.o\n LIB_OBJS += match-trees.o\n LIB_OBJS += merge.o\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\ndissimilarity index 93%\nindex 4eabc11..f6df274 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -1,1106 +1,61 @@\n-/*\n- * Another stupid program, this one parsing the headers of an\n- * email to figure out authorship and subject\n- */\n-#include \"cache.h\"\n-#include \"builtin.h\"\n-#include \"utf8.h\"\n-#include \"strbuf.h\"\n-\n-#define MAX_BOUNDARIES 5\n-\n-struct mailinfo {\n-\tFILE *input;\n-\tFILE *output;\n-\tFILE *patchfile;\n-\n-\tstruct strbuf name;\n-\tstruct strbuf email;\n-\tint keep_subject;\n-\tint keep_non_patch_brackets_in_subject;\n-\tint add_message_id;\n-\tint use_scissors;\n-\tint use_inbody_headers; /* defaults to 1 */\n-\tconst char *metainfo_charset;\n-\n-\tstruct strbuf *content[MAX_BOUNDARIES];\n-\tstruct strbuf **content_top;\n-\tstruct strbuf charset;\n-\tchar *message_id;\n-\tenum  {\n-\t\tTE_DONTCARE, TE_QP, TE_BASE64\n-\t} transfer_encoding;\n-\tint patch_lines;\n-\tint filter_stage; /* still reading log or are we copying patch? */\n-\tint header_stage; /* still checking in-body headers? */\n-\tstruct strbuf **p_hdr_data;\n-\tstruct strbuf **s_hdr_data;\n-\n-\tstruct strbuf log_message;\n-};\n-\n-static void cleanup_space(struct strbuf *sb)\n-{\n-\tsize_t pos, cnt;\n-\tfor (pos = 0; pos < sb->len; pos++) {\n-\t\tif (isspace(sb->buf[pos])) {\n-\t\t\tsb->buf[pos] = ' ';\n-\t\t\tfor (cnt = 0; isspace(sb->buf[pos + cnt + 1]); cnt++);\n-\t\t\tstrbuf_remove(sb, pos + 1, cnt);\n-\t\t}\n-\t}\n-}\n-\n-static void get_sane_name(struct strbuf *out, struct strbuf *name, struct strbuf *email)\n-{\n-\tstruct strbuf *src = name;\n-\tif (name->len < 3 || 60 < name->len || strchr(name->buf, '@') ||\n-\t\tstrchr(name->buf, '<') || strchr(name->buf, '>'))\n-\t\tsrc = email;\n-\telse if (name == out)\n-\t\treturn;\n-\tstrbuf_reset(out);\n-\tstrbuf_addbuf(out, src);\n-}\n-\n-static void parse_bogus_from(struct mailinfo *mi, const struct strbuf *line)\n-{\n-\t/* John Doe <johndoe> */\n-\n-\tchar *bra, *ket;\n-\t/* This is fallback, so do not bother if we already have an\n-\t * e-mail address.\n-\t */\n-\tif (mi->email.len)\n-\t\treturn;\n-\n-\tbra = strchr(line->buf, '<');\n-\tif (!bra)\n-\t\treturn;\n-\tket = strchr(bra, '>');\n-\tif (!ket)\n-\t\treturn;\n-\n-\tstrbuf_reset(&mi->email);\n-\tstrbuf_add(&mi->email, bra + 1, ket - bra - 1);\n-\n-\tstrbuf_reset(&mi->name);\n-\tstrbuf_add(&mi->name, line->buf, bra - line->buf);\n-\tstrbuf_trim(&mi->name);\n-\tget_sane_name(&mi->name, &mi->name, &mi->email);\n-}\n-\n-static void handle_from(struct mailinfo *mi, const struct strbuf *from)\n-{\n-\tchar *at;\n-\tsize_t el;\n-\tstruct strbuf f;\n-\n-\tstrbuf_init(&f, from->len);\n-\tstrbuf_addbuf(&f, from);\n-\n-\tat = strchr(f.buf, '@');\n-\tif (!at) {\n-\t\tparse_bogus_from(mi, from);\n-\t\treturn;\n-\t}\n-\n-\t/*\n-\t * If we already have one email, don't take any confusing lines\n-\t */\n-\tif (mi->email.len && strchr(at + 1, '@')) {\n-\t\tstrbuf_release(&f);\n-\t\treturn;\n-\t}\n-\n-\t/* Pick up the string around '@', possibly delimited with <>\n-\t * pair; that is the email part.\n-\t */\n-\twhile (at > f.buf) {\n-\t\tchar c = at[-1];\n-\t\tif (isspace(c))\n-\t\t\tbreak;\n-\t\tif (c == '<') {\n-\t\t\tat[-1] = ' ';\n-\t\t\tbreak;\n-\t\t}\n-\t\tat--;\n-\t}\n-\tel = strcspn(at, \" \\n\\t\\r\\v\\f>\");\n-\tstrbuf_reset(&mi->email);\n-\tstrbuf_add(&mi->email, at, el);\n-\tstrbuf_remove(&f, at - f.buf, el + (at[el] ? 1 : 0));\n-\n-\t/* The remainder is name.  It could be\n-\t *\n-\t * - \"John Doe <john.doe@xz>\"\t\t\t(a), or\n-\t * - \"john.doe@xz (John Doe)\"\t\t\t(b), or\n-\t * - \"John (zzz) Doe <john.doe@xz> (Comment)\"\t(c)\n-\t *\n-\t * but we have removed the email part, so\n-\t *\n-\t * - remove extra spaces which could stay after email (case 'c'), and\n-\t * - trim from both ends, possibly removing the () pair at the end\n-\t *   (cases 'a' and 'b').\n-\t */\n-\tcleanup_space(&f);\n-\tstrbuf_trim(&f);\n-\tif (f.buf[0] == '(' && f.len && f.buf[f.len - 1] == ')') {\n-\t\tstrbuf_remove(&f, 0, 1);\n-\t\tstrbuf_setlen(&f, f.len - 1);\n-\t}\n-\n-\tget_sane_name(&mi->name, &f, &mi->email);\n-\tstrbuf_release(&f);\n-}\n-\n-static void handle_header(struct strbuf **out, const struct strbuf *line)\n-{\n-\tif (!*out) {\n-\t\t*out = xmalloc(sizeof(struct strbuf));\n-\t\tstrbuf_init(*out, line->len);\n-\t} else\n-\t\tstrbuf_reset(*out);\n-\n-\tstrbuf_addbuf(*out, line);\n-}\n-\n-/* NOTE NOTE NOTE.  We do not claim we do full MIME.  We just attempt\n- * to have enough heuristics to grok MIME encoded patches often found\n- * on our mailing lists.  For example, we do not even treat header lines\n- * case insensitively.\n- */\n-\n-static int slurp_attr(const char *line, const char *name, struct strbuf *attr)\n-{\n-\tconst char *ends, *ap = strcasestr(line, name);\n-\tsize_t sz;\n-\n-\tstrbuf_setlen(attr, 0);\n-\tif (!ap)\n-\t\treturn 0;\n-\tap += strlen(name);\n-\tif (*ap == '\"') {\n-\t\tap++;\n-\t\tends = \"\\\"\";\n-\t}\n-\telse\n-\t\tends = \"; \\t\";\n-\tsz = strcspn(ap, ends);\n-\tstrbuf_add(attr, ap, sz);\n-\treturn 1;\n-}\n-\n-static void handle_content_type(struct mailinfo *mi, struct strbuf *line)\n-{\n-\tstruct strbuf *boundary = xmalloc(sizeof(struct strbuf));\n-\tstrbuf_init(boundary, line->len);\n-\n-\tif (slurp_attr(line->buf, \"boundary=\", boundary)) {\n-\t\tstrbuf_insert(boundary, 0, \"--\", 2);\n-\t\tif (++mi->content_top >= &mi->content[MAX_BOUNDARIES]) {\n-\t\t\tfprintf(stderr, \"Too many boundaries to handle\\n\");\n-\t\t\texit(1);\n-\t\t}\n-\t\t*(mi->content_top) = boundary;\n-\t\tboundary = NULL;\n-\t}\n-\tslurp_attr(line->buf, \"charset=\", &mi->charset);\n-\n-\tif (boundary) {\n-\t\tstrbuf_release(boundary);\n-\t\tfree(boundary);\n-\t}\n-}\n-\n-static void handle_message_id(struct mailinfo *mi, const struct strbuf *line)\n-{\n-\tif (mi->add_message_id)\n-\t\tmi->message_id = strdup(line->buf);\n-}\n-\n-static void handle_content_transfer_encoding(struct mailinfo *mi,\n-\t\t\t\t\t     const struct strbuf *line)\n-{\n-\tif (strcasestr(line->buf, \"base64\"))\n-\t\tmi->transfer_encoding = TE_BASE64;\n-\telse if (strcasestr(line->buf, \"quoted-printable\"))\n-\t\tmi->transfer_encoding = TE_QP;\n-\telse\n-\t\tmi->transfer_encoding = TE_DONTCARE;\n-}\n-\n-static int is_multipart_boundary(struct mailinfo *mi, const struct strbuf *line)\n-{\n-\tstruct strbuf *content_top = *(mi->content_top);\n-\n-\treturn ((content_top->len <= line->len) &&\n-\t\t!memcmp(line->buf, content_top->buf, content_top->len));\n-}\n-\n-static void cleanup_subject(struct mailinfo *mi, struct strbuf *subject)\n-{\n-\tsize_t at = 0;\n-\n-\twhile (at < subject->len) {\n-\t\tchar *pos;\n-\t\tsize_t remove;\n-\n-\t\tswitch (subject->buf[at]) {\n-\t\tcase 'r': case 'R':\n-\t\t\tif (subject->len <= at + 3)\n-\t\t\t\tbreak;\n-\t\t\tif ((subject->buf[at + 1] == 'e' ||\n-\t\t\t     subject->buf[at + 1] == 'E') &&\n-\t\t\t    subject->buf[at + 2] == ':') {\n-\t\t\t\tstrbuf_remove(subject, at, 3);\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\t\t\tat++;\n-\t\t\tbreak;\n-\t\tcase ' ': case '\\t': case ':':\n-\t\t\tstrbuf_remove(subject, at, 1);\n-\t\t\tcontinue;\n-\t\tcase '[':\n-\t\t\tpos = strchr(subject->buf + at, ']');\n-\t\t\tif (!pos)\n-\t\t\t\tbreak;\n-\t\t\tremove = pos - subject->buf + at + 1;\n-\t\t\tif (!mi->keep_non_patch_brackets_in_subject ||\n-\t\t\t    (7 <= remove &&\n-\t\t\t     memmem(subject->buf + at, remove, \"PATCH\", 5)))\n-\t\t\t\tstrbuf_remove(subject, at, remove);\n-\t\t\telse {\n-\t\t\t\tat += remove;\n-\t\t\t\t/*\n-\t\t\t\t * If the input had a space after the ], keep\n-\t\t\t\t * it.  We don't bother with finding the end of\n-\t\t\t\t * the space, since we later normalize it\n-\t\t\t\t * anyway.\n-\t\t\t\t */\n-\t\t\t\tif (isspace(subject->buf[at]))\n-\t\t\t\t\tat += 1;\n-\t\t\t}\n-\t\t\tcontinue;\n-\t\t}\n-\t\tbreak;\n-\t}\n-\tstrbuf_trim(subject);\n-}\n-\n-#define MAX_HDR_PARSED 10\n-static const char *header[MAX_HDR_PARSED] = {\n-\t\"From\",\"Subject\",\"Date\",\n-};\n-\n-static inline int cmp_header(const struct strbuf *line, const char *hdr)\n-{\n-\tint len = strlen(hdr);\n-\treturn !strncasecmp(line->buf, hdr, len) && line->len > len &&\n-\t\t\tline->buf[len] == ':' && isspace(line->buf[len + 1]);\n-}\n-\n-static int is_format_patch_separator(const char *line, int len)\n-{\n-\tstatic const char SAMPLE[] =\n-\t\t\"From e6807f3efca28b30decfecb1732a56c7db1137ee Mon Sep 17 00:00:00 2001\\n\";\n-\tconst char *cp;\n-\n-\tif (len != strlen(SAMPLE))\n-\t\treturn 0;\n-\tif (!skip_prefix(line, \"From \", &cp))\n-\t\treturn 0;\n-\tif (strspn(cp, \"0123456789abcdef\") != 40)\n-\t\treturn 0;\n-\tcp += 40;\n-\treturn !memcmp(SAMPLE + (cp - line), cp, strlen(SAMPLE) - (cp - line));\n-}\n-\n-static struct strbuf *decode_q_segment(const struct strbuf *q_seg, int rfc2047)\n-{\n-\tconst char *in = q_seg->buf;\n-\tint c;\n-\tstruct strbuf *out = xmalloc(sizeof(struct strbuf));\n-\tstrbuf_init(out, q_seg->len);\n-\n-\twhile ((c = *in++) != 0) {\n-\t\tif (c == '=') {\n-\t\t\tint d = *in++;\n-\t\t\tif (d == '\\n' || !d)\n-\t\t\t\tbreak; /* drop trailing newline */\n-\t\t\tstrbuf_addch(out, (hexval(d) << 4) | hexval(*in++));\n-\t\t\tcontinue;\n-\t\t}\n-\t\tif (rfc2047 && c == '_') /* rfc2047 4.2 (2) */\n-\t\t\tc = 0x20;\n-\t\tstrbuf_addch(out, c);\n-\t}\n-\treturn out;\n-}\n-\n-static struct strbuf *decode_b_segment(const struct strbuf *b_seg)\n-{\n-\t/* Decode in..ep, possibly in-place to ot */\n-\tint c, pos = 0, acc = 0;\n-\tconst char *in = b_seg->buf;\n-\tstruct strbuf *out = xmalloc(sizeof(struct strbuf));\n-\tstrbuf_init(out, b_seg->len);\n-\n-\twhile ((c = *in++) != 0) {\n-\t\tif (c == '+')\n-\t\t\tc = 62;\n-\t\telse if (c == '/')\n-\t\t\tc = 63;\n-\t\telse if ('A' <= c && c <= 'Z')\n-\t\t\tc -= 'A';\n-\t\telse if ('a' <= c && c <= 'z')\n-\t\t\tc -= 'a' - 26;\n-\t\telse if ('0' <= c && c <= '9')\n-\t\t\tc -= '0' - 52;\n-\t\telse\n-\t\t\tcontinue; /* garbage */\n-\t\tswitch (pos++) {\n-\t\tcase 0:\n-\t\t\tacc = (c << 2);\n-\t\t\tbreak;\n-\t\tcase 1:\n-\t\t\tstrbuf_addch(out, (acc | (c >> 4)));\n-\t\t\tacc = (c & 15) << 4;\n-\t\t\tbreak;\n-\t\tcase 2:\n-\t\t\tstrbuf_addch(out, (acc | (c >> 2)));\n-\t\t\tacc = (c & 3) << 6;\n-\t\t\tbreak;\n-\t\tcase 3:\n-\t\t\tstrbuf_addch(out, (acc | c));\n-\t\t\tacc = pos = 0;\n-\t\t\tbreak;\n-\t\t}\n-\t}\n-\treturn out;\n-}\n-\n-static void convert_to_utf8(struct mailinfo *mi,\n-\t\t\t    struct strbuf *line, const char *charset)\n-{\n-\tchar *out;\n-\n-\tif (!mi->metainfo_charset || !charset || !*charset)\n-\t\treturn;\n-\n-\tif (same_encoding(mi->metainfo_charset, charset))\n-\t\treturn;\n-\tout = reencode_string(line->buf, mi->metainfo_charset, charset);\n-\tif (!out)\n-\t\tdie(\"cannot convert from %s to %s\",\n-\t\t    charset, mi->metainfo_charset);\n-\tstrbuf_attach(line, out, strlen(out), strlen(out));\n-}\n-\n-static void decode_header(struct mailinfo *mi, struct strbuf *it)\n-{\n-\tchar *in, *ep, *cp;\n-\tstruct strbuf outbuf = STRBUF_INIT, *dec;\n-\tstruct strbuf charset_q = STRBUF_INIT, piecebuf = STRBUF_INIT;\n-\n-\tin = it->buf;\n-\twhile (in - it->buf <= it->len && (ep = strstr(in, \"=?\")) != NULL) {\n-\t\tint encoding;\n-\t\tstrbuf_reset(&charset_q);\n-\t\tstrbuf_reset(&piecebuf);\n-\n-\t\tif (in != ep) {\n-\t\t\t/*\n-\t\t\t * We are about to process an encoded-word\n-\t\t\t * that begins at ep, but there is something\n-\t\t\t * before the encoded word.\n-\t\t\t */\n-\t\t\tchar *scan;\n-\t\t\tfor (scan = in; scan < ep; scan++)\n-\t\t\t\tif (!isspace(*scan))\n-\t\t\t\t\tbreak;\n-\n-\t\t\tif (scan != ep || in == it->buf) {\n-\t\t\t\t/*\n-\t\t\t\t * We should not lose that \"something\",\n-\t\t\t\t * unless we have just processed an\n-\t\t\t\t * encoded-word, and there is only LWS\n-\t\t\t\t * before the one we are about to process.\n-\t\t\t\t */\n-\t\t\t\tstrbuf_add(&outbuf, in, ep - in);\n-\t\t\t}\n-\t\t}\n-\t\t/* E.g.\n-\t\t * ep : \"=?iso-2022-jp?B?GyR...?= foo\"\n-\t\t * ep : \"=?ISO-8859-1?Q?Foo=FCbar?= baz\"\n-\t\t */\n-\t\tep += 2;\n-\n-\t\tif (ep - it->buf >= it->len || !(cp = strchr(ep, '?')))\n-\t\t\tgoto release_return;\n-\n-\t\tif (cp + 3 - it->buf > it->len)\n-\t\t\tgoto release_return;\n-\t\tstrbuf_add(&charset_q, ep, cp - ep);\n-\n-\t\tencoding = cp[1];\n-\t\tif (!encoding || cp[2] != '?')\n-\t\t\tgoto release_return;\n-\t\tep = strstr(cp + 3, \"?=\");\n-\t\tif (!ep)\n-\t\t\tgoto release_return;\n-\t\tstrbuf_add(&piecebuf, cp + 3, ep - cp - 3);\n-\t\tswitch (tolower(encoding)) {\n-\t\tdefault:\n-\t\t\tgoto release_return;\n-\t\tcase 'b':\n-\t\t\tdec = decode_b_segment(&piecebuf);\n-\t\t\tbreak;\n-\t\tcase 'q':\n-\t\t\tdec = decode_q_segment(&piecebuf, 1);\n-\t\t\tbreak;\n-\t\t}\n-\t\tconvert_to_utf8(mi, dec, charset_q.buf);\n-\n-\t\tstrbuf_addbuf(&outbuf, dec);\n-\t\tstrbuf_release(dec);\n-\t\tfree(dec);\n-\t\tin = ep + 2;\n-\t}\n-\tstrbuf_addstr(&outbuf, in);\n-\tstrbuf_reset(it);\n-\tstrbuf_addbuf(it, &outbuf);\n-release_return:\n-\tstrbuf_release(&outbuf);\n-\tstrbuf_release(&charset_q);\n-\tstrbuf_release(&piecebuf);\n-}\n-\n-static int check_header(struct mailinfo *mi,\n-\t\t\tconst struct strbuf *line,\n-\t\t\tstruct strbuf *hdr_data[], int overwrite)\n-{\n-\tint i, ret = 0, len;\n-\tstruct strbuf sb = STRBUF_INIT;\n-\n-\t/* search for the interesting parts */\n-\tfor (i = 0; header[i]; i++) {\n-\t\tint len = strlen(header[i]);\n-\t\tif ((!hdr_data[i] || overwrite) && cmp_header(line, header[i])) {\n-\t\t\t/* Unwrap inline B and Q encoding, and optionally\n-\t\t\t * normalize the meta information to utf8.\n-\t\t\t */\n-\t\t\tstrbuf_add(&sb, line->buf + len + 2, line->len - len - 2);\n-\t\t\tdecode_header(mi, &sb);\n-\t\t\thandle_header(&hdr_data[i], &sb);\n-\t\t\tret = 1;\n-\t\t\tgoto check_header_out;\n-\t\t}\n-\t}\n-\n-\t/* Content stuff */\n-\tif (cmp_header(line, \"Content-Type\")) {\n-\t\tlen = strlen(\"Content-Type: \");\n-\t\tstrbuf_add(&sb, line->buf + len, line->len - len);\n-\t\tdecode_header(mi, &sb);\n-\t\tstrbuf_insert(&sb, 0, \"Content-Type: \", len);\n-\t\thandle_content_type(mi, &sb);\n-\t\tret = 1;\n-\t\tgoto check_header_out;\n-\t}\n-\tif (cmp_header(line, \"Content-Transfer-Encoding\")) {\n-\t\tlen = strlen(\"Content-Transfer-Encoding: \");\n-\t\tstrbuf_add(&sb, line->buf + len, line->len - len);\n-\t\tdecode_header(mi, &sb);\n-\t\thandle_content_transfer_encoding(mi, &sb);\n-\t\tret = 1;\n-\t\tgoto check_header_out;\n-\t}\n-\tif (cmp_header(line, \"Message-Id\")) {\n-\t\tlen = strlen(\"Message-Id: \");\n-\t\tstrbuf_add(&sb, line->buf + len, line->len - len);\n-\t\tdecode_header(mi, &sb);\n-\t\thandle_message_id(mi, &sb);\n-\t\tret = 1;\n-\t\tgoto check_header_out;\n-\t}\n-\n-\t/* for inbody stuff */\n-\tif (starts_with(line->buf, \">From\") && isspace(line->buf[5])) {\n-\t\tret = is_format_patch_separator(line->buf + 1, line->len - 1);\n-\t\tgoto check_header_out;\n-\t}\n-\tif (starts_with(line->buf, \"[PATCH]\") && isspace(line->buf[7])) {\n-\t\tfor (i = 0; header[i]; i++) {\n-\t\t\tif (!strcmp(\"Subject\", header[i])) {\n-\t\t\t\thandle_header(&hdr_data[i], line);\n-\t\t\t\tret = 1;\n-\t\t\t\tgoto check_header_out;\n-\t\t\t}\n-\t\t}\n-\t}\n-\n-check_header_out:\n-\tstrbuf_release(&sb);\n-\treturn ret;\n-}\n-\n-static void decode_transfer_encoding(struct mailinfo *mi, struct strbuf *line)\n-{\n-\tstruct strbuf *ret;\n-\n-\tswitch (mi->transfer_encoding) {\n-\tcase TE_QP:\n-\t\tret = decode_q_segment(line, 0);\n-\t\tbreak;\n-\tcase TE_BASE64:\n-\t\tret = decode_b_segment(line);\n-\t\tbreak;\n-\tcase TE_DONTCARE:\n-\tdefault:\n-\t\treturn;\n-\t}\n-\tstrbuf_reset(line);\n-\tstrbuf_addbuf(line, ret);\n-\tstrbuf_release(ret);\n-\tfree(ret);\n-}\n-\n-static inline int patchbreak(const struct strbuf *line)\n-{\n-\tsize_t i;\n-\n-\t/* Beginning of a \"diff -\" header? */\n-\tif (starts_with(line->buf, \"diff -\"))\n-\t\treturn 1;\n-\n-\t/* CVS \"Index: \" line? */\n-\tif (starts_with(line->buf, \"Index: \"))\n-\t\treturn 1;\n-\n-\t/*\n-\t * \"--- <filename>\" starts patches without headers\n-\t * \"---<sp>*\" is a manual separator\n-\t */\n-\tif (line->len < 4)\n-\t\treturn 0;\n-\n-\tif (starts_with(line->buf, \"---\")) {\n-\t\t/* space followed by a filename? */\n-\t\tif (line->buf[3] == ' ' && !isspace(line->buf[4]))\n-\t\t\treturn 1;\n-\t\t/* Just whitespace? */\n-\t\tfor (i = 3; i < line->len; i++) {\n-\t\t\tunsigned char c = line->buf[i];\n-\t\t\tif (c == '\\n')\n-\t\t\t\treturn 1;\n-\t\t\tif (!isspace(c))\n-\t\t\t\tbreak;\n-\t\t}\n-\t\treturn 0;\n-\t}\n-\treturn 0;\n-}\n-\n-static int is_scissors_line(const struct strbuf *line)\n-{\n-\tsize_t i, len = line->len;\n-\tint scissors = 0, gap = 0;\n-\tint first_nonblank = -1;\n-\tint last_nonblank = 0, visible, perforation = 0, in_perforation = 0;\n-\tconst char *buf = line->buf;\n-\n-\tfor (i = 0; i < len; i++) {\n-\t\tif (isspace(buf[i])) {\n-\t\t\tif (in_perforation) {\n-\t\t\t\tperforation++;\n-\t\t\t\tgap++;\n-\t\t\t}\n-\t\t\tcontinue;\n-\t\t}\n-\t\tlast_nonblank = i;\n-\t\tif (first_nonblank < 0)\n-\t\t\tfirst_nonblank = i;\n-\t\tif (buf[i] == '-') {\n-\t\t\tin_perforation = 1;\n-\t\t\tperforation++;\n-\t\t\tcontinue;\n-\t\t}\n-\t\tif (i + 1 < len &&\n-\t\t    (!memcmp(buf + i, \">8\", 2) || !memcmp(buf + i, \"8<\", 2) ||\n-\t\t     !memcmp(buf + i, \">%\", 2) || !memcmp(buf + i, \"%<\", 2))) {\n-\t\t\tin_perforation = 1;\n-\t\t\tperforation += 2;\n-\t\t\tscissors += 2;\n-\t\t\ti++;\n-\t\t\tcontinue;\n-\t\t}\n-\t\tin_perforation = 0;\n-\t}\n-\n-\t/*\n-\t * The mark must be at least 8 bytes long (e.g. \"-- >8 --\").\n-\t * Even though there can be arbitrary cruft on the same line\n-\t * (e.g. \"cut here\"), in order to avoid misidentification, the\n-\t * perforation must occupy more than a third of the visible\n-\t * width of the line, and dashes and scissors must occupy more\n-\t * than half of the perforation.\n-\t */\n-\n-\tvisible = last_nonblank - first_nonblank + 1;\n-\treturn (scissors && 8 <= visible &&\n-\t\tvisible < perforation * 3 &&\n-\t\tgap * 2 < perforation);\n-}\n-\n-static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n-{\n-\tassert(!mi->filter_stage);\n-\n-\tif (mi->header_stage) {\n-\t\tif (!line->len || (line->len == 1 && line->buf[0] == '\\n'))\n-\t\t\treturn 0;\n-\t}\n-\n-\tif (mi->use_inbody_headers && mi->header_stage) {\n-\t\tmi->header_stage = check_header(mi, line, mi->s_hdr_data, 0);\n-\t\tif (mi->header_stage)\n-\t\t\treturn 0;\n-\t} else\n-\t\t/* Only trim the first (blank) line of the commit message\n-\t\t * when ignoring in-body headers.\n-\t\t */\n-\t\tmi->header_stage = 0;\n-\n-\t/* normalize the log message to UTF-8. */\n-\tconvert_to_utf8(mi, line, mi->charset.buf);\n-\n-\tif (mi->use_scissors && is_scissors_line(line)) {\n-\t\tint i;\n-\n-\t\tstrbuf_setlen(&mi->log_message, 0);\n-\t\tmi->header_stage = 1;\n-\n-\t\t/*\n-\t\t * We may have already read \"secondary headers\"; purge\n-\t\t * them to give ourselves a clean restart.\n-\t\t */\n-\t\tfor (i = 0; header[i]; i++) {\n-\t\t\tif (mi->s_hdr_data[i])\n-\t\t\t\tstrbuf_release(mi->s_hdr_data[i]);\n-\t\t\tmi->s_hdr_data[i] = NULL;\n-\t\t}\n-\t\treturn 0;\n-\t}\n-\n-\tif (patchbreak(line)) {\n-\t\tif (mi->message_id)\n-\t\t\tstrbuf_addf(&mi->log_message,\n-\t\t\t\t    \"Message-Id: %s\\n\", mi->message_id);\n-\t\treturn 1;\n-\t}\n-\n-\tstrbuf_addbuf(&mi->log_message, line);\n-\treturn 0;\n-}\n-\n-static void handle_patch(struct mailinfo *mi, const struct strbuf *line)\n-{\n-\tfwrite(line->buf, 1, line->len, mi->patchfile);\n-\tmi->patch_lines++;\n-}\n-\n-static void handle_filter(struct mailinfo *mi, struct strbuf *line)\n-{\n-\tswitch (mi->filter_stage) {\n-\tcase 0:\n-\t\tif (!handle_commit_msg(mi, line))\n-\t\t\tbreak;\n-\t\tmi->filter_stage++;\n-\tcase 1:\n-\t\thandle_patch(mi, line);\n-\t\tbreak;\n-\t}\n-}\n-\n-static int is_rfc2822_header(const struct strbuf *line)\n-{\n-\t/*\n-\t * The section that defines the loosest possible\n-\t * field name is \"3.6.8 Optional fields\".\n-\t *\n-\t * optional-field = field-name \":\" unstructured CRLF\n-\t * field-name = 1*ftext\n-\t * ftext = %d33-57 / %59-126\n-\t */\n-\tint ch;\n-\tchar *cp = line->buf;\n-\n-\t/* Count mbox From headers as headers */\n-\tif (starts_with(cp, \"From \") || starts_with(cp, \">From \"))\n-\t\treturn 1;\n-\n-\twhile ((ch = *cp++)) {\n-\t\tif (ch == ':')\n-\t\t\treturn 1;\n-\t\tif ((33 <= ch && ch <= 57) ||\n-\t\t    (59 <= ch && ch <= 126))\n-\t\t\tcontinue;\n-\t\tbreak;\n-\t}\n-\treturn 0;\n-}\n-\n-static int read_one_header_line(struct strbuf *line, FILE *in)\n-{\n-\t/* Get the first part of the line. */\n-\tif (strbuf_getline(line, in, '\\n'))\n-\t\treturn 0;\n-\n-\t/*\n-\t * Is it an empty line or not a valid rfc2822 header?\n-\t * If so, stop here, and return false (\"not a header\")\n-\t */\n-\tstrbuf_rtrim(line);\n-\tif (!line->len || !is_rfc2822_header(line)) {\n-\t\t/* Re-add the newline */\n-\t\tstrbuf_addch(line, '\\n');\n-\t\treturn 0;\n-\t}\n-\n-\t/*\n-\t * Now we need to eat all the continuation lines..\n-\t * Yuck, 2822 header \"folding\"\n-\t */\n-\tfor (;;) {\n-\t\tint peek;\n-\t\tstruct strbuf continuation = STRBUF_INIT;\n-\n-\t\tpeek = fgetc(in); ungetc(peek, in);\n-\t\tif (peek != ' ' && peek != '\\t')\n-\t\t\tbreak;\n-\t\tif (strbuf_getline(&continuation, in, '\\n'))\n-\t\t\tbreak;\n-\t\tcontinuation.buf[0] = ' ';\n-\t\tstrbuf_rtrim(&continuation);\n-\t\tstrbuf_addbuf(line, &continuation);\n-\t}\n-\n-\treturn 1;\n-}\n-\n-static int find_boundary(struct mailinfo *mi, struct strbuf *line)\n-{\n-\twhile (!strbuf_getline(line, mi->input, '\\n')) {\n-\t\tif (*(mi->content_top) && is_multipart_boundary(mi, line))\n-\t\t\treturn 1;\n-\t}\n-\treturn 0;\n-}\n-\n-static int handle_boundary(struct mailinfo *mi, struct strbuf *line)\n-{\n-\tstruct strbuf newline = STRBUF_INIT;\n-\n-\tstrbuf_addch(&newline, '\\n');\n-again:\n-\tif (line->len >= (*(mi->content_top))->len + 2 &&\n-\t    !memcmp(line->buf + (*(mi->content_top))->len, \"--\", 2)) {\n-\t\t/* we hit an end boundary */\n-\t\t/* pop the current boundary off the stack */\n-\t\tstrbuf_release(*(mi->content_top));\n-\t\tfree(*(mi->content_top));\n-\t\t*(mi->content_top) = NULL;\n-\n-\t\t/* technically won't happen as is_multipart_boundary()\n-\t\t   will fail first.  But just in case..\n-\t\t */\n-\t\tif (--mi->content_top < mi->content) {\n-\t\t\tfprintf(stderr, \"Detected mismatched boundaries, \"\n-\t\t\t\t\t\"can't recover\\n\");\n-\t\t\texit(1);\n-\t\t}\n-\t\thandle_filter(mi, &newline);\n-\t\tstrbuf_release(&newline);\n-\n-\t\t/* skip to the next boundary */\n-\t\tif (!find_boundary(mi, line))\n-\t\t\treturn 0;\n-\t\tgoto again;\n-\t}\n-\n-\t/* set some defaults */\n-\tmi->transfer_encoding = TE_DONTCARE;\n-\tstrbuf_reset(&mi->charset);\n-\n-\t/* slurp in this section's info */\n-\twhile (read_one_header_line(line, mi->input))\n-\t\tcheck_header(mi, line, mi->p_hdr_data, 0);\n-\n-\tstrbuf_release(&newline);\n-\t/* replenish line */\n-\tif (strbuf_getline(line, mi->input, '\\n'))\n-\t\treturn 0;\n-\tstrbuf_addch(line, '\\n');\n-\treturn 1;\n-}\n-\n-static void handle_body(struct mailinfo *mi, struct strbuf *line)\n-{\n-\tstruct strbuf prev = STRBUF_INIT;\n-\n-\t/* Skip up to the first boundary */\n-\tif (*(mi->content_top)) {\n-\t\tif (!find_boundary(mi, line))\n-\t\t\tgoto handle_body_out;\n-\t}\n-\n-\tdo {\n-\t\t/* process any boundary lines */\n-\t\tif (*(mi->content_top) && is_multipart_boundary(mi, line)) {\n-\t\t\t/* flush any leftover */\n-\t\t\tif (prev.len) {\n-\t\t\t\thandle_filter(mi, &prev);\n-\t\t\t\tstrbuf_reset(&prev);\n-\t\t\t}\n-\t\t\tif (!handle_boundary(mi, line))\n-\t\t\t\tgoto handle_body_out;\n-\t\t}\n-\n-\t\t/* Unwrap transfer encoding */\n-\t\tdecode_transfer_encoding(mi, line);\n-\n-\t\tswitch (mi->transfer_encoding) {\n-\t\tcase TE_BASE64:\n-\t\tcase TE_QP:\n-\t\t{\n-\t\t\tstruct strbuf **lines, **it, *sb;\n-\n-\t\t\t/* Prepend any previous partial lines */\n-\t\t\tstrbuf_insert(line, 0, prev.buf, prev.len);\n-\t\t\tstrbuf_reset(&prev);\n-\n-\t\t\t/*\n-\t\t\t * This is a decoded line that may contain\n-\t\t\t * multiple new lines.  Pass only one chunk\n-\t\t\t * at a time to handle_filter()\n-\t\t\t */\n-\t\t\tlines = strbuf_split(line, '\\n');\n-\t\t\tfor (it = lines; (sb = *it); it++) {\n-\t\t\t\tif (*(it + 1) == NULL) /* The last line */\n-\t\t\t\t\tif (sb->buf[sb->len - 1] != '\\n') {\n-\t\t\t\t\t\t/* Partial line, save it for later. */\n-\t\t\t\t\t\tstrbuf_addbuf(&prev, sb);\n-\t\t\t\t\t\tbreak;\n-\t\t\t\t\t}\n-\t\t\t\thandle_filter(mi, sb);\n-\t\t\t}\n-\t\t\t/*\n-\t\t\t * The partial chunk is saved in \"prev\" and will be\n-\t\t\t * appended by the next iteration of read_line_with_nul().\n-\t\t\t */\n-\t\t\tstrbuf_list_free(lines);\n-\t\t\tbreak;\n-\t\t}\n-\t\tdefault:\n-\t\t\thandle_filter(mi, line);\n-\t\t}\n-\n-\t} while (!strbuf_getwholeline(line, mi->input, '\\n'));\n-\n-handle_body_out:\n-\tstrbuf_release(&prev);\n-}\n-\n-static void output_header_lines(FILE *fout, const char *hdr, const struct strbuf *data)\n-{\n-\tconst char *sp = data->buf;\n-\twhile (1) {\n-\t\tchar *ep = strchr(sp, '\\n');\n-\t\tint len;\n-\t\tif (!ep)\n-\t\t\tlen = strlen(sp);\n-\t\telse\n-\t\t\tlen = ep - sp;\n-\t\tfprintf(fout, \"%s: %.*s\\n\", hdr, len, sp);\n-\t\tif (!ep)\n-\t\t\tbreak;\n-\t\tsp = ep + 1;\n-\t}\n-}\n-\n-static void handle_info(struct mailinfo *mi)\n-{\n-\tstruct strbuf *hdr;\n-\tint i;\n-\n-\tfor (i = 0; header[i]; i++) {\n-\t\t/* only print inbody headers if we output a patch file */\n-\t\tif (mi->patch_lines && mi->s_hdr_data[i])\n-\t\t\thdr = mi->s_hdr_data[i];\n-\t\telse if (mi->p_hdr_data[i])\n-\t\t\thdr = mi->p_hdr_data[i];\n-\t\telse\n-\t\t\tcontinue;\n-\n-\t\tif (!strcmp(header[i], \"Subject\")) {\n-\t\t\tif (!mi->keep_subject) {\n-\t\t\t\tcleanup_subject(mi, hdr);\n-\t\t\t\tcleanup_space(hdr);\n-\t\t\t}\n-\t\t\toutput_header_lines(mi->output, \"Subject\", hdr);\n-\t\t} else if (!strcmp(header[i], \"From\")) {\n-\t\t\tcleanup_space(hdr);\n-\t\t\thandle_from(mi, hdr);\n-\t\t\tfprintf(mi->output, \"Author: %s\\n\", mi->name.buf);\n-\t\t\tfprintf(mi->output, \"Email: %s\\n\", mi->email.buf);\n-\t\t} else {\n-\t\t\tcleanup_space(hdr);\n-\t\t\tfprintf(mi->output, \"%s: %s\\n\", header[i], hdr->buf);\n-\t\t}\n-\t}\n-\tfprintf(mi->output, \"\\n\");\n-}\n-\n-static int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)\n-{\n-\tFILE *cmitmsg;\n-\tint peek;\n-\tstruct strbuf line = STRBUF_INIT;\n-\n-\tcmitmsg = fopen(msg, \"w\");\n-\tif (!cmitmsg) {\n-\t\tperror(msg);\n-\t\treturn -1;\n-\t}\n-\tmi->patchfile = fopen(patch, \"w\");\n-\tif (!mi->patchfile) {\n-\t\tperror(patch);\n-\t\tfclose(cmitmsg);\n-\t\treturn -1;\n-\t}\n-\n-\tmi->p_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*(mi->p_hdr_data)));\n-\tmi->s_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*(mi->s_hdr_data)));\n-\n-\tdo {\n-\t\tpeek = fgetc(mi->input);\n-\t} while (isspace(peek));\n-\tungetc(peek, mi->input);\n-\n-\t/* process the email header */\n-\twhile (read_one_header_line(&line, mi->input))\n-\t\tcheck_header(mi, &line, mi->p_hdr_data, 1);\n-\n-\thandle_body(mi, &line);\n-\tfwrite(mi->log_message.buf, 1, mi->log_message.len, cmitmsg);\n-\tfclose(cmitmsg);\n-\tfclose(mi->patchfile);\n-\n-\thandle_info(mi);\n-\n-\treturn 0;\n-}\n-\n-static int git_mailinfo_config(const char *var, const char *value, void *mi_)\n-{\n-\tstruct mailinfo *mi = mi_;\n-\n-\tif (!starts_with(var, \"mailinfo.\"))\n-\t\treturn git_default_config(var, value, NULL);\n-\tif (!strcmp(var, \"mailinfo.scissors\")) {\n-\t\tmi->use_scissors = git_config_bool(var, value);\n-\t\treturn 0;\n-\t}\n-\t/* perhaps others here */\n-\treturn 0;\n-}\n-\n-static void setup_mailinfo(struct mailinfo *mi)\n-{\n-\tmemset(mi, 0, sizeof(*mi));\n-\tstrbuf_init(&mi->name, 0);\n-\tstrbuf_init(&mi->email, 0);\n-\tstrbuf_init(&mi->charset, 0);\n-\tstrbuf_init(&mi->log_message, 0);\n-\tmi->header_stage = 1;\n-\tmi->use_inbody_headers = 1;\n-\tmi->content_top = mi->content;\n-\tgit_config(git_mailinfo_config, &mi);\n-}\n-\n-static void clear_mailinfo(struct mailinfo *mi)\n-{\n-\tint i;\n-\n-\tstrbuf_release(&mi->name);\n-\tstrbuf_release(&mi->email);\n-\tstrbuf_release(&mi->charset);\n-\tfree(mi->message_id);\n-\n-\tfor (i = 0; mi->p_hdr_data[i]; i++)\n-\t\tstrbuf_release(mi->p_hdr_data[i]);\n-\tfree(mi->p_hdr_data);\n-\tfor (i = 0; mi->s_hdr_data[i]; i++)\n-\t\tstrbuf_release(mi->s_hdr_data[i]);\n-\tfree(mi->s_hdr_data);\n-\n-\twhile (mi->content < mi->content_top) {\n-\t\tfree(*(mi->content_top));\n-\t\tmi->content_top--;\n-\t}\n-\n-\tstrbuf_release(&mi->log_message);\n-}\n-\n-static const char mailinfo_usage[] =\n-\t\"git mailinfo [-k | -b] [-m | --message-id] [-u | --encoding=<encoding> | -n] [--scissors | --no-scissors] <msg> <patch> < mail >info\";\n-\n-int cmd_mailinfo(int argc, const char **argv, const char *prefix)\n-{\n-\tconst char *def_charset;\n-\tstruct mailinfo mi;\n-\tint status;\n-\n-\t/* NEEDSWORK: might want to do the optional .git/ directory\n-\t * discovery\n-\t */\n-\tsetup_mailinfo(&mi);\n-\n-\tdef_charset = get_commit_output_encoding();\n-\tmi.metainfo_charset = def_charset;\n-\n-\twhile (1 < argc && argv[1][0] == '-') {\n-\t\tif (!strcmp(argv[1], \"-k\"))\n-\t\t\tmi.keep_subject = 1;\n-\t\telse if (!strcmp(argv[1], \"-b\"))\n-\t\t\tmi.keep_non_patch_brackets_in_subject = 1;\n-\t\telse if (!strcmp(argv[1], \"-m\") || !strcmp(argv[1], \"--message-id\"))\n-\t\t\tmi.add_message_id = 1;\n-\t\telse if (!strcmp(argv[1], \"-u\"))\n-\t\t\tmi.metainfo_charset = def_charset;\n-\t\telse if (!strcmp(argv[1], \"-n\"))\n-\t\t\tmi.metainfo_charset = NULL;\n-\t\telse if (starts_with(argv[1], \"--encoding=\"))\n-\t\t\tmi.metainfo_charset = argv[1] + 11;\n-\t\telse if (!strcmp(argv[1], \"--scissors\"))\n-\t\t\tmi.use_scissors = 1;\n-\t\telse if (!strcmp(argv[1], \"--no-scissors\"))\n-\t\t\tmi.use_scissors = 0;\n-\t\telse if (!strcmp(argv[1], \"--no-inbody-headers\"))\n-\t\t\tmi.use_inbody_headers = 0;\n-\t\telse\n-\t\t\tusage(mailinfo_usage);\n-\t\targc--; argv++;\n-\t}\n-\n-\tif (argc != 3)\n-\t\tusage(mailinfo_usage);\n-\n-\tmi.input = stdin;\n-\tmi.output = stdout;\n-\tstatus = !!mailinfo(&mi, argv[1], argv[2]);\n-\tclear_mailinfo(&mi);\n-\n-\treturn status;\n-}\n+/*\n+ * Another stupid program, this one parsing the headers of an\n+ * email to figure out authorship and subject\n+ */\n+#include \"cache.h\"\n+#include \"builtin.h\"\n+#include \"utf8.h\"\n+#include \"strbuf.h\"\n+#include \"mailinfo.h\"\n+\n+static const char mailinfo_usage[] =\n+\t\"git mailinfo [-k | -b] [-m | --message-id] [-u | --encoding=<encoding> | -n] [--scissors | --no-scissors] <msg> <patch> < mail >info\";\n+\n+int cmd_mailinfo(int argc, const char **argv, const char *prefix)\n+{\n+\tconst char *def_charset;\n+\tstruct mailinfo mi;\n+\tint status;\n+\n+\t/* NEEDSWORK: might want to do the optional .git/ directory\n+\t * discovery\n+\t */\n+\tsetup_mailinfo(&mi);\n+\n+\tdef_charset = get_commit_output_encoding();\n+\tmi.metainfo_charset = def_charset;\n+\n+\twhile (1 < argc && argv[1][0] == '-') {\n+\t\tif (!strcmp(argv[1], \"-k\"))\n+\t\t\tmi.keep_subject = 1;\n+\t\telse if (!strcmp(argv[1], \"-b\"))\n+\t\t\tmi.keep_non_patch_brackets_in_subject = 1;\n+\t\telse if (!strcmp(argv[1], \"-m\") || !strcmp(argv[1], \"--message-id\"))\n+\t\t\tmi.add_message_id = 1;\n+\t\telse if (!strcmp(argv[1], \"-u\"))\n+\t\t\tmi.metainfo_charset = def_charset;\n+\t\telse if (!strcmp(argv[1], \"-n\"))\n+\t\t\tmi.metainfo_charset = NULL;\n+\t\telse if (starts_with(argv[1], \"--encoding=\"))\n+\t\t\tmi.metainfo_charset = argv[1] + 11;\n+\t\telse if (!strcmp(argv[1], \"--scissors\"))\n+\t\t\tmi.use_scissors = 1;\n+\t\telse if (!strcmp(argv[1], \"--no-scissors\"))\n+\t\t\tmi.use_scissors = 0;\n+\t\telse if (!strcmp(argv[1], \"--no-inbody-headers\"))\n+\t\t\tmi.use_inbody_headers = 0;\n+\t\telse\n+\t\t\tusage(mailinfo_usage);\n+\t\targc--; argv++;\n+\t}\n+\n+\tif (argc != 3)\n+\t\tusage(mailinfo_usage);\n+\n+\tmi.input = stdin;\n+\tmi.output = stdout;\n+\tstatus = !!mailinfo(&mi, argv[1], argv[2]);\n+\tclear_mailinfo(&mi);\n+\n+\treturn status;\n+}\ndiff --git a/builtin/mailinfo.c b/mailinfo.c\nsimilarity index 90%\ncopy from builtin/mailinfo.c\ncopy to mailinfo.c\nindex 4eabc11..df6cfef 100644\n--- a/builtin/mailinfo.c\n+++ b/mailinfo.c\n@@ -1,43 +1,7 @@\n-/*\n- * Another stupid program, this one parsing the headers of an\n- * email to figure out authorship and subject\n- */\n #include \"cache.h\"\n-#include \"builtin.h\"\n #include \"utf8.h\"\n #include \"strbuf.h\"\n-\n-#define MAX_BOUNDARIES 5\n-\n-struct mailinfo {\n-\tFILE *input;\n-\tFILE *output;\n-\tFILE *patchfile;\n-\n-\tstruct strbuf name;\n-\tstruct strbuf email;\n-\tint keep_subject;\n-\tint keep_non_patch_brackets_in_subject;\n-\tint add_message_id;\n-\tint use_scissors;\n-\tint use_inbody_headers; /* defaults to 1 */\n-\tconst char *metainfo_charset;\n-\n-\tstruct strbuf *content[MAX_BOUNDARIES];\n-\tstruct strbuf **content_top;\n-\tstruct strbuf charset;\n-\tchar *message_id;\n-\tenum  {\n-\t\tTE_DONTCARE, TE_QP, TE_BASE64\n-\t} transfer_encoding;\n-\tint patch_lines;\n-\tint filter_stage; /* still reading log or are we copying patch? */\n-\tint header_stage; /* still checking in-body headers? */\n-\tstruct strbuf **p_hdr_data;\n-\tstruct strbuf **s_hdr_data;\n-\n-\tstruct strbuf log_message;\n-};\n+#include \"mailinfo.h\"\n \n static void cleanup_space(struct strbuf *sb)\n {\n@@ -962,7 +926,7 @@ static void handle_info(struct mailinfo *mi)\n \tfprintf(mi->output, \"\\n\");\n }\n \n-static int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)\n+int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)\n {\n \tFILE *cmitmsg;\n \tint peek;\n@@ -1016,7 +980,7 @@ static int git_mailinfo_config(const char *var, const char *value, void *mi_)\n \treturn 0;\n }\n \n-static void setup_mailinfo(struct mailinfo *mi)\n+void setup_mailinfo(struct mailinfo *mi)\n {\n \tmemset(mi, 0, sizeof(*mi));\n \tstrbuf_init(&mi->name, 0);\n@@ -1029,7 +993,7 @@ static void setup_mailinfo(struct mailinfo *mi)\n \tgit_config(git_mailinfo_config, &mi);\n }\n \n-static void clear_mailinfo(struct mailinfo *mi)\n+void clear_mailinfo(struct mailinfo *mi)\n {\n \tint i;\n \n@@ -1052,55 +1016,3 @@ static void clear_mailinfo(struct mailinfo *mi)\n \n \tstrbuf_release(&mi->log_message);\n }\n-\n-static const char mailinfo_usage[] =\n-\t\"git mailinfo [-k | -b] [-m | --message-id] [-u | --encoding=<encoding> | -n] [--scissors | --no-scissors] <msg> <patch> < mail >info\";\n-\n-int cmd_mailinfo(int argc, const char **argv, const char *prefix)\n-{\n-\tconst char *def_charset;\n-\tstruct mailinfo mi;\n-\tint status;\n-\n-\t/* NEEDSWORK: might want to do the optional .git/ directory\n-\t * discovery\n-\t */\n-\tsetup_mailinfo(&mi);\n-\n-\tdef_charset = get_commit_output_encoding();\n-\tmi.metainfo_charset = def_charset;\n-\n-\twhile (1 < argc && argv[1][0] == '-') {\n-\t\tif (!strcmp(argv[1], \"-k\"))\n-\t\t\tmi.keep_subject = 1;\n-\t\telse if (!strcmp(argv[1], \"-b\"))\n-\t\t\tmi.keep_non_patch_brackets_in_subject = 1;\n-\t\telse if (!strcmp(argv[1], \"-m\") || !strcmp(argv[1], \"--message-id\"))\n-\t\t\tmi.add_message_id = 1;\n-\t\telse if (!strcmp(argv[1], \"-u\"))\n-\t\t\tmi.metainfo_charset = def_charset;\n-\t\telse if (!strcmp(argv[1], \"-n\"))\n-\t\t\tmi.metainfo_charset = NULL;\n-\t\telse if (starts_with(argv[1], \"--encoding=\"))\n-\t\t\tmi.metainfo_charset = argv[1] + 11;\n-\t\telse if (!strcmp(argv[1], \"--scissors\"))\n-\t\t\tmi.use_scissors = 1;\n-\t\telse if (!strcmp(argv[1], \"--no-scissors\"))\n-\t\t\tmi.use_scissors = 0;\n-\t\telse if (!strcmp(argv[1], \"--no-inbody-headers\"))\n-\t\t\tmi.use_inbody_headers = 0;\n-\t\telse\n-\t\t\tusage(mailinfo_usage);\n-\t\targc--; argv++;\n-\t}\n-\n-\tif (argc != 3)\n-\t\tusage(mailinfo_usage);\n-\n-\tmi.input = stdin;\n-\tmi.output = stdout;\n-\tstatus = !!mailinfo(&mi, argv[1], argv[2]);\n-\tclear_mailinfo(&mi);\n-\n-\treturn status;\n-}\ndiff --git a/mailinfo.h b/mailinfo.h\nnew file mode 100644\nindex 0000000..27841be\n--- /dev/null\n+++ b/mailinfo.h\n@@ -0,0 +1,40 @@\n+#ifndef MAILINFO_H\n+#define MAILINFO_H\n+\n+#define MAX_BOUNDARIES 5\n+\n+struct mailinfo {\n+\tFILE *input;\n+\tFILE *output;\n+\tFILE *patchfile;\n+\n+\tstruct strbuf name;\n+\tstruct strbuf email;\n+\tint keep_subject;\n+\tint keep_non_patch_brackets_in_subject;\n+\tint add_message_id;\n+\tint use_scissors;\n+\tint use_inbody_headers; /* defaults to 1 */\n+\tconst char *metainfo_charset;\n+\n+\tstruct strbuf *content[MAX_BOUNDARIES];\n+\tstruct strbuf **content_top;\n+\tstruct strbuf charset;\n+\tchar *message_id;\n+\tenum  {\n+\t\tTE_DONTCARE, TE_QP, TE_BASE64\n+\t} transfer_encoding;\n+\tint patch_lines;\n+\tint filter_stage; /* still reading log or are we copying patch? */\n+\tint header_stage; /* still checking in-body headers? */\n+\tstruct strbuf **p_hdr_data;\n+\tstruct strbuf **s_hdr_data;\n+\n+\tstruct strbuf log_message;\n+};\n+\n+extern void setup_mailinfo(struct mailinfo *);\n+extern int mailinfo(struct mailinfo *, const char *msg, const char *patch);\n+extern void clear_mailinfo(struct mailinfo *);\n+\n+#endif /* MAILINFO_H */\n-- \n2.6.2-383-g144b2e6\n"},{"id":"271906","messageId":"1445239731-10677-33-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1445239731-10677-1-git-send-email-gitster@pobox.com","subject":"[PATCH v3 32/34] mailinfo: handle charset conversion errors in the caller","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-19T07:28:49Z","receivedAt":"2015-10-19T07:28:49Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Instead of dying in convert_to_utf8(), just report an error and let\nthe callers handle it.  Between the two callers:\n\n - decode_header() silently punts when it cannot parse a broken\n   RFC2047 encoded text (e.g. when it sees anything other than B or\n   Q after it sees \"=?<charset>\") by jumping to release_return,\n   returning the string it successfully parsed out so far, to the\n   caller.  A piece of string that convert_to_utf8() cannot handle\n   can be treated the same way.\n\n - handle_commit_msg() doesn't cope with a malformed line well, so\n   die there for now.  We'll lift this even higher in later changes\n   in this series.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n mailinfo.c | 19 +++++++++++--------\n 1 file changed, 11 insertions(+), 8 deletions(-)\n\ndiff --git a/mailinfo.c b/mailinfo.c\nindex df6cfef..4fbf38f 100644\n--- a/mailinfo.c\n+++ b/mailinfo.c\n@@ -344,21 +344,22 @@ static struct strbuf *decode_b_segment(const struct strbuf *b_seg)\n \treturn out;\n }\n \n-static void convert_to_utf8(struct mailinfo *mi,\n-\t\t\t    struct strbuf *line, const char *charset)\n+static int convert_to_utf8(struct mailinfo *mi,\n+\t\t\t   struct strbuf *line, const char *charset)\n {\n \tchar *out;\n \n \tif (!mi->metainfo_charset || !charset || !*charset)\n-\t\treturn;\n+\t\treturn 0;\n \n \tif (same_encoding(mi->metainfo_charset, charset))\n-\t\treturn;\n+\t\treturn 0;\n \tout = reencode_string(line->buf, mi->metainfo_charset, charset);\n \tif (!out)\n-\t\tdie(\"cannot convert from %s to %s\",\n-\t\t    charset, mi->metainfo_charset);\n+\t\treturn error(\"cannot convert from %s to %s\",\n+\t\t\t     charset, mi->metainfo_charset);\n \tstrbuf_attach(line, out, strlen(out), strlen(out));\n+\treturn 0;\n }\n \n static void decode_header(struct mailinfo *mi, struct strbuf *it)\n@@ -424,7 +425,8 @@ static void decode_header(struct mailinfo *mi, struct strbuf *it)\n \t\t\tdec = decode_q_segment(&piecebuf, 1);\n \t\t\tbreak;\n \t\t}\n-\t\tconvert_to_utf8(mi, dec, charset_q.buf);\n+\t\tif (convert_to_utf8(mi, dec, charset_q.buf))\n+\t\t\tgoto release_return;\n \n \t\tstrbuf_addbuf(&outbuf, dec);\n \t\tstrbuf_release(dec);\n@@ -637,7 +639,8 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n \t\tmi->header_stage = 0;\n \n \t/* normalize the log message to UTF-8. */\n-\tconvert_to_utf8(mi, line, mi->charset.buf);\n+\tif (convert_to_utf8(mi, line, mi->charset.buf))\n+\t\texit(128);\n \n \tif (mi->use_scissors && is_scissors_line(line)) {\n \t\tint i;\n-- \n2.6.2-383-g144b2e6\n"},{"id":"271912","messageId":"1445239731-10677-34-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1445239731-10677-1-git-send-email-gitster@pobox.com","subject":"[PATCH v3 33/34] mailinfo: remove calls to exit() and die() deep in the callchain","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-19T07:28:50Z","receivedAt":"2015-10-19T07:28:50Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The top-level mailinfo() would instead punt when the code in the\ndeeper part of the callchain detects an unrecoverable error in the\ninput.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n mailinfo.c | 30 ++++++++++++++++++++++--------\n mailinfo.h |  1 +\n 2 files changed, 23 insertions(+), 8 deletions(-)\n\ndiff --git a/mailinfo.c b/mailinfo.c\nindex 4fbf38f..9d009fa 100644\n--- a/mailinfo.c\n+++ b/mailinfo.c\n@@ -163,8 +163,10 @@ static void handle_content_type(struct mailinfo *mi, struct strbuf *line)\n \tif (slurp_attr(line->buf, \"boundary=\", boundary)) {\n \t\tstrbuf_insert(boundary, 0, \"--\", 2);\n \t\tif (++mi->content_top >= &mi->content[MAX_BOUNDARIES]) {\n-\t\t\tfprintf(stderr, \"Too many boundaries to handle\\n\");\n-\t\t\texit(1);\n+\t\t\terror(\"Too many boundaries to handle\");\n+\t\t\tmi->input_error = -1;\n+\t\t\tmi->content_top = &mi->content[MAX_BOUNDARIES] - 1;\n+\t\t\treturn;\n \t\t}\n \t\t*(mi->content_top) = boundary;\n \t\tboundary = NULL;\n@@ -355,9 +357,11 @@ static int convert_to_utf8(struct mailinfo *mi,\n \tif (same_encoding(mi->metainfo_charset, charset))\n \t\treturn 0;\n \tout = reencode_string(line->buf, mi->metainfo_charset, charset);\n-\tif (!out)\n+\tif (!out) {\n+\t\tmi->input_error = -1;\n \t\treturn error(\"cannot convert from %s to %s\",\n \t\t\t     charset, mi->metainfo_charset);\n+\t}\n \tstrbuf_attach(line, out, strlen(out), strlen(out));\n \treturn 0;\n }\n@@ -367,6 +371,7 @@ static void decode_header(struct mailinfo *mi, struct strbuf *it)\n \tchar *in, *ep, *cp;\n \tstruct strbuf outbuf = STRBUF_INIT, *dec;\n \tstruct strbuf charset_q = STRBUF_INIT, piecebuf = STRBUF_INIT;\n+\tint found_error = 1; /* pessimism */\n \n \tin = it->buf;\n \twhile (in - it->buf <= it->len && (ep = strstr(in, \"=?\")) != NULL) {\n@@ -436,10 +441,14 @@ static void decode_header(struct mailinfo *mi, struct strbuf *it)\n \tstrbuf_addstr(&outbuf, in);\n \tstrbuf_reset(it);\n \tstrbuf_addbuf(it, &outbuf);\n+\tfound_error = 0;\n release_return:\n \tstrbuf_release(&outbuf);\n \tstrbuf_release(&charset_q);\n \tstrbuf_release(&piecebuf);\n+\n+\tif (found_error)\n+\t\tmi->input_error = -1;\n }\n \n static int check_header(struct mailinfo *mi,\n@@ -640,7 +649,7 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n \n \t/* normalize the log message to UTF-8. */\n \tif (convert_to_utf8(mi, line, mi->charset.buf))\n-\t\texit(128);\n+\t\treturn 0; /* mi->input_error already set */\n \n \tif (mi->use_scissors && is_scissors_line(line)) {\n \t\tint i;\n@@ -783,12 +792,15 @@ again:\n \t\t   will fail first.  But just in case..\n \t\t */\n \t\tif (--mi->content_top < mi->content) {\n-\t\t\tfprintf(stderr, \"Detected mismatched boundaries, \"\n-\t\t\t\t\t\"can't recover\\n\");\n-\t\t\texit(1);\n+\t\t\terror(\"Detected mismatched boundaries, can't recover\");\n+\t\t\tmi->input_error = -1;\n+\t\t\tmi->content_top = mi->content;\n+\t\t\treturn 0;\n \t\t}\n \t\thandle_filter(mi, &newline);\n \t\tstrbuf_release(&newline);\n+\t\tif (mi->input_error)\n+\t\t\treturn 0;\n \n \t\t/* skip to the next boundary */\n \t\tif (!find_boundary(mi, line))\n@@ -873,6 +885,8 @@ static void handle_body(struct mailinfo *mi, struct strbuf *line)\n \t\t\thandle_filter(mi, line);\n \t\t}\n \n+\t\tif (mi->input_error)\n+\t\t\tbreak;\n \t} while (!strbuf_getwholeline(line, mi->input, '\\n'));\n \n handle_body_out:\n@@ -966,7 +980,7 @@ int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)\n \n \thandle_info(mi);\n \n-\treturn 0;\n+\treturn mi->input_error;\n }\n \n static int git_mailinfo_config(const char *var, const char *value, void *mi_)\ndiff --git a/mailinfo.h b/mailinfo.h\nindex 27841be..5bf257d 100644\n--- a/mailinfo.h\n+++ b/mailinfo.h\n@@ -31,6 +31,7 @@ struct mailinfo {\n \tstruct strbuf **s_hdr_data;\n \n \tstruct strbuf log_message;\n+\tint input_error;\n };\n \n extern void setup_mailinfo(struct mailinfo *);\n-- \n2.6.2-383-g144b2e6\n"},{"id":"271911","messageId":"1445239731-10677-35-git-send-email-gitster@pobox.com","threadId":"40552","inReplyTo":"1445239731-10677-1-git-send-email-gitster@pobox.com","subject":"[PATCH v3 34/34] am: make direct call to mailinfo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-19T07:28:51Z","receivedAt":"2015-10-19T07:28:51Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"And finally the endgame.  Instead of spawning \"git mailinfo\" via the\nrun_command() API the same number of times as there are incoming\npatches, make direct internal call to the libified mailinfo() from\n\"git am\" to reduce the spawning overhead, which would matter on some\nplatforms.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/am.c | 42 +++++++++++++++++++++++-------------------\n 1 file changed, 23 insertions(+), 19 deletions(-)\n\ndiff --git a/builtin/am.c b/builtin/am.c\nindex 4f77e07..1873307 100644\n--- a/builtin/am.c\n+++ b/builtin/am.c\n@@ -27,6 +27,7 @@\n #include \"notes-utils.h\"\n #include \"rerere.h\"\n #include \"prompt.h\"\n+#include \"mailinfo.h\"\n \n /**\n  * Returns 1 if the file is empty or does not exist, 0 otherwise.\n@@ -1258,58 +1259,61 @@ static void am_append_signoff(struct am_state *state)\n static int parse_mail(struct am_state *state, const char *mail)\n {\n \tFILE *fp;\n-\tstruct child_process cp = CHILD_PROCESS_INIT;\n \tstruct strbuf sb = STRBUF_INIT;\n \tstruct strbuf msg = STRBUF_INIT;\n \tstruct strbuf author_name = STRBUF_INIT;\n \tstruct strbuf author_date = STRBUF_INIT;\n \tstruct strbuf author_email = STRBUF_INIT;\n \tint ret = 0;\n+\tstruct mailinfo mi;\n \n-\tcp.git_cmd = 1;\n-\tcp.in = xopen(mail, O_RDONLY, 0);\n-\tcp.out = xopen(am_path(state, \"info\"), O_WRONLY | O_CREAT, 0777);\n+\tsetup_mailinfo(&mi);\n \n-\targv_array_push(&cp.args, \"mailinfo\");\n-\targv_array_push(&cp.args, state->utf8 ? \"-u\" : \"-n\");\n+\tif (state->utf8)\n+\t\tmi.metainfo_charset = get_commit_output_encoding();\n+\telse\n+\t\tmi.metainfo_charset = NULL;\n \n \tswitch (state->keep) {\n \tcase KEEP_FALSE:\n \t\tbreak;\n \tcase KEEP_TRUE:\n-\t\targv_array_push(&cp.args, \"-k\");\n+\t\tmi.keep_subject = 1;\n \t\tbreak;\n \tcase KEEP_NON_PATCH:\n-\t\targv_array_push(&cp.args, \"-b\");\n+\t\tmi.keep_non_patch_brackets_in_subject = 1;\n \t\tbreak;\n \tdefault:\n \t\tdie(\"BUG: invalid value for state->keep\");\n \t}\n \n \tif (state->message_id)\n-\t\targv_array_push(&cp.args, \"-m\");\n+\t\tmi.add_message_id = 1;\n \n \tswitch (state->scissors) {\n \tcase SCISSORS_UNSET:\n \t\tbreak;\n \tcase SCISSORS_FALSE:\n-\t\targv_array_push(&cp.args, \"--no-scissors\");\n+\t\tmi.use_scissors = 0;\n \t\tbreak;\n \tcase SCISSORS_TRUE:\n-\t\targv_array_push(&cp.args, \"--scissors\");\n+\t\tmi.use_scissors = 1;\n \t\tbreak;\n \tdefault:\n \t\tdie(\"BUG: invalid value for state->scissors\");\n \t}\n \n-\targv_array_push(&cp.args, am_path(state, \"msg\"));\n-\targv_array_push(&cp.args, am_path(state, \"patch\"));\n-\n-\tif (run_command(&cp) < 0)\n+\tmi.input = fopen(mail, \"r\");\n+\tif (!mi.input)\n+\t\tdie(\"could not open input\");\n+\tmi.output = fopen(am_path(state, \"info\"), \"w\");\n+\tif (!mi.output)\n+\t\tdie(\"could not open output 'info'\");\n+\tif (mailinfo(&mi, am_path(state, \"msg\"), am_path(state, \"patch\")))\n \t\tdie(\"could not parse patch\");\n \n-\tclose(cp.in);\n-\tclose(cp.out);\n+\tfclose(mi.input);\n+\tfclose(mi.output);\n \n \t/* Extract message and author information */\n \tfp = xfopen(am_path(state, \"info\"), \"r\");\n@@ -1341,8 +1345,7 @@ static int parse_mail(struct am_state *state, const char *mail)\n \t}\n \n \tstrbuf_addstr(&msg, \"\\n\\n\");\n-\tif (strbuf_read_file(&msg, am_path(state, \"msg\"), 0) < 0)\n-\t\tdie_errno(_(\"could not read '%s'\"), am_path(state, \"msg\"));\n+\tstrbuf_addbuf(&msg, &mi.log_message);\n \tstripspace(&msg, 0);\n \n \tif (state->signoff)\n@@ -1366,6 +1369,7 @@ finish:\n \tstrbuf_release(&author_email);\n \tstrbuf_release(&author_name);\n \tstrbuf_release(&sb);\n+\tclear_mailinfo(&mi);\n \treturn ret;\n }\n \n-- \n2.6.2-383-g144b2e6\n"},{"id":"271953","messageId":"CAPig+cQ5bcaTEsGMP7_LZKD4ze8vQAaqcw7kbhU7rZQXGdDRUQ@mail.gmail.com","threadId":"40552","inReplyTo":"1445239731-10677-11-git-send-email-gitster@pobox.com","subject":"Re: [PATCH v3 10/34] mailinfo: move global \"line\" into mailinfo() function","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2015-10-19T22:57:03Z","receivedAt":"2015-10-19T22:57:03Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Mon, Oct 19, 2015 at 3:28 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> With the previous steps, it becomes clear that the mailinfo()\n> function is the only one that wants the \"line\" to be directly\n> touchable.  Move it to the function scope of this function.\n>\n> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n> ---\n> diff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\n> index 12d1eda..c8dc73f 100644\n> --- a/builtin/mailinfo.c\n> +++ b/builtin/mailinfo.c\n> @@ -12,7 +12,6 @@ static FILE *cmitmsg, *patchfile, *fin, *fout;\n>  static int keep_subject;\n>  static int keep_non_patch_brackets_in_subject;\n>  static const char *metainfo_charset;\n> -static struct strbuf line = STRBUF_INIT;\n>  static struct strbuf name = STRBUF_INIT;\n>  static struct strbuf email = STRBUF_INIT;\n>  static char *message_id;\n> @@ -966,6 +965,8 @@ static void handle_info(void)\n>  static int mailinfo(FILE *in, FILE *out, const char *msg, const char *patch)\n>  {\n>         int peek;\n> +       struct strbuf line = STRBUF_INIT;\n\nDoes there need to be a corresponding strbuf_release(&line) at the end\nof the function?\n\n>         fin = in;\n>         fout = out;\n>\n> --\n> 2.6.2-383-g144b2e6\n"},{"id":"271954","messageId":"CAPig+cS32_rf3cCLUKne-aMc+YJRqThOiZ+sjZ6DrV4BW8PL-Q@mail.gmail.com","threadId":"40552","inReplyTo":"1445239731-10677-20-git-send-email-gitster@pobox.com","subject":"Re: [PATCH v3 19/34] mailinfo: move check for metainfo_charset to convert_to_utf8()","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2015-10-19T22:57:53Z","receivedAt":"2015-10-19T22:57:53Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Mon, Oct 19, 2015 at 3:28 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> All callers of this function refrains from calling it when\n\ns/refrains/refrain/\n\n> mi->metainfo_charset is NULL; move the check to the callee,\n> as it already has a few conditions at its beginning to turn\n> it into a no-op.\n>\n> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n> ---\n> diff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\n> index 26fd9b1..737d0fc 100644\n> --- a/builtin/mailinfo.c\n> +++ b/builtin/mailinfo.c\n> @@ -524,7 +524,7 @@ static void convert_to_utf8(struct mailinfo *mi,\n>  {\n>         char *out;\n>\n> -       if (!charset || !*charset)\n> +       if (!mi->metainfo_charset || !charset || !*charset)\n>                 return;\n>\n>         if (same_encoding(mi->metainfo_charset, charset))\n> @@ -599,8 +599,7 @@ static void decode_header(struct mailinfo *mi, struct strbuf *it)\n>                         dec = decode_q_segment(&piecebuf, 1);\n>                         break;\n>                 }\n> -               if (mi->metainfo_charset)\n> -                       convert_to_utf8(mi, dec, charset_q.buf);\n> +               convert_to_utf8(mi, dec, charset_q.buf);\n>\n>                 strbuf_addbuf(&outbuf, dec);\n>                 strbuf_release(dec);\n> @@ -745,8 +744,7 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n>                 mi->header_stage = 0;\n>\n>         /* normalize the log message to UTF-8. */\n> -       if (mi->metainfo_charset)\n> -               convert_to_utf8(mi, line, charset.buf);\n> +       convert_to_utf8(mi, line, charset.buf);\n>\n>         if (mi->use_scissors && is_scissors_line(line)) {\n>                 int i;\n> --\n> 2.6.2-383-g144b2e6\n"},{"id":"271960","messageId":"xmqq7fmi9kwu.fsf@gitster.mtv.corp.google.com","threadId":"40552","inReplyTo":"CAPig+cQ5bcaTEsGMP7_LZKD4ze8vQAaqcw7kbhU7rZQXGdDRUQ@mail.gmail.com","subject":"Re: [PATCH v3 10/34] mailinfo: move global \"line\" into mailinfo() function","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-20T05:19:29Z","receivedAt":"2015-10-20T05:19:29Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Eric Sunshine <sunshine@sunshineco.com> writes:\n\n> On Mon, Oct 19, 2015 at 3:28 AM, Junio C Hamano <gitster@pobox.com> wrote:\n>> With the previous steps, it becomes clear that the mailinfo()\n>> function is the only one that wants the \"line\" to be directly\n>> touchable.  Move it to the function scope of this function.\n>>\n>> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n>> ---\n>> diff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\n>> index 12d1eda..c8dc73f 100644\n>> --- a/builtin/mailinfo.c\n>> +++ b/builtin/mailinfo.c\n>> @@ -12,7 +12,6 @@ static FILE *cmitmsg, *patchfile, *fin, *fout;\n>>  static int keep_subject;\n>>  static int keep_non_patch_brackets_in_subject;\n>>  static const char *metainfo_charset;\n>> -static struct strbuf line = STRBUF_INIT;\n>>  static struct strbuf name = STRBUF_INIT;\n>>  static struct strbuf email = STRBUF_INIT;\n>>  static char *message_id;\n>> @@ -966,6 +965,8 @@ static void handle_info(void)\n>>  static int mailinfo(FILE *in, FILE *out, const char *msg, const char *patch)\n>>  {\n>>         int peek;\n>> +       struct strbuf line = STRBUF_INIT;\n>\n> Does there need to be a corresponding strbuf_release(&line) at the end\n> of the function?\n\nIndeed.\nThanks.\n"},{"id":"271997","messageId":"xmqqh9ll6xo8.fsf@gitster.mtv.corp.google.com","threadId":"40552","inReplyTo":"1445239731-10677-1-git-send-email-gitster@pobox.com","subject":"Re: [PATCH v3 00/34] libify mailinfo and call it directly from am","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-20T21:24:23Z","receivedAt":"2015-10-20T21:24:23Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> During the discussion on the recent \"git am\" regression, I noticed\n> that the command reimplemented in C spawns one \"mailsplit\" and then\n> spawns \"mailinfo\" followed by \"apply --index\" to commit the changes\n> described in each message.  As there are platforms where spawning\n> subprocess via run_command() interface is heavy-weight, something\n> that is conceptually very simple like \"mailinfo\" is better called\n> directly inside the process---something that is lightweight and\n> frequently used is where the overhead of run_command() would be felt\n> most.\n\nAlthough I still haven't seen any offer to help from those who work\non the platforms that may benefit from this series the most, I have\nsome numbers on my desktop (Dell T3500 2.66GHz Xeon X5650 with 12GB,\nrunning Ubuntu), where the cost of spawning is not as costly as\nelsewhere, making this series less pressing.\n\nBetween 'master' and the version with this series (on 'jch'),\napplying this 34-patch series itself on top of 'master' using \"git\nam\", best of 5 numbers for running:\n\n    time git am mbox >/dev/null\n\nare\n\n      (master)                 (with the series)\n    real    0m0.648s            real    0m0.537s\n    user    0m0.358s            user    0m0.338s\n    sys     0m0.172s            sys     0m0.154s\n\nI haven't re-read the series to catch leaks yet, so in that sense\nthe series is still not ready to be merged to 'next' (of course,\nhelp with fresh set of eyes is very much appreciated here).\n"},{"id":"271998","messageId":"CAGZ79kYAW+T+sVz3c_q+P7brf6OvcQgeZEBnkM3U52vNYc0CqA@mail.gmail.com","threadId":"40552","inReplyTo":"xmqqh9ll6xo8.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v3 00/34] libify mailinfo and call it directly from am","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2015-10-20T22:01:46Z","receivedAt":"2015-10-20T22:01:46Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Tue, Oct 20, 2015 at 2:24 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Junio C Hamano <gitster@pobox.com> writes:\n>\n>> During the discussion on the recent \"git am\" regression, I noticed\n>> that the command reimplemented in C spawns one \"mailsplit\" and then\n>> spawns \"mailinfo\" followed by \"apply --index\" to commit the changes\n>> described in each message.  As there are platforms where spawning\n>> subprocess via run_command() interface is heavy-weight, something\n>> that is conceptually very simple like \"mailinfo\" is better called\n>> directly inside the process---something that is lightweight and\n>> frequently used is where the overhead of run_command() would be felt\n>> most.\n>\n> Although I still haven't seen any offer to help from those who work\n> on the platforms that may benefit from this series the most, I have\n> some numbers on my desktop (Dell T3500 2.66GHz Xeon X5650 with 12GB,\n> running Ubuntu), where the cost of spawning is not as costly as\n> elsewhere, making this series less pressing.\n\nAs far as I understand, this only helps for mailing list workflows, which\nin my limited view of the world is only found in established infrastructure\nprojects, who tend to be maintained by people who run some kind of\nab-nomination of unix.\n(\"Are there people in Windows land who heavily use the email workflow?\")\n\n>\n> Between 'master' and the version with this series (on 'jch'),\n> applying this 34-patch series itself on top of 'master' using \"git\n> am\", best of 5 numbers for running:\n>\n>     time git am mbox >/dev/null\n>\n> are\n>\n>       (master)                 (with the series)\n>     real    0m0.648s            real    0m0.537s\n>     user    0m0.358s            user    0m0.338s\n>     sys     0m0.172s            sys     0m0.154s\n>\n> I haven't re-read the series to catch leaks yet, so in that sense\n> the series is still not ready to be merged to 'next' (of course,\n> help with fresh set of eyes is very much appreciated here).\n\nI'll take another look after sending out my series.\n\n> --\n> To unsubscribe from this list: send the line \"unsubscribe git\" in\n> the body of a message to majordomo@vger.kernel.org\n> More majordomo info at  http://vger.kernel.org/majordomo-info.html\n"},{"id":"271999","messageId":"xmqqd1w96vq7.fsf@gitster.mtv.corp.google.com","threadId":"40552","inReplyTo":"CAGZ79kYAW+T+sVz3c_q+P7brf6OvcQgeZEBnkM3U52vNYc0CqA@mail.gmail.com","subject":"Re: [PATCH v3 00/34] libify mailinfo and call it directly from am","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-20T22:06:24Z","receivedAt":"2015-10-20T22:06:24Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Stefan Beller <sbeller@google.com> writes:\n\n> As far as I understand, this only helps for mailing list workflows, which\n> in my limited view of the world is only found in established infrastructure\n> projects, who tend to be maintained by people who run some kind of\n> ab-nomination of unix.\n> (\"Are there people in Windows land who heavily use the email workflow?\")\n\nForgot that \"am\" is a workhorse behind \"rebase\"?\n"},{"id":"272000","messageId":"CAGZ79kYXX3jDPvS1E=8oyVvjSjbMxY0Qk45Ad6cdSUq=Ee2SgA@mail.gmail.com","threadId":"40552","inReplyTo":"xmqqd1w96vq7.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v3 00/34] libify mailinfo and call it directly from am","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2015-10-20T22:08:14Z","receivedAt":"2015-10-20T22:08:14Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Tue, Oct 20, 2015 at 3:06 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Stefan Beller <sbeller@google.com> writes:\n>\n>> As far as I understand, this only helps for mailing list workflows, which\n>> in my limited view of the world is only found in established infrastructure\n>> projects, who tend to be maintained by people who run some kind of\n>> ab-nomination of unix.\n>> (\"Are there people in Windows land who heavily use the email workflow?\")\n>\n> Forgot that \"am\" is a workhorse behind \"rebase\"?\n>\n\nYes, I was deceived by the name of the series (\"it must be mail related and only\nmail related\" was my thinking).\n"},{"id":"272036","messageId":"5627B496.7030102@ramsayjones.plus.com","threadId":"40552","inReplyTo":"xmqqh9ll6xo8.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v3 00/34] libify mailinfo and call it directly from am","fromName":"Ramsay Jones","fromEmail":"ramsay@ramsayjones.plus.com","sentAt":"2015-10-21T15:51:50Z","receivedAt":"2015-10-21T15:51:50Z","isPatch":true,"sender":{"key":"ramsay@ramsayjones.plus.com","avatar":"https://avatars.githubusercontent.com/u/33702710?v=4"},"body":"\n\nOn 20/10/15 22:24, Junio C Hamano wrote:\n> Junio C Hamano <gitster@pobox.com> writes:\n> \n>> During the discussion on the recent \"git am\" regression, I noticed\n>> that the command reimplemented in C spawns one \"mailsplit\" and then\n>> spawns \"mailinfo\" followed by \"apply --index\" to commit the changes\n>> described in each message.  As there are platforms where spawning\n>> subprocess via run_command() interface is heavy-weight, something\n>> that is conceptually very simple like \"mailinfo\" is better called\n>> directly inside the process---something that is lightweight and\n>> frequently used is where the overhead of run_command() would be felt\n>> most.\n> \n> Although I still haven't seen any offer to help from those who work\n> on the platforms that may benefit from this series the most, I have\n> some numbers on my desktop (Dell T3500 2.66GHz Xeon X5650 with 12GB,\n> running Ubuntu), where the cost of spawning is not as costly as\n> elsewhere, making this series less pressing.\n\nI suspect that I haven't tested exactly the same version as you, but I had\na quick look at testing this on Cygwin today. I have included a complete\ntranscript (below), so you can see what I did wrong! :-P\n\n> \n> Between 'master' and the version with this series (on 'jch'),\n> applying this 34-patch series itself on top of 'master' using \"git\n> am\", best of 5 numbers for running:\n> \n>     time git am mbox >/dev/null\n> \n> are\n> \n>       (master)                 (with the series)\n>     real    0m0.648s            real    0m0.537s\n>     user    0m0.358s            user    0m0.338s\n>     sys     0m0.172s            sys     0m0.154s\n> \n\nThe corresponding times for me were:\n\n    (master)           (with the series)\n  real\t0m9.760s      real\t0m5.744s\n  user\t0m0.531s      user\t0m0.656s\n  sys\t0m5.726s      sys\t0m3.520s\n\nSo, yes, a noticeable improvement! :)\n\nHTH\n\nATB,\nRamsay Jones\n\n  $ uname -a\n  CYGWIN_NT-6.3 satellite 2.2.1(0.289/5/3) 2015-08-20 11:42 x86_64 Cygwin\n  $ pwd\n  /home/ramsay/git\n  $ git log --decorate --oneline -1\n  74301d6 (HEAD -> master, origin/master, origin/HEAD) Sync with maint\n  $ ./git version\n  git version 2.6.2.280.g74301d6\n  $ git format-patch --stdout 2a5ce7c^..896df93 >mailinfo.mbox\n  $ git format-patch --stdout a4106a8^..559e247 >>mailinfo.mbox\n  $ git checkout -b master-mailinfo master\n  Switched to a new branch 'master-mailinfo'\n  $ time ./git am mailinfo.mbox\n  Applying: mailinfo: remove a no-op call convert_to_utf8(it, \"\")\n  Applying: mailinfo: fold decode_header_bq() into decode_header()\n  Applying: mailinfo: fix an off-by-one error in the boundary stack\n  Applying: mailinfo: explicitly close file handle to the patch output\n  Applying: mailinfo: move handle_boundary() lower\n  Applying: mailinfo: get rid of function-local static states\n  Applying: mailinfo: do not let handle_body() touch global \"line\" directly\n  Applying: mailinfo: do not let handle_boundary() touch global \"line\" directly\n  Applying: mailinfo: do not let find_boundary() touch global \"line\" directly\n  Applying: mailinfo: move global \"line\" into mailinfo() function\n  Applying: mailinfo: introduce \"struct mailinfo\" to hold globals\n  Applying: mailinfo: move keep_subject & keep_non_patch_bracket to struct mailinfo\n  Applying: mailinfo: move global \"FILE *fin, *fout\" to struct mailinfo\n  Applying: mailinfo: move filter/header stage to struct mailinfo\n  Applying: mailinfo: move patch_lines to struct mailinfo\n  Applying: mailinfo: move add_message_id and message_id to struct mailinfo\n  Applying: mailinfo: move use_scissors and use_inbody_headers to struct mailinfo\n  Applying: mailinfo: move metainfo_charset to struct mailinfo\n  Applying: mailinfo: move check for metainfo_charset to convert_to_utf8()\n  Applying: mailinfo: move transfer_encoding to struct mailinfo\n  Applying: mailinfo: move charset to struct mailinfo\n  Applying: mailinfo: move cmitmsg and patchfile to struct mailinfo\n  Applying: mailinfo: move [ps]_hdr_data to struct mailinfo\n  Applying: mailinfo: move content/content_top to struct mailinfo\n  Applying: mailinfo: handle_commit_msg() shouldn't be called after finding patchbreak\n  Applying: mailinfo: keep the parsed log message in a strbuf\n  Applying: mailinfo: move read_one_header_line() closer to its callers\n  Applying: mailinfo: move check_header() after the helpers it uses\n  Applying: mailinfo: move cleanup_space() before its users\n  Applying: mailinfo: move definition of MAX_HDR_PARSED closer to its use\n  Applying: mailinfo: libify\n  Applying: mailinfo: handle charset conversion errors in the caller\n  Applying: mailinfo: remove calls to exit() and die() deep in the callchain\n  Applying: am: make direct call to mailinfo\n  Applying: mailinfo: plug strbuf leak during continuation line handling\n  \n  real\t0m9.760s\n  user\t0m0.531s\n  sys\t0m5.726s\n  $ \n  \n  $ make clean >/dev/null 2>&1\n  $ make >out.mi 2>&1\n  $ ./git version\n  git version 2.6.2.315.g1e9f6ff\n  $ git describe\n  v2.6.2-315-g1e9f6ff\n  $ git checkout -b new-mailinfo master\n  Switched to a new branch 'new-mailinfo'\n  $ time ./git am mailinfo.mbox\n  Applying: mailinfo: remove a no-op call convert_to_utf8(it, \"\")\n  Applying: mailinfo: fold decode_header_bq() into decode_header()\n  Applying: mailinfo: fix an off-by-one error in the boundary stack\n  Applying: mailinfo: explicitly close file handle to the patch output\n  Applying: mailinfo: move handle_boundary() lower\n  Applying: mailinfo: get rid of function-local static states\n  Applying: mailinfo: do not let handle_body() touch global \"line\" directly\n  Applying: mailinfo: do not let handle_boundary() touch global \"line\" directly\n  Applying: mailinfo: do not let find_boundary() touch global \"line\" directly\n  Applying: mailinfo: move global \"line\" into mailinfo() function\n  Applying: mailinfo: introduce \"struct mailinfo\" to hold globals\n  Applying: mailinfo: move keep_subject & keep_non_patch_bracket to struct mailinfo\n  Applying: mailinfo: move global \"FILE *fin, *fout\" to struct mailinfo\n  Applying: mailinfo: move filter/header stage to struct mailinfo\n  Applying: mailinfo: move patch_lines to struct mailinfo\n  Applying: mailinfo: move add_message_id and message_id to struct mailinfo\n  Applying: mailinfo: move use_scissors and use_inbody_headers to struct mailinfo\n  Applying: mailinfo: move metainfo_charset to struct mailinfo\n  Applying: mailinfo: move check for metainfo_charset to convert_to_utf8()\n  Applying: mailinfo: move transfer_encoding to struct mailinfo\n  Applying: mailinfo: move charset to struct mailinfo\n  Applying: mailinfo: move cmitmsg and patchfile to struct mailinfo\n  Applying: mailinfo: move [ps]_hdr_data to struct mailinfo\n  Applying: mailinfo: move content/content_top to struct mailinfo\n  Applying: mailinfo: handle_commit_msg() shouldn't be called after finding patchbreak\n  Applying: mailinfo: keep the parsed log message in a strbuf\n  Applying: mailinfo: move read_one_header_line() closer to its callers\n  Applying: mailinfo: move check_header() after the helpers it uses\n  Applying: mailinfo: move cleanup_space() before its users\n  Applying: mailinfo: move definition of MAX_HDR_PARSED closer to its use\n  Applying: mailinfo: libify\n  Applying: mailinfo: handle charset conversion errors in the caller\n  Applying: mailinfo: remove calls to exit() and die() deep in the callchain\n  Applying: am: make direct call to mailinfo\n  Applying: mailinfo: plug strbuf leak during continuation line handling\n  \n  real\t0m5.744s\n  user\t0m0.656s\n  sys\t0m3.520s\n  $ \n\n  $ git rev-parse master-mailinfo^{tree} new-mailinfo^{tree}\n  cebb1a110f3af9f4393bb66b942ae28e2743f233\n  cebb1a110f3af9f4393bb66b942ae28e2743f233\n  $ \n"},{"id":"272059","messageId":"5627EFE4.1060106@kdbg.org","threadId":"40552","inReplyTo":"5627B496.7030102@ramsayjones.plus.com","subject":"Re: [PATCH v3 00/34] libify mailinfo and call it directly from am","fromName":"Johannes Sixt","fromEmail":"j6t@kdbg.org","sentAt":"2015-10-21T20:04:52Z","receivedAt":"2015-10-21T20:04:52Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Am 21.10.2015 um 17:51 schrieb Ramsay Jones:\n> On 20/10/15 22:24, Junio C Hamano wrote:\n>> Junio C Hamano <gitster@pobox.com> writes:\n>> some numbers on my desktop (Dell T3500 2.66GHz Xeon X5650 with 12GB,\n>> running Ubuntu),\n>\n> I suspect that I haven't tested exactly the same version as you, but I had\n> a quick look at testing this on Cygwin today. I have included a complete\n> transcript (below), so you can see what I did wrong! :-P\n>\n>>\n>> Between 'master' and the version with this series (on 'jch'),\n>> applying this 34-patch series itself on top of 'master' using \"git\n>> am\", best of 5 numbers for running:\n>>\n>>      time git am mbox >/dev/null\n>>\n>> are\n>>\n>>        (master)                 (with the series)\n>>      real    0m0.648s            real    0m0.537s\n>>      user    0m0.358s            user    0m0.338s\n>>      sys     0m0.172s            sys     0m0.154s\n>>\n>\n> The corresponding times for me were:\n>\n>      (master)           (with the series)\n>    real\t0m9.760s      real\t0m5.744s\n>    user\t0m0.531s      user\t0m0.656s\n>    sys\t0m5.726s      sys\t0m3.520s\n>\n> So, yes, a noticeable improvement! :)\n\nSame here, on Windows built with the old msysgit environment:\n\n(master)             (with the series)\nreal    0m3.147s      real    0m1.947s\nuser    0m0.016s      user    0m0.000s\nsys     0m0.015s      sys     0m0.031s\n\nAlthough I tested 'git am patches/*' where the patches/* are the result \nof 'git-format-patch v2.6.1..github/jc/mailinfo-lib'.\n\n-- Hannes\n"},{"id":"272060","messageId":"xmqqlhawugrp.fsf@gitster.mtv.corp.google.com","threadId":"40552","inReplyTo":"5627EFE4.1060106@kdbg.org","subject":"Re: [PATCH v3 00/34] libify mailinfo and call it directly from am","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-21T20:07:54Z","receivedAt":"2015-10-21T20:07:54Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Sixt <j6t@kdbg.org> writes:\n\n> Am 21.10.2015 um 17:51 schrieb Ramsay Jones:\n>> On 20/10/15 22:24, Junio C Hamano wrote:\n>>>\n>>>      time git am mbox >/dev/null\n>>>\n>>> are\n>>>\n>>>        (master)                 (with the series)\n>>>      real    0m0.648s            real    0m0.537s\n>>>      user    0m0.358s            user    0m0.338s\n>>>      sys     0m0.172s            sys     0m0.154s\n>>>\n>>\n>> The corresponding times for me were:\n>>\n>>      (master)           (with the series)\n>>    real\t0m9.760s      real\t0m5.744s\n>>    user\t0m0.531s      user\t0m0.656s\n>>    sys\t0m5.726s      sys\t0m3.520s\n>>\n>> So, yes, a noticeable improvement! :)\n>\n> Same here, on Windows built with the old msysgit environment:\n>\n> (master)             (with the series)\n> real    0m3.147s      real    0m1.947s\n> user    0m0.016s      user    0m0.000s\n> sys     0m0.015s      sys     0m0.031s\n>\n> Although I tested 'git am patches/*' where the patches/* are the\n> result of 'git-format-patch v2.6.1..github/jc/mailinfo-lib'.\n\nThanks, both.\n"},{"id":"272061","messageId":"CAGZ79kaCA5HLF7mLY9OC_JrZ9ZhfURdcLoZxQ4rMwmMyWHf_sg@mail.gmail.com","threadId":"40552","inReplyTo":"1445239731-10677-15-git-send-email-gitster@pobox.com","subject":"Re: [PATCH v3 14/34] mailinfo: move filter/header stage to struct mailinfo","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2015-10-21T20:20:20Z","receivedAt":"2015-10-21T20:20:20Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Mon, Oct 19, 2015 at 12:28 AM, Junio C Hamano <gitster@pobox.com> wrote:\n\n> @@ -28,6 +31,7 @@ static enum  {\n>\n>  static struct strbuf charset = STRBUF_INIT;\n>  static int patch_lines;\n> +\n\nnitpicking here. Why is this patch the best in series to introduce a\nnew line at this position? ;)\n\n>  static struct strbuf **p_hdr_data, **s_hdr_data;\n>  static int use_scissors;\n>  static int add_message_id;\n> @@ -718,25 +722,25 @@ static int is_scissors_line(const struct strbuf *line)\n>                 gap * 2 < perforation);\n>  }\n"},{"id":"272062","messageId":"CAGZ79kZkms9SS3YpyEK4tmUPZ3TwXRF1M30X58GrS8dV13rJng@mail.gmail.com","threadId":"40552","inReplyTo":"1445239731-10677-18-git-send-email-gitster@pobox.com","subject":"Re: [PATCH v3 17/34] mailinfo: move use_scissors and use_inbody_headers to struct mailinfo","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2015-10-21T20:24:48Z","receivedAt":"2015-10-21T20:24:48Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Mon, Oct 19, 2015 at 12:28 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n> ---\n>  builtin/mailinfo.c | 23 +++++++++++++----------\n>  1 file changed, 13 insertions(+), 10 deletions(-)\n>\n> diff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\n> index c0522f2..2c8f249 100644\n> --- a/builtin/mailinfo.c\n> +++ b/builtin/mailinfo.c\n> @@ -20,6 +20,8 @@ struct mailinfo {\n>         int keep_subject;\n>         int keep_non_patch_brackets_in_subject;\n>         int add_message_id;\n> +       int use_scissors;\n> +       int use_inbody_headers; /* defaults to 1 */\n\nIMHO there is no need for the comment here, stating its default.\nThat can be looked up in the init function, which is as convenient as\nreading globals in a file?\n\n>\n>         char *message_id;\n>         int patch_lines;\n> @@ -34,8 +36,6 @@ static enum  {\n>  static struct strbuf charset = STRBUF_INIT;\n>\n>  static struct strbuf **p_hdr_data, **s_hdr_data;\n> -static int use_scissors;\n> -static int use_inbody_headers = 1;\n>\n>  #define MAX_HDR_PARSED 10\n>  #define MAX_BOUNDARIES 5\n> @@ -734,7 +734,7 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n>                         return 0;\n>         }\n>\n> -       if (use_inbody_headers && mi->header_stage) {\n> +       if (mi->use_inbody_headers && mi->header_stage) {\n>                 mi->header_stage = check_header(mi, line, s_hdr_data, 0);\n>                 if (mi->header_stage)\n>                         return 0;\n> @@ -748,7 +748,7 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n>         if (metainfo_charset)\n>                 convert_to_utf8(line, charset.buf);\n>\n> -       if (use_scissors && is_scissors_line(line)) {\n> +       if (mi->use_scissors && is_scissors_line(line)) {\n>                 int i;\n>                 if (fseek(cmitmsg, 0L, SEEK_SET))\n>                         die_errno(\"Could not rewind output message file\");\n> @@ -1009,12 +1009,14 @@ static int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)\n>         return 0;\n>  }\n>\n> -static int git_mailinfo_config(const char *var, const char *value, void *unused)\n> +static int git_mailinfo_config(const char *var, const char *value, void *mi_)\n>  {\n> +       struct mailinfo *mi = mi_;\n> +\n>         if (!starts_with(var, \"mailinfo.\"))\n> -               return git_default_config(var, value, unused);\n> +               return git_default_config(var, value, NULL);\n>         if (!strcmp(var, \"mailinfo.scissors\")) {\n> -               use_scissors = git_config_bool(var, value);\n> +               mi->use_scissors = git_config_bool(var, value);\n>                 return 0;\n>         }\n>         /* perhaps others here */\n> @@ -1027,6 +1029,7 @@ static void setup_mailinfo(struct mailinfo *mi)\n>         strbuf_init(&mi->name, 0);\n>         strbuf_init(&mi->email, 0);\n>         mi->header_stage = 1;\n> +       mi->use_inbody_headers = 1;\n>         git_config(git_mailinfo_config, &mi);\n>  }\n>\n> @@ -1068,11 +1071,11 @@ int cmd_mailinfo(int argc, const char **argv, const char *prefix)\n>                 else if (starts_with(argv[1], \"--encoding=\"))\n>                         metainfo_charset = argv[1] + 11;\n>                 else if (!strcmp(argv[1], \"--scissors\"))\n> -                       use_scissors = 1;\n> +                       mi.use_scissors = 1;\n>                 else if (!strcmp(argv[1], \"--no-scissors\"))\n> -                       use_scissors = 0;\n> +                       mi.use_scissors = 0;\n>                 else if (!strcmp(argv[1], \"--no-inbody-headers\"))\n> -                       use_inbody_headers = 0;\n> +                       mi.use_inbody_headers = 0;\n>                 else\n>                         usage(mailinfo_usage);\n>                 argc--; argv++;\n> --\n> 2.6.2-383-g144b2e6\n>\n> --\n> To unsubscribe from this list: send the line \"unsubscribe git\" in\n> the body of a message to majordomo@vger.kernel.org\n> More majordomo info at  http://vger.kernel.org/majordomo-info.html\n"},{"id":"272065","messageId":"CAGZ79kaTBtb_4fFSa4b83Lu0x1N-0PvSODvuxGGLdUfZ1SkMnw@mail.gmail.com","threadId":"40552","inReplyTo":"1445239731-10677-24-git-send-email-gitster@pobox.com","subject":"Re: [PATCH v3 23/34] mailinfo: move [ps]_hdr_data to struct mailinfo","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2015-10-21T20:30:45Z","receivedAt":"2015-10-21T20:30:45Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Mon, Oct 19, 2015 at 12:28 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> @@ -733,7 +733,7 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)\n>         }\n>\n>         if (mi->use_inbody_headers && mi->header_stage) {\n> -               mi->header_stage = check_header(mi, line, s_hdr_data, 0);\n> +               mi->header_stage = check_header(mi, line, mi->s_hdr_data, 0);\n\nWould it make sense to get rid of the third argument for check_header instead?\nWe already pass in mi, so check_header can access s_hdr_data?\n\n>                 if (mi->header_stage)\n"},{"id":"272066","messageId":"CAGZ79kbRLVaNNR=ZuMZNtJD2vorV5K1-wZ+R9CY5FY_zS3i95Q@mail.gmail.com","threadId":"40552","inReplyTo":"1445239731-10677-25-git-send-email-gitster@pobox.com","subject":"Re: [PATCH v3 24/34] mailinfo: move content/content_top to struct mailinfo","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2015-10-21T20:36:01Z","receivedAt":"2015-10-21T20:36:01Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Mon, Oct 19, 2015 at 12:28 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n> ---\n>  builtin/mailinfo.c | 45 ++++++++++++++++++++++++++-------------------\n>  1 file changed, 26 insertions(+), 19 deletions(-)\n>\n> diff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\n> index 2c194da..ec65805 100644\n> --- a/builtin/mailinfo.c\n> +++ b/builtin/mailinfo.c\n> @@ -7,6 +7,8 @@\n>  #include \"utf8.h\"\n>  #include \"strbuf.h\"\n>\n> +#define MAX_BOUNDARIES 5\n> +\n>  struct mailinfo {\n>         FILE *input;\n>         FILE *output;\n> @@ -22,6 +24,8 @@ struct mailinfo {\n>         int use_inbody_headers; /* defaults to 1 */\n>         const char *metainfo_charset;\n>\n> +       struct strbuf *content[MAX_BOUNDARIES];\n> +       struct strbuf **content_top;\n>         struct strbuf charset;\n>         char *message_id;\n>         enum  {\n> @@ -35,7 +39,6 @@ struct mailinfo {\n>  };\n>\n>  #define MAX_HDR_PARSED 10\n> -#define MAX_BOUNDARIES 5\n\nWould it make sense to also move MAX_HDR_PARSED, such that we have all\ndefines in one place? The previous patch moved HDR related stuff around, so\neither there or here?\n\n\n>\n>  static void cleanup_space(struct strbuf *sb);\n>\n> @@ -180,10 +183,6 @@ static int slurp_attr(const char *line, const char *name, struct strbuf *attr)\n>         return 1;\n>  }\n>\n> -static struct strbuf *content[MAX_BOUNDARIES];\n> -\n> -static struct strbuf **content_top = content;\n> -\n>  static void handle_content_type(struct mailinfo *mi, struct strbuf *line)\n>  {\n>         struct strbuf *boundary = xmalloc(sizeof(struct strbuf));\n> @@ -191,11 +190,11 @@ static void handle_content_type(struct mailinfo *mi, struct strbuf *line)\n>\n>         if (slurp_attr(line->buf, \"boundary=\", boundary)) {\n>                 strbuf_insert(boundary, 0, \"--\", 2);\n> -               if (++content_top >= &content[MAX_BOUNDARIES]) {\n> +               if (++mi->content_top >= &mi->content[MAX_BOUNDARIES]) {\n>                         fprintf(stderr, \"Too many boundaries to handle\\n\");\n>                         exit(1);\n>                 }\n> -               *content_top = boundary;\n> +               *(mi->content_top) = boundary;\n>                 boundary = NULL;\n>         }\n>         slurp_attr(line->buf, \"charset=\", &mi->charset);\n> @@ -223,10 +222,12 @@ static void handle_content_transfer_encoding(struct mailinfo *mi,\n>                 mi->transfer_encoding = TE_DONTCARE;\n>  }\n>\n> -static int is_multipart_boundary(const struct strbuf *line)\n> +static int is_multipart_boundary(struct mailinfo *mi, const struct strbuf *line)\n>  {\n> -       return (((*content_top)->len <= line->len) &&\n> -               !memcmp(line->buf, (*content_top)->buf, (*content_top)->len));\n> +       struct strbuf *content_top = *(mi->content_top);\n> +\n> +       return ((content_top->len <= line->len) &&\n> +               !memcmp(line->buf, content_top->buf, content_top->len));\n>  }\n>\n>  static void cleanup_subject(struct mailinfo *mi, struct strbuf *subject)\n> @@ -799,7 +800,7 @@ static void handle_filter(struct mailinfo *mi, struct strbuf *line)\n>  static int find_boundary(struct mailinfo *mi, struct strbuf *line)\n>  {\n>         while (!strbuf_getline(line, mi->input, '\\n')) {\n> -               if (*content_top && is_multipart_boundary(line))\n> +               if (*(mi->content_top) && is_multipart_boundary(mi, line))\n>                         return 1;\n>         }\n>         return 0;\n> @@ -811,18 +812,18 @@ static int handle_boundary(struct mailinfo *mi, struct strbuf *line)\n>\n>         strbuf_addch(&newline, '\\n');\n>  again:\n> -       if (line->len >= (*content_top)->len + 2 &&\n> -           !memcmp(line->buf + (*content_top)->len, \"--\", 2)) {\n> +       if (line->len >= (*(mi->content_top))->len + 2 &&\n> +           !memcmp(line->buf + (*(mi->content_top))->len, \"--\", 2)) {\n>                 /* we hit an end boundary */\n>                 /* pop the current boundary off the stack */\n> -               strbuf_release(*content_top);\n> -               free(*content_top);\n> -               *content_top = NULL;\n> +               strbuf_release(*(mi->content_top));\n> +               free(*(mi->content_top));\n> +               *(mi->content_top) = NULL;\n>\n>                 /* technically won't happen as is_multipart_boundary()\n>                    will fail first.  But just in case..\n>                  */\n> -               if (--content_top < content) {\n> +               if (--mi->content_top < mi->content) {\n>                         fprintf(stderr, \"Detected mismatched boundaries, \"\n>                                         \"can't recover\\n\");\n>                         exit(1);\n> @@ -857,14 +858,14 @@ static void handle_body(struct mailinfo *mi, struct strbuf *line)\n>         struct strbuf prev = STRBUF_INIT;\n>\n>         /* Skip up to the first boundary */\n> -       if (*content_top) {\n> +       if (*(mi->content_top)) {\n>                 if (!find_boundary(mi, line))\n>                         goto handle_body_out;\n>         }\n>\n>         do {\n>                 /* process any boundary lines */\n> -               if (*content_top && is_multipart_boundary(line)) {\n> +               if (*(mi->content_top) && is_multipart_boundary(mi, line)) {\n>                         /* flush any leftover */\n>                         if (prev.len) {\n>                                 handle_filter(mi, &prev);\n> @@ -1028,6 +1029,7 @@ static void setup_mailinfo(struct mailinfo *mi)\n>         strbuf_init(&mi->charset, 0);\n>         mi->header_stage = 1;\n>         mi->use_inbody_headers = 1;\n> +       mi->content_top = mi->content;\n>         git_config(git_mailinfo_config, &mi);\n>  }\n>\n> @@ -1046,6 +1048,11 @@ static void clear_mailinfo(struct mailinfo *mi)\n>         for (i = 0; mi->s_hdr_data[i]; i++)\n>                 strbuf_release(mi->s_hdr_data[i]);\n>         free(mi->s_hdr_data);\n> +\n> +       while (mi->content < mi->content_top) {\n> +               free(*(mi->content_top));\n> +               mi->content_top--;\n> +       }\n>  }\n>\n>  static const char mailinfo_usage[] =\n> --\n> 2.6.2-383-g144b2e6\n>\n> --\n> To unsubscribe from this list: send the line \"unsubscribe git\" in\n> the body of a message to majordomo@vger.kernel.org\n> More majordomo info at  http://vger.kernel.org/majordomo-info.html\n"},{"id":"272068","messageId":"xmqq8u6wue91.fsf@gitster.mtv.corp.google.com","threadId":"40552","inReplyTo":"CAGZ79kZkms9SS3YpyEK4tmUPZ3TwXRF1M30X58GrS8dV13rJng@mail.gmail.com","subject":"Re: [PATCH v3 17/34] mailinfo: move use_scissors and use_inbody_headers to struct mailinfo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-21T21:02:18Z","receivedAt":"2015-10-21T21:02:18Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Stefan Beller <sbeller@google.com> writes:\n\n> On Mon, Oct 19, 2015 at 12:28 AM, Junio C Hamano <gitster@pobox.com> wrote:\n>> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n>> ---\n>>  builtin/mailinfo.c | 23 +++++++++++++----------\n>>  1 file changed, 13 insertions(+), 10 deletions(-)\n>>\n>> diff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\n>> index c0522f2..2c8f249 100644\n>> --- a/builtin/mailinfo.c\n>> +++ b/builtin/mailinfo.c\n>> @@ -20,6 +20,8 @@ struct mailinfo {\n>>         int keep_subject;\n>>         int keep_non_patch_brackets_in_subject;\n>>         int add_message_id;\n>> +       int use_scissors;\n>> +       int use_inbody_headers; /* defaults to 1 */\n>\n> IMHO there is no need for the comment here, stating its default.\n> That can be looked up in the init function, which is as convenient as\n> reading globals in a file?\n\nIt was crucial to ensure correctness during conversion, that is, a\nconversion done in\n\n (1) Remove \"static int use_inbody_headers = 1\"\n (2) Add \"int use_inbody_headers;\"\n (3) Update setup_mailinfo()\n\nsequence would have lost a clue as to what the right value to assign\nin step (3).  Tweaking (2) to leave \"/* this starts at 1 */\" helped\navoid such a mistake.\n\nWhen reading the end result, the above three appear to have been\ndone simultaneously, so I agree that the comment does not help.\n"},{"id":"272069","messageId":"xmqqzizcszke.fsf@gitster.mtv.corp.google.com","threadId":"40552","inReplyTo":"CAGZ79kbRLVaNNR=ZuMZNtJD2vorV5K1-wZ+R9CY5FY_zS3i95Q@mail.gmail.com","subject":"Re: [PATCH v3 24/34] mailinfo: move content/content_top to struct mailinfo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-21T21:04:49Z","receivedAt":"2015-10-21T21:04:49Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Stefan Beller <sbeller@google.com> writes:\n\n> On Mon, Oct 19, 2015 at 12:28 AM, Junio C Hamano <gitster@pobox.com> wrote:\n>> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n>> ---\n>>  builtin/mailinfo.c | 45 ++++++++++++++++++++++++++-------------------\n>>  1 file changed, 26 insertions(+), 19 deletions(-)\n>>\n>> diff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\n>> index 2c194da..ec65805 100644\n>> --- a/builtin/mailinfo.c\n>> +++ b/builtin/mailinfo.c\n>> @@ -7,6 +7,8 @@\n>>  #include \"utf8.h\"\n>>  #include \"strbuf.h\"\n>>\n>> +#define MAX_BOUNDARIES 5\n>> +\n>>  struct mailinfo {\n>>         FILE *input;\n>>         FILE *output;\n>> @@ -22,6 +24,8 @@ struct mailinfo {\n>>         int use_inbody_headers; /* defaults to 1 */\n>>         const char *metainfo_charset;\n>>\n>> +       struct strbuf *content[MAX_BOUNDARIES];\n>> +       struct strbuf **content_top;\n>>         struct strbuf charset;\n>>         char *message_id;\n>>         enum  {\n>> @@ -35,7 +39,6 @@ struct mailinfo {\n>>  };\n>>\n>>  #define MAX_HDR_PARSED 10\n>> -#define MAX_BOUNDARIES 5\n>\n> Would it make sense to also move MAX_HDR_PARSED, such that we have all\n> defines in one place?\n\nLooking at their final resting place, I do not think so.\n"},{"id":"272072","messageId":"CAGZ79kY95wfbktyEji+jcyB3sbdyVCmmJajnBQTr3Hrg_PFvpA@mail.gmail.com","threadId":"40552","inReplyTo":"xmqqzizcszke.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v3 24/34] mailinfo: move content/content_top to struct mailinfo","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2015-10-21T21:08:59Z","receivedAt":"2015-10-21T21:08:59Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Wed, Oct 21, 2015 at 2:04 PM, Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Looking at their final resting place, I do not think so.\n\nRight, I comment along the way without looking ahead, so this was a bad comment.\n"},{"id":"272077","messageId":"xmqqoafru82p.fsf_-_@gitster.mtv.corp.google.com","threadId":"40552","inReplyTo":"1445239731-10677-1-git-send-email-gitster@pobox.com","subject":"[PATCH v4 00/35] libify mailinfo and call it directly from am","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-21T23:15:42Z","receivedAt":"2015-10-21T23:15:42Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The change in the endgame since v3 ($gmane/279832) is almost none\n(interdiff attached at the end), so I won't be sending the patches\nthemselves.  The bulk out of the miniscule interdiff comes from the\nfifth \"plug strbuf leak\" patch.\n\nThe patches have been reordered to make the structure of the series\nclearer:\n\nPreliminary fixes:\n\n  mailinfo: remove a no-op call convert_to_utf8(it, \"\")\n  mailinfo: fold decode_header_bq() into decode_header()\n  mailinfo: fix an off-by-one error in the boundary stack\n  mailinfo: explicitly close file handle to the patch output\n  mailinfo: plug strbuf leak during continuation line handling\n\nGroup related things together and remove forward declarations:\n\n  mailinfo: move handle_boundary() lower\n  mailinfo: move read_one_header_line() closer to its callers\n  mailinfo: move check_header() after the helpers it uses\n  mailinfo: move cleanup_space() before its users\n  mailinfo: move definition of MAX_HDR_PARSED closer to its use\n\nPreliminary logic clean-up:\n\n  mailinfo: get rid of function-local static states\n  mailinfo: do not let handle_body() touch global \"line\" directly\n  mailinfo: do not let handle_boundary() touch global \"line\" directly\n  mailinfo: do not let find_boundary() touch global \"line\" directly\n  mailinfo: move global \"line\" into mailinfo() function\n\nGetting rid of the globals:\n\n  mailinfo: introduce \"struct mailinfo\" to hold globals\n  mailinfo: move keep_subject & keep_non_patch_bracket to struct mailinfo\n  mailinfo: move global \"FILE *fin, *fout\" to struct mailinfo\n  mailinfo: move filter/header stage to struct mailinfo\n  mailinfo: move patch_lines to struct mailinfo\n  mailinfo: move add_message_id and message_id to struct mailinfo\n  mailinfo: move use_scissors and use_inbody_headers to struct mailinfo\n  mailinfo: move metainfo_charset to struct mailinfo\n  mailinfo: move check for metainfo_charset to convert_to_utf8()\n  mailinfo: move transfer_encoding to struct mailinfo\n  mailinfo: move charset to struct mailinfo\n  mailinfo: move cmitmsg and patchfile to struct mailinfo\n  mailinfo: move [ps]_hdr_data to struct mailinfo\n  mailinfo: move content/content_top to struct mailinfo\n\nLibify:\n\n  mailinfo: handle_commit_msg() shouldn't be called after finding patchbreak\n  mailinfo: keep the parsed log message in a strbuf\n  mailinfo: libify\n\nLifting the error handling to the caller:\n\n  mailinfo: handle charset conversion errors in the caller\n  mailinfo: remove calls to exit() and die() deep in the callchain\n\nEndgame:\n\n  am: make direct call to mailinfo\n\n Makefile           |    1 +\n builtin/am.c       |   42 ++-\n builtin/mailinfo.c | 1055 +---------------------------------------------------\n mailinfo.c         | 1037 +++++++++++++++++++++++++++++++++++++++++++++++++++\n mailinfo.h         |   41 ++\n 5 files changed, 1122 insertions(+), 1054 deletions(-)\n create mode 100644 mailinfo.c\n create mode 100644 mailinfo.h\n\n-- \n2.6.2-377-g450896c\n\n\n(Interdiff)\n\ndiff --git a/mailinfo.c b/mailinfo.c\nindex 49eaa99..e157ca6 100644\n--- a/mailinfo.c\n+++ b/mailinfo.c\n@@ -729,6 +729,8 @@ static int is_rfc2822_header(const struct strbuf *line)\n \n static int read_one_header_line(struct strbuf *line, FILE *in)\n {\n+\tstruct strbuf continuation = STRBUF_INIT;\n+\n \t/* Get the first part of the line. */\n \tif (strbuf_getline(line, in, '\\n'))\n \t\treturn 0;\n@@ -750,7 +752,6 @@ static int read_one_header_line(struct strbuf *line, FILE *in)\n \t */\n \tfor (;;) {\n \t\tint peek;\n-\t\tstruct strbuf continuation = STRBUF_INIT;\n \n \t\tpeek = fgetc(in); ungetc(peek, in);\n \t\tif (peek != ' ' && peek != '\\t')\n@@ -761,6 +762,7 @@ static int read_one_header_line(struct strbuf *line, FILE *in)\n \t\tstrbuf_rtrim(&continuation);\n \t\tstrbuf_addbuf(line, &continuation);\n \t}\n+\tstrbuf_release(&continuation);\n \n \treturn 1;\n }\ndiff --git a/mailinfo.h b/mailinfo.h\nindex 5bf257d..93776a7 100644\n--- a/mailinfo.h\n+++ b/mailinfo.h\n@@ -14,7 +14,7 @@ struct mailinfo {\n \tint keep_non_patch_brackets_in_subject;\n \tint add_message_id;\n \tint use_scissors;\n-\tint use_inbody_headers; /* defaults to 1 */\n+\tint use_inbody_headers;\n \tconst char *metainfo_charset;\n \n \tstruct strbuf *content[MAX_BOUNDARIES];\n"},{"id":"272241","messageId":"alpine.DEB.1.00.1510261524000.31610@s15462909.onlinehome-server.info","threadId":"40552","inReplyTo":"5627EFE4.1060106@kdbg.org","subject":"Re: [PATCH v3 00/34] libify mailinfo and call it directly from am","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2015-10-26T14:25:25Z","receivedAt":"2015-10-26T14:25:25Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Wed, 21 Oct 2015, Johannes Sixt wrote:\n\n> Am 21.10.2015 um 17:51 schrieb Ramsay Jones:\n> > On 20/10/15 22:24, Junio C Hamano wrote:\n> > > Junio C Hamano <gitster@pobox.com> writes:\n> > > some numbers on my desktop (Dell T3500 2.66GHz Xeon X5650 with 12GB,\n> > > running Ubuntu),\n> >\n> > I suspect that I haven't tested exactly the same version as you, but I had\n> > a quick look at testing this on Cygwin today. I have included a complete\n> > transcript (below), so you can see what I did wrong! :-P\n> >\n> > >\n> > > Between 'master' and the version with this series (on 'jch'),\n> > > applying this 34-patch series itself on top of 'master' using \"git\n> > > am\", best of 5 numbers for running:\n> > >\n> > >      time git am mbox >/dev/null\n> > >\n> > > are\n> > >\n> > >        (master)                 (with the series)\n> > >      real    0m0.648s            real    0m0.537s\n> > >      user    0m0.358s            user    0m0.338s\n> > >      sys     0m0.172s            sys     0m0.154s\n> > >\n> >\n> > The corresponding times for me were:\n> >\n> >      (master)           (with the series)\n> >    real\t0m9.760s      real\t0m5.744s\n> >    user\t0m0.531s      user\t0m0.656s\n> >    sys\t0m5.726s      sys\t0m3.520s\n> >\n> > So, yes, a noticeable improvement! :)\n> \n> Same here, on Windows built with the old msysgit environment:\n> \n> (master)             (with the series)\n> real    0m3.147s      real    0m1.947s\n> user    0m0.016s      user    0m0.000s\n> sys     0m0.015s      sys     0m0.031s\n> \n> Although I tested 'git am patches/*' where the patches/* are the result of\n> 'git-format-patch v2.6.1..github/jc/mailinfo-lib'.\n\n2.548s vs 2.068s here.\n\nCiao,\nJohannes\n"},{"id":"272251","messageId":"xmqq4mhdii92.fsf@gitster.mtv.corp.google.com","threadId":"40552","inReplyTo":"alpine.DEB.1.00.1510261524000.31610@s15462909.onlinehome-server.info","subject":"Re: [PATCH v3 00/34] libify mailinfo and call it directly from am","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-26T18:42:33Z","receivedAt":"2015-10-26T18:42:33Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n>> > The corresponding times for me were:\n>> >\n>> >      (master)           (with the series)\n>> >    real\t0m9.760s      real\t0m5.744s\n>> >    user\t0m0.531s      user\t0m0.656s\n>> >    sys\t0m5.726s      sys\t0m3.520s\n>> >\n>> > So, yes, a noticeable improvement! :)\n>> \n>> Same here, on Windows built with the old msysgit environment:\n>> \n>> (master)             (with the series)\n>> real    0m3.147s      real    0m1.947s\n>> user    0m0.016s      user    0m0.000s\n>> sys     0m0.015s      sys     0m0.031s\n>> \n>> Although I tested 'git am patches/*' where the patches/* are the result of\n>> 'git-format-patch v2.6.1..github/jc/mailinfo-lib'.\n>\n> 2.548s vs 2.068s here.\n>\n> Ciao,\n> Johannes\n\nThanks.  Let's start thinking about moving it forward.\n"}]}