From 3eefc189172b88dece6fb6d479b3ed13cc483dbc Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 18 Apr 2006 16:45:27 -0700 Subject: Tentative built-in format-patch. This only does --stdout right now. To write into separate files with pretty-printed filenames like the real thing does, it needs a bit mroe work. Signed-off-by: Junio C Hamano --- commit.c | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) (limited to 'commit.c') diff --git a/commit.c b/commit.c index 2717dd81c3..af747bde61 100644 --- a/commit.c +++ b/commit.c @@ -36,6 +36,8 @@ enum cmit_fmt get_commit_format(const char *arg) return CMIT_FMT_FULL; if (!strcmp(arg, "=fuller")) return CMIT_FMT_FULLER; + if (!strcmp(arg, "=email")) + return CMIT_FMT_EMAIL; if (!strcmp(arg, "=oneline")) return CMIT_FMT_ONELINE; die("invalid --pretty format"); @@ -428,6 +430,10 @@ static int add_user_info(const char *what, enum cmit_fmt fmt, char *buf, const c time = strtoul(date, &date, 10); tz = strtol(date, NULL, 10); + if (fmt == CMIT_FMT_EMAIL) { + what = "From"; + filler = ""; + } ret = sprintf(buf, "%s: %.*s%.*s\n", what, (fmt == CMIT_FMT_FULLER) ? 4 : 0, filler, namelen, line); @@ -435,6 +441,9 @@ static int add_user_info(const char *what, enum cmit_fmt fmt, char *buf, const c case CMIT_FMT_MEDIUM: ret += sprintf(buf + ret, "Date: %s\n", show_date(time, tz)); break; + case CMIT_FMT_EMAIL: + ret += sprintf(buf + ret, "Date: %s\n", show_date(time, tz)); + break; case CMIT_FMT_FULLER: ret += sprintf(buf + ret, "%sDate: %s\n", what, show_date(time, tz)); break; @@ -445,10 +454,12 @@ static int add_user_info(const char *what, enum cmit_fmt fmt, char *buf, const c return ret; } -static int is_empty_line(const char *line, int len) +static int is_empty_line(const char *line, int *len_p) { + int len = *len_p; while (len && isspace(line[len-1])) len--; + *len_p = len; return !len; } @@ -457,7 +468,8 @@ static int add_merge_info(enum cmit_fmt fmt, char *buf, const struct commit *com struct commit_list *parent = commit->parents; int offset; - if ((fmt == CMIT_FMT_ONELINE) || !parent || !parent->next) + if ((fmt == CMIT_FMT_ONELINE) || (fmt == CMIT_FMT_EMAIL) || + !parent || !parent->next) return 0; offset = sprintf(buf, "Merge:"); @@ -480,9 +492,15 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit { int hdr = 1, body = 0; unsigned long offset = 0; - int indent = (fmt == CMIT_FMT_ONELINE) ? 0 : 4; + int indent = 4; int parents_shown = 0; const char *msg = commit->buffer; + const char *subject = NULL; + + if (fmt == CMIT_FMT_EMAIL) + subject = "Subject: "; + if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL) + indent = 0; for (;;) { const char *line = msg; @@ -506,7 +524,7 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit if (hdr) { if (linelen == 1) { hdr = 0; - if (fmt != CMIT_FMT_ONELINE) + if ((fmt != CMIT_FMT_ONELINE) && !subject) buf[offset++] = '\n'; continue; } @@ -544,20 +562,28 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit continue; } - if (is_empty_line(line, linelen)) { + if (is_empty_line(line, &linelen)) { if (!body) continue; + if (subject) + continue; if (fmt == CMIT_FMT_SHORT) break; } else { body = 1; } + if (subject) { + memcpy(buf + offset, subject, 9); + offset += 9; + } memset(buf + offset, ' ', indent); memcpy(buf + offset + indent, line, linelen); offset += linelen + indent; + buf[offset++] = '\n'; if (fmt == CMIT_FMT_ONELINE) break; + subject = NULL; } while (offset && isspace(buf[offset-1])) offset--; -- cgit v1.2.3 From 4c4b158b8f31a19f724a84b11fa538bfbf465d32 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 19 Apr 2006 15:16:08 -0700 Subject: Minor tweak on subject line in --pretty=email Signed-off-by: Junio C Hamano --- commit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'commit.c') diff --git a/commit.c b/commit.c index af747bde61..06e00987cc 100644 --- a/commit.c +++ b/commit.c @@ -498,7 +498,7 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit const char *subject = NULL; if (fmt == CMIT_FMT_EMAIL) - subject = "Subject: "; + subject = "Subject: [PATCH] "; if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL) indent = 0; -- cgit v1.2.3 From 53f420ef00ca6cc3554084c4c9fb89f50c634f58 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 22 Apr 2006 03:06:13 -0700 Subject: git-fmt-patch: thinkofix to show [PATCH] properly. Updating "subject" variable without changing the hardcoded number of bytes to memcpy from it would not help much. Signed-off-by: Junio C Hamano --- commit.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'commit.c') diff --git a/commit.c b/commit.c index 06e00987cc..f4e4eea014 100644 --- a/commit.c +++ b/commit.c @@ -574,8 +574,9 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit } if (subject) { - memcpy(buf + offset, subject, 9); - offset += 9; + int slen = strlen(subject); + memcpy(buf + offset, subject, slen); + offset += slen; } memset(buf + offset, ' ', indent); memcpy(buf + offset + indent, line, linelen); -- cgit v1.2.3 From 2a3870432395e78c82a870bf1a177b8d5b8fbdf0 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 1 May 2006 01:44:33 -0700 Subject: Use RFC2822 dates from "git fmt-patch". Still Work-in-progress git fmt-patch (should it be known as format-patch-ng?) is matched with the fix made by Huw Davies in 262a6ef76a1dde97ab50d79fa5cd6d3f9f125765 commit to use RFC2822 date format. Signed-off-by: Junio C Hamano --- commit.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'commit.c') diff --git a/commit.c b/commit.c index f4e4eea014..42b44bba52 100644 --- a/commit.c +++ b/commit.c @@ -442,7 +442,8 @@ static int add_user_info(const char *what, enum cmit_fmt fmt, char *buf, const c ret += sprintf(buf + ret, "Date: %s\n", show_date(time, tz)); break; case CMIT_FMT_EMAIL: - ret += sprintf(buf + ret, "Date: %s\n", show_date(time, tz)); + ret += sprintf(buf + ret, "Date: %s\n", + show_rfc2822_date(time, tz)); break; case CMIT_FMT_FULLER: ret += sprintf(buf + ret, "%sDate: %s\n", what, show_date(time, tz)); -- cgit v1.2.3 From 596524b33d50e47e2375cec9e00aff59f0e8278b Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 5 May 2006 04:30:52 +0200 Subject: Teach fmt-patch about --numbered Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- commit.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'commit.c') diff --git a/commit.c b/commit.c index 42b44bba52..93b3903ea7 100644 --- a/commit.c +++ b/commit.c @@ -489,17 +489,14 @@ static int add_merge_info(enum cmit_fmt fmt, char *buf, const struct commit *com return offset; } -unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit, unsigned long len, char *buf, unsigned long space, int abbrev) +unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit, unsigned long len, char *buf, unsigned long space, int abbrev, const char *subject) { int hdr = 1, body = 0; unsigned long offset = 0; int indent = 4; int parents_shown = 0; const char *msg = commit->buffer; - const char *subject = NULL; - if (fmt == CMIT_FMT_EMAIL) - subject = "Subject: [PATCH] "; if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL) indent = 0; -- cgit v1.2.3 From 698ce6f87e0d6db380f7306e190e8586da184577 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 20 May 2006 15:40:29 +0200 Subject: fmt-patch: Support --attach This patch touches a couple of files, because it adds options to print a custom text just after the subject of a commit, and just after the diffstat. [jc: made "many dashes" used as the boundary leader into a single variable, to reduce the possibility of later tweaks to miscount the number of dashes to break it.] Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- commit.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'commit.c') diff --git a/commit.c b/commit.c index 84558bac29..0b163d4857 100644 --- a/commit.c +++ b/commit.c @@ -498,7 +498,7 @@ static int add_merge_info(enum cmit_fmt fmt, char *buf, const struct commit *com return offset; } -unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit, unsigned long len, char *buf, unsigned long space, int abbrev, const char *subject) +unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit, unsigned long len, char *buf, unsigned long space, int abbrev, const char *subject, const char *after_subject) { int hdr = 1, body = 0; unsigned long offset = 0; @@ -591,6 +591,14 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit buf[offset++] = '\n'; if (fmt == CMIT_FMT_ONELINE) break; + if (after_subject) { + int slen = strlen(after_subject); + if (slen > space - offset - 1) + slen = space - offset - 1; + memcpy(buf + offset, after_subject, slen); + offset += slen; + after_subject = NULL; + } subject = NULL; } while (offset && isspace(buf[offset-1])) -- cgit v1.2.3 From cdd406e389bd6e0b2ad9394340a366c0c5ae27fc Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 16 May 2006 02:29:42 -0700 Subject: CMIT_FMT_EMAIL: Q-encode Subject: and display-name part of From: fields. By convention, the commit message and the author/committer names in the commit objects are UTF-8 encoded. When formatting for e-mails, Q-encode them according to RFC 2047. While we are at it, generate the content-type and content-transfer-encoding headers as well. Signed-off-by: Junio C Hamano --- commit.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 72 insertions(+), 7 deletions(-) (limited to 'commit.c') diff --git a/commit.c b/commit.c index 0b163d4857..7597fba70a 100644 --- a/commit.c +++ b/commit.c @@ -422,6 +422,46 @@ static int get_one_line(const char *msg, unsigned long len) return ret; } +static int is_rfc2047_special(char ch) +{ + return ((ch & 0x80) || (ch == '=') || (ch == '?') || (ch == '_')); +} + +static int add_rfc2047(char *buf, const char *line, int len) +{ + char *bp = buf; + int i, needquote; + static const char q_utf8[] = "=?utf-8?q?"; + + for (i = needquote = 0; !needquote && i < len; i++) { + unsigned ch = line[i]; + if (ch & 0x80) + needquote++; + if ((i + 1 < len) && + (ch == '=' && line[i+1] == '?')) + needquote++; + } + if (!needquote) + return sprintf(buf, "%.*s", len, line); + + memcpy(bp, q_utf8, sizeof(q_utf8)-1); + bp += sizeof(q_utf8)-1; + for (i = 0; i < len; i++) { + unsigned ch = line[i]; + if (is_rfc2047_special(ch)) { + sprintf(bp, "=%02X", ch); + bp += 3; + } + else if (ch == ' ') + *bp++ = '_'; + else + *bp++ = ch; + } + memcpy(bp, "?=", 2); + bp += 2; + return bp - buf; +} + static int add_user_info(const char *what, enum cmit_fmt fmt, char *buf, const char *line) { char *date; @@ -440,12 +480,26 @@ static int add_user_info(const char *what, enum cmit_fmt fmt, char *buf, const c tz = strtol(date, NULL, 10); if (fmt == CMIT_FMT_EMAIL) { - what = "From"; + char *name_tail = strchr(line, '<'); + int display_name_length; + if (!name_tail) + return 0; + while (line < name_tail && isspace(name_tail[-1])) + name_tail--; + display_name_length = name_tail - line; filler = ""; + strcpy(buf, "From: "); + ret = strlen(buf); + ret += add_rfc2047(buf + ret, line, display_name_length); + memcpy(buf + ret, name_tail, namelen - display_name_length); + ret += namelen - display_name_length; + buf[ret++] = '\n'; + } + else { + ret = sprintf(buf, "%s: %.*s%.*s\n", what, + (fmt == CMIT_FMT_FULLER) ? 4 : 0, + filler, namelen, line); } - ret = sprintf(buf, "%s: %.*s%.*s\n", what, - (fmt == CMIT_FMT_FULLER) ? 4 : 0, - filler, namelen, line); switch (fmt) { case CMIT_FMT_MEDIUM: ret += sprintf(buf + ret, "Date: %s\n", show_date(time, tz)); @@ -584,13 +638,24 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit int slen = strlen(subject); memcpy(buf + offset, subject, slen); offset += slen; + offset += add_rfc2047(buf + offset, line, linelen); + } + else { + memset(buf + offset, ' ', indent); + memcpy(buf + offset + indent, line, linelen); + offset += linelen + indent; } - memset(buf + offset, ' ', indent); - memcpy(buf + offset + indent, line, linelen); - offset += linelen + indent; buf[offset++] = '\n'; if (fmt == CMIT_FMT_ONELINE) break; + if (subject) { + static const char header[] = + "Content-Type: text/plain; charset=UTF-8\n" + "Content-Transfer-Encoding: 8bit\n"; + memcpy(buf + offset, header, sizeof(header)-1); + offset += sizeof(header)-1; + subject = NULL; + } if (after_subject) { int slen = strlen(after_subject); if (slen > space - offset - 1) -- cgit v1.2.3 From c831da664799eb4dbf082a843c34c66889548768 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 21 May 2006 23:55:00 -0700 Subject: builtin format-patch: squelch content-type for 7-bit ASCII When --attach is not used, usually we do not say Content-Type: and fluff, but if the commit message is not 7-bit ASCII, mark it as "text/plain; charset=UTF-8". This unclutters output somewhat. Signed-off-by: Junio C Hamano --- commit.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'commit.c') diff --git a/commit.c b/commit.c index 7597fba70a..94f470b75c 100644 --- a/commit.c +++ b/commit.c @@ -559,10 +559,24 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit int indent = 4; int parents_shown = 0; const char *msg = commit->buffer; + int plain_non_ascii = 0; if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL) indent = 0; + /* After-subject is used to pass in Content-Type: multipart + * MIME header; in that case we do not have to do the + * plaintext content type even if the commit message has + * non 7-bit ASCII character. Otherwise, check if we need + * to say this is not a 7-bit ASCII. + */ + if (fmt == CMIT_FMT_EMAIL && !after_subject) { + int i; + for (i = 0; !plain_non_ascii && msg[i] && i < len; i++) + if (msg[i] & 0x80) + plain_non_ascii = 1; + } + for (;;) { const char *line = msg; int linelen = get_one_line(msg, len); @@ -648,13 +662,12 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit buf[offset++] = '\n'; if (fmt == CMIT_FMT_ONELINE) break; - if (subject) { + if (subject && plain_non_ascii) { static const char header[] = "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n"; memcpy(buf + offset, header, sizeof(header)-1); offset += sizeof(header)-1; - subject = NULL; } if (after_subject) { int slen = strlen(after_subject); -- cgit v1.2.3