Commit d43974fb5cbfda6ec28fc92b83d03db0af73748b

Brian Lopez 2018-01-16T13:40:26

Change trailer API to return a simple array

diff --git a/include/git2/message.h b/include/git2/message.h
index a74dcc2..e3c9fe7 100644
--- a/include/git2/message.h
+++ b/include/git2/message.h
@@ -38,7 +38,18 @@ GIT_BEGIN_DECL
  */
 GIT_EXTERN(int) git_message_prettify(git_buf *out, const char *message, int strip_comments, char comment_char);
 
-typedef int(*git_message_trailer_cb)(const char *key, const char *value, void *payload);
+typedef struct {
+  const char *key;
+  const char *value;
+} git_message_trailer;
+
+typedef struct {
+  git_message_trailer *trailers;
+  size_t count;
+
+  /* private */
+  char *_trailer_block;
+} git_message_trailer_array;
 
 /**
  * Parse trailers out of a message, calling a callback once for each trailer.
@@ -48,15 +59,14 @@ typedef int(*git_message_trailer_cb)(const char *key, const char *value, void *p
  * Trailers are key/value pairs in the last paragraph of a message, not
  * including any patches or conflicts that may be present.
  *
+ * @param arr A pre-allocated git_message_trailer_array struct to be filled in
+ *            with any trailers found during parsing.
  * @param message The message to be parsed
- * @param cb The callback to call for each trailer found in the message. The
- *     key and value arguments are pointers to NUL-terminated C strings. These
- *     pointers are only guaranteed to be valid until the callback returns.
- *     User code must make a copy of this data should it need to be retained
- * @param payload Pointer to callback data (optional)
  * @return 0 on success, or non-zero callback return value.
  */
-GIT_EXTERN(int) git_message_trailers(const char *message, git_message_trailer_cb cb, void *payload);
+GIT_EXTERN(int) git_message_trailers(git_message_trailer_array *arr, const char *message);
+
+GIT_EXTERN(void) git_message_trailer_array_free(git_message_trailer_array *arr);
 
 /** @} */
 GIT_END_DECL
diff --git a/src/trailer.c b/src/trailer.c
index cfefc53..79db9a4 100644
--- a/src/trailer.c
+++ b/src/trailer.c
@@ -4,6 +4,7 @@
  * This file is part of libgit2, distributed under the GNU GPL v2 with
  * a Linking Exception. For full terms see the included COPYING file.
  */
+#include "array.h"
 #include "common.h"
 #include "git2/message.h"
 
@@ -279,13 +280,16 @@ enum trailer_state {
 #define NEXT(st) { state = (st); ptr++; continue; }
 #define GOTO(st) { state = (st); continue; }
 
-int git_message_trailers(const char *message, git_message_trailer_cb cb, void *payload)
+typedef git_array_t(git_message_trailer) git_array_trailer_t;
+
+int git_message_trailers(git_message_trailer_array *trailer_arr, const char *message)
 {
 	enum trailer_state state = S_START;
 	int rc = 0;
 	char *ptr;
 	char *key = NULL;
 	char *value = NULL;
+	git_array_trailer_t arr = GIT_ARRAY_INIT;
 
 	size_t trailer_len;
 	char *trailer = find_trailer(message, &trailer_len);
@@ -373,9 +377,10 @@ int git_message_trailers(const char *message, git_message_trailer_cb cb, void *p
 				GOTO(S_VALUE_END);
 			}
 			case S_VALUE_END: {
-				if ((rc = cb(key, value, payload))) {
-					goto ret;
-				}
+				git_message_trailer *t = git_array_alloc(arr);
+
+				t->key = key;
+				t->value = value;
 
 				key = NULL;
 				value = NULL;
@@ -397,6 +402,15 @@ int git_message_trailers(const char *message, git_message_trailer_cb cb, void *p
 	}
 
 ret:
-	git__free(trailer);
+	trailer_arr->_trailer_block = trailer;
+	trailer_arr->trailers = arr.ptr;
+	trailer_arr->count = arr.size;
+
 	return rc;
 }
+
+void git_message_trailer_array_free(git_message_trailer_array *arr)
+{
+	git__free(arr->_trailer_block);
+	git__free(arr->trailers);
+}
diff --git a/tests/message/trailer.c b/tests/message/trailer.c
index 83fc778..77ad710 100644
--- a/tests/message/trailer.c
+++ b/tests/message/trailer.c
@@ -6,32 +6,22 @@ struct trailer {
 	const char *value;
 };
 
-struct cb_state {
-	struct trailer *trailer;
-};
-
-static int trailer_cb(const char *key, const char *value, void *st_)
-{
-	struct cb_state *st = st_;
-
-	cl_assert_equal_s(st->trailer->key, key);
-	cl_assert_equal_s(st->trailer->value, value);
-
-	st->trailer++;
-
-	return 0;
-}
-
 static void assert_trailers(const char *message, struct trailer *trailers)
 {
-	struct cb_state st = { trailers };
+	git_message_trailer_array arr;
 
-	int rc = git_message_trailers(message, trailer_cb, &st);
+	int rc = git_message_trailers(&arr, message);
 
-	cl_assert_equal_s(NULL, st.trailer->key);
-	cl_assert_equal_s(NULL, st.trailer->value);
+	cl_assert_equal_i(0, rc);
+
+	for(size_t i=0; i<arr.count; i++) {
+		cl_assert_equal_s(arr.trailers[i].key, trailers[i].key);
+		cl_assert_equal_s(arr.trailers[i].value, trailers[i].value);
+	}
 
 	cl_assert_equal_i(0, rc);
+
+	git_message_trailer_array_free(&arr);
 }
 
 void test_message_trailer__simple(void)