From: Junio C Hamano Date: Fri, 23 Feb 2007 05:34:36 +0000 (-0800) Subject: Merge branches 'lt/crlf' and 'jc/apply-config' X-Git-Tag: v1.5.1-rc1~258 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/ef1a5c2fa8bc67abea6cbacf975ea3260cd40fa3?hp=-c Merge branches 'lt/crlf' and 'jc/apply-config' * lt/crlf: Teach core.autocrlf to 'git apply' t0020: add test for auto-crlf Make AutoCRLF ternary variable. Lazy man's auto-CRLF * jc/apply-config: t4119: test autocomputing -p for traditional diff input. git-apply: guess correct -p value for non-git patches. git-apply: notice "diff --git" patch again Fix botched "leak fix" t4119: add test for traditional patch and different p_value apply: fix memory leak in prefix_one() git-apply: require -p when working in a subdirectory. git-apply: do not lose cwd when run from a subdirectory. Teach 'git apply' to look at $HOME/.gitconfig even outside of a repository Teach 'git apply' to look at $GIT_DIR/config --- ef1a5c2fa8bc67abea6cbacf975ea3260cd40fa3 diff --combined Makefile index 35be5e2049,60496ff957,40bdcff696..fbe05f938e --- a/Makefile +++ b/Makefile @@@@ -28,10 -28,6 -28,6 +28,10 @@@@ all: # # Define NO_STRLCPY if you don't have strlcpy. # ++# Define NO_STRTOUMAX if you don't have strtoumax in the C library. ++# If your compiler also does not support long long or does not have ++# strtoull, define NO_STRTOULL. ++# # Define NO_SETENV if you don't have setenv in the C library. # # Define NO_SYMLINK_HEAD if you never want .git/HEAD to be a symbolic link. @@@@ -176,7 -172,7 -172,7 +176,7 @@@@ SCRIPT_SH = git-merge-one-file.sh git-parse-remote.sh \ git-pull.sh git-rebase.sh \ git-repack.sh git-request-pull.sh git-reset.sh \ -- git-resolve.sh git-revert.sh git-sh-setup.sh \ ++ git-revert.sh git-sh-setup.sh \ git-tag.sh git-verify-tag.sh \ git-applymbox.sh git-applypatch.sh git-am.sh \ git-merge.sh git-merge-stupid.sh git-merge-octopus.sh \ @@@@ -266,7 -262,8 -262,7 +266,8 @@@@ LIB_OBJS = revision.o pager.o tree-walk.o xdiff-interface.o \ write_or_die.o trace.o list-objects.o grep.o \ alloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS) \ - - color.o wt-status.o archive-zip.o archive-tar.o shallow.o utf8.o + + color.o wt-status.o archive-zip.o archive-tar.o shallow.o utf8.o \ + + convert.o BUILTIN_OBJS = \ builtin-add.o \ @@@@ -284,6 -281,7 -280,7 +285,6 @@@@ builtin-diff.o \ builtin-diff-files.o \ builtin-diff-index.o \ -- builtin-diff-stages.o \ builtin-diff-tree.o \ builtin-fmt-merge-msg.o \ builtin-for-each-ref.o \ @@@@ -295,7 -293,6 -292,6 +296,7 @@@@ builtin-ls-tree.o \ builtin-mailinfo.o \ builtin-mailsplit.o \ ++ builtin-merge-base.o \ builtin-merge-file.o \ builtin-mv.o \ builtin-name-rev.o \ @@@@ -357,13 -354,11 -353,11 +358,13 @@@@ ifeq ($(uname_S),SunOS NO_UNSETENV = YesPlease NO_SETENV = YesPlease NO_C99_FORMAT = YesPlease ++ NO_STRTOUMAX = YesPlease endif ifeq ($(uname_R),5.9) NO_UNSETENV = YesPlease NO_SETENV = YesPlease NO_C99_FORMAT = YesPlease ++ NO_STRTOUMAX = YesPlease endif INSTALL = ginstall TAR = gtar @@@@ -523,13 -518,6 -517,6 +524,13 @@@@ ifdef NO_STRLCP COMPAT_CFLAGS += -DNO_STRLCPY COMPAT_OBJS += compat/strlcpy.o endif ++ifdef NO_STRTOUMAX ++ COMPAT_CFLAGS += -DNO_STRTOUMAX ++ COMPAT_OBJS += compat/strtoumax.o ++endif ++ifdef NO_STRTOULL ++ COMPAT_CFLAGS += -DNO_STRTOULL ++endif ifdef NO_SETENV COMPAT_CFLAGS += -DNO_SETENV COMPAT_OBJS += compat/setenv.o @@@@ -895,8 -883,7 -882,7 +896,8 @@@@ dist: git.spec git-archiv $(TAR) rf $(GIT_TARNAME).tar \ $(GIT_TARNAME)/git.spec \ $(GIT_TARNAME)/version \ -- $(GIT_TARNAME)/git-gui/version ++ $(GIT_TARNAME)/git-gui/version \ ++ $(GIT_TARNAME)/git-gui/credits @rm -rf $(GIT_TARNAME) gzip -f -9 $(GIT_TARNAME).tar @@@@ -953,14 -940,11 -939,11 +954,14 @@@@ check-docs: case "$$v" in \ git-merge-octopus | git-merge-ours | git-merge-recursive | \ git-merge-resolve | git-merge-stupid | \ ++ git-add--interactive | git-fsck-objects | git-init-db | \ ++ git-repo-config | \ git-ssh-pull | git-ssh-push ) continue ;; \ esac ; \ test -f "Documentation/$$v.txt" || \ echo "no doc: $$v"; \ -- grep -q "^gitlink:$$v\[[0-9]\]::" Documentation/git.txt || \ ++ sed -e '1,/^__DATA__/d' Documentation/cmd-list.perl | \ ++ grep -q "^$$v[ ]" || \ case "$$v" in \ git) ;; \ *) echo "no link: $$v";; \ diff --combined builtin-apply.c index d67817834b,45c4acbd20,c7d4bdd474..630d8fd652 --- a/builtin-apply.c +++ b/builtin-apply.c @@@@ -28,6 -28,6 -28,7 +28,7 @@@@ static int newfd = -1 static int unidiff_zero; static int p_value = 1; ++ static int p_value_known; static int check_index; static int write_index; static int cached; @@@@ -144,6 -144,6 -145,7 +145,7 @@@@ struct patch unsigned long deflate_origlen; int lines_added, lines_deleted; int score; ++ unsigned int is_toplevel_relative:1; unsigned int inaccurate_eof:1; unsigned int is_binary:1; unsigned int is_copy:1; @@@@ -238,7 -238,7 -240,7 +240,7 @@@@ static int name_terminate(const char *n return 1; } -- static char * find_name(const char *line, char *def, int p_value, int terminate) ++ static char *find_name(const char *line, char *def, int p_value, int terminate) { int len; const char *start = line; @@@@ -311,11 -311,11 -313,54 +313,54 @@@@ return name; } ++ static int count_slashes(const char *cp) ++ { ++ int cnt = 0; ++ char ch; ++ ++ while ((ch = *cp++)) ++ if (ch == '/') ++ cnt++; ++ return cnt; ++ } ++ ++ /* ++ * Given the string after "--- " or "+++ ", guess the appropriate ++ * p_value for the given patch. ++ */ ++ static int guess_p_value(const char *nameline) ++ { ++ char *name, *cp; ++ int val = -1; ++ ++ if (is_dev_null(nameline)) ++ return -1; ++ name = find_name(nameline, NULL, 0, TERM_SPACE | TERM_TAB); ++ if (!name) ++ return -1; ++ cp = strchr(name, '/'); ++ if (!cp) ++ val = 0; ++ else if (prefix) { ++ /* ++ * Does it begin with "a/$our-prefix" and such? Then this is ++ * very likely to apply to our directory. ++ */ ++ if (!strncmp(name, prefix, prefix_length)) ++ val = count_slashes(prefix); ++ else { ++ cp++; ++ if (!strncmp(cp, prefix, prefix_length)) ++ val = count_slashes(prefix) + 1; ++ } ++ } ++ free(name); ++ return val; ++ } ++ /* * Get the name etc info from the --/+++ lines of a traditional patch header * -- * NOTE! This hardcodes "-p1" behaviour in filename detection. -- * * FIXME! The end-of-filename heuristics are kind of screwy. For existing * files, we can happily check the index for a match, but for creating a * new file we should try to match whatever "patch" does. I have no idea. @@@@ -326,6 -326,6 -371,16 +371,16 @@@@ static void parse_traditional_patch(con first += 4; /* skip "--- " */ second += 4; /* skip "+++ " */ ++ if (!p_value_known) { ++ int p, q; ++ p = guess_p_value(first); ++ q = guess_p_value(second); ++ if (p < 0) p = q; ++ if (0 <= p && p == q) { ++ p_value = p; ++ p_value_known = 1; ++ } ++ } if (is_dev_null(first)) { patch->is_new = 1; patch->is_delete = 0; @@@@ -787,6 -787,6 -842,7 +842,7 @@@@ static int find_header(char *line, unsi { unsigned long offset, len; ++ patch->is_toplevel_relative = 0; patch->is_rename = patch->is_copy = 0; patch->is_new = patch->is_delete = -1; patch->old_mode = patch->new_mode = 0; @@@@ -831,6 -831,6 -887,7 +887,7 @@@@ die("git diff header lacks filename information (line %d)", linenr); patch->old_name = patch->new_name = patch->def_name; } ++ patch->is_toplevel_relative = 1; *hdrsize = git_hdr_len; return offset; } @@@@ -1129,11 -1129,11 -1186,11 +1186,11 @@@@ static struct fragment *parse_binary_hu *status_p = 0; -- if (!strncmp(buffer, "delta ", 6)) { ++ if (!prefixcmp(buffer, "delta ")) { patch_method = BINARY_DELTA_DEFLATED; origlen = strtoul(buffer + 6, NULL, 10); } -- else if (!strncmp(buffer, "literal ", 8)) { ++ else if (!prefixcmp(buffer, "literal ")) { patch_method = BINARY_LITERAL_DEFLATED; origlen = strtoul(buffer + 8, NULL, 10); } @@@@ -1393,28 -1393,39 -1450,28 +1450,39 @@@@ static void show_stats(struct patch *pa free(qname); } - -static int read_old_data(struct stat *st, const char *path, void *buf, unsigned long size) + +static int read_old_data(struct stat *st, const char *path, char **buf_p, unsigned long *alloc_p, unsigned long *size_p) { int fd; unsigned long got; + + unsigned long nsize; + + char *nbuf; + + unsigned long size = *size_p; + + char *buf = *buf_p; switch (st->st_mode & S_IFMT) { case S_IFLNK: - - return readlink(path, buf, size); + + return readlink(path, buf, size) != size; case S_IFREG: fd = open(path, O_RDONLY); if (fd < 0) return error("unable to open %s", path); got = 0; for (;;) { - - int ret = xread(fd, (char *) buf + got, size - got); + + int ret = xread(fd, buf + got, size - got); if (ret <= 0) break; got += ret; } close(fd); - - return got; - - + + nsize = got; + + nbuf = buf; + + if (convert_to_git(path, &nbuf, &nsize)) { + + free(buf); + + *buf_p = nbuf; + + *alloc_p = nsize; + + *size_p = nsize; + + } + + return got != size; default: return -1; } @@@@ -1910,7 -1921,7 -1967,7 +1978,7 @@@@ static int apply_data(struct patch *pat size = st->st_size; alloc = size + 8192; buf = xmalloc(alloc); - - if (read_old_data(st, patch->old_name, buf, alloc) != size) + + if (read_old_data(st, patch->old_name, &buf, &alloc, &size)) return error("read of %s failed", patch->old_name); } @@@@ -1988,7 -1999,7 -2045,7 +2056,7 @@@@ static int check_patch(struct patch *pa return error("%s: %s", old_name, strerror(errno)); if (!cached) -- st_mode = ntohl(create_ce_mode(st.st_mode)); ++ st_mode = ntohl(ce_mode_from_stat(ce, st.st_mode)); if (patch->is_new < 0) patch->is_new = 0; @@@@ -2232,7 -2243,7 -2289,7 +2300,7 @@@@ static void patch_stats(struct patch *p } } -- static void remove_file(struct patch *patch) ++ static void remove_file(struct patch *patch, int rmdir_empty) { if (write_index) { if (remove_file_from_cache(patch->old_name) < 0) @@@@ -2240,7 -2251,7 -2297,7 +2308,7 @@@@ cache_tree_invalidate_path(active_cache_tree, patch->old_name); } if (!cached) { -- if (!unlink(patch->old_name)) { ++ if (!unlink(patch->old_name) && rmdir_empty) { char *name = xstrdup(patch->old_name); char *end = strrchr(name, '/'); while (end) { @@@@ -2282,12 -2293,22 -2339,12 +2350,22 @@@@ static void add_index_file(const char * static int try_create_file(const char *path, unsigned int mode, const char *buf, unsigned long size) { int fd; + + char *nbuf; + + unsigned long nsize; if (S_ISLNK(mode)) /* Although buf:size is counted string, it also is NUL * terminated. */ return symlink(buf, path); + + nsize = size; + + nbuf = (char *) buf; + + if (convert_to_working_tree(path, &nbuf, &nsize)) { + + free((char *) buf); + + buf = nbuf; + + size = nsize; + + } + + fd = open(path, O_CREAT | O_EXCL | O_WRONLY, (mode & 0100) ? 0777 : 0666); if (fd < 0) return -1; @@@@ -2373,7 -2394,7 -2430,7 +2451,7 @@@@ static void write_out_one_result(struc { if (patch->is_delete > 0) { if (phase == 0) -- remove_file(patch); ++ remove_file(patch, 1); return; } if (patch->is_new > 0 || patch->is_copy) { @@@@ -2386,7 -2407,7 -2443,7 +2464,7 @@@@ * thing: remove the old, write the new */ if (phase == 0) -- remove_file(patch); ++ remove_file(patch, 0); if (phase == 1) create_file(patch); } @@@@ -2508,6 -2529,6 -2565,32 +2586,32 @@@@ static int use_patch(struct patch *p return 1; } ++ static void prefix_one(char **name) ++ { ++ char *old_name = *name; ++ if (!old_name) ++ return; ++ *name = xstrdup(prefix_filename(prefix, prefix_length, *name)); ++ free(old_name); ++ } ++ ++ static void prefix_patches(struct patch *p) ++ { ++ if (!prefix || p->is_toplevel_relative) ++ return; ++ for ( ; p; p = p->next) { ++ if (p->new_name == p->old_name) { ++ char *prefixed = p->new_name; ++ prefix_one(&prefixed); ++ p->new_name = p->old_name = prefixed; ++ } ++ else { ++ prefix_one(&p->new_name); ++ prefix_one(&p->old_name); ++ } ++ } ++ } ++ static int apply_patch(int fd, const char *filename, int inaccurate_eof) { unsigned long offset, size; @@@@ -2530,11 -2551,11 -2613,14 +2634,14 @@@@ break; if (apply_in_reverse) reverse_patches(patch); ++ if (prefix) ++ prefix_patches(patch); if (use_patch(patch)) { patch_stats(patch); *listp = patch; listp = &patch->next; -- } else { ++ } ++ else { /* perhaps free it a bit better? */ free(patch); skipped_patch++; @@@@ -2595,9 -2616,10 -2681,16 +2702,16 @@@@ int cmd_apply(int argc, const char **ar int read_stdin = 1; int inaccurate_eof = 0; int errs = 0; ++ int is_not_gitdir = 0; const char *whitespace_option = NULL; ++ prefix = setup_git_directory_gently(&is_not_gitdir); ++ prefix_length = prefix ? strlen(prefix) : 0; ++ git_config(git_apply_config); ++ if (apply_default_whitespace) ++ parse_whitespace_option(apply_default_whitespace); + for (i = 1; i < argc; i++) { const char *arg = argv[i]; char *end; @@@@ -2608,15 -2630,15 -2701,16 +2722,16 @@@@ read_stdin = 0; continue; } -- if (!strncmp(arg, "--exclude=", 10)) { ++ if (!prefixcmp(arg, "--exclude=")) { struct excludes *x = xmalloc(sizeof(*x)); x->path = arg + 10; x->next = excludes; excludes = x; continue; } -- if (!strncmp(arg, "-p", 2)) { ++ if (!prefixcmp(arg, "-p")) { p_value = atoi(arg + 2); ++ p_value_known = 1; continue; } if (!strcmp(arg, "--no-add")) { @@@@ -2648,10 -2670,10 -2742,14 +2763,14 @@@@ continue; } if (!strcmp(arg, "--index")) { ++ if (is_not_gitdir) ++ die("--index outside a repository"); check_index = 1; continue; } if (!strcmp(arg, "--cached")) { ++ if (is_not_gitdir) ++ die("--cached outside a repository"); check_index = 1; cached = 1; continue; @@@@ -2669,13 -2691,13 -2767,13 +2788,13 @@@@ line_termination = 0; continue; } -- if (!strncmp(arg, "-C", 2)) { ++ if (!prefixcmp(arg, "-C")) { p_context = strtoul(arg + 2, &end, 0); if (*end != '\0') die("unrecognized context count '%s'", arg + 2); continue; } -- if (!strncmp(arg, "--whitespace=", 13)) { ++ if (!prefixcmp(arg, "--whitespace=")) { whitespace_option = arg + 13; parse_whitespace_option(arg + 13); continue; @@@@ -2700,14 -2722,14 -2798,6 +2819,6 @@@@ inaccurate_eof = 1; continue; } -- -- if (check_index && prefix_length < 0) { -- prefix = setup_git_directory(); -- prefix_length = prefix ? strlen(prefix) : 0; -- git_config(git_apply_config); -- if (!whitespace_option && apply_default_whitespace) -- parse_whitespace_option(apply_default_whitespace); -- } if (0 < prefix_length) arg = prefix_filename(prefix, prefix_length, arg); diff --combined cache.h index 04f8e63baf,9c019e8bba,c62b0b090d..8bbc14299d --- a/cache.h +++ b/cache.h @@@@ -106,16 -106,6 -106,6 +106,16 @@@@ static inline unsigned int create_ce_mo return htonl(S_IFLNK); return htonl(S_IFREG | ce_permissions(mode)); } ++static inline unsigned int ce_mode_from_stat(struct cache_entry *ce, unsigned int mode) ++{ ++ extern int trust_executable_bit; ++ if (!trust_executable_bit && S_ISREG(mode)) { ++ if (ce && S_ISREG(ntohl(ce->ce_mode))) ++ return ce->ce_mode; ++ return create_ce_mode(0666); ++ } ++ return create_ce_mode(mode); ++} #define canon_mode(mode) \ (S_ISREG(mode) ? (S_IFREG | ce_permissions(mode)) : \ S_ISLNK(mode) ? S_IFLNK : S_IFDIR) @@@@ -211,6 -201,7 -201,6 +211,7 @@@@ extern const char *apply_default_whites extern int zlib_compression_level; extern size_t packed_git_window_size; extern size_t packed_git_limit; + +extern int auto_crlf; #define GIT_REPO_VERSION 0 extern int repository_format_version; @@@@ -478,4 -469,8 -468,4 +479,8 @@@@ extern int nfvasprintf(char **str, cons extern void trace_printf(const char *format, ...); extern void trace_argv_printf(const char **argv, int count, const char *format, ...); + +/* convert.c */ + +extern int convert_to_git(const char *path, char **bufp, unsigned long *sizep); + +extern int convert_to_working_tree(const char *path, char **bufp, unsigned long *sizep); + + #endif /* CACHE_H */ diff --combined config.c index c938aa0b15,e8ae919b52,d82107124a..8b6cf1aaa5 --- a/config.c +++ b/config.c @@@@ -310,14 -310,12 -310,12 +310,14 @@@@ int git_default_config(const char *var } if (!strcmp(var, "core.packedgitwindowsize")) { -- int pgsz = getpagesize(); ++ int pgsz_x2 = getpagesize() * 2; packed_git_window_size = git_config_int(var, value); -- packed_git_window_size /= pgsz; -- if (packed_git_window_size < 2) -- packed_git_window_size = 2; -- packed_git_window_size *= pgsz; ++ ++ /* This value must be multiple of (pagesize * 2) */ ++ packed_git_window_size /= pgsz_x2; ++ if (packed_git_window_size < 1) ++ packed_git_window_size = 1; ++ packed_git_window_size *= pgsz_x2; return 0; } @@@@ -326,6 -324,15 -324,6 +326,15 @@@@ return 0; } + + if (!strcmp(var, "core.autocrlf")) { + + if (value && !strcasecmp(value, "input")) { + + auto_crlf = -1; + + return 0; + + } + + auto_crlf = git_config_bool(var, value); + + return 0; + + } + + if (!strcmp(var, "user.name")) { strlcpy(git_default_name, value, sizeof(git_default_name)); return 0; diff --combined diff.c index 019ecbc1fa,561587cace,13b9b6c560..5ecb122255 --- a/diff.c +++ b/diff.c @@@@ -77,7 -77,7 -77,7 +77,7 @@@@ int git_diff_ui_config(const char *var diff_detect_rename_default = DIFF_DETECT_RENAME; return 0; } -- if (!strncmp(var, "diff.color.", 11) || !strncmp(var, "color.diff.", 11)) { ++ if (!prefixcmp(var, "diff.color.") || !prefixcmp(var, "color.diff.")) { int slot = parse_diff_color_slot(var, 11); color_parse(value, var, diff_colors[slot]); return 0; @@@@ -184,59 -184,42 -184,42 +184,59 @@@@ static void print_line_count(int count } } --static void copy_file(int prefix, const char *data, int size) ++static void copy_file(int prefix, const char *data, int size, ++ const char *set, const char *reset) { int ch, nl_just_seen = 1; while (0 < size--) { ch = *data++; -- if (nl_just_seen) ++ if (nl_just_seen) { ++ fputs(set, stdout); putchar(prefix); -- putchar(ch); -- if (ch == '\n') ++ } ++ if (ch == '\n') { nl_just_seen = 1; -- else ++ fputs(reset, stdout); ++ } else nl_just_seen = 0; ++ putchar(ch); } if (!nl_just_seen) -- printf("\n\\ No newline at end of file\n"); ++ printf("%s\n\\ No newline at end of file\n", reset); } static void emit_rewrite_diff(const char *name_a, const char *name_b, struct diff_filespec *one, -- struct diff_filespec *two) ++ struct diff_filespec *two, ++ int color_diff) { int lc_a, lc_b; ++ const char *name_a_tab, *name_b_tab; ++ const char *metainfo = diff_get_color(color_diff, DIFF_METAINFO); ++ const char *fraginfo = diff_get_color(color_diff, DIFF_FRAGINFO); ++ const char *old = diff_get_color(color_diff, DIFF_FILE_OLD); ++ const char *new = diff_get_color(color_diff, DIFF_FILE_NEW); ++ const char *reset = diff_get_color(color_diff, DIFF_RESET); ++ ++ name_a_tab = strchr(name_a, ' ') ? "\t" : ""; ++ name_b_tab = strchr(name_b, ' ') ? "\t" : ""; ++ diff_populate_filespec(one, 0); diff_populate_filespec(two, 0); lc_a = count_lines(one->data, one->size); lc_b = count_lines(two->data, two->size); -- printf("--- a/%s\n+++ b/%s\n@@ -", name_a, name_b); ++ printf("%s--- a/%s%s%s\n%s+++ b/%s%s%s\n%s@@ -", ++ metainfo, name_a, name_a_tab, reset, ++ metainfo, name_b, name_b_tab, reset, fraginfo); print_line_count(lc_a); printf(" +"); print_line_count(lc_b); -- printf(" @@\n"); ++ printf(" @@%s\n", reset); if (lc_a) -- copy_file('-', one->data, one->size); ++ copy_file('-', one->data, one->size, old, reset); if (lc_b) -- copy_file('+', two->data, two->size); ++ copy_file('+', two->data, two->size, new, reset); } static int fill_mmfile(mmfile_t *mf, struct diff_filespec *one) @@@@ -415,16 -398,22 -398,22 +415,16 @@@@ static void emit_line(const char *set, puts(reset); } --static void emit_add_line(const char *reset, struct emit_callback *ecbdata, const char *line, int len) ++static void emit_line_with_ws(int nparents, ++ const char *set, const char *reset, const char *ws, ++ const char *line, int len) { -- int col0 = ecbdata->nparents; ++ int col0 = nparents; int last_tab_in_indent = -1; int last_space_in_indent = -1; int i; int tail = len; int need_highlight_leading_space = 0; -- const char *ws = diff_get_color(ecbdata->color_diff, DIFF_WHITESPACE); -- const char *set = diff_get_color(ecbdata->color_diff, DIFF_FILE_NEW); -- -- if (!*ws) { -- emit_line(set, reset, line, len); -- return; -- } -- /* The line is a newly added line. Does it have funny leading * whitespaces? In indent, SP should never precede a TAB. */ @@@@ -479,18 -468,6 -468,6 +479,18 @@@@ emit_line(set, reset, line + i, len - i); } ++static void emit_add_line(const char *reset, struct emit_callback *ecbdata, const char *line, int len) ++{ ++ const char *ws = diff_get_color(ecbdata->color_diff, DIFF_WHITESPACE); ++ const char *set = diff_get_color(ecbdata->color_diff, DIFF_FILE_NEW); ++ ++ if (!*ws) ++ emit_line(set, reset, line, len); ++ else ++ emit_line_with_ws(ecbdata->nparents, set, reset, ws, ++ line, len); ++} ++ static void fn_out_consume(void *priv, char *line, unsigned long len) { int i; @@@@ -500,15 -477,8 -477,8 +500,15 @@@@ const char *reset = diff_get_color(ecbdata->color_diff, DIFF_RESET); if (ecbdata->label_path[0]) { -- printf("%s--- %s%s\n", set, ecbdata->label_path[0], reset); -- printf("%s+++ %s%s\n", set, ecbdata->label_path[1], reset); ++ const char *name_a_tab, *name_b_tab; ++ ++ name_a_tab = strchr(ecbdata->label_path[0], ' ') ? "\t" : ""; ++ name_b_tab = strchr(ecbdata->label_path[1], ' ') ? "\t" : ""; ++ ++ printf("%s--- %s%s%s\n", ++ set, ecbdata->label_path[0], reset, name_a_tab); ++ printf("%s+++ %s%s%s\n", ++ set, ecbdata->label_path[1], reset, name_b_tab); ecbdata->label_path[0] = ecbdata->label_path[1] = NULL; } @@@@ -900,44 -870,30 -870,30 +900,44 @@@@ static void show_numstat(struct diffsta struct checkdiff_t { struct xdiff_emit_state xm; const char *filename; -- int lineno; ++ int lineno, color_diff; }; static void checkdiff_consume(void *priv, char *line, unsigned long len) { struct checkdiff_t *data = priv; ++ const char *ws = diff_get_color(data->color_diff, DIFF_WHITESPACE); ++ const char *reset = diff_get_color(data->color_diff, DIFF_RESET); ++ const char *set = diff_get_color(data->color_diff, DIFF_FILE_NEW); if (line[0] == '+') { -- int i, spaces = 0; ++ int i, spaces = 0, space_before_tab = 0, white_space_at_end = 0; /* check space before tab */ for (i = 1; i < len && (line[i] == ' ' || line[i] == '\t'); i++) if (line[i] == ' ') spaces++; if (line[i - 1] == '\t' && spaces) -- printf("%s:%d: space before tab:%.*s\n", -- data->filename, data->lineno, (int)len, line); ++ space_before_tab = 1; /* check white space at line end */ if (line[len - 1] == '\n') len--; if (isspace(line[len - 1])) -- printf("%s:%d: white space at end: %.*s\n", -- data->filename, data->lineno, (int)len, line); ++ white_space_at_end = 1; ++ ++ if (space_before_tab || white_space_at_end) { ++ printf("%s:%d: %s", data->filename, data->lineno, ws); ++ if (space_before_tab) { ++ printf("space before tab"); ++ if (white_space_at_end) ++ putchar(','); ++ } ++ if (white_space_at_end) ++ printf("white space at end"); ++ printf(":%s ", reset); ++ emit_line_with_ws(1, set, reset, ws, line, len); ++ } data->lineno++; } else if (line[0] == ' ') @@@@ -1094,8 -1050,7 -1050,7 +1094,8 @@@@ static void builtin_diff(const char *na if ((one->mode ^ two->mode) & S_IFMT) goto free_ab_and_return; if (complete_rewrite) { -- emit_rewrite_diff(name_a, name_b, one, two); ++ emit_rewrite_diff(name_a, name_b, one, two, ++ o->color_diff); goto free_ab_and_return; } } @@@@ -1130,9 -1085,9 -1085,9 +1130,9 @@@@ xecfg.flags = XDL_EMIT_FUNCNAMES; if (!diffopts) ; -- else if (!strncmp(diffopts, "--unified=", 10)) ++ else if (!prefixcmp(diffopts, "--unified=")) xecfg.ctxlen = strtoul(diffopts + 10, NULL, 10); -- else if (!strncmp(diffopts, "-u", 2)) ++ else if (!prefixcmp(diffopts, "-u")) xecfg.ctxlen = strtoul(diffopts + 2, NULL, 10); ecb.outf = xdiff_outf; ecb.priv = &ecbdata; @@@@ -1196,7 -1151,7 -1151,7 +1196,7 @@@@ static void builtin_diffstat(const cha static void builtin_checkdiff(const char *name_a, const char *name_b, struct diff_filespec *one, -- struct diff_filespec *two) ++ struct diff_filespec *two, struct diff_options *o) { mmfile_t mf1, mf2; struct checkdiff_t data; @@@@ -1208,7 -1163,6 -1163,6 +1208,7 @@@@ data.xm.consume = checkdiff_consume; data.filename = name_b ? name_b : name_a; data.lineno = 0; ++ data.color_diff = o->color_diff; if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0) die("unable to read files to diff"); @@@@ -1378,6 -1332,9 -1332,6 +1378,9 @@@@ int diff_populate_filespec(struct diff_ reuse_worktree_file(s->path, s->sha1, 0)) { struct stat st; int fd; + + char *buf; + + unsigned long size; + + if (lstat(s->path, &st) < 0) { if (errno == ENOENT) { err_empty: @@@@ -1410,7 -1367,19 -1364,7 +1413,19 @@@@ s->data = xmmap(NULL, s->size, PROT_READ, MAP_PRIVATE, fd, 0); close(fd); s->should_munmap = 1; - - /* FIXME! CRLF -> LF conversion goes here, based on "s->path" */ + + + + /* + + * Convert from working tree format to canonical git format + + */ + + buf = s->data; + + size = s->size; + + if (convert_to_git(s->path, &buf, &size)) { + + munmap(s->data, s->size); + + s->should_munmap = 0; + + s->data = buf; + + s->size = size; + + s->should_free = 1; + + } } else { char type[20]; @@@@ -1819,7 -1788,7 -1773,7 +1834,7 @@@@ static void run_checkdiff(struct diff_f diff_fill_sha1_info(p->one); diff_fill_sha1_info(p->two); -- builtin_checkdiff(name, other, p->one, p->two); ++ builtin_checkdiff(name, other, p->one, p->two, o); } void diff_setup(struct diff_options *options) @@@@ -1968,7 -1937,7 -1922,7 +1983,7 @@@@ int diff_opt_parse(struct diff_options else if (!strcmp(arg, "--shortstat")) { options->output_format |= DIFF_FORMAT_SHORTSTAT; } -- else if (!strncmp(arg, "--stat", 6)) { ++ else if (!prefixcmp(arg, "--stat")) { char *end; int width = options->stat_width; int name_width = options->stat_name_width; @@@@ -1977,9 -1946,9 -1931,9 +1992,9 @@@@ switch (*arg) { case '-': -- if (!strncmp(arg, "-width=", 7)) ++ if (!prefixcmp(arg, "-width=")) width = strtoul(arg + 7, &end, 10); -- else if (!strncmp(arg, "-name-width=", 12)) ++ else if (!prefixcmp(arg, "-name-width=")) name_width = strtoul(arg + 12, &end, 10); break; case '=': @@@@ -2004,7 -1973,7 -1958,7 +2019,7 @@@@ } else if (!strcmp(arg, "-z")) options->line_termination = 0; -- else if (!strncmp(arg, "-l", 2)) ++ else if (!prefixcmp(arg, "-l")) options->rename_limit = strtoul(arg+2, NULL, 10); else if (!strcmp(arg, "--full-index")) options->full_index = 1; @@@@ -2021,31 -1990,31 -1975,31 +2036,31 @@@@ options->output_format |= DIFF_FORMAT_NAME_STATUS; else if (!strcmp(arg, "-R")) options->reverse_diff = 1; -- else if (!strncmp(arg, "-S", 2)) ++ else if (!prefixcmp(arg, "-S")) options->pickaxe = arg + 2; else if (!strcmp(arg, "-s")) { options->output_format |= DIFF_FORMAT_NO_OUTPUT; } -- else if (!strncmp(arg, "-O", 2)) ++ else if (!prefixcmp(arg, "-O")) options->orderfile = arg + 2; -- else if (!strncmp(arg, "--diff-filter=", 14)) ++ else if (!prefixcmp(arg, "--diff-filter=")) options->filter = arg + 14; else if (!strcmp(arg, "--pickaxe-all")) options->pickaxe_opts = DIFF_PICKAXE_ALL; else if (!strcmp(arg, "--pickaxe-regex")) options->pickaxe_opts = DIFF_PICKAXE_REGEX; -- else if (!strncmp(arg, "-B", 2)) { ++ else if (!prefixcmp(arg, "-B")) { if ((options->break_opt = diff_scoreopt_parse(arg)) == -1) return -1; } -- else if (!strncmp(arg, "-M", 2)) { ++ else if (!prefixcmp(arg, "-M")) { if ((options->rename_score = diff_scoreopt_parse(arg)) == -1) return -1; options->detect_rename = DIFF_DETECT_RENAME; } -- else if (!strncmp(arg, "-C", 2)) { ++ else if (!prefixcmp(arg, "-C")) { if ((options->rename_score = diff_scoreopt_parse(arg)) == -1) return -1; @@@@ -2055,7 -2024,7 -2009,7 +2070,7 @@@@ options->find_copies_harder = 1; else if (!strcmp(arg, "--abbrev")) options->abbrev = DEFAULT_ABBREV; -- else if (!strncmp(arg, "--abbrev=", 9)) { ++ else if (!prefixcmp(arg, "--abbrev=")) { options->abbrev = strtoul(arg + 9, NULL, 10); if (options->abbrev < MINIMUM_ABBREV) options->abbrev = MINIMUM_ABBREV; @@@@ -2070,8 -2039,6 -2024,6 +2085,8 @@@@ options->xdl_opts |= XDF_IGNORE_WHITESPACE; else if (!strcmp(arg, "-b") || !strcmp(arg, "--ignore-space-change")) options->xdl_opts |= XDF_IGNORE_WHITESPACE_CHANGE; ++ else if (!strcmp(arg, "--ignore-space-at-eol")) ++ options->xdl_opts |= XDF_IGNORE_WHITESPACE_AT_EOL; else if (!strcmp(arg, "--color-words")) options->color_diff = options->color_diff_words = 1; else if (!strcmp(arg, "--no-renames")) @@@@ -2564,7 -2531,7 -2516,7 +2579,7 @@@@ static void patch_id_consume(void *priv int new_len; /* Ignore line numbers when computing the SHA1 of the patch */ -- if (!strncmp(line, "@@ -", 4)) ++ if (!prefixcmp(line, "@@ -")) return; new_len = remove_space(line, len); diff --combined sha1_file.c index 2c870314d5,6ec67b2923,8ad7fad825..9a1dee051a --- a/sha1_file.c +++ b/sha1_file.c @@@@ -407,6 -407,7 -407,7 +407,6 @@@@ static unsigned int peak_pack_open_wind static unsigned int pack_open_windows; static size_t peak_pack_mapped; static size_t pack_mapped; --static size_t page_size; struct packed_git *packed_git; void pack_report() @@@@ -415,7 -416,7 -416,7 +415,7 @@@@ "pack_report: getpagesize() = %10" SZ_FMT "\n" "pack_report: core.packedGitWindowSize = %10" SZ_FMT "\n" "pack_report: core.packedGitLimit = %10" SZ_FMT "\n", -- page_size, ++ (size_t) getpagesize(), packed_git_window_size, packed_git_limit); fprintf(stderr, @@@@ -661,9 -662,10 -662,10 +661,9 @@@@ unsigned char* use_pack(struct packed_g break; } if (!win) { -- if (!page_size) -- page_size = getpagesize(); ++ size_t window_align = packed_git_window_size / 2; win = xcalloc(1, sizeof(*win)); -- win->offset = (offset / page_size) * page_size; ++ win->offset = (offset / window_align) * window_align; win->len = p->pack_size - win->offset; if (win->len > packed_git_window_size) win->len = packed_git_window_size; @@@@ -1545,13 -1547,11 -1547,11 +1545,13 @@@@ int pretend_sha1_file(void *buf, unsign co = &cached_objects[cached_object_nr++]; co->size = len; co->type = strdup(type); ++ co->buf = xmalloc(len); ++ memcpy(co->buf, buf, len); hashcpy(co->sha1, sha1); return 0; } --void * read_sha1_file(const unsigned char *sha1, char *type, unsigned long *size) ++void *read_sha1_file(const unsigned char *sha1, char *type, unsigned long *size) { unsigned long mapsize; void *map, *buf; @@@@ -2082,7 -2082,7 -2082,7 +2082,7 @@@@ int index_fd(unsigned char *sha1, int f { unsigned long size = st->st_size; void *buf; - - int ret; + + int ret, re_allocated = 0; buf = ""; if (size) @@@@ -2091,11 -2091,30 -2091,11 +2091,30 @@@@ if (!type) type = blob_type; - - /* FIXME: CRLF -> LF conversion here for blobs! We'll need the path! */ + + + + /* + + * Convert blobs to git internal format + + */ + + if (!strcmp(type, blob_type)) { + + unsigned long nsize = size; + + char *nbuf = buf; + + if (convert_to_git(NULL, &nbuf, &nsize)) { + + if (size) + + munmap(buf, size); + + size = nsize; + + buf = nbuf; + + re_allocated = 1; + + } + + } + + if (write_object) ret = write_sha1_file(buf, size, type, sha1); else ret = hash_sha1_file(buf, size, type, sha1); + + if (re_allocated) { + + free(buf); + + return ret; + + } if (size) munmap(buf, size); return ret;