#include "blob.h"
#include "delta.h"
#include "builtin.h"
-#include "path-list.h"
+#include "string-list.h"
+#include "dir.h"
/*
* --check turns on checking that the working tree matches the
* the case where more than one patches touch the same file.
*/
-static struct path_list fn_table;
+static struct string_list fn_table;
static uint32_t hash_line(const char *cp, size_t len)
{
static void read_patch_file(struct strbuf *sb, int fd)
{
if (strbuf_read(sb, fd, 0) < 0)
- die("git-apply: read returned %s", strerror(errno));
+ die("git apply: read returned %s", strerror(errno));
/*
* Make sure that we have some slop in the buffer
const char *start = line;
if (*line == '"') {
- struct strbuf name;
+ struct strbuf name = STRBUF_INIT;
/*
* Proposed "new-style" GNU patch/diff format; see
* http://marc.theaimsgroup.com/?l=git&m=112927316408690&w=2
*/
- strbuf_init(&name, 0);
if (!unquote_c_style(&name, line, NULL)) {
char *cp;
name = orig_name;
len = strlen(name);
if (isnull)
- die("git-apply: bad git-diff - expected /dev/null, got %s on line %d", name, linenr);
+ die("git apply: bad git-diff - expected /dev/null, got %s on line %d", name, linenr);
another = find_name(line, NULL, p_value, TERM_TAB);
if (!another || memcmp(another, name, len))
- die("git-apply: bad git-diff - inconsistent %s filename on line %d", oldnew, linenr);
+ die("git apply: bad git-diff - inconsistent %s filename on line %d", oldnew, linenr);
free(another);
return orig_name;
}
else {
/* expect "/dev/null" */
if (memcmp("/dev/null", line, 9) || line[9] != '\n')
- die("git-apply: bad git-diff - expected /dev/null on line %d", linenr);
+ die("git apply: bad git-diff - expected /dev/null on line %d", linenr);
return NULL;
}
}
if (*line == '"') {
const char *cp;
- struct strbuf first;
- struct strbuf sp;
-
- strbuf_init(&first, 0);
- strbuf_init(&sp, 0);
+ struct strbuf first = STRBUF_INIT;
+ struct strbuf sp = STRBUF_INIT;
if (unquote_c_style(&first, line, &second))
goto free_and_fail1;
*/
for (second = name; second < line + llen; second++) {
if (*second == '"') {
- struct strbuf sp;
+ struct strbuf sp = STRBUF_INIT;
const char *np;
- strbuf_init(&sp, 0);
if (unquote_c_style(&sp, second, NULL))
goto free_and_fail2;
* the default name from the header.
*/
patch->def_name = git_header_name(line, len);
+ if (patch->def_name && root) {
+ char *s = xmalloc(root_len + strlen(patch->def_name) + 1);
+ strcpy(s, root);
+ strcpy(s + root_len, patch->def_name);
+ free(patch->def_name);
+ patch->def_name = s;
+ }
line += len;
size -= len;
static void show_stats(struct patch *patch)
{
- struct strbuf qname;
+ struct strbuf qname = STRBUF_INIT;
char *cp = patch->new_name ? patch->new_name : patch->old_name;
int max, add, del;
- strbuf_init(&qname, 0);
quote_c_style(cp, &qname, NULL, 0);
/*
fixlen = ws_fix_copy(buf, orig, oldlen, ws_rule, NULL);
/* Try fixing the line in the target */
- if (sizeof(tgtfixbuf) < tgtlen)
+ if (sizeof(tgtfixbuf) > tgtlen)
tgtfix = tgtfixbuf;
else
tgtfix = xmalloc(tgtlen);
/*
* A hunk to change lines at the beginning would begin with
* @@ -1,L +N,M @@
+ * but we need to be careful. -U0 that inserts before the second
+ * line also has this pattern.
*
* And a hunk to add to an empty file would begin with
* @@ -0,0 +N,M @@
* In other words, a hunk that is (frag->oldpos <= 1) with or
* without leading context must match at the beginning.
*/
- match_beginning = frag->oldpos <= 1;
+ match_beginning = (!frag->oldpos ||
+ (frag->oldpos == 1 && !unidiff_zero));
/*
* A hunk without trailing lines must match at the end.
static struct patch *in_fn_table(const char *name)
{
- struct path_list_item *item;
+ struct string_list_item *item;
if (name == NULL)
return NULL;
- item = path_list_lookup(name, &fn_table);
+ item = string_list_lookup(name, &fn_table);
if (item != NULL)
return (struct patch *)item->util;
static void add_to_fn_table(struct patch *patch)
{
- struct path_list_item *item;
+ struct string_list_item *item;
/*
* Always add new_name unless patch is a deletion
* file creations and copies
*/
if (patch->new_name != NULL) {
- item = path_list_insert(patch->new_name, &fn_table);
+ item = string_list_insert(patch->new_name, &fn_table);
item->util = patch;
}
* later chunks shouldn't patch old names
*/
if ((patch->new_name == NULL) || (patch->is_rename)) {
- item = path_list_insert(patch->old_name, &fn_table);
+ item = string_list_insert(patch->old_name, &fn_table);
item->util = (struct patch *) -1;
}
}
static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *ce)
{
- struct strbuf buf;
+ struct strbuf buf = STRBUF_INIT;
struct image image;
size_t len;
char *img;
struct patch *tpatch;
- strbuf_init(&buf, 0);
-
if (!(patch->is_copy || patch->is_rename) &&
((tpatch = in_fn_table(patch->old_name)) != NULL)) {
if (tpatch == (struct patch *) -1) {
sha1_ptr = sha1;
ce = make_cache_entry(patch->old_mode, sha1_ptr, name, 0, 0);
+ if (!ce)
+ die("make_cache_entry failed for path '%s'", name);
if (add_index_entry(&result, ce, ADD_CACHE_OK_TO_ADD))
die ("Could not add %s to temporary index", name);
}
warning("unable to remove submodule %s",
patch->old_name);
} else if (!unlink(patch->old_name) && rmdir_empty) {
- char *name = xstrdup(patch->old_name);
- char *end = strrchr(name, '/');
- while (end) {
- *end = 0;
- if (rmdir(name))
- break;
- end = strrchr(name, '/');
- }
- free(name);
+ remove_path(patch->old_name);
}
}
}
static int try_create_file(const char *path, unsigned int mode, const char *buf, unsigned long size)
{
int fd;
- struct strbuf nbuf;
+ struct strbuf nbuf = STRBUF_INIT;
if (S_ISGITLINK(mode)) {
struct stat st;
if (fd < 0)
return -1;
- strbuf_init(&nbuf, 0);
if (convert_to_working_tree(path, buf, size, &nbuf)) {
size = nbuf.len;
buf = nbuf.buf;
static struct lock_file lock_file;
-static struct excludes {
- struct excludes *next;
- const char *path;
-} *excludes;
+static struct string_list limit_by_name;
+static int has_include;
+static void add_name_limit(const char *name, int exclude)
+{
+ struct string_list_item *it;
+
+ it = string_list_append(name, &limit_by_name);
+ it->util = exclude ? NULL : (void *) 1;
+}
static int use_patch(struct patch *p)
{
const char *pathname = p->new_name ? p->new_name : p->old_name;
- struct excludes *x = excludes;
- while (x) {
- if (fnmatch(x->path, pathname, 0) == 0)
- return 0;
- x = x->next;
- }
+ int i;
+
+ /* Paths outside are not touched regardless of "--include" */
if (0 < prefix_length) {
int pathlen = strlen(pathname);
if (pathlen <= prefix_length ||
memcmp(prefix, pathname, prefix_length))
return 0;
}
- return 1;
+
+ /* See if it matches any of exclude/include rule */
+ for (i = 0; i < limit_by_name.nr; i++) {
+ struct string_list_item *it = &limit_by_name.items[i];
+ if (!fnmatch(it->string, pathname, 0))
+ return (it->util != NULL);
+ }
+
+ /*
+ * If we had any include, a path that does not match any rule is
+ * not used. Otherwise, we saw bunch of exclude rules (or none)
+ * and such a path is used.
+ */
+ return !has_include;
}
+
static void prefix_one(char **name)
{
char *old_name = *name;
static int apply_patch(int fd, const char *filename, int options)
{
size_t offset;
- struct strbuf buf;
+ struct strbuf buf = STRBUF_INIT;
struct patch *list = NULL, **listp = &list;
int skipped_patch = 0;
/* FIXME - memory leak when using multiple patch files as inputs */
- memset(&fn_table, 0, sizeof(struct path_list));
- strbuf_init(&buf, 0);
+ memset(&fn_table, 0, sizeof(struct string_list));
patch_input_file = filename;
read_patch_file(&buf, fd);
offset = 0;
continue;
}
if (!prefixcmp(arg, "--exclude=")) {
- struct excludes *x = xmalloc(sizeof(*x));
- x->path = arg + 10;
- x->next = excludes;
- excludes = x;
+ add_name_limit(arg + 10, 1);
+ continue;
+ }
+ if (!prefixcmp(arg, "--include=")) {
+ add_name_limit(arg + 10, 0);
+ has_include = 1;
continue;
}
if (!prefixcmp(arg, "-p")) {