X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=builtin-apply.c;h=8411b38c7963852bffeb6dea1494399e8c9daa02;hb=fed1b5cac0cc3ae324dc004181a276ea16589951;hp=61b51315edb040b19e7e17314c66780bab1be346;hpb=c7f9cb14286fff23bfe65033d4ec63f84c77f554;p=git.git diff --git a/builtin-apply.c b/builtin-apply.c index 61b51315e..8411b38c7 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -41,7 +41,7 @@ static int apply_in_reverse; static int apply_with_reject; static int apply_verbosely; static int no_add; -static int show_index_info; +static const char *fake_ancestor; static int line_termination = '\n'; static unsigned long p_context = ULONG_MAX; static const char apply_usage[] = @@ -152,7 +152,7 @@ struct patch { unsigned int is_rename:1; struct fragment *fragments; char *result; - unsigned long resultsize; + size_t resultsize; char old_sha1_prefix[41]; char new_sha1_prefix[41]; struct patch *next; @@ -163,15 +163,14 @@ static void say_patch_name(FILE *output, const char *pre, struct patch *patch, c fputs(pre, output); if (patch->old_name && patch->new_name && strcmp(patch->old_name, patch->new_name)) { - write_name_quoted(NULL, 0, patch->old_name, 1, output); + quote_c_style(patch->old_name, NULL, output, 0); fputs(" => ", output); - write_name_quoted(NULL, 0, patch->new_name, 1, output); - } - else { + quote_c_style(patch->new_name, NULL, output, 0); + } else { const char *n = patch->new_name; if (!n) n = patch->old_name; - write_name_quoted(NULL, 0, n, 1, output); + quote_c_style(n, NULL, output, 0); } fputs(post, output); } @@ -179,23 +178,18 @@ static void say_patch_name(FILE *output, const char *pre, struct patch *patch, c #define CHUNKSIZE (8192) #define SLOP (16) -static void *read_patch_file(int fd, unsigned long *sizep) +static void read_patch_file(struct strbuf *sb, int fd) { - struct strbuf buf; - - strbuf_init(&buf, 0); - if (strbuf_read(&buf, fd, 0) < 0) + if (strbuf_read(sb, fd, 0) < 0) die("git-apply: read returned %s", strerror(errno)); - *sizep = buf.len; /* * Make sure that we have some slop in the buffer * so that we can do speculative "memcmp" etc, and * see to it that it is NUL-filled. */ - strbuf_grow(&buf, SLOP); - memset(buf.buf + buf.len, 0, SLOP); - return strbuf_detach(&buf); + strbuf_grow(sb, SLOP); + memset(sb->buf + sb->len, 0, SLOP); } static unsigned long linelen(const char *buffer, unsigned long size) @@ -231,35 +225,33 @@ static char *find_name(const char *line, char *def, int p_value, int terminate) { int len; const char *start = line; - char *name; if (*line == '"') { + struct strbuf name; + /* Proposed "new-style" GNU patch/diff format; see * http://marc.theaimsgroup.com/?l=git&m=112927316408690&w=2 */ - name = unquote_c_style(line, NULL); - if (name) { - char *cp = name; - while (p_value) { - cp = strchr(name, '/'); + strbuf_init(&name, 0); + if (!unquote_c_style(&name, line, NULL)) { + char *cp; + + for (cp = name.buf; p_value; p_value--) { + cp = strchr(cp, '/'); if (!cp) break; cp++; - p_value--; } if (cp) { /* name can later be freed, so we need * to memmove, not just return cp */ - memmove(name, cp, strlen(cp) + 1); + strbuf_remove(&name, 0, cp - name.buf); free(def); - return name; - } - else { - free(name); - name = NULL; + return strbuf_detach(&name, NULL); } } + strbuf_release(&name); } for (;;) { @@ -291,13 +283,10 @@ static char *find_name(const char *line, char *def, int p_value, int terminate) int deflen = strlen(def); if (deflen < len && !strncmp(start, def, deflen)) return def; + free(def); } - name = xmalloc(len + 1); - memcpy(name, start, len); - name[len] = 0; - free(def); - return name; + return xmemdupz(start, len); } static int count_slashes(const char *cp) @@ -570,29 +559,30 @@ static const char *stop_at_slash(const char *line, int llen) */ static char *git_header_name(char *line, int llen) { - int len; const char *name; const char *second = NULL; + size_t len; line += strlen("diff --git "); llen -= strlen("diff --git "); if (*line == '"') { const char *cp; - char *first = unquote_c_style(line, &second); - if (!first) - return NULL; + struct strbuf first; + struct strbuf sp; + + strbuf_init(&first, 0); + strbuf_init(&sp, 0); + + if (unquote_c_style(&first, line, &second)) + goto free_and_fail1; /* advance to the first slash */ - cp = stop_at_slash(first, strlen(first)); - if (!cp || cp == first) { - /* we do not accept absolute paths */ - free_first_and_fail: - free(first); - return NULL; - } - len = strlen(cp+1); - memmove(first, cp+1, len+1); /* including NUL */ + cp = stop_at_slash(first.buf, first.len); + /* we do not accept absolute paths */ + if (!cp || cp == first.buf) + goto free_and_fail1; + strbuf_remove(&first, 0, cp + 1 - first.buf); /* second points at one past closing dq of name. * find the second name. @@ -601,40 +591,40 @@ static char *git_header_name(char *line, int llen) second++; if (line + llen <= second) - goto free_first_and_fail; + goto free_and_fail1; if (*second == '"') { - char *sp = unquote_c_style(second, NULL); - if (!sp) - goto free_first_and_fail; - cp = stop_at_slash(sp, strlen(sp)); - if (!cp || cp == sp) { - free_both_and_fail: - free(sp); - goto free_first_and_fail; - } + if (unquote_c_style(&sp, second, NULL)) + goto free_and_fail1; + cp = stop_at_slash(sp.buf, sp.len); + if (!cp || cp == sp.buf) + goto free_and_fail1; /* They must match, otherwise ignore */ - if (strcmp(cp+1, first)) - goto free_both_and_fail; - free(sp); - return first; + if (strcmp(cp + 1, first.buf)) + goto free_and_fail1; + strbuf_release(&sp); + return strbuf_detach(&first, NULL); } /* unquoted second */ cp = stop_at_slash(second, line + llen - second); if (!cp || cp == second) - goto free_first_and_fail; + goto free_and_fail1; cp++; - if (line + llen - cp != len + 1 || - memcmp(first, cp, len)) - goto free_first_and_fail; - return first; + if (line + llen - cp != first.len + 1 || + memcmp(first.buf, cp, first.len)) + goto free_and_fail1; + return strbuf_detach(&first, NULL); + + free_and_fail1: + strbuf_release(&first); + strbuf_release(&sp); + return NULL; } /* unquoted first name */ name = stop_at_slash(line, llen); if (!name || name == line) return NULL; - name++; /* since the first name is unquoted, a dq if exists must be @@ -642,28 +632,30 @@ static char *git_header_name(char *line, int llen) */ for (second = name; second < line + llen; second++) { if (*second == '"') { - const char *cp = second; + struct strbuf sp; const char *np; - char *sp = unquote_c_style(second, NULL); - - if (!sp) - return NULL; - np = stop_at_slash(sp, strlen(sp)); - if (!np || np == sp) { - free_second_and_fail: - free(sp); - return NULL; - } + + strbuf_init(&sp, 0); + if (unquote_c_style(&sp, second, NULL)) + goto free_and_fail2; + + np = stop_at_slash(sp.buf, sp.len); + if (!np || np == sp.buf) + goto free_and_fail2; np++; - len = strlen(np); - if (len < cp - name && + + len = sp.buf + sp.len - np; + if (len < second - name && !strncmp(np, name, len) && isspace(name[len])) { /* Good */ - memmove(sp, np, len + 1); - return sp; + strbuf_remove(&sp, 0, np - sp.buf); + return strbuf_detach(&sp, NULL); } - goto free_second_and_fail; + + free_and_fail2: + strbuf_release(&sp); + return NULL; } } @@ -687,10 +679,7 @@ static char *git_header_name(char *line, int llen) break; } if (second[len] == '\n' && !memcmp(name, second, len)) { - char *ret = xmalloc(len + 1); - memcpy(ret, name, len); - ret[len] = 0; - return ret; + return xmemdupz(name, len); } } } @@ -1384,67 +1373,54 @@ static const char minuses[]= "-------------------------------------------------- static void show_stats(struct patch *patch) { - const char *prefix = ""; - char *name = patch->new_name; - char *qname = NULL; - int len, max, add, del, total; - - if (!name) - name = patch->old_name; + struct strbuf qname; + char *cp = patch->new_name ? patch->new_name : patch->old_name; + int max, add, del; - if (0 < (len = quote_c_style(name, NULL, NULL, 0))) { - qname = xmalloc(len + 1); - quote_c_style(name, qname, NULL, 0); - name = qname; - } + strbuf_init(&qname, 0); + quote_c_style(cp, &qname, NULL, 0); /* * "scale" the filename */ - len = strlen(name); max = max_len; if (max > 50) max = 50; - if (len > max) { - char *slash; - prefix = "..."; - max -= 3; - name += len - max; - slash = strchr(name, '/'); - if (slash) - name = slash; + + if (qname.len > max) { + cp = strchr(qname.buf + qname.len + 3 - max, '/'); + if (!cp) + cp = qname.buf + qname.len + 3 - max; + strbuf_splice(&qname, 0, cp - qname.buf, "...", 3); } - len = max; + + if (patch->is_binary) { + printf(" %-*s | Bin\n", max, qname.buf); + strbuf_release(&qname); + return; + } + + printf(" %-*s |", max, qname.buf); + strbuf_release(&qname); /* * scale the add/delete */ - max = max_change; - if (max + len > 70) - max = 70 - len; - + max = max + max_change > 70 ? 70 - max : max_change; add = patch->lines_added; del = patch->lines_deleted; - total = add + del; if (max_change > 0) { - total = (total * max + max_change / 2) / max_change; + int total = ((add + del) * max + max_change / 2) / max_change; add = (add * max + max_change / 2) / max_change; del = total - add; } - if (patch->is_binary) - printf(" %s%-*s | Bin\n", prefix, len, name); - else - printf(" %s%-*s |%5d %.*s%.*s\n", prefix, - len, name, patch->lines_added + patch->lines_deleted, - add, pluses, del, minuses); - free(qname); + printf("%5d %.*s%.*s\n", patch->lines_added + patch->lines_deleted, + add, pluses, del, minuses); } static int read_old_data(struct stat *st, const char *path, struct strbuf *buf) { - int fd; - switch (st->st_mode & S_IFMT) { case S_IFLNK: strbuf_grow(buf, st->st_size); @@ -1453,14 +1429,8 @@ static int read_old_data(struct stat *st, const char *path, struct strbuf *buf) strbuf_setlen(buf, st->st_size); return 0; case S_IFREG: - fd = open(path, O_RDONLY); - if (fd < 0) - return error("unable to open %s", path); - if (strbuf_read(buf, fd, st->st_size) < 0) { - close(fd); - return -1; - } - close(fd); + if (strbuf_read_file(buf, path, st->st_size) != st->st_size) + return error("unable to open or read %s", path); convert_to_git(path, buf->buf, buf->len, buf); return 0; default: @@ -1612,15 +1582,22 @@ static int apply_line(char *output, const char *patch, int plen) buf = output; if (need_fix_leading_space) { + int consecutive_spaces = 0; /* between patch[1..last_tab_in_indent] strip the * funny spaces, updating them to tab as needed. */ for (i = 1; i < last_tab_in_indent; i++, plen--) { char ch = patch[i]; - if (ch != ' ') + if (ch != ' ') { + consecutive_spaces = 0; *output++ = ch; - else if ((i % 8) == 0) - *output++ = '\t'; + } else { + consecutive_spaces++; + if (consecutive_spaces == 8) { + *output++ = '\t'; + consecutive_spaces = 0; + } + } } fixed = 1; i = last_tab_in_indent; @@ -1978,8 +1955,7 @@ static int apply_data(struct patch *patch, struct stat *st, struct cache_entry * if (apply_fragments(&buf, patch) < 0) return -1; /* note with --reject this succeeds. */ - patch->result = buf.buf; - patch->resultsize = buf.len; + patch->result = strbuf_detach(&buf, &patch->resultsize); if (0 < patch->is_delete && patch->resultsize) return error("removal patch leaves file contents"); @@ -2152,9 +2128,26 @@ static int check_patch_list(struct patch *patch) return err; } -static void show_index_list(struct patch *list) +/* This function tries to read the sha1 from the current index */ +static int get_current_sha1(const char *path, unsigned char *sha1) +{ + int pos; + + if (read_cache() < 0) + return -1; + pos = cache_name_pos(path, strlen(path)); + if (pos < 0) + return -1; + hashcpy(sha1, active_cache[pos]->sha1); + return 0; +} + +/* Build an index that contains the just the files needed for a 3way merge */ +static void build_fake_ancestor(struct patch *list, const char *filename) { struct patch *patch; + struct index_state result = { 0 }; + int fd; /* Once we start supporting the reverse patch, it may be * worth showing the new sha1 prefix, but until then... @@ -2162,24 +2155,36 @@ static void show_index_list(struct patch *list) for (patch = list; patch; patch = patch->next) { const unsigned char *sha1_ptr; unsigned char sha1[20]; + struct cache_entry *ce; const char *name; name = patch->old_name ? patch->old_name : patch->new_name; if (0 < patch->is_new) - sha1_ptr = null_sha1; + continue; else if (get_sha1(patch->old_sha1_prefix, sha1)) - die("sha1 information is lacking or useless (%s).", - name); + /* git diff has no index line for mode/type changes */ + if (!patch->lines_added && !patch->lines_deleted) { + if (get_current_sha1(patch->new_name, sha1) || + get_current_sha1(patch->old_name, sha1)) + die("mode change for %s, which is not " + "in current HEAD", name); + sha1_ptr = sha1; + } else + die("sha1 information is lacking or useless " + "(%s).", name); else sha1_ptr = sha1; - printf("%06o %s ",patch->old_mode, sha1_to_hex(sha1_ptr)); - if (line_termination && quote_c_style(name, NULL, NULL, 0)) - quote_c_style(name, NULL, stdout, 0); - else - fputs(name, stdout); - putchar(line_termination); + ce = make_cache_entry(patch->old_mode, sha1_ptr, name, 0, 0); + if (add_index_entry(&result, ce, ADD_CACHE_OK_TO_ADD)) + die ("Could not add %s to temporary index", name); } + + fd = open(filename, O_WRONLY | O_CREAT, 0666); + if (fd < 0 || write_index(&result, fd) || close(fd)) + die ("Could not write temporary index to %s", filename); + + discard_index(&result); } static void stat_patch_list(struct patch *patch) @@ -2204,13 +2209,8 @@ static void numstat_patch_list(struct patch *patch) if (patch->is_binary) printf("-\t-\t"); else - printf("%d\t%d\t", - patch->lines_added, patch->lines_deleted); - if (line_termination && quote_c_style(name, NULL, NULL, 0)) - quote_c_style(name, NULL, stdout, 0); - else - fputs(name, stdout); - putchar(line_termination); + printf("%d\t%d\t", patch->lines_added, patch->lines_deleted); + write_name_quoted(name, stdout, line_termination); } } @@ -2319,7 +2319,6 @@ static void remove_file(struct patch *patch, int rmdir_empty) if (update_index) { if (remove_file_from_cache(patch->old_name) < 0) die("unable to remove %s from index", patch->old_name); - cache_tree_invalidate_path(active_cache_tree, patch->old_name); } if (!cached) { if (S_ISGITLINK(patch->old_mode)) { @@ -2467,7 +2466,6 @@ static void create_file(struct patch *patch) mode = S_IFREG | 0644; create_one_file(path, mode, buf, size); add_index_file(path, mode, buf, size); - cache_tree_invalidate_path(active_cache_tree, path); } /* phase zero is to remove, phase one is to create */ @@ -2638,22 +2636,22 @@ static void prefix_patches(struct patch *p) static int apply_patch(int fd, const char *filename, int inaccurate_eof) { - unsigned long offset, size; - char *buffer = read_patch_file(fd, &size); + size_t offset; + struct strbuf buf; struct patch *list = NULL, **listp = &list; int skipped_patch = 0; + strbuf_init(&buf, 0); patch_input_file = filename; - if (!buffer) - return -1; + read_patch_file(&buf, fd); offset = 0; - while (size > 0) { + while (offset < buf.len) { struct patch *patch; int nr; patch = xcalloc(1, sizeof(*patch)); patch->inaccurate_eof = inaccurate_eof; - nr = parse_chunk(buffer + offset, size, patch); + nr = parse_chunk(buf.buf + offset, buf.len - offset, patch); if (nr < 0) break; if (apply_in_reverse) @@ -2671,7 +2669,6 @@ static int apply_patch(int fd, const char *filename, int inaccurate_eof) skipped_patch++; } offset += nr; - size -= nr; } if (whitespace_error && (new_whitespace == error_on_whitespace)) @@ -2694,8 +2691,8 @@ static int apply_patch(int fd, const char *filename, int inaccurate_eof) if (apply && write_out_results(list, skipped_patch)) exit(1); - if (show_index_info) - show_index_list(list); + if (fake_ancestor) + build_fake_ancestor(list, fake_ancestor); if (diffstat) stat_patch_list(list); @@ -2706,7 +2703,7 @@ static int apply_patch(int fd, const char *filename, int inaccurate_eof) if (summary) summary_patch_list(list); - free(buffer); + strbuf_release(&buf); return 0; } @@ -2803,9 +2800,11 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix) apply = 1; continue; } - if (!strcmp(arg, "--index-info")) { + if (!strcmp(arg, "--build-fake-ancestor")) { apply = 0; - show_index_info = 1; + if (++i >= argc) + die ("need a filename"); + fake_ancestor = argv[i]; continue; } if (!strcmp(arg, "-z")) {