On Wed, May 7, 2025 at 10:25 AM Patrick Steinhardt <ps@xxxxxx> wrote: > > On Tue, Apr 29, 2025 at 04:52:41PM +0200, Christian Couder wrote: > > +/* > > + * Linked list for promisor remotes involved in the "promisor-remote" > > + * protocol capability. > > + * > > + * 'fields' contains a defined set of field name/value pairs for > > + * each promisor remote. Field names are stored in the 'string' > > + * member, and values in the 'util' member. > > + * > > + * Currently supported field names: > > + * - "name": The name of the promisor remote. > > + * - "url": The URL of the promisor remote. > > + * > > + * Except for "name", each "<field_name>/<field_value>" pair should > > + * correspond to a "remote.<name>.<field_name>" config variable set to > > + * <field_value> where "<name>" is a promisor remote name. > > + * > > + * 'fields' should not be sorted, as we will rely on the order we put > > + * things into it. So, for example, 'string_list_append()' should be > > + * used instead of 'string_list_insert()'. > > + */ > > +struct promisor_info { > > + struct promisor_info *next; > > + struct string_list fields; > > Now that we have a restricted set of accepted fields, wouldn't it be > easier to store those as individual members of this struct directly? I have done so in the v3. The struct now looks like this at the end of the series: struct promisor_info { struct promisor_info *next; const char *name; const char *url; const char *filter; const char *token; }; > [snip] > > /* > > - * Find first index of 'nicks' where there is 'nick'. 'nick' is > > - * compared case sensitively to the strings in 'nicks'. If not found > > - * 'nicks->nr' is returned. > > + * Find first element of 'p' where the 'name' field is 'nick'. 'nick' > > + * is compared case sensitively to the strings in 'p'. If not found > > + * NULL is returned. > > */ > > -static size_t remote_nick_find(struct strvec *nicks, const char *nick) > > +static struct promisor_info *remote_nick_find(struct promisor_info *p, const char *nick) > > { > > - for (size_t i = 0; i < nicks->nr; i++) > > - if (!strcmp(nicks->v[i], nick)) > > - return i; > > - return nicks->nr; > > + for (; p; p = p->next) { > > + if (strcmp(p->fields.items[0].string, "name")) > > + BUG("First field of promisor info should be 'name', but was '%s'.", > > + p->fields.items[0].string); > > + if (!strcmp(p->fields.items[0].util, nick)) > > + return p; > > + } > > + return NULL; > > } > > > > enum accept_promisor { > > If so, we could also simplify code like this because we wouldn't have to > assume any indices anymore. Yeah, it simplifies things, but on the other hand in some places the fields cannot be handled in a generic way, so we have things like: if (!strcmp(elem, promisor_field_name)) info->name = value; else if (!strcmp(elem, promisor_field_url)) info->url = value; else if (!strcasecmp(elem, promisor_field_filter)) info->filter = value; else if (!strcasecmp(elem, promisor_field_token)) info->token = value; Anyway I think that it's not too bad.