diff options
author | Junio C Hamano <gitster@pobox.com> | 2009-08-22 05:47:44 +0400 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2009-08-22 05:47:44 +0400 |
commit | bcd45e27d8790d8981d4c6734bc573363121efd3 (patch) | |
tree | 8693e3c78697d0ad72c976e798276c635bbc15cf | |
parent | f5d5ea525b6aa8b6435d4e8c92f5e797b4076fc0 (diff) | |
parent | c2ca1d79dbd54b06a05e5d14a897699e59dc9f9f (diff) |
Merge branch 'bc/mailsplit-cr-at-eol'
* bc/mailsplit-cr-at-eol:
Allow mailsplit (and hence git-am) to handle mails with CRLF line-endings
builtin-mailsplit.c: remove read_line_with_nul() since it is no longer used
builtin-mailinfo,builtin-mailsplit: use strbufs
strbuf: add new function strbuf_getwholeline()
-rw-r--r-- | builtin-mailinfo.c | 8 | ||||
-rw-r--r-- | builtin-mailsplit.c | 45 | ||||
-rw-r--r-- | builtin.h | 1 | ||||
-rwxr-xr-x | git-am.sh | 8 | ||||
-rw-r--r-- | strbuf.c | 15 | ||||
-rw-r--r-- | strbuf.h | 1 | ||||
-rwxr-xr-x | t/t3400-rebase.sh | 26 |
7 files changed, 61 insertions, 43 deletions
diff --git a/builtin-mailinfo.c b/builtin-mailinfo.c index 92637ac0ba..b0b5d8f6cb 100644 --- a/builtin-mailinfo.c +++ b/builtin-mailinfo.c @@ -765,7 +765,6 @@ static void handle_filter(struct strbuf *line) static void handle_body(void) { - int len = 0; struct strbuf prev = STRBUF_INIT; /* Skip up to the first boundary */ @@ -775,8 +774,6 @@ static void handle_body(void) } do { - strbuf_setlen(&line, line.len + len); - /* process any boundary lines */ if (*content_top && is_multipart_boundary(&line)) { /* flush any leftover */ @@ -832,10 +829,7 @@ static void handle_body(void) handle_filter(&line); } - strbuf_reset(&line); - if (strbuf_avail(&line) < 100) - strbuf_grow(&line, 100); - } while ((len = read_line_with_nul(line.buf, strbuf_avail(&line), fin))); + } while (!strbuf_getwholeline(&line, fin, '\n')); handle_body_out: strbuf_release(&prev); diff --git a/builtin-mailsplit.c b/builtin-mailsplit.c index ad5f6b593d..ee6ca0ebcd 100644 --- a/builtin-mailsplit.c +++ b/builtin-mailsplit.c @@ -7,6 +7,7 @@ #include "cache.h" #include "builtin.h" #include "string-list.h" +#include "strbuf.h" static const char git_mailsplit_usage[] = "git mailsplit [-d<prec>] [-f<n>] [-b] -o<directory> [<mbox>|<Maildir>...]"; @@ -42,26 +43,8 @@ static int is_from_line(const char *line, int len) return 1; } -/* Could be as small as 64, enough to hold a Unix "From " line. */ -static char buf[4096]; - -/* We cannot use fgets() because our lines can contain NULs */ -int read_line_with_nul(char *buf, int size, FILE *in) -{ - int len = 0, c; - - for (;;) { - c = getc(in); - if (c == EOF) - break; - buf[len++] = c; - if (c == '\n' || len + 1 >= size) - break; - } - buf[len] = '\0'; - - return len; -} +static struct strbuf buf = STRBUF_INIT; +static int keep_cr; /* Called with the first line (potentially partial) * already in buf[] -- normally that should begin with @@ -71,10 +54,9 @@ int read_line_with_nul(char *buf, int size, FILE *in) static int split_one(FILE *mbox, const char *name, int allow_bare) { FILE *output = NULL; - int len = strlen(buf); int fd; int status = 0; - int is_bare = !is_from_line(buf, len); + int is_bare = !is_from_line(buf.buf, buf.len); if (is_bare && !allow_bare) goto corrupt; @@ -88,20 +70,23 @@ static int split_one(FILE *mbox, const char *name, int allow_bare) * "From " and having something that looks like a date format. */ for (;;) { - int is_partial = len && buf[len-1] != '\n'; + if (!keep_cr && buf.len > 1 && buf.buf[buf.len-1] == '\n' && + buf.buf[buf.len-2] == '\r') { + strbuf_setlen(&buf, buf.len-2); + strbuf_addch(&buf, '\n'); + } - if (fwrite(buf, 1, len, output) != len) + if (fwrite(buf.buf, 1, buf.len, output) != buf.len) die_errno("cannot write output"); - len = read_line_with_nul(buf, sizeof(buf), mbox); - if (len == 0) { + if (strbuf_getwholeline(&buf, mbox, '\n')) { if (feof(mbox)) { status = 1; break; } die_errno("cannot read mbox"); } - if (!is_partial && !is_bare && is_from_line(buf, len)) + if (!is_bare && is_from_line(buf.buf, buf.len)) break; /* done with one message */ } fclose(output); @@ -166,7 +151,7 @@ static int split_maildir(const char *maildir, const char *dir, goto out; } - if (fgets(buf, sizeof(buf), f) == NULL) { + if (strbuf_getwholeline(&buf, f, '\n')) { error("cannot read mail %s (%s)", file, strerror(errno)); goto out; } @@ -203,7 +188,7 @@ static int split_mbox(const char *file, const char *dir, int allow_bare, } while (isspace(peek)); ungetc(peek, f); - if (fgets(buf, sizeof(buf), f) == NULL) { + if (strbuf_getwholeline(&buf, f, '\n')) { /* empty stdin is OK */ if (f != stdin) { error("cannot read mbox %s", file); @@ -248,6 +233,8 @@ int cmd_mailsplit(int argc, const char **argv, const char *prefix) nr = strtol(arg+2, NULL, 10); } else if ( arg[1] == 'b' && !arg[2] ) { allow_bare = 1; + } else if (!strcmp(arg, "--keep-cr")) { + keep_cr = 1; } else if ( arg[1] == 'o' && arg[2] ) { dir = arg+2; } else if ( arg[1] == '-' && !arg[2] ) { @@ -13,7 +13,6 @@ extern const char git_more_info_string[]; extern void list_common_cmds_help(void); extern const char *help_unknown_cmd(const char *cmd); extern void prune_packed_objects(int); -extern int read_line_with_nul(char *buf, int size, FILE *file); extern int fmt_merge_msg(int merge_summary, struct strbuf *in, struct strbuf *out); extern int commit_tree(const char *msg, unsigned char *tree, @@ -211,7 +211,13 @@ check_patch_format () { split_patches () { case "$patch_format" in mbox) - git mailsplit -d"$prec" -o"$dotest" -b -- "$@" > "$dotest/last" || + case "$rebasing" in + '') + keep_cr= ;; + ?*) + keep_cr=--keep-cr ;; + esac + git mailsplit -d"$prec" -o"$dotest" -b $keep_cr -- "$@" > "$dotest/last" || clean_abort ;; stgit-series) @@ -322,7 +322,7 @@ int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint) return -1; } -int strbuf_getline(struct strbuf *sb, FILE *fp, int term) +int strbuf_getwholeline(struct strbuf *sb, FILE *fp, int term) { int ch; @@ -332,10 +332,10 @@ int strbuf_getline(struct strbuf *sb, FILE *fp, int term) strbuf_reset(sb); while ((ch = fgetc(fp)) != EOF) { - if (ch == term) - break; strbuf_grow(sb, 1); sb->buf[sb->len++] = ch; + if (ch == term) + break; } if (ch == EOF && sb->len == 0) return EOF; @@ -344,6 +344,15 @@ int strbuf_getline(struct strbuf *sb, FILE *fp, int term) return 0; } +int strbuf_getline(struct strbuf *sb, FILE *fp, int term) +{ + if (strbuf_getwholeline(sb, fp, term)) + return EOF; + if (sb->buf[sb->len-1] == term) + strbuf_setlen(sb, sb->len-1); + return 0; +} + int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint) { int fd, len; @@ -126,6 +126,7 @@ extern ssize_t strbuf_read(struct strbuf *, int fd, size_t hint); extern int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint); extern int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint); +extern int strbuf_getwholeline(struct strbuf *, FILE *, int); extern int strbuf_getline(struct strbuf *, FILE *, int); extern void stripspace(struct strbuf *buf, int skip_comments); diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh index c5c29ccc4f..4e6a44b623 100755 --- a/t/t3400-rebase.sh +++ b/t/t3400-rebase.sh @@ -3,9 +3,10 @@ # Copyright (c) 2005 Amos Waterland # -test_description='git rebase should not destroy author information +test_description='git rebase assorted tests -This test runs git rebase and checks that the author information is not lost. +This test runs git rebase and checks that the author information is not lost +among other things. ' . ./test-lib.sh @@ -133,4 +134,25 @@ test_expect_success 'rebase -q is quiet' ' test ! -s output.out ' +q_to_cr () { + tr Q '\015' +} + +test_expect_success 'Rebase a commit that sprinkles CRs in' ' + ( + echo "One" + echo "TwoQ" + echo "Three" + echo "FQur" + echo "Five" + ) | q_to_cr >CR && + git add CR && + test_tick && + git commit -a -m "A file with a line with CR" && + git tag file-with-cr && + git checkout HEAD^0 && + git rebase --onto HEAD^^ HEAD^ && + git diff --exit-code file-with-cr:CR HEAD:CR +' + test_done |