I have been wanting to provide a tag value array variant to this post for a while now as I belive it is more easy to follow than a plain value array. It does the same thing but use the tag too. The memory and performance overhead of using tag_value instead of value is negligible here, while the advantage is slightly improved readability:
// NOTE: See the original post for the other changes needed to the original (here ConfD-6.7.1) arpstat.c file
...
static int navals;
static int max_nobjs = 100; // Chunk size hardcoded here to simplify
static int get_next_object_tag(struct confd_trans_ctx *tctx,
confd_hkeypath_t *keypath, long next)
{
int i;
confd_tag_value_t *tv;
struct confd_tag_next_object *tobj;
struct arpdata *dp = tctx->t_opaque;
struct aentry *curr;
if (next == -1) { /* first call */
if (need_arp(dp)) {
if (run_arp(dp) == CONFD_ERR)
return CONFD_ERR;
}
curr = dp->arp_entries;
} else {
curr = (struct aentry *)next;
}
if (curr == NULL) {
confd_data_reply_next_key(tctx, NULL, -1, -1);
return CONFD_OK;
}
tobj = malloc(sizeof(struct confd_tag_next_object) * (max_nobjs + 1));
tv = (confd_tag_value_t *) malloc(sizeof(confd_tag_value_t) * max_nobjs * navals);
for (i = 0; curr != NULL && i < max_nobjs; curr = curr->next, i++) { /* Collect max_nobjs or as many as there is rows in the table / list entries */
tobj[i].tv = &tv[i * navals];
CONFD_SET_TAG_IPV4(&(tobj[i].tv[0]), arpe_ip, curr->ip4);
CONFD_SET_TAG_STR(&(tobj[i].tv[1]), arpe_ifname, curr->iface);
if (curr->hwaddr == NULL) {
CONFD_SET_TAG_NOEXISTS(&(tobj[i].tv[2]), arpe_hwaddr);
} else {
CONFD_SET_TAG_STR(&(tobj[i].tv[2]), arpe_hwaddr, curr->hwaddr);
}
CONFD_SET_TAG_BOOL(&(tobj[i].tv[3]), arpe_permanent, curr->perm);
CONFD_SET_TAG_BOOL(&(tobj[i].tv[4]), arpe_published, curr->pub);
tobj[i].n = navals;
tobj[i].next = (long)curr->next;
}
if (curr == NULL) {
tobj[i++].tv = NULL;
}
confd_data_reply_next_object_tag_value_arrays(tctx, tobj, i, 0); /* Reply with an array of object arrays. I.e. the whole table / list */
free(tv);
free(tobj);
return CONFD_OK;
}
int main(int argc, char *argv[])
{
...
data.get_next_object = get_next_object_tag;
...
if (confd_load_schemas((struct sockaddr*)&addr,
sizeof (struct sockaddr_in)) != CONFD_OK)
confd_fatal("Failed to load schemas from confd\n");
object = confd_cs_node_cd(NULL, "/arpe:arpentries/arpe");
navals = confd_max_object_size(object);
...
}