+
+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;
+}
+
+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);
+}
+
+void cgit_fprintf_filter(struct cgit_filter *filter, FILE *f, const char *prefix)
+{
+ filter->fprintf(filter, f, prefix);
+}
+
+
+
+static const struct {
+ const char *prefix;
+ struct cgit_filter *(*ctor)(const char *cmd, filter_type filtertype);
+} filter_specs[] = {
+ { "exec", new_exec_filter },
+};
+
+struct cgit_filter *cgit_new_filter(const char *cmd, filter_type filtertype)
+{
+ char *colon;
+ int i;
+ size_t len;
+ if (!cmd || !cmd[0])
+ return NULL;
+
+ colon = strchr(cmd, ':');
+ len = colon - cmd;
+ /*
+ * In case we're running on Windows, don't allow a single letter before
+ * the colon.
+ */
+ if (len == 1)
+ colon = NULL;
+
+ /* If no prefix is given, exec filter is the default. */
+ if (!colon)
+ return new_exec_filter(cmd, filtertype);
+
+ for (i = 0; i < ARRAY_SIZE(filter_specs); i++) {
+ if (len == strlen(filter_specs[i].prefix) &&
+ !strncmp(filter_specs[i].prefix, cmd, len))
+ return filter_specs[i].ctor(colon + 1, filtertype);
+ }
+
+ die("Invalid filter type: %.*s", (int) len, cmd);
+}
+