/* vim: set expandtab ts=4 sw=4: */ /* * You may redistribute this program and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "memory/Allocator.h" #include "benc/Dict.h" #include "benc/String.h" #include int32_t Dict_size(const Dict* dictionary) { if (dictionary != NULL) { struct Dict_Entry* entry = *dictionary; int32_t i; for (i = 0; entry != NULL; i++) { entry = entry->next; } return i; } return 0; } static Object* lookupObject(const Dict* dictionary, const String* key) { if (dictionary == NULL || key == NULL) { return NULL; } const struct Dict_Entry* curr = *dictionary; while (curr != NULL) { if (String_equals(key, curr->key)) { return curr->val; } curr = curr->next; } /* key not found */ return NULL; } /** @see Object.h */ int64_t* Dict_getInt(const Dict* dictionary, const String* key) { Object* obj = lookupObject(dictionary, key); if (obj == NULL || obj->type != Object_INTEGER) { return NULL; } return &(obj->as.number); } /** @see Object.h */ String* Dict_getString(const Dict* dictionary, const String* key) { Object* obj = lookupObject(dictionary, key); if (obj == NULL || obj->type != Object_STRING) { return NULL; } return obj->as.string; } /** @see Object.h */ Dict* Dict_getDict(const Dict* dictionary, const String* key) { Object* obj = lookupObject(dictionary, key); if (obj == NULL || obj->type != Object_DICT) { return NULL; } return obj->as.dictionary; } /** @see Object.h */ List* Dict_getList(const Dict* dictionary, const String* key) { Object* obj = lookupObject(dictionary, key); if (obj == NULL || obj->type != Object_LIST) { return NULL; } return obj->as.list; } /** @see Object.h */ Dict* Dict_new(struct Allocator* allocator) { return Allocator_calloc(allocator, sizeof(Dict), 1); } /** * Put a key:value pair into a dictionary. * NOTE: This will not copy the given object, * only add a pointer to it in the dictionary. * If dictionary is NULL then a new dictionary will be created and returned. * * @param dictionary this must be a bencoded dictionary or NULL, if NULL then a new dictionary is made. * @param key the reference key to use for putting the entry in the dictionary. * @param value the value to insert with the key. * @param allocator the means to get memory for storing the dictionary entry wrapper. * @return if the dictionary parameter is NULL then this will be the newly created dictionary. * Otherwise: if the key already exists in the dictionary then the value which was * displaced by the put, if not then NULL. */ static Object* putObject(Dict* dictionary, const String* key, Object* value, struct Allocator* allocator) { struct Dict_Entry** prev_p = dictionary; struct Dict_Entry* current = *dictionary; while (current != NULL) { int cmp = String_compare(key, current->key); if (cmp < 0) { break; } else if (cmp == 0) { Object* out = current->val; current->val = value; return out; } prev_p = &(current->next); current = current->next; } struct Dict_Entry* entry = Allocator_malloc(allocator, sizeof(struct Dict_Entry)); entry->key = (String*) key; // need to drop the const :( entry->val = value; entry->next = current; *prev_p = entry; return NULL; } /** @see Object.h */ Object* Dict_putInt(Dict* dictionary, const String* key, int64_t value, struct Allocator* allocator) { Object* v = Allocator_clone(allocator, (&(Object) { .type = Object_INTEGER, .as.number = value })); return putObject(dictionary, key, v, allocator); } /** @see Object.h */ Object* Dict_putString(Dict* dictionary, const String* key, String* value, struct Allocator* allocator) { if (key == NULL || value == NULL) { return NULL; } Object* v = Allocator_clone(allocator, (&(Object) { .type = Object_STRING, .as.string = value })); return putObject(dictionary, key, v, allocator); } /** @see Object.h */ Object* Dict_putList(Dict* dictionary, const String* key, List* value, struct Allocator* allocator) { if (key == NULL || value == NULL) { return NULL; } Object* v = Allocator_clone(allocator, (&(Object) { .type = Object_LIST, /* Lists and dictionaries are double pointers so they have to be loaded. */ .as.list = value })); return putObject(dictionary, key, v, allocator); } Object* Dict_putDict(Dict* dictionary, const String* key, Dict* value, struct Allocator* allocator) { if (key == NULL || value == NULL) { return NULL; } Object* v = Allocator_clone(allocator, (&(Object) { .type = Object_DICT, /* Lists and dictionaries are double pointers so they have to be loaded. */ .as.dictionary = value })); return putObject(dictionary, key, v, allocator); } /** @see Object.h */ int32_t Dict_remove(Dict* dictionary, const String* key) { struct Dict_Entry** prev_p = dictionary; struct Dict_Entry* current = *dictionary; while (current != NULL) { if (String_equals(key, current->key)) { *prev_p = current->next; return 1; } prev_p = &(current->next); current = current->next; } return 0; }