* To remove a leaf_node:
* Search to the tree location appropriate for the given leaf_node's key:
* - If location does not hold a matching entry, abort and do nothing.
+ * - Copy the matching entry's value into the given entry.
* - Replace the matching leaf_node with a NULL entry (and free the leaf_node).
* - Consolidate int_nodes repeatedly, while walking up the tree towards root.
*/
-static void note_tree_remove(struct notes_tree *t, struct int_node *tree,
- unsigned char n, struct leaf_node *entry)
+static void note_tree_remove(struct notes_tree *t,
+ struct int_node *tree, unsigned char n,
+ struct leaf_node *entry)
{
struct leaf_node *l;
struct int_node *parent_stack[20];
return; /* key mismatch, nothing to remove */
/* we have found a matching entry */
+ hashcpy(entry->val_sha1, l->val_sha1);
free(l);
*p = SET_PTR_TYPE(NULL, PTR_TYPE_NULL);
return 0;
}
- /* we will separate the notes by a newline anyway */
+ /* we will separate the notes by two newlines anyway */
if (cur_msg[cur_len - 1] == '\n')
cur_len--;
/* concatenate cur_msg and new_msg into buf */
- buf_len = cur_len + 1 + new_len;
+ buf_len = cur_len + 2 + new_len;
buf = (char *) xmalloc(buf_len);
memcpy(buf, cur_msg, cur_len);
buf[cur_len] = '\n';
- memcpy(buf + cur_len + 1, new_msg, new_len);
+ buf[cur_len + 1] = '\n';
+ memcpy(buf + cur_len + 2, new_msg, new_len);
free(cur_msg);
free(new_msg);
return 0;
}
+static int string_list_add_note_lines(struct string_list *sort_uniq_list,
+ const unsigned char *sha1)
+{
+ char *data;
+ unsigned long len;
+ enum object_type t;
+ struct strbuf buf = STRBUF_INIT;
+ struct strbuf **lines = NULL;
+ int i, list_index;
+
+ if (is_null_sha1(sha1))
+ return 0;
+
+ /* read_sha1_file NUL-terminates */
+ data = read_sha1_file(sha1, &t, &len);
+ if (t != OBJ_BLOB || !data || !len) {
+ free(data);
+ return t != OBJ_BLOB || !data;
+ }
+
+ strbuf_attach(&buf, data, len, len + 1);
+ lines = strbuf_split(&buf, '\n');
+
+ for (i = 0; lines[i]; i++) {
+ if (lines[i]->buf[lines[i]->len - 1] == '\n')
+ strbuf_setlen(lines[i], lines[i]->len - 1);
+ if (!lines[i]->len)
+ continue; /* skip empty lines */
+ list_index = string_list_find_insert_index(sort_uniq_list,
+ lines[i]->buf, 0);
+ if (list_index < 0)
+ continue; /* skip duplicate lines */
+ string_list_insert_at_index(sort_uniq_list, list_index,
+ lines[i]->buf);
+ }
+
+ strbuf_list_free(lines);
+ strbuf_release(&buf);
+ return 0;
+}
+
+static int string_list_join_lines_helper(struct string_list_item *item,
+ void *cb_data)
+{
+ struct strbuf *buf = cb_data;
+ strbuf_addstr(buf, item->string);
+ strbuf_addch(buf, '\n');
+ return 0;
+}
+
+int combine_notes_cat_sort_uniq(unsigned char *cur_sha1,
+ const unsigned char *new_sha1)
+{
+ struct string_list sort_uniq_list = { NULL, 0, 0, 1 };
+ struct strbuf buf = STRBUF_INIT;
+ int ret = 1;
+
+ /* read both note blob objects into unique_lines */
+ if (string_list_add_note_lines(&sort_uniq_list, cur_sha1))
+ goto out;
+ if (string_list_add_note_lines(&sort_uniq_list, new_sha1))
+ goto out;
+
+ /* create a new blob object from sort_uniq_list */
+ if (for_each_string_list(&sort_uniq_list,
+ string_list_join_lines_helper, &buf))
+ goto out;
+
+ ret = write_sha1_file(buf.buf, buf.len, blob_type, cur_sha1);
+
+out:
+ strbuf_release(&buf);
+ string_list_clear(&sort_uniq_list, 0);
+ return ret;
+}
+
static int string_list_add_one_ref(const char *path, const unsigned char *sha1,
int flag, void *cb)
{
strbuf_release(&globbuf);
}
-static int string_list_add_refs_from_list(struct string_list_item *item,
- void *cb)
-{
- struct string_list *list = cb;
- string_list_add_refs_by_glob(list, item->string);
- return 0;
-}
-
static int notes_display_config(const char *k, const char *v, void *cb)
{
int *load_refs = cb;
load_subtree(t, &root_tree, t->root, 0);
}
-struct load_notes_cb_data {
- int counter;
- struct notes_tree **trees;
-};
-
-static int load_one_display_note_ref(struct string_list_item *item,
- void *cb_data)
-{
- struct load_notes_cb_data *c = cb_data;
- struct notes_tree *t = xcalloc(1, sizeof(struct notes_tree));
- init_notes(t, item->string, combine_notes_ignore, 0);
- c->trees[c->counter++] = t;
- return 0;
-}
-
struct notes_tree **load_notes_trees(struct string_list *refs)
{
+ struct string_list_item *item;
+ int counter = 0;
struct notes_tree **trees;
- struct load_notes_cb_data cb_data;
trees = xmalloc((refs->nr+1) * sizeof(struct notes_tree *));
- cb_data.counter = 0;
- cb_data.trees = trees;
- for_each_string_list(refs, load_one_display_note_ref, &cb_data);
- trees[cb_data.counter] = NULL;
+ for_each_string_list_item(item, refs) {
+ struct notes_tree *t = xcalloc(1, sizeof(struct notes_tree));
+ init_notes(t, item->string, combine_notes_ignore, 0);
+ trees[counter++] = t;
+ }
+ trees[counter] = NULL;
return trees;
}
git_config(notes_display_config, &load_config_refs);
- if (opt && opt->extra_notes_refs)
- for_each_string_list(opt->extra_notes_refs,
- string_list_add_refs_from_list,
- &display_notes_refs);
+ if (opt && opt->extra_notes_refs) {
+ struct string_list_item *item;
+ for_each_string_list_item(item, opt->extra_notes_refs)
+ string_list_add_refs_by_glob(&display_notes_refs,
+ item->string);
+ }
display_notes_trees = load_notes_trees(&display_notes_refs);
string_list_clear(&display_notes_refs, 0);
return note_tree_insert(t, t->root, 0, l, PTR_TYPE_NOTE, combine_notes);
}
-void remove_note(struct notes_tree *t, const unsigned char *object_sha1)
+int remove_note(struct notes_tree *t, const unsigned char *object_sha1)
{
struct leaf_node l;
if (!t)
t = &default_notes_tree;
assert(t->initialized);
- t->dirty = 1;
hashcpy(l.key_sha1, object_sha1);
hashclr(l.val_sha1);
note_tree_remove(t, t->root, 0, &l);
+ if (is_null_sha1(l.val_sha1)) // no note was removed
+ return 1;
+ t->dirty = 1;
+ return 0;
}
const unsigned char *get_note(struct notes_tree *t,