Function pointer iterator in Berkeley DB - c

I'm implementing an iterator to go over the records from a Berkeley DB. However, it seems I need to set the DB_DBT_USERMEM flag before the call to cursor->get with DB_NEXT.
Doing it that way would make my iterator less cohesive and will have to implement multiple iterators for each data type I want to retrieve.
Is there a way to have a generic iterator that can traverse structures w/o pointers, and basic data types? Here's what I'm trying to achieve.
#include <stdio.h>
#include <string.h>
#include <db.h>
// let this function handle integers and use DB_DBT_USERMEM for memory alignment
void integer_items(DBT key, DBT data) {
int number = 0;
data.data = &number;
data.flags = DB_DBT_USERMEM;
data.ulen = sizeof(int);
printf("key is: %s, data is: %d\n", (char *) key.data,number);
}
// let this function handle pointer structs. No need for DB_DBT_USERMEM
void ptr_struct_items(DBT key, DBT data) {
// MY_STRUCT user;
// marshall struct...
// buffsize = sizeof(int) +(strlen(user.familiar_name) + strlen(user.surname) + 2);
// databuff = malloc(buffsize);
// memset(databuff, 0, buffsize);
// ...
// printf("key is: %s, data is: %d\n", (char *) key.data,number);
}
int iterator(DB *database, void(*function)(DBT key, DBT data)) {
DBT key, data;
DBC *cursor;
memset(&key, 0, sizeof(DBT));
memset(&data, 0, sizeof(DBT));
database->cursor(database, NULL, &cursor, 0);
while(cursor->c_get(cursor, &key, &data, DB_NEXT) == 0){
(*function)(key, data);
}
cursor->c_close(cursor);
return 0;
}
int main() {
DB_ENV *myEnv;
DB *dbp;
DBT key, data;
int r, v = 10;
char *k = "Test";
db_env_create(&myEnv, 0);
myEnv->open(myEnv, "./", DB_CREATE | DB_INIT_MPOOL, 0);
db_create(&dbp, myEnv, 0);
dbp->open(dbp, NULL, "test.db", NULL, DB_HASH, DB_CREATE, 0664);
memset(&key, 0, sizeof(key));
memset(&data, 0, sizeof(data));
key.data = k;
key.size = strlen(k) +1;
data.data = &v;
data.size = sizeof(int);
if((r=dbp->put(dbp, NULL, &key, &data, 0)!=0))
fprintf(stderr, "%s\n", db_strerror(r));
iterator(dbp, integer_items);
iterator(dbp, ptr_struct_items);
return 0;
}

You almost always want to use DB_DBT_USERMEM, if only to avoiding the malloc() from inside BDB for DB_DBT_MALLOC/REALLOC. When you use it, you must pass in your own memory large enough to hold the largest item in your database. This holds for the key DBT too, as you may want to use it there.
In your example, as the key and data are so small, I'd just put character arrays on the stack in your "iterator" function, and then initialize key and data after the call to memset(). What you've got above is wrong because you're setting USERMEM after the call to c_get().
Here's a reworked example that gives BDB 256 bytes to work with for key and data.
void integer_items(DBT key, DBT data) {
int number = 0;
if (data.size == sizeof number) {
number = *(int *)data.data;
printf("key is: %s, data is: %d\n", (char *) key.data, number);
}
}
int iterator(DB *database, void(*function)(DBT key, DBT data)) {
DBT key, data;
DBC *cursor;
char kmem[256];
char dmem[256];
memset(&key, 0, sizeof(DBT));
memset(&data, 0, sizeof(DBT));
key.flags = DB_DBT_USERMEM;
key.data = kmem;
key.ulen = sizeof kmem;
data.flags = DB_DBT_USERMEM;
data.data = dmem;
data.ulen = sizeof dmem;
database->cursor(database, NULL, &cursor, 0);
while(cursor->c_get(cursor, &key, &data, DB_NEXT) == 0){
(*function)(key, data);
}
cursor->c_close(cursor);
return 0;
}
To handle different structures inside your iterator, include the data type as part of the key somehow. For example, instead of a bare integer for the key, use a struct, and have the first character define which kind of type it is. Then, inside your iterator function, you can switch on that.

Related

Can't set cbData in RegSetValue

I am trying to create a registry key with type REG_SZ and with a value longer than 4 chars.
But I can't figure out the right way to pass the data as argument :
#include <windows.h>
#include <stdio.h>
HKEY OpenKey(HKEY hRootKey, wchar_t* strKey)
{
HKEY hKey;
LONG nError = RegOpenKeyEx(hRootKey, strKey, 0, KEY_ALL_ACCESS, &hKey);
if (nError == ERROR_FILE_NOT_FOUND)
{
printf("Debug: Creating registry key\n");
nError = RegCreateKeyEx(hRootKey, strKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL);
}
if (nError) {
printf("Error: Could not find or create\n");
}
return hKey;
}
void SetValSZ(HKEY hKey, LPCTSTR lpValue, LPCTSTR data)
{
LONG nError = RegSetValueEx(hKey, lpValue, 0, REG_SZ, (const BYTE*) data, sizeof(data));
if (nError)
printf("Error: Could not set registry value\n");
}
int main()
{
HKEY hKey = OpenKey(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Policies\\Microsoft\\FVE");
const wchar_t data[] = L"AAAABBBBCCCC";
SetValSZ(hKey, L"RecoveryKeyMessage", data);
RegCloseKey(hKey);
return 0;
}
When I run it, only the first 4 characters are saved.
I must have a type mistake...
Do you have any idea to help me to fix it ?
Thank you.
PS: I hope my english is clear enoth, feel free to ask me more if it isn't.
void SetValSZ(HKEY hKey, LPCTSTR lpValue, LPCTSTR data)
{
RegSetValueEx(hKey, lpValue, 0, REG_SZ, (const BYTE*) data, sizeof(data));
}
data is being passed as a pointer to a function, so its actual size will be lost. sizeof(data) is translated to the size of a pointer, which is 4 bytes in this case.
You have to either pass in the size as a parameter:
int len = sizeof(data);
SetValSZ(..., data, len);
Or better yet, use wcslen() to calculate the string length, then multiply that by sizeof(wchar_t).
Since you are using those T macros, the function can be written as:
RegSetValueEx(hKey,lpValue,0,REG_SZ,(const BYTE*)data,sizeof(TCHAR)*(lstrlen(data) + 1));
Edit: The size should also include the terminating null character

How to use snprintf instead of strcpy in this situation?

void put(char* key, int value)
{
int i = 0;
// Iterate through elements of hashtable
while (array[i].flag == 1)
{
// If key already exists, update the value
// and return
if (strcmp(array[i].data->key, key) == 0)
{
array[i].data->value = value;
return;
}
i = i + 1;
// Error Handling, when end of hashtable is reached
if (i == max)
{
i = 0;
// p rintf("\n Hash table is full, cannot insert any more item \n");
// return;
}
}
// Insert new item into the hashtable
array[i].flag = 1;
array[i].data = (struct item*) malloc(sizeof(struct item));
array[i].data->key = (char *)malloc((strlen(key)+1)*sizeof(char));
// so here I have to use snprintf instead of strcy because it's
// forbidden, and I don't know how
**strcpy(array[i].data->key, key);**
//snprintf(array[i].data->key,sizeof(key),"%s",key);
array[i].data->value = value;
}
Firstly, never cast malloc, and do not forget verify the return value of malloc.
array[i].data = malloc(sizeof(struct item));
if (!array[i].data) {
// handle error
return; // for example
}
array[i].data->key = malloc((strlen(key)+1)*sizeof(char));
if (!array[i].data->key) {
// handle error
}
Using strlen instead of sizeof that returns the size of pointer, not the length of string:
snprintf(array[i].data->key, strlen(key) + 1,"%s", key);
here I have to use snprintf instead of strcy because it's forbidden, and I don't know how
strcpy() can overflow is the destination is insufficient. That really does not apply here as the needed space is allocated.
// array[i].data = (struct item*) malloc(sizeof(struct item));
// array[i].data->key = (char *)malloc((strlen(key)+1)*sizeof(char));
// strcpy(array[i].data->key, key);
array[i].data = malloc(sizeof *(array[i].data));
size_t sz = strlen(key) + 1;
array[i].data->key = malloc(sz);
snprintf(array[i].data->key, sz, "%s", key);
// or
strcpy(array[i].data->key, key);
// or
memcpy(array[i].data->key, key, sz);
Cast not needed
size of of referenced data better to use that sizeof type.
Avoid 2 trips finding the length.
Returns check omitted for brevity.
With checks
array[i].data = malloc(sizeof *(array[i].data));
if (array[i].data == NULL) return fail; // or do something to indicate error
size_t sz = strlen(key) + 1;
array[i].data->key = malloc(sz);
if (array[i].data->key == NULL) return fail;
int count = snprintf(array[i].data->key, sz, "%s", key);
if (count < 0 || (unsigned) count >= sz) return fail;
Primary mistake
OP's attempt fails as sizeof(key) is the size of a pointer, perhaps 2, 4 or 8. Instead, what is needed is the size of the allocation for array[i].data->key as in sz (see above) or strlen(key) + 1.
snprintf(array[i].data->key,sizeof(key),"%s",key); // bad

Not seeing same value of integer upon returning to main class

I am working off some skeleton code for a hash table implementation. In the main class, there is a portion which checks for the key in the table. It allows for duplicates so the it is expecting to return an array of a specified size, and if the entries exceed that size then it is called again with a larger array. My issue is with the "num_results" pointer which is declared just before.
int num_values = 1;
valType* values = malloc(1 * sizeof(valType));
int* num_results = NULL;
get(ht, key, values, num_values, num_results);
printf("num_results: %d\n", (*num_results));
if ((*num_results) > num_values) {
values = realloc(values, (*num_results) * sizeof(valType));
get(ht, 0, values, num_values, num_results);
}
for (int i = 0; i < (*num_results); i++) {
printf("value of %d is %d \n", i, values[i]);
}
free(values);
It is declared to null (presumably because if there are no results then the memory isn't wasted?)
int get(hashtable* ht, keyType key, valType *values, int num_values, int* num_results) {
int slot = key % sizeof(ht);
struct node *entry = ht->entries[slot];
if(entry == NULL){
printf("There are no matching hashed keys");
return -1;
}
// Allocate the num_results, as just a NULL pointer was passed
if((num_results = malloc(sizeof(int))) == NULL){
return -1;
}
// Start it at 0 so that it cxan be incremented as we check
(*num_results) = 0;
printf("num_results: %d\n", (*num_results));
int temp = num_values;
while(entry != NULL){
if(entry->key == key){
++(*num_results);
if(temp != 0){
values[num_values-temp] = entry->value;
--temp;
}
}
entry = entry->next;
}
printf("num_results: %d\n", (*num_results));
return 0;
}
This is the get function, and as you can see I allocate the memory needed, set it to 0, and it increments as expected. The output looks like:
num_results: 0
num_results: 2
num_results: 73896
This confuses me, as clearly the 2 result is from the last line of the method, and the last printout comes immediately after returning to the main... What is happening here? Why is the value changing?
You have to pass the pointer num_results by reference. Otherwise the function deals with a copy of the pointer.
For example
int get(hashtable* ht, keyType key, valType *values, int num_values, int ** num_results) {
// ...
if(( *num_results = malloc(sizeof(int))) == NULL){
return -1;
}
//…
A function call will look like
get(ht, key, values, num_values, &num_results);
Actually I do not see a great sense to declare the variable num_results as a pointer and allocate dynamically a memory for it in the function. I would declare it at least as having the type unsigned int.
For example
unsigned int num_results = 0;
and then the function get could look like
int get(hashtable* ht, keyType key, valType *values, int num_values, unsigned int *num_results) {
//…
*num_results = 0;
//…
and called like
get(ht, key, values, num_values, &num_results);
Pay attention to that instead of
int slot = key % sizeof(ht);
it seems you mean
int slot = key % sizeof( *ht);

storing C struct as binary with SET in redis (hiredis)

I'm trying to save a binary blob of my structure as value in Redis (via hiredis) using SET. I set it with one execution of my program and try to retrieve it later in another run. For some reason, I'm not able to get the dynamically allocated string back.
Here's the simplified code fragments of what I'm doing. In the real implementation, my struct is more complex with strings, linked lists, sub structs.
typedef struct mytest {
int myInt;
char *myStr;
} mytest;
char *key = strdup("test_key");
int vsize = 0;
mytest t;
memset(&t, 0, sizeof(t));
t.myInt = 100;
vsize += sizeof(t.myInt);
t.myStr = strdup("test_string");
vsize += strlen(t.myStr);
redisReply *reply = 0;
// set value
reply = redisCommand(context, "SET %b %b", key, (size_t) strlen(key), &t, (size_t) vsize);
if (!reply)
return REDIS_ERR;
freeReplyObject(reply);
// get the value back
reply = redisCommand(context, "GET %b", key, (size_t) strlen(key));
struct mytest *retval = (struct mytest *) reply->str;
printf("GET %s: myInt = %d myStr = %s", retval->myInt, retval->myStr);
I have following questions:
What am I doing wrong here?
Is SET/GET the correct way to store complex data structure or should I use something else in Redis? I want to access the structure as single entity and not as separate fields.
In case of member linked lists, how should they be stored?
I couldn't find any examples that address my use case, so any examples would help.
Your code do not work properly because of variable to contains string myStr as a pointer to string rather than string itself:
reply = redisCommand(context, "SET %b %b", key, (size_t) strlen(key), &t, (size_t) vsize);
Try to work with this like that:
redisReply *reply = redisCommand(context, "SET %b %b", key, (size_t) strlen(key), t.myStr, t.myInt);
...
struct mytest;
memset(&mytest, 0, sizeof(mytest));
reply = redisCommand(context, "GET %b", key, (size_t) strlen(key));
mytest.myInt = strlen(reply->str);
mytest.myStr = strdup(reply->str);
freeReplyObject (reply);

Does C support key-value pair data structure? [duplicate]

I am implementing a way to transfer a set of data to a programmable dongle. The dongle is based on a smart card technology and can execute an arbitrary code inside. The input and output data is passed as a binary blocks that can be accessed via input and output pointers.
I would like to use an associative array to simplify the data processing code. Everything should work this way:
First the host application:
// Host application in C++
in_data["method"] = "calc_r";
in_data["id"] = 12;
in_data["loc_a"] = 56.19;
in_data["loc_l"] = 44.02;
processor->send(in_data);
Next the code inside the dongle:
// Some dongle function in C
char* method_name = assoc_get_string(in_data, "method");
int id = assoc_get_int(in_data, "id");
float loc_a = assoc_get_float(in_data, "loc_a");
float loc_l = assoc_get_float(in_data, "loc_l");
So my question is about the dongle part functionality. Is there C code or library to implement such an associative array behavior like the above?
Glib's hash table. implements a map interface or (associative array).
And it's most likely the most used hash table implementation for C.
GHashTable *table=g_hash_table_new(g_str_hash, g_str_equal);
/* put */
g_hash_table_insert(table,"SOME_KEY","SOME_VALUE");
/* get */
gchar *value = (gchar *) g_hash_table_lookup(table,"SOME_KEY");
My suspicion is that you would have to write your own. If I understand the architecture you are describing, then you will need to send the entire chunk of data in a single piece. If so, then most libraries will not work for that because they will most likely be allocating multiple pieces of memory, which would require multiple transfers (and an inside understanding of the structure). It would be similar to trying to use a library hash function and then sending its contents over the network on a socket just by passing the root pointer to the send function.
It would be possible to write some utilities of your own that manage a very simple associative array (or hash) in a single block of memory. If the amount of data is small, it could use a simple linear search for the entries and would be a fairly compact bit of code.
Try uthash, a header library implementing a hash table in C. It's small and fairly easy to use.
This is an old thread, but I thought this might still be useful for anyone out there looking for an implementation. It doesn't take too much code; I did mine in ~100 lines of without any extra library. I called it a dictionary since it parallels (sort of) the python datatype. Here is my code:
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
typedef struct hollow_list hollow_list;
struct hollow_list{
unsigned int size;
void *value;
bool *written;
hollow_list *children;
};
//Creates a hollow list and allocates all of the needed memory
hollow_list hollow_list_create(unsigned int size){
hollow_list output;
output = (hollow_list) {.size = size, .value = (void *) 0, .written = calloc(size, sizeof(bool)), .children = calloc(size, sizeof(hollow_list))};
return output;
}
//Frees all memory of associated with a hollow list and its children
void hollow_list_free(hollow_list *l, bool free_values){
int i;
for(i = 0; i < l->size; i++){
hollow_list_free(l->children + i, free_values);
}
if(free_values){
free(l->value);
}
free(l);
}
//Reads from the hollow list and returns a pointer to the item's data
void *hollow_list_read(hollow_list *l, unsigned int index){
if(index == 0){
return l->value;
}
unsigned int bit_checker;
bit_checker = 1<<(l->size - 1);
int i;
for(i = 0; i < l->size; i++){
if(bit_checker & index){
if(l->written[i] == true){
return hollow_list_read(l->children + i, bit_checker ^ index);
} else {
return (void *) 0;
}
}
bit_checker >>= 1;
}
}
//Writes to the hollow list, allocating memory only as it needs
void hollow_list_write(hollow_list *l, unsigned int index, void *value){
if(index == 0){
l->value = value;
} else {
unsigned int bit_checker;
bit_checker = 1<<(l->size - 1);
int i;
for(i = 0; i < l->size; i++){
if(bit_checker & index){
if(!l->written[i]){
l->children[i] = hollow_list_create(l->size - i - 1);
l->written[i] = true;
}
hollow_list_write(l->children + i, bit_checker ^ index, value);
break;
}
bit_checker >>= 1;
}
}
}
typedef struct dictionary dictionary;
struct dictionary{
void *value;
hollow_list *child;
};
dictionary dictionary_create(){
dictionary output;
output.child = malloc(sizeof(hollow_list));
*output.child = hollow_list_create(8);
output.value = (void *) 0;
return output;
}
void dictionary_write(dictionary *dict, char *index, unsigned int strlen, void *value){
void *hollow_list_value;
dictionary *new_dict;
int i;
for(i = 0; i < strlen; i++){
hollow_list_value = hollow_list_read(dict->child, (int) index[i]);
if(hollow_list_value == (void *) 0){
new_dict = malloc(sizeof(dictionary));
*new_dict = dictionary_create();
hollow_list_write(dict->child, (int) index[i], new_dict);
dict = new_dict;
} else {
dict = (dictionary *) hollow_list_value;
}
}
dict->value = value;
}
void *dictionary_read(dictionary *dict, char *index, unsigned int strlen){
void *hollow_list_value;
dictionary *new_dict;
int i;
for(i = 0; i < strlen; i++){
hollow_list_value = hollow_list_read(dict->child, (int) index[i]);
if(hollow_list_value == (void *) 0){
return hollow_list_value;
} else {
dict = (dictionary *) hollow_list_value;
}
}
return dict->value;
}
int main(){
char index0[] = "hello, this is a test";
char index1[] = "hello, this is also a test";
char index2[] = "hello world";
char index3[] = "hi there!";
char index4[] = "this is something";
char index5[] = "hi there";
int item0 = 0;
int item1 = 1;
int item2 = 2;
int item3 = 3;
int item4 = 4;
dictionary d;
d = dictionary_create();
dictionary_write(&d, index0, 21, &item0);
dictionary_write(&d, index1, 26, &item1);
dictionary_write(&d, index2, 11, &item2);
dictionary_write(&d, index3, 13, &item3);
dictionary_write(&d, index4, 17, &item4);
printf("%d\n", *((int *) dictionary_read(&d, index0, 21)));
printf("%d\n", *((int *) dictionary_read(&d, index1, 26)));
printf("%d\n", *((int *) dictionary_read(&d, index2, 11)));
printf("%d\n", *((int *) dictionary_read(&d, index3, 13)));
printf("%d\n", *((int *) dictionary_read(&d, index4, 17)));
printf("%d\n", ((int) dictionary_read(&d, index5, 8)));
}
Unfortunately you can't replicate the list[x] syntax, but this is the best alternative I have come up with.
Yes, but it will not work in the way you have specified. It will instead use a struct to store the data and functions that operate on that struct, giving you the result you want. See A Simple Associative Array Library In C. Example of use:
struct map_t *test;
test=map_create();
map_set(test,"One","Won");
map_set(test,"Two","Too");
map_set(test,"Four","Fore");
GLib's Hash Tables and Balanced Binary Trees might be what you're after.
Mark Wilkins gave you the right answer. If you want to send the data as a single chunk, you need to understand how C++ maps are represented in your architecture and write the access functions.
Anyway, if you decide to recreate the map on the dongle, I've written a small C library where you could write thinks like:
tbl_t in_data=NULL;
tblSetSS(in_data,"method","calc_r");
tblSetSN(in_data,"id",12);
tblSetSF(in_data,"loc_a",56.19);
tblSetSF(in_data,"loc_l",44.02);
and then:
char *method_name = tblGetP(in_data, "method");
int id = tblGetN(in_data, "id");
float loc_a = tblGetF(in_data, "loc_a");
float loc_l = tblGetF(in_data, "loc_l");
The hashtable is a variation of the Hopscotch hash, which is rather good on average, and you can have any mix of type for keys and data (i.e. you can use an entire table as a key).
The focus for that functions was on easing programming rather than pure speed and the code is not thoroughly tested but if you like the idea and want to expand on it, you can have a look at the code on googlecode.
(There are other things like variable length strings and a fast sttring pattern matching function but those might not be of interest in this case).

Resources