diff options
author | Edward Thomson <ethomson@edwardthomson.com> | 2013-04-30 23:56:41 +0400 |
---|---|---|
committer | Edward Thomson <ethomson@edwardthomson.com> | 2013-05-01 01:01:11 +0400 |
commit | 0462fba538b380551cbd5d8c05281352ba7a7471 (patch) | |
tree | ea9c353de8f20b0ed68fb0cf3c747677d876b9fe /src/index.c | |
parent | bec65a5e994bc4701216c9ca2c7dae83770b3edc (diff) |
renames!
Diffstat (limited to 'src/index.c')
-rw-r--r-- | src/index.c | 218 |
1 files changed, 218 insertions, 0 deletions
diff --git a/src/index.c b/src/index.c index fe3a2104b..656fb5bc5 100644 --- a/src/index.c +++ b/src/index.c @@ -35,6 +35,7 @@ static const unsigned int INDEX_VERSION_NUMBER_EXT = 3; static const unsigned int INDEX_HEADER_SIG = 0x44495243; static const char INDEX_EXT_TREECACHE_SIG[] = {'T', 'R', 'E', 'E'}; static const char INDEX_EXT_UNMERGED_SIG[] = {'R', 'E', 'U', 'C'}; +static const char INDEX_EXT_CONFLICT_NAME_SIG[] = {'N', 'A', 'M', 'E'}; #define INDEX_OWNER(idx) ((git_repository *)(GIT_REFCOUNT_OWNER(idx))) @@ -187,6 +188,46 @@ static int index_icmp(const void *a, const void *b) return diff; } +static int conflict_name_cmp(const void *a, const void *b) +{ + const git_index_name_entry *name_a = a; + const git_index_name_entry *name_b = b; + + if (name_a->ancestor && !name_b->ancestor) + return 1; + + if (!name_a->ancestor && name_b->ancestor) + return -1; + + if (name_a->ancestor) + return strcmp(name_a->ancestor, name_b->ancestor); + + if (!name_a->ours || !name_b->ours) + return 0; + + return strcmp(name_a->ours, name_b->ours); +} + +static int conflict_name_icmp(const void *a, const void *b) +{ + const git_index_name_entry *name_a = a; + const git_index_name_entry *name_b = b; + + if (name_a->ancestor && !name_b->ancestor) + return 1; + + if (!name_a->ancestor && name_b->ancestor) + return -1; + + if (name_a->ancestor) + return strcasecmp(name_a->ancestor, name_b->ancestor); + + if (!name_a->ours || !name_b->ours) + return 0; + + return strcasecmp(name_a->ours, name_b->ours); +} + static int reuc_srch(const void *key, const void *array_member) { const git_index_reuc_entry *reuc = array_member; @@ -278,6 +319,7 @@ int git_index_open(git_index **index_out, const char *index_path) } if (git_vector_init(&index->entries, 32, index_cmp) < 0 || + git_vector_init(&index->names, 32, conflict_name_cmp) < 0 || git_vector_init(&index->reuc, 32, reuc_cmp) < 0) return -1; @@ -331,6 +373,8 @@ void git_index_clear(git_index *index) git_index_reuc_clear(index); + git_index_name_clear(index); + git_futils_filestamp_set(&index->stamp, NULL); git_tree_cache_free(index->tree); @@ -1042,6 +1086,72 @@ int git_index_has_conflicts(const git_index *index) return 0; } +unsigned int git_index_name_entrycount(git_index *index) +{ + assert(index); + return (unsigned int)index->names.length; +} + +const git_index_name_entry *git_index_name_get_byindex( + git_index *index, size_t n) +{ + assert(index); + + git_vector_sort(&index->names); + return git_vector_get(&index->names, n); +} + +int git_index_name_add(git_index *index, + const char *ancestor, const char *ours, const char *theirs) +{ + git_index_name_entry *conflict_name; + + assert ((ancestor && ours) || (ancestor && theirs) || (ours && theirs)); + + conflict_name = git__calloc(1, sizeof(git_index_name_entry)); + GITERR_CHECK_ALLOC(conflict_name); + + if (ancestor) { + conflict_name->ancestor = git__strdup(ancestor); + GITERR_CHECK_ALLOC(conflict_name->ancestor); + } + + if (ours) { + conflict_name->ours = git__strdup(ours); + GITERR_CHECK_ALLOC(conflict_name->ours); + } + + if (theirs) { + conflict_name->theirs = git__strdup(theirs); + GITERR_CHECK_ALLOC(conflict_name->theirs); + } + + return git_vector_insert(&index->names, conflict_name); +} + +void git_index_name_clear(git_index *index) +{ + size_t i; + git_index_name_entry *conflict_name; + + assert(index); + + git_vector_foreach(&index->names, i, conflict_name) { + if (conflict_name->ancestor) + git__free(conflict_name->ancestor); + + if (conflict_name->ours) + git__free(conflict_name->ours); + + if (conflict_name->theirs) + git__free(conflict_name->theirs); + + git__free(conflict_name); + } + + git_vector_clear(&index->names); +} + unsigned int git_index_reuc_entrycount(git_index *index) { assert(index); @@ -1228,6 +1338,52 @@ static int read_reuc(git_index *index, const char *buffer, size_t size) return 0; } + +static int read_conflict_names(git_index *index, const char *buffer, size_t size) +{ + size_t len; + + /* This gets called multiple times, the vector might already be initialized */ + if (index->names._alloc_size == 0 && + git_vector_init(&index->names, 16, conflict_name_cmp) < 0) + return -1; + +#define read_conflict_name(ptr) \ + len = strlen(buffer) + 1; \ + if (size < len) \ + return index_error_invalid("reading conflict name entries"); \ + \ + if (len == 1) \ + ptr = NULL; \ + else { \ + ptr = git__malloc(len); \ + GITERR_CHECK_ALLOC(ptr); \ + memcpy(ptr, buffer, len); \ + } \ + \ + buffer += len; \ + size -= len; + + while (size) { + git_index_name_entry *conflict_name = git__calloc(1, sizeof(git_index_name_entry)); + GITERR_CHECK_ALLOC(conflict_name); + + read_conflict_name(conflict_name->ancestor); + read_conflict_name(conflict_name->ours); + read_conflict_name(conflict_name->theirs); + + if (git_vector_insert(&index->names, conflict_name) < 0) + return -1; + } + +#undef read_conflict_name + + /* entries are guaranteed to be sorted on-disk */ + index->names.sorted = 1; + + return 0; +} + static size_t read_entry(git_index_entry *dest, const void *buffer, size_t buffer_size) { size_t path_length, entry_size; @@ -1332,6 +1488,9 @@ static size_t read_extension(git_index *index, const char *buffer, size_t buffer } else if (memcmp(dest.signature, INDEX_EXT_UNMERGED_SIG, 4) == 0) { if (read_reuc(index, buffer + 8, dest.extension_size) < 0) return 0; + } else if (memcmp(dest.signature, INDEX_EXT_CONFLICT_NAME_SIG, 4) == 0) { + if (read_conflict_names(index, buffer + 8, dest.extension_size) < 0) + return 0; } /* else, unsupported extension. We cannot parse this, but we can skip * it by returning `total_size */ @@ -1545,6 +1704,61 @@ static int write_extension(git_filebuf *file, struct index_extension *header, gi return error; } +static int create_name_extension_data(git_buf *name_buf, git_index_name_entry *conflict_name) +{ + int error = 0; + + if (conflict_name->ancestor == NULL) + error = git_buf_put(name_buf, "\0", 1); + else + error = git_buf_put(name_buf, conflict_name->ancestor, strlen(conflict_name->ancestor) + 1); + + if (error != 0) + goto on_error; + + if (conflict_name->ours == NULL) + error = git_buf_put(name_buf, "\0", 1); + else + error = git_buf_put(name_buf, conflict_name->ours, strlen(conflict_name->ours) + 1); + + if (error != 0) + goto on_error; + + if (conflict_name->theirs == NULL) + error = git_buf_put(name_buf, "\0", 1); + else + error = git_buf_put(name_buf, conflict_name->theirs, strlen(conflict_name->theirs) + 1); + +on_error: + return error; +} + +static int write_name_extension(git_index *index, git_filebuf *file) +{ + git_buf name_buf = GIT_BUF_INIT; + git_vector *out = &index->names; + git_index_name_entry *conflict_name; + struct index_extension extension; + size_t i; + int error = 0; + + git_vector_foreach(out, i, conflict_name) { + if ((error = create_name_extension_data(&name_buf, conflict_name)) < 0) + goto done; + } + + memset(&extension, 0x0, sizeof(struct index_extension)); + memcpy(&extension.signature, INDEX_EXT_CONFLICT_NAME_SIG, 4); + extension.extension_size = (uint32_t)name_buf.size; + + error = write_extension(file, &extension, &name_buf); + + git_buf_free(&name_buf); + +done: + return error; +} + static int create_reuc_extension_data(git_buf *reuc_buf, git_index_reuc_entry *reuc) { int i; @@ -1615,6 +1829,10 @@ static int write_index(git_index *index, git_filebuf *file) /* TODO: write tree cache extension */ + /* write the rename conflict extension */ + if (index->names.length > 0 && write_name_extension(index, file) < 0) + return -1; + /* write the reuc extension */ if (index->reuc.length > 0 && write_reuc_extension(index, file) < 0) return -1; |