summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--builtin-mailinfo.c8
-rw-r--r--builtin-mailsplit.c45
-rw-r--r--builtin.h1
-rwxr-xr-xgit-am.sh8
-rw-r--r--strbuf.c15
-rw-r--r--strbuf.h1
-rwxr-xr-xt/t3400-rebase.sh26
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] ) {
diff --git a/builtin.h b/builtin.h
index 20427d2963..9993dfcf99 100644
--- a/builtin.h
+++ b/builtin.h
@@ -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,
diff --git a/git-am.sh b/git-am.sh
index f719f6e654..5396be2279 100755
--- a/git-am.sh
+++ b/git-am.sh
@@ -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)
diff --git a/strbuf.c b/strbuf.c
index f03d11702b..a6153dca27 100644
--- a/strbuf.c
+++ b/strbuf.c
@@ -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;
diff --git a/strbuf.h b/strbuf.h
index eaa8704d5f..d05e056dd3 100644
--- a/strbuf.h
+++ b/strbuf.h
@@ -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