trailer: add interface for iterating over commit trailers
The trailer code knows how to parse out the trailers and re-format them, but there's no easy way to iterate over the trailers (you can use trailer_info, but you have to then do a bunch of extra parsing). Let's add an iteration interface that makes this easy to do. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Jeff King committed
Sep 27, 2020 at 04:40 UTC
f0939a0eb157cb23cd300d32ee0bff2f82aa5959
2 files changed
+79
-2
trailer.c
+36
@@ -1185,3 +1185,39 @@ void format_trailers_from_commit(struct strbuf *out, const char *msg,
1185
format_trailer_info(out, &info, opts);
1186
trailer_info_release(&info);
1187
}
1188
+
1189
+void trailer_iterator_init(struct trailer_iterator *iter, const char *msg)
1190
+{
1191
+ struct process_trailer_options opts = PROCESS_TRAILER_OPTIONS_INIT;
1192
+ strbuf_init(&iter->key, 0);
1193
+ strbuf_init(&iter->val, 0);
1194
+ opts.no_divider = 1;
1195
+ trailer_info_get(&iter->info, msg, &opts);
1196
+ iter->cur = 0;
1197
+}
1198
+
1199
+int trailer_iterator_advance(struct trailer_iterator *iter)
1200
+{
1201
+ while (iter->cur < iter->info.trailer_nr) {
1202
+ char *trailer = iter->info.trailers[iter->cur++];
1203
+ int separator_pos = find_separator(trailer, separators);
1204
+
1205
+ if (separator_pos < 1)
1206
+ continue; /* not a real trailer */
1207
+
1208
+ strbuf_reset(&iter->key);
1209
+ strbuf_reset(&iter->val);
1210
+ parse_trailer(&iter->key, &iter->val, NULL,
1211
+ trailer, separator_pos);
1212
+ unfold_value(&iter->val);
1213
+ return 1;
1214
+ }
1215
+ return 0;
1216
+}
1217
+
1218
+void trailer_iterator_release(struct trailer_iterator *iter)
1219
+{
1220
+ trailer_info_release(&iter->info);
1221
+ strbuf_release(&iter->val);
1222
+ strbuf_release(&iter->key);
1223
+}
trailer.h
+43
-2
@@ -2,8 +2,7 @@
2
#define TRAILER_H
3
4
#include "list.h"
5
-
6
-struct strbuf;
5
+#include "strbuf.h"
6
7
enum trailer_where {
8
WHERE_DEFAULT,
@@ -103,4 +102,46 @@ void trailer_info_release(struct trailer_info *info);
102
void format_trailers_from_commit(struct strbuf *out, const char *msg,
103
const struct process_trailer_options *opts);
104
105
+/*
106
+ * An interface for iterating over the trailers found in a particular commit
107
+ * message. Use like:
108
+ *
109
+ * struct trailer_iterator iter;
110
+ * trailer_iterator_init(&iter, msg);
111
+ * while (trailer_iterator_advance(&iter))
112
+ * ... do something with iter.key and iter.val ...
113
+ * trailer_iterator_release(&iter);
114
+ */
115
+struct trailer_iterator {
116
+ struct strbuf key;
117
+ struct strbuf val;
118
+
119
+ /* private */
120
+ struct trailer_info info;
121
+ size_t cur;
122
+};
123
+
124
+/*
125
+ * Initialize "iter" in preparation for walking over the trailers in the commit
126
+ * message "msg". The "msg" pointer must remain valid until the iterator is
127
+ * released.
128
+ *
129
+ * After initializing, note that key/val will not yet point to any trailer.
130
+ * Call advance() to parse the first one (if any).
131
+ */
132
+void trailer_iterator_init(struct trailer_iterator *iter, const char *msg);
133
+
134
+/*
135
+ * Advance to the next trailer of the iterator. Returns 0 if there is no such
136
+ * trailer, and 1 otherwise. The key and value of the trailer can be
137
+ * fetched from the iter->key and iter->value fields (which are valid
138
+ * only until the next advance).
139
+ */
140
+int trailer_iterator_advance(struct trailer_iterator *iter);
141
+
142
+/*
143
+ * Release all resources associated with the trailer iteration.
144
+ */
145
+void trailer_iterator_release(struct trailer_iterator *iter);
146
+
147
#endif /* TRAILER_H */