|
|
|
/* SPDX-License-Identifier: GPL-3.0-or-later */
|
|
|
|
/* Copyright 2022 Ivan Polyakov */
|
|
|
|
|
|
|
|
#include "keyval.h"
|
|
|
|
#include "utils.h"
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Reallocate key-value storage with new capacity.
|
|
|
|
*
|
|
|
|
* \param keyval Key-value storage.
|
|
|
|
* \param capacity New capacity.
|
|
|
|
*
|
|
|
|
* \return Status code.
|
|
|
|
*/
|
|
|
|
static int rpd_keyval_realloc(rpd_keyval *keyval, int capacity);
|
|
|
|
|
|
|
|
int rpd_keyval_init(rpd_keyval *keyval, int capacity)
|
|
|
|
{
|
|
|
|
keyval->size = keyval->capacity = 0;
|
|
|
|
keyval->unique = 1;
|
|
|
|
|
|
|
|
if (capacity == 0) {
|
|
|
|
keyval->items = NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
keyval->items = (rpd_keyval_item *) malloc(sizeof(rpd_keyval_item) * capacity);
|
|
|
|
if (!keyval->items) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
keyval->capacity = capacity;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int rpd_keyval_insert(rpd_keyval *keyval, const char *key, const char *value)
|
|
|
|
{
|
|
|
|
if (!key || !value)
|
|
|
|
return 1;
|
|
|
|
if (keyval->size == keyval->capacity) {
|
|
|
|
int tmp = keyval->capacity == 0 ? 10 : keyval->capacity * 2;
|
|
|
|
if ((tmp = rpd_keyval_realloc(keyval, tmp)))
|
|
|
|
return tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
rpd_keyval_item *item = rpd_keyval_find(keyval, key);
|
|
|
|
if (item && keyval->unique) {
|
|
|
|
free(item->key);
|
|
|
|
item->key = NULL;
|
|
|
|
if (item->val) {
|
|
|
|
free(item->val);
|
|
|
|
item->val = NULL;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
item = &keyval->items[keyval->size];
|
|
|
|
keyval->size++;
|
|
|
|
}
|
|
|
|
|
|
|
|
item->key = rpd_strdup(key);
|
|
|
|
item->val = rpd_strdup(value);
|
|
|
|
|
|
|
|
return item->key && item->val ? 0 : 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
rpd_keyval_item *rpd_keyval_find(const rpd_keyval *keyval, const char *key)
|
|
|
|
{
|
|
|
|
int i = 0;
|
|
|
|
while (i < keyval->size) {
|
|
|
|
if (!strcmp(keyval->items[i].key, key)) {
|
|
|
|
return keyval->items + i;
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
rpd_keyval_item **rpd_keyval_findall(const rpd_keyval *keyval, const char *key)
|
|
|
|
{
|
|
|
|
int i = 0, n = 0;
|
|
|
|
rpd_keyval_item **items = NULL;
|
|
|
|
while (i < keyval->size) {
|
|
|
|
if (!strcmp(keyval->items[i].key, key)) {
|
|
|
|
n++;
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
if (!n)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
items = malloc(sizeof(rpd_keyval_item *) * (n + 1));
|
|
|
|
if (!items)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
items[n] = NULL;
|
|
|
|
i = 0, n = 0;
|
|
|
|
while (i < keyval->size) {
|
|
|
|
if (!strcmp(keyval->items[i].key, key)) {
|
|
|
|
items[n] = keyval->items + i;
|
|
|
|
n++;
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return items;
|
|
|
|
}
|
|
|
|
|
|
|
|
void rpd_keyval_cleanup(rpd_keyval *keyval)
|
|
|
|
{
|
|
|
|
if (keyval->items) {
|
|
|
|
int i = 0;
|
|
|
|
while (i < keyval->size) {
|
|
|
|
rpd_keyval_item *item = keyval->items + i;
|
|
|
|
free(item->key);
|
|
|
|
if (item->val) {
|
|
|
|
free(item->val);
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
keyval->size = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int rpd_keyval_realloc(rpd_keyval *keyval, int capacity)
|
|
|
|
{
|
|
|
|
keyval->items = realloc(keyval->items, sizeof(rpd_keyval_item) * capacity);
|
|
|
|
if (!keyval->items) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
keyval->capacity = capacity;
|
|
|
|
return 0;
|
|
|
|
}
|