userdiff: add and use for_each_userdiff_driver()

Refactor the userdiff_find_by_namelen() function so that a new for_each_userdiff_driver() API function does most of the work. This will be useful for the same reason we've got other for_each_*() API functions as part of various APIs, and will be used in a follow-up commit. Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Ævar Arnfjörð Bjarmason committed Apr 8, 2021 at 17:04 UTC f12fa9ee6c87efa8a926973bd203ef327686fb62
2 files changed +71 -12
userdiff.c
+58 -12
@@ -259,20 +259,33 @@ static struct userdiff_driver driver_false = {
259 { NULL, 0 }
260 };
261
262 -static struct userdiff_driver *userdiff_find_by_namelen(const char *k, size_t len)
262 +struct find_by_namelen_data {
263 + const char *name;
264 + size_t len;
265 + struct userdiff_driver *driver;
266 +};
267 +
268 +static int userdiff_find_by_namelen_cb(struct userdiff_driver *driver,
269 + enum userdiff_driver_type type, void *priv)
270 {
264 - int i;
265 - for (i = 0; i < ndrivers; i++) {
266 - struct userdiff_driver *drv = drivers + i;
267 - if (!strncmp(drv->name, k, len) && !drv->name[len])
268 - return drv;
269 - }
270 - for (i = 0; i < ARRAY_SIZE(builtin_drivers); i++) {
271 - struct userdiff_driver *drv = builtin_drivers + i;
272 - if (!strncmp(drv->name, k, len) && !drv->name[len])
273 - return drv;
271 + struct find_by_namelen_data *cb_data = priv;
272 +
273 + if (!strncmp(driver->name, cb_data->name, cb_data->len) &&
274 + !driver->name[cb_data->len]) {
275 + cb_data->driver = driver;
276 + return 1; /* tell the caller to stop iterating */
277 }
275 - return NULL;
278 + return 0;
279 +}
280 +
281 +static struct userdiff_driver *userdiff_find_by_namelen(const char *name, size_t len)
282 +{
283 + struct find_by_namelen_data udcbdata = {
284 + .name = name,
285 + .len = len,
286 + };
287 + for_each_userdiff_driver(userdiff_find_by_namelen_cb, &udcbdata);
288 + return udcbdata.driver;
289 }
290
291 static int parse_funcname(struct userdiff_funcname *f, const char *k,
@@ -379,3 +392,36 @@ struct userdiff_driver *userdiff_get_textconv(struct repository *r,
392
393 return driver;
394 }
395 +
396 +static int for_each_userdiff_driver_list(each_userdiff_driver_fn fn,
397 + enum userdiff_driver_type type, void *cb_data,
398 + struct userdiff_driver *drv,
399 + int drv_size)
400 +{
401 + int i;
402 + int ret;
403 + for (i = 0; i < drv_size; i++) {
404 + struct userdiff_driver *item = drv + i;
405 + if ((ret = fn(item, type, cb_data)))
406 + return ret;
407 + }
408 + return 0;
409 +}
410 +
411 +int for_each_userdiff_driver(each_userdiff_driver_fn fn, void *cb_data)
412 +{
413 + int ret;
414 +
415 + ret = for_each_userdiff_driver_list(fn, USERDIFF_DRIVER_TYPE_CUSTOM,
416 + cb_data, drivers, ndrivers);
417 + if (ret)
418 + return ret;
419 +
420 + ret = for_each_userdiff_driver_list(fn, USERDIFF_DRIVER_TYPE_BUILTIN,
421 + cb_data, builtin_drivers,
422 + ARRAY_SIZE(builtin_drivers));
423 + if (ret)
424 + return ret;
425 +
426 + return 0;
427 +}
userdiff.h
+13
@@ -21,6 +21,12 @@ struct userdiff_driver {
21 struct notes_cache *textconv_cache;
22 int textconv_want_cache;
23 };
24 +enum userdiff_driver_type {
25 + USERDIFF_DRIVER_TYPE_BUILTIN = 1<<0,
26 + USERDIFF_DRIVER_TYPE_CUSTOM = 1<<1,
27 +};
28 +typedef int (*each_userdiff_driver_fn)(struct userdiff_driver *,
29 + enum userdiff_driver_type, void *);
30
31 int userdiff_config(const char *k, const char *v);
32 struct userdiff_driver *userdiff_find_by_name(const char *name);
@@ -34,4 +40,11 @@ struct userdiff_driver *userdiff_find_by_path(struct index_state *istate,
40 struct userdiff_driver *userdiff_get_textconv(struct repository *r,
41 struct userdiff_driver *driver);
42
43 +/*
44 + * Iterate over all userdiff drivers. The userdiff_driver_type
45 + * argument to each_userdiff_driver_fn indicates their type. Return
46 + * non-zero to exit early from the loop.
47 + */
48 +int for_each_userdiff_driver(each_userdiff_driver_fn, void *);
49 +
50 #endif /* USERDIFF */