263 lines
6.9 KiB
C
263 lines
6.9 KiB
C
#include "key_value_pair.h"
|
|
|
|
#include <ctype.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
char *key_value_pair_to_string(key_value_pair *kv)
|
|
{
|
|
char *str = malloc(sizeof(char) * (strlen(kv->key) + strlen(kv->value) + 1));
|
|
if (str == NULL) return NULL;
|
|
|
|
strcpy(str, kv->key);
|
|
strcat(str, kv->value);
|
|
|
|
return str;
|
|
}
|
|
|
|
char *key_value_pair_list_to_string(key_value_pair **head){
|
|
key_value_pair *kvp_it = *head;
|
|
|
|
char *ret = NULL;
|
|
|
|
while(kvp_it != NULL){
|
|
char *kvp2str = kvp_it->toString(kvp_it);
|
|
if(kvp2str == NULL){
|
|
kvp_it = kvp_it->next;
|
|
continue;
|
|
}
|
|
if(!ret){
|
|
ret = strdup(kvp2str);
|
|
free(kvp2str);
|
|
kvp_it = kvp_it->next;
|
|
}
|
|
else{
|
|
char *tmp = realloc(ret, strlen(ret) + strlen(kvp2str) + 1);
|
|
if(!tmp){
|
|
free(ret);
|
|
perror("Failed to reallocate memory for ret");
|
|
free(kvp2str);
|
|
return NULL;
|
|
}
|
|
ret = tmp;
|
|
strcat(ret, kvp2str);
|
|
free(kvp2str);
|
|
kvp_it = kvp_it->next;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
// initializes a new instance of key_value_pair with given values on given pointer
|
|
key_value_pair *init_key_value_pair(const char *key, const char *value)
|
|
{
|
|
key_value_pair *kv = (key_value_pair*)malloc(sizeof(key_value_pair));
|
|
if (kv == NULL)
|
|
{
|
|
perror("Failed to allocate memory for key_value_pair");
|
|
return NULL;
|
|
}
|
|
kv->key = strdup(key);
|
|
if (kv->key == NULL)
|
|
{
|
|
free(kv);
|
|
perror("Failed to allocate memory for key_value_pair->key");
|
|
return NULL;
|
|
}
|
|
kv->value = strdup(value);
|
|
if (kv->value == NULL)
|
|
{
|
|
free(kv->key);
|
|
free(kv);
|
|
perror("Failed to allocate memory for key_value_pair->value");
|
|
return NULL;
|
|
}
|
|
|
|
kv->next = NULL;
|
|
kv->toString = key_value_pair_to_string;
|
|
|
|
return kv;
|
|
}
|
|
|
|
// frees the given instance of struct key_value_pair
|
|
void free_key_value_pair(key_value_pair **kv)
|
|
{
|
|
if (*kv == NULL) return;
|
|
|
|
free((*kv)->key);
|
|
free((*kv)->value);
|
|
free(*kv);
|
|
|
|
*kv = NULL;
|
|
}
|
|
|
|
// frees whole key_value_pair list structure
|
|
void free_key_value_pairs(key_value_pair **head, key_value_pair **tail)
|
|
{
|
|
while (*head != NULL)
|
|
{
|
|
key_value_pair *toFree = *head;
|
|
*head = (*head)->next;
|
|
free_key_value_pair(&toFree);
|
|
}
|
|
*tail = NULL;
|
|
}
|
|
|
|
int sum_f(const char *str){
|
|
if(str == NULL) return 0;
|
|
int sum = 0;
|
|
size_t len = strlen(str);
|
|
for(size_t i = 0; i < len; i++){
|
|
sum += str[i] - 48;
|
|
}
|
|
return sum;
|
|
}
|
|
|
|
// adds given key_value_pair to list
|
|
int add_key_value_pair(key_value_pair *kv, key_value_pair **head, key_value_pair **tail, bool concat)
|
|
{
|
|
if (!head || !*head)
|
|
{
|
|
*head = kv;
|
|
*tail = kv;
|
|
}
|
|
else
|
|
{
|
|
key_value_pair *iterator = *head;
|
|
key_value_pair *prev = iterator;
|
|
while (iterator != NULL)
|
|
{
|
|
if (strcmp(kv->key, iterator->key) == 0)
|
|
{
|
|
if(concat){
|
|
char *bak = iterator->value;
|
|
iterator->value = (char*)realloc(iterator->value, strlen(iterator->value) + strlen(kv->value) + 1);
|
|
if (iterator->value == NULL)
|
|
{
|
|
iterator->value = bak;
|
|
return -1;
|
|
}
|
|
strcat(iterator->value, kv->value);
|
|
free_key_value_pair(&kv);
|
|
}
|
|
else{
|
|
long sum = atol(iterator->value) + atol(kv->value);
|
|
char buffer[32];
|
|
snprintf(buffer, sizeof(buffer), "%ld", sum);
|
|
char *tmp = realloc(iterator->value, strlen(buffer) + 1);
|
|
if (!tmp) {
|
|
return -1;
|
|
}
|
|
iterator->value = tmp;
|
|
strcpy(iterator->value, buffer);
|
|
free_key_value_pair(&kv);
|
|
}
|
|
return 0;
|
|
}
|
|
prev = iterator;
|
|
iterator = iterator->next;
|
|
}
|
|
prev->next = kv;
|
|
*tail = kv;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// removes given key_value_pair from list
|
|
void remove_key_value_pair(key_value_pair *kv, key_value_pair **head, key_value_pair **tail)
|
|
{
|
|
if (*head == NULL || kv == NULL) return;
|
|
if (*head == kv)
|
|
{
|
|
*head = (*head)->next;
|
|
if (*tail == kv) *tail = NULL;
|
|
return;
|
|
}
|
|
|
|
key_value_pair *iterator = *head;
|
|
if (iterator == NULL) return;
|
|
|
|
while (iterator != NULL)
|
|
{
|
|
if (iterator->next == kv)
|
|
{
|
|
iterator->next = kv->next;
|
|
if (*tail == kv) *tail = iterator;
|
|
return;
|
|
}
|
|
iterator = iterator->next;
|
|
}
|
|
}
|
|
|
|
void defragment_key_value_pairs(key_value_pair **head, key_value_pair **tail){
|
|
if(!head || !*head || !tail || !*tail) return;
|
|
|
|
key_value_pair *slow_it = *head;
|
|
|
|
while(slow_it){
|
|
key_value_pair *prev = slow_it;
|
|
slow_it = slow_it->next;
|
|
key_value_pair *fast_it = slow_it;
|
|
|
|
while(fast_it){
|
|
if(strcmp(prev->key, fast_it->key) == 0){
|
|
remove_key_value_pair(prev, head, tail);
|
|
int toInsertValue = (int)atol(prev->value);
|
|
int toAddOnValue = (int)atol(fast_it->value);
|
|
char value[16];
|
|
snprintf(value, 16, "%d", toInsertValue + toAddOnValue);
|
|
free(fast_it->value);
|
|
fast_it->value = strdup(value);
|
|
free_key_value_pair(&prev);
|
|
}
|
|
fast_it = fast_it->next;
|
|
}
|
|
}
|
|
}
|
|
|
|
void extract_key_value_pairs(char *red_str, key_value_pair **head, key_value_pair **tail, bool doReduce){
|
|
char *it = red_str;
|
|
bool reading_value = false;
|
|
char *word_start = it;
|
|
size_t word_length = 0;
|
|
size_t value_length = 0;
|
|
|
|
while(true){
|
|
if(!*it || (isalpha(*it) && reading_value)){
|
|
char key[word_length + 1];
|
|
strncpy(key, word_start, word_length);
|
|
key[word_length] = '\0';
|
|
char value[16];
|
|
if(doReduce){
|
|
snprintf(value, 16, "%d", (int)value_length);
|
|
}
|
|
else{
|
|
strncpy(value, word_start + word_length, value_length);
|
|
value[value_length] = '\0';
|
|
}
|
|
|
|
key_value_pair *kv = init_key_value_pair(key, value);
|
|
add_key_value_pair(kv, head, tail, false);
|
|
|
|
// reset
|
|
word_length = 0;
|
|
value_length = 0;
|
|
word_start = it;
|
|
reading_value = false;
|
|
|
|
if(!*it) break;
|
|
continue;
|
|
}
|
|
if(isalpha(*it)){
|
|
word_length++;
|
|
it++;
|
|
}
|
|
else{
|
|
reading_value = true; // reassigning true is faster than if checks every iteration
|
|
value_length++;
|
|
it++;
|
|
}
|
|
}
|
|
}
|