/* Modifies dst, but never the actual dst pointer */ void tconfig_merge(struct tconfig_block *src, struct tconfig_block *dst) { struct tconfig_block *tmp; int depth = 0; /* We want to start at the initial positions and traverse down from * there, copying the keys and values and subkeys maintaining current * order if it already exists. */ if (src == NULL || dst == NULL) return; while (src != NULL) { if (src->child != NULL) { /* Do wildcards recursively, I only figure it will * get a few levels in depth */ if ((src->value != NULL) && !strcmp(src->value,"*")) { /* The trick is to loop through the current depth * matching the key to the wildcard's key, if so, * and call this function after going to child of each * making them both in the toplevel during the merge */ tmp = dst; while (tmp->prev != NULL) tmp = tmp->prev; while (tmp != NULL) { if (tmp->key != NULL) { if (!strcmp(src->key,tmp->key)) { if (tmp->child == NULL) { tmp->child = tmalloc(sizeof(struct tconfig_block)); tmp->child->parent = tmp; tmp = tmp->child; tmp->key = NULL; tmp->value = NULL; tmp->prev = NULL; tmp->next = NULL; tmp->child = NULL; tmp = tmp->parent; /* Return back to the parent */ } tconfig_merge(src->child,tmp->child); } } tmp = tmp->next; } src = src->next; continue; } tmp = dst; /* Make sure it's at the beginning */ while (tmp->prev != NULL) tmp = tmp->prev; while (tmp != NULL) { if (tmp->key != NULL) { if (!strcmp(src->key,tmp->key) && !strcmp(src->value,tmp->value)) { /* It's a match, merely attach to it */ dst = tmp->child; break; } } tmp = tmp->next; } if (tmp == NULL) { /* No matches, create they key/value parent node */ while (dst->next != NULL && dst->key != NULL) dst = dst->next; if (dst->key != NULL) { dst->next = tmalloc(sizeof(struct tconfig_block)); dst->next->prev = dst; dst->next->next = NULL; dst = dst->next; } dst->key = tstrdup(src->key); dst->value = tstrdup(src->value); dst->parent = NULL; dst->child = tmalloc(sizeof(struct tconfig_block)); dst->child->parent = dst; dst = dst->child; dst->key = NULL; dst->value = NULL; dst->child = NULL; dst->prev = NULL; dst->next = NULL; } depth++; src = src->child; continue; } tmp = dst; /* Make sure it's at the beginning */ while (tmp->prev != NULL) tmp = tmp->prev; while (tmp != NULL) { if (tmp->key != NULL) { /* No Duplicate keys on merge unless prepended with @ */ if (!strcmp(src->key,tmp->key) && src->key[0] != '@') { /* Ignore dupes */ break; } } tmp = tmp->next; } if (tmp == NULL) { /* go to the end of the list */ while (dst->next != NULL && dst->key != NULL) dst = dst->next; if (dst->key != NULL) { dst->next = tmalloc(sizeof(struct tconfig_block)); dst->next->prev = dst; dst = dst->next; dst->next = NULL; dst->parent = NULL; dst->child = NULL; } if (src->key[0] == '@') dst->key = tstrdup(&src->key[1]); else dst->key = tstrdup(src->key); dst->value = tstrdup(src->value); dst->next = NULL; } while (src->next == NULL) { if (depth == 0) return; while (src->prev != NULL) src = src->prev; /* Do the same to dst */ while (dst->prev != NULL) dst = dst->prev; src = src->parent; dst = dst->parent; depth--; } src = src->next; } }