+static void fprintf_exec_filter(struct cgit_filter *base, FILE *f, const char *prefix)
+{
+ struct cgit_exec_filter *filter = (struct cgit_exec_filter *) base;
+ fprintf(f, "%sexec:%s\n", prefix, filter->cmd);
+}
+
+static void cleanup_exec_filter(struct cgit_filter *base)
+{
+ struct cgit_exec_filter *filter = (struct cgit_exec_filter *) base;
+ if (filter->argv) {
+ free(filter->argv);
+ filter->argv = NULL;
+ }
+ if (filter->cmd) {
+ free(filter->cmd);
+ filter->cmd = NULL;
+ }
+}
+
+static struct cgit_filter *new_exec_filter(const char *cmd, int argument_count)
+{
+ struct cgit_exec_filter *f;
+ int args_size = 0;
+
+ f = xmalloc(sizeof(*f));
+ /* We leave argv for now and assign it below. */
+ cgit_exec_filter_init(f, xstrdup(cmd), NULL);
+ f->base.argument_count = argument_count;
+ args_size = (2 + argument_count) * sizeof(char *);
+ f->argv = xmalloc(args_size);
+ memset(f->argv, 0, args_size);
+ f->argv[0] = f->cmd;
+ return &f->base;
+}
+
+void cgit_exec_filter_init(struct cgit_exec_filter *filter, char *cmd, char **argv)
+{
+ memset(filter, 0, sizeof(*filter));
+ filter->base.open = open_exec_filter;
+ filter->base.close = close_exec_filter;
+ filter->base.fprintf = fprintf_exec_filter;
+ filter->base.cleanup = cleanup_exec_filter;
+ filter->cmd = cmd;
+ filter->argv = argv;
+ /* The argument count for open_filter is zero by default, unless called from new_filter, above. */
+ filter->base.argument_count = 0;
+}
+
+int cgit_open_filter(struct cgit_filter *filter, ...)
+{
+ int result;
+ va_list ap;
+ va_start(ap, filter);
+ result = filter->open(filter, ap);
+ va_end(ap);
+ return result;
+}
+
+int cgit_close_filter(struct cgit_filter *filter)
+{
+ return filter->close(filter);
+}
+