I have a very weird error with the xmlNewChild function using libxml2. I tried to keep the post as short as possible so I removed some insignificant logic. A boolean variable is defined for each variable to be written and when setting the variable value, the boolean is set to TRUE indicating if the tag is present, and if it is, it's written, otherwise is skipped
I have defined a structure as follows:
tyedef struct _xml_parse_t
{
const char *name;
void *variable;
int type;
_xml_parse_t *childs;
} xml_parse_t;
Another function parses this structure and writes it to a char*. the function is defined as follows:
int generate_xml(xml_parse_t *p, char *out, const char*root)
{
xmlChar *s = NULL;
int size = 0;
xmlDocPtr doc = NULL;
xmlNodePtr root_node = NULL;
doc = xmlNewDoc(NULL);
if(NULL == doc)
return -1;
root_node = xmlNewNode(NULL, BAD_CAST root);
if(NULL == root_node)
return -1;
else
xmlDocSetRootElement(doc, root_node);
if(-1 == writeXmlToDoc(p, doc, root_node))
return -1;
xmlDocDumpFormatMemoryEnc(doc, &s, &size, "UTF-8", 1);
if(NULL == s)
return -1;
if(SUCCEED == ret)
strcpy(out, (char *)s);
if(NULL != s)
xmlFree(s);
xmlFreeDoc(doc);
xmlCleanupParser();
xmlMemoryDump();
return 0;
}
The writeXmlToDoc is defined as below
int writeXmlToDoc(xml_parse_t *parse, xmlDocPtr doc,
xmlNodePtr root_node)
{
xml_parse_t *p = parse;
xmlNodePtr node;
while(NULL != p->name)
{
if( NODE_TYPE_PARENT == p->type && NULL != p->childs)
{
node = xmlNewChild(root_node, NULL, BAD_CAST p->name, NULL);
if(-1 == writeXmlToDoc(p->childs, doc, node))
return -1;
}
else
{
printf("Current value being written [%s]", (char *)cvtToXmlChar(p->variable, p->type));
node = xmlNewChild(root_node, NULL, BAD_CAST p->name,
BAD_CAST cvtToXmlChar(p->variable, p->type));
}
p++;
}
return 0;
}
To keep this post as short as possible, the cvtToXmlChar checks the type of the variable and casts it to xmlChar and the printf before the xmlNewChild is showing correct value of the variable.
xml_parse_t child_parse[] = {
/* Name var Type Childs*/
{"ChildInt", &test_int1, NODE_TYPE_INT, NULL },
{"ChildLong", &test_long1, NODE_TYPE_LONG, NULL },
{"ChildChar", test_char1, NODE_TYPE_STRING, NULL },
{"ChildShort", &test_short1, NODE_TYPE_SHORT, NULL },
{"ChildDouble", &test_double1,NODE_TYPE_DOUBLE, NULL },
{ NULL }
};
xml_parse_t parent_parse[] = {
/* Name var Type Childs*/
{"ParentInt", &test_int, NODE_TYPE_INT, NULL },
{"ParentLong", &test_long, NODE_TYPE_LONG, NULL },
{"ParentChar", test_char, NODE_TYPE_STRING, NULL },
{"ParentShort", &test_short, NODE_TYPE_SHORT, NULL },
{"ParentDouble", &test_double, NODE_TYPE_DOUBLE, NULL },
{"ParentParent", NULL, NODE_TYPE_PARENT, child_parse },
{ NULL }
};
and the variables set as follows:
test_int = 1;
test_int1 = 2;
test_long = 1;
test_long1 = 2;
sprintf(test_char, "TestParentCharTag");
sprintf(test_char1, "TestChildCharTag");
test_short = 1;
test_short1 = 2;
test_double = 1;
test_double1 = 2;
The problem is, the output string has 2 missing values. Following is the output of running the test
<ROOTELEMENT>
<ParentInt>1</ParentInt>
<ParentLong></ParentLong>
<ParentChar>TestParentCharTag</ParentChar>
<ParentShort>1</ParentShort>
<ParentDouble>1.000000</ParentDouble>
<ParentParent>
<ChildInt></ChildInt>
<ChildLong>2</ChildLong>
<ChildChar>TestChildCharTag</ChildChar>
<ChildShort>2</ChildShort>
<ChildDouble>2.000000</ChildDouble>
</ParentParent>
</ROOTELEMENT>
I'm not sure why but I had to use
xmlNodeSetContent(node, BAD_CAST cvtToXmlChar(variable, type));
after using the xmlNewChild.
I'm not sure about this solution (it's not really the best one) but it did the trick.
I still appreciate if I can get an explanation on the behavior above.
Related
I am trying to insert Node to Binary tree. This is my function for creating Node (rest is done).
void BVSCreate_function(TNodef *rootPtr, function_save token) {
TNodef *newPtr = malloc(sizeof(struct tnodef));
if (newPtr == NULL) {
fprintf(stderr, "99");
return;
}
TNodef init;
string initStr;
initStr.str = NULL;
initStr.length = 0;
initStr.alloc = 0;
newPtr = &init;
newPtr->content = &initStr;
newPtr->leftPtr = NULL;
newPtr->rightPtr = NULL;
newPtr->return_type = token.ret_value;
newPtr->parameters = token.param_count;
strCpyStr(newPtr->content, token.content);
rootPtr = newPtr;
}
void BVSInsert_function(TNodef *rootPtr, function_save token) {
if (rootPtr == NULL) {
BVSCreate_function(rootPtr, token);
} else {
if ((strCmpStr(token.content, rootPtr->content)) < 0) {
BVSCreate_function(rootPtr->leftPtr, token);
} else
if ((strCmpStr(token.content, rootPtr->content)) > 0) {
BVSCreate_function(rootPtr->rightPtr, token);
}
}
}
When TNodef and function_save are structs:
typedef struct {
string *content;
int param_count;
int ret_value;
} function_save;
typedef struct tnodef {
string *content;
struct tnodef *leftPtr;
struct tnodef *rightPtr;
int parameters;
int return_type;
} TNodef;
Where string is defined as this struct:
typedef struct {
char *str; // content of string
int length; // length of string
int alloc; // amount of memory allocated
} string;
strCpystr function :
int strCpyStr(string *s1, string *s2) {
int len2 = s2->length;
if (len2 > s1->alloc) {
if (((s1->str) = (char *)realloc(s1->str, len2 + 1)) == NULL) {
return 1;
}
s1->alloc = len2 + 1;
}
strcpy(s1->str, s2->str);
s1->length = len2 + 1;
return 0;
}
I am trying to create a node in binary tree and put there information from struct function_save.
But when I try to print this tree after insert it shows me that tree is still empty.
Your code in BVSCreate_function has undefined behavior because:
newPtr = &init; discards the allocated node and instead uses a local structure that will become invalid as soon as the function returns.
newPtr->content = &initStr; is incorrect for the same reason: you should allocate memory for the string too or possibly modify the TNodeDef to make content a string object instead of a pointer.
Function BVSInsert_function does not return the updated root pointer, hence the caller's root node is never updated. You could change the API, passing the address of the pointer to be updated.
There is also a confusion in BVSInsert_function: it should call itself recursively when walking down the tree instead of calling BVSCreate_function.
Here is a modified version:
/* Allocate the node and return 1 if successful, -1 on failure */
int BVSCreate_function(TNodef **rootPtr, function_save token) {
TNodef *newPtr = malloc(sizeof(*newPtr));
string *newStr = malloc(sizeof(*content));
if (newPtr == NULL || newStr == NULL) {
fprintf(stderr, "99");
free(newPtr);
free(newStr);
return -1;
}
newStr->str = NULL;
newStr->length = 0;
newStr->alloc = 0;
newPtr->content = newStr;
newPtr->leftPtr = NULL;
newPtr->rightPtr = NULL;
newPtr->return_type = token.ret_value;
newPtr->parameters = token.param_count;
strCpyStr(newPtr->content, token.content);
*rootPtr = newPtr;
return 1;
}
int BVSInsert_function(TNodef **rootPtr, function_save token) {
if (*rootPtr == NULL) {
return BVSCreate_function(rootPtr, token);
} else {
if (strCmpStr(token.content, rootPtr->content) < 0) {
return BVSInsert_function(&rootPtr->leftPtr, token);
} else
if ((strCmpStr(token.content, rootPtr->content)) > 0) {
return BVSInsert_function(&rootPtr->rightPtr, token);
} else {
/* function is already present: return 0 */
return 0;
}
}
}
Note also that function strCpyStr may write beyond the end of the allocated area is len2 == s1->alloc, assuming s1->len is the length of the string, excluding the null terminator.
Here is a modified version:
int strCpyStr(string *s1, const string *s2) {
int len2 = s2->length;
if (len2 >= s1->alloc) {
char *newstr = (char *)realloc(s1->str, len2 + 1);
if (newstr == NULL) {
return 1;
}
s1->str = newstr;
s1->alloc = len2 + 1;
}
strcpy(s1->str, s2->str);
s1->length = len2;
return 0;
}
map contains - returns whether or not a key exists inside the map.
mapPut - Gives a specific key a given value and adding it to the map by order, if the key exists, the value is overridden.
mapRemove - Removes a pair of (key, data) elements for which the key matches a given element (by the key compare function).
mapGetFirst - Sets the internal iterator to the first key in the map, and returns it.
MapKeyElement mapGetFirst(Map map){
if(map == NULL){
return NULL;
}
if (map->head == NULL){
return NULL;
}
map->iterator = map->head;
return (map->copyMapKeyElements(map->iterator->key));
}
mapGetNext - Advances the internal iterator to the next key and
returns it.
MapKeyElement mapGetNext(Map map){
if(map == NULL){
return NULL;
}
if((map->iterator->next)== NULL) {
return NULL;
}
map->iterator = map->iterator->next;
return (map->copyMapKeyElements(map->iterator->key));
}
typedef struct MapElements_t{
MapDataElement data;
MapKeyElement key;
struct MapElements_t* next;
} *MapElements;
struct Map_t{
copyMapDataElements copyMapDataElements;
copyMapKeyElements copyMapKeyElements;
freeMapDataElements freeMapDataElements;
freeMapKeyElements freeMapKeyElements;
compareMapKeyElements compareMapKeyElements;
MapElements head;
MapElements iterator;
};
/* ...... */
MapResult mapPut(Map map, MapKeyElement keyElement, MapDataElement dataElement) {
if ((map == NULL) || (keyElement == NULL) || (dataElement == NULL)) {
return MAP_NULL_ARGUMENT;
}
if (mapContains(map, keyElement)) {
mapRemove(map, keyElement);
}
MapElements new_map_element = malloc(sizeof(new_map_element));
if (new_map_element == NULL) {
return MAP_OUT_OF_MEMORY;
}
new_map_element->data = dataElement;
new_map_element->key = keyElement;
new_map_element->next = NULL;
if(map->head == NULL){
map->head = new_map_element;
map->iterator = map->head;
return MAP_SUCCESS;
}
mapGetFirst(map);
if (map->compareMapKeyElements(keyElement, map->iterator->key) < 0){
new_map_element->next = map->iterator;
map->head = new_map_element;
return MAP_SUCCESS;
}
while(map->iterator->next != NULL) {
if (map->compareMapKeyElements(keyElement, map->iterator->next->key) < 0) {
new_map_element->next = map->iterator->next;
map->iterator = new_map_element;
return MAP_SUCCESS;
}
mapGetNext(map);
}
map->iterator->next = new_map_element;
return MAP_SUCCESS;
}
You have typedefs that include a pointer, such as typedef struct MapElements_t{...} *MapElements; which makes the type MapElements a pointer.
This is discouraged and for the following reason:
When you do
MapElements new_map_element = malloc(sizeof(new_map_element));
you are allocating the size of a pointer, not the size of the thing pointed to. In your case you should do:
MapElements new_map_element = malloc(sizeof(*new_map_element));
but preferably you would do:
typedef struct MapElements_t
{
//...
struct MapElements_t* next;
} MapElements;
so you make a variable that is a pointer to the thing have explicitly the *.
MapElements *new_map_element = malloc(sizeof(*new_map_element));
The fault was here; I have to replace this code:
new_map_element->data = dataElement;
new_map_element->key = keyElement;
with this code:
new_map_element->data = map->copyMapDataElements(dataElement);
new_map_element->key = map->copyMapKeyElements(keyElement);
I am new to C and am trying to code up a data structure, primarily, a ternary search tree. I am working under the assumption (for now) that valid char inputs are being passed in. I am having some issues with my insert function. Note that I am also inserting the original string in the last TSTnode where the last character of str will also be held.
Here is what I have so far
struct TSTnode {
char* word; // NULL if no word ends here
char self;
struct TSTnode *left, *sub, *right;
};
int insert_tst(struct TSTnode** tree, const char* str) {
return _insert(tree, str, 0);
}
int _insert(struct TSTnode** tree, const char* str, int position) {
if((*tree) == NULL) {
*tree = new_tst_node(*(str+position));
position = position + 1;
if(*(str+position) == '\0') {
(*tree)->word = strcpy((*tree)->word,str);
return 1;
}
}
else if ((*tree)->self > *(str+position)) {
position = position + 1;
_insert( &((*tree)->left), str, position);
}
else if ((*tree)->self < *(str+position)) {
position = position + 1;
_insert( &((*tree)->right), str, position);
}
else {
position = position + 1;
_insert( &((*tree)->sub), str, position);
}
return 0;
}
struct TSTnode* new_tst_node(char self) {
struct TSTnode* newNode = (struct TSTnode*) malloc(sizeof(struct
TSTnode));
if (newNode == NULL) {
return NULL;
}
newNode->word = NULL;
newNode->self = self;
newNode->left = NULL;
newNode->right = NULL;
newNode->sub = NULL;
return newNode;
}
Here is how I am testing:
struct TSTnode* tree = NULL;
char* words[1] = {"hello"};
for (int i = 0; i < 1; i++) {
if (insert_tst(&tree, words[i]) == 0) {
//print some error
}
else { //success }
EDIT - My issue is that none of my conditional branches are being taken and the insert function simply goes straight to return 0.
Note: You confusingly use tree for both TSTnode* and TSTnode**. I'm going to use tree_ptr for the latter, and pretend that you did the same.
Your claim is false. The body of if((*tree_ptr) == NULL) is executed. You do have a number of problems, though.
You don't handle the case where *tree_ptr == NULL && *(str+position+1) != '\0'.
You don't correctly handle the case where *tree_ptr != NULL && *(str+position+1) == '\0'.
You always return 0 when *tree_ptr != NULL || str[1] != '\0'.
You never allocate word, but you deference it. The thing is, you shouldn't be storing the string again anyway!
You don't handle the case where str[0] == '\0' (empty string).
Fixed:
int insert_tst(struct TSTnode** tree_ptr, const char* str) {
if (!*str)
return 0; /* Zero-length strings are not supported. */
return insert_tst_helper(tree_ptr, str, 0);
}
int insert_tst_helper(struct TSTnode** tree_ptr, const char* str, int position) {
if (*tree_ptr == NULL) {
*tree_ptr = new_tst_node(*(str+position));
if (*tree_ptr == NULL)
return 0; /* Memory allocation error. */
}
if (*(str+position+1) == '\0') { /* If the next char is a NUL */
(*tree_ptr)->is_word = 1;
return 1;
}
else if ((*tree_ptr)->self > *(str+position)) {
position = position + 1;
return insert_tst_helper( &((*tree_ptr)->left), str, position);
}
else if ((*tree_ptr)->self < *(str+position)) {
position = position + 1;
return insert_tst_helper( &((*tree_ptr)->right), str, position);
}
else {
position = position + 1;
return insert_tst_helper( &((*tree_ptr)->sub), str, position);
}
}
Untested.
Let's clean this up, though.
*(str+position)simplifies tostr[position]
ch == '\0'simplifies toch == 0then to!ch
position = position + 1; return insert_tst_helper(..., str, position);simplifies to++position; return insert_tst_helper(..., str, position);then toreturn insert_tst_helper(..., str, position+1);then toreturn insert_tst_helper(..., str+1, 0);then toreturn insert_tst(..., str+1);
Why is recursion being used at all???
Fixed:
int insert_tst(struct TSTnode** tree_ptr, const char* str) {
if (!*str)
return 0; /* Zero-length strings are not supported. */
while (1) {
if (*tree_ptr == NULL) {
*tree_ptr = new_tst_node(*str);
if (*tree_ptr == NULL)
return 0; /* Memory allocation error. */
}
if (!*(str+1)) { /* If the next char is a NUL */
(*tree_ptr)->is_word = 1;
return 1;
}
int cmp = *str - (*tree_ptr)->self;
if (cmp < 0) { tree_ptr = &( (*tree_ptr)->left ); }
else if (cmp > 0) { tree_ptr = &( (*tree_ptr)->right ); }
else { tree_ptr = &( (*tree_ptr)->sub ); }
++str;
}
}
Untested.
So i am stuck on this for quite some time now. I use libxml2 and it works great for another part in the code but i cant seem to figure this one out and its bugging me like crazy.
I have this xml code:
<MetaCommandSet>
<MetaCommand name="ChangeSystemInterval">
<ArgumentList>
<Argument name="Interval" argumentTypeRef="UnsignedByteType"></Argument>
</ArgumentList>
</MetaCommand>
Now what i want is the name of the command and its arguments. This means that it has to stay in the same meta command so that i can collect al the arguments and than save this to for example a struct.
Code snippet:
for (cur_node = a_node; cur_node; cur_node = cur_node->next)
{
DATA TM_tmp;
COMMAND TC_tmp;
if(!xmlStrcmp(cur_node->name, "MetaCommand"))
{
TC_tmp.functionName = malloc(strlen((xmlGetProp(cur_node, "name") + 1)));
TC_tmp.functionName = xmlGetProp(cur_node, "name");
printf("Name: %s\n",TC_tmp.functionName);
/*
It now needs to keep looping this so i get every argument but it cant find any childs after argumentList
*/
}
createArray(cur_node->children);
I am nog getting further than getting the MetaCommand name. I am already looping threw all elements and if its a MetaCommand element i want to proceed with what i stated above.
Please give me some ideas
taken from one of my source coeds. You have to dive one level deeper than me, i have < pricing>< price age_group="">< EUR>...< /EUR>< /pricing>< /price>
{
while (cur != NULL) {
if (xmlStrcmp(cur->name, (const xmlChar *) "pricing") == 0) {
cur = cur->xmlChildrenNode;
while (cur != NULL) {
if (xmlStrcmp(cur->name, (const xmlChar *) "price") == 0) {
xmlNodePtr node = cur->xmlChildrenNode;
if (*kopf == NULL) {
*kopf = (Pricing *)HeapMalloc(sizeof(Pricing), "Pricing", 0);
ret = *kopf;
} else {
ret->next = (Pricing *)HeapMalloc(sizeof(Pricing), "Pricing", 0);
ret = ret->next;
}
parseAttribut(cur, "age_group", &(ret->age_group), fehler);
parseElement(doc, node, "EUR", &(ret->price), fehler);
}
cur = cur->next;
}
break;
}
cur = cur->next;
}
}
void parseAttribut(xmlNodePtr node, const xmlChar *str, xmlChar **dest, short muss, short *fehler)
{
*dest = xmlGetProp(node, str);
return;
}
void parseElement(xmlDocPtr doc, xmlNodePtr node, const xmlChar *str, xmlChar **dest, short muss, short *fehler)
{
short found = FALSE;
while (node) {
if (xmlStrcmp(node->name, str) == 0) {
*dest = xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
found = TRUE;
break;
}
node = node->next;
}
return;
}
I have an assignment for class that I have to write a program to read and write key, value pairs to disk. I am using a linked list to store the keys, and read in values whenever I need to from disk. However, I am having trouble changing and deleting values. I am using this to test it: http://gaming.jhu.edu/~phf/2010/fall/cs120/src/sdbm-examples.tar.gz. Code below. Basically, I need some help figuring out errors, because this is the first assignment we have had to use pointers on, and I am just dying in all the segfaults and everything else. Just some advice would be greatly appreciated.
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <stdbool.h>
#include "sdbm.h"
FILE *db;
bool opened = false, needNewDB = false;
int err = 0, keyLen = 0;
char *filename;
typedef struct Key_{
char *name;
char *val;
long offset;
struct Key_ *next;
} Key;
Key *head = NULL,*tail = NULL, *lastHas = NULL, *beforeLastHas = NULL;
/**
* Create new database with given name. You still have
* to sdbm_open() the database to access it. Return true
* on success, false on failure.
*/
void listAdd() {
if (tail != NULL) {
tail->next = (Key *) malloc(sizeof(Key));
tail = tail->next;
}
else {
tail = (Key *)malloc(sizeof(Key));
head = tail;
}
tail->next = NULL;
tail->name = NULL;
tail->val = NULL;
}
bool sdbm_create( const char *name ) { //Errors: 1) fopen failed 2) fclose failed on new db
filename = malloc(sizeof(*name));
strcpy(filename,name);
FILE *temp = fopen(name, "w");
if (temp == NULL) {
printf("Couldn't create file %s\n",name);
err = 1;
return false;
}
if (fclose(temp) == EOF) {
printf("Couldn't close created file %s\n",name);
err = 2;
return false;
}
return true;
}
/**
* Open existing database with given name. Return true on
* success, false on failure.
*/
bool sdbm_open( const char *name ) { //Errors: 3) couldn't open database
db = fopen(name,"r+");
if (db == NULL) {
err = 3;
printf("Couldn't open database file %s\n",name);
return false;
}
opened = true;
int c;
bool inKey = true;
char currKey[MAX_KEY_LENGTH];
while ((c = getc(db)) != EOF) {
if (!inKey && c == '\0') {
inKey = true;
}
else if (inKey && c == '\0') {
currKey[keyLen] = '\0';
listAdd();
tail->offset = ftell(db);
tail->name = malloc(sizeof(*currKey));
strcpy(tail->name,currKey);
keyLen = 0;
inKey = false;
}
else if (inKey) {
currKey[keyLen] = c;
keyLen++;
}
}
Key *curr = head;
while (curr != NULL) {
printf("Key: %s\n",curr->name);
curr = curr->next;
}
return true;
}
void readVal(char *value, long offset) {
fseek(db,offset,SEEK_SET);
int c;
for (int i = 0; (c = getc(db)) != '\0'; i++) {
*(value + i) = c;
}
}
/**
* Synchronize all changes in database (if any) to disk.
* Useful if implementation caches intermediate results
* in memory instead of writing them to disk directly.
* Return true on success, false on failure.
*/
bool sdbm_sync() {
if (!needNewDB) {
Key *curr = head;
fseek(db,0,SEEK_END);
while (curr != NULL) {
if (curr->val != NULL) {
fprintf(db,"%s%c%s%c",curr->name,'\0',curr->val,'\0');
}
curr = curr->next;
}
}
else {
FILE *temp;
sdbm_create("tRpdxD.p4ed");
temp = fopen("tRpdxD.p4ed","w");
Key *curr = head;
while (curr != NULL) {
if (curr->val != NULL) {
fprintf(temp,"%s%c%s%c",curr->name, '\0', curr->val, '\0');
}else {
char *tempS = malloc(MAX_VALUE_LENGTH);
readVal(tempS, curr->offset);
fprintf(temp,"%s%c%s%c",curr->name,'\0',tempS,'\0');
free(tempS);
}
fflush(temp);
fflush(db);
curr = curr->next;
}
fclose(db);
remove(filename);
rename("tRpdxD.p4ed",filename);
db = fopen(filename,"r+");
}
fflush(db);
return true;
}
/**
* Close database, synchronizing changes (if any). Return
* true on success, false on failure.
*/
bool sdbm_close() { // Errors: 5) Couldn't close database
sdbm_sync();
Key *tmp = head;
while (head->next != NULL) {
tmp = head;
head = head->next;
free(tmp->name);
if (tmp->val != NULL) {
free(tmp->val);
}
free(tmp);
}
if (fclose(db) == EOF) {
err = 5;
printf("Couldn't close database.\n");
return false;
}
return true;
}
/**
* Return error code for last failed database operation.
*/
int sdbm_error() {
return err;
}
/**
* Is given key in database?
*/
bool sdbm_has( const char *key ) {
if (head == NULL) {
return false;
}
Key *curr = head;
lastHas = NULL;
beforeLastHas = NULL;
while (curr != NULL) {
if (!strcmp(curr->name,key)) {
lastHas = curr;
return true;
}
beforeLastHas = curr;
curr = curr->next;
}
return false;
}
/**
* Get value associated with given key in database.
* Return true on success, false on failure.
*
* Precondition: sdbm_has(key)
*/
bool sdbm_get( const char *key, char *value ) { //Errors: 6)Don't have key
if (!sdbm_has(key)) {
printf("Precondition sdbm_has(%s) failed", key);
err = 6;
return false;
}
readVal(value, lastHas->offset);
return true;
}
/**
* Update value associated with given key in database
* to given value. Return true on success, false on
* failure.
*
* Precondition: sdbm_has(key)
*/
bool sdbm_put( const char *key, const char *value ) {
if (!sdbm_has(key)) {
printf("Precondition !sdbm_has(%s) failed",key);
err = 7;
return false;
}
sdbm_remove(key);
sdbm_insert(key,value);
return true;
}
/**
* Insert given key and value into database as a new
* association. Return true on success, false on
* failure.
*
* Precondition: !sdbm_has(key)
*/
bool sdbm_insert( const char *key, const char *value ) { //Errors: 7)Already have key 8)Invalid key or value length
if (sdbm_has(key)) {
printf("Precondition !sdbm_has(%s) failed",key);
err = 7;
return false;
}
if (strlen(key) < MIN_KEY_LENGTH || strlen(key) > MAX_KEY_LENGTH || strlen(value) < MIN_VALUE_LENGTH || strlen(value) > MAX_VALUE_LENGTH) {
printf("Invalid key or value length");
err = 8;
return false;
}
listAdd();
tail->name = (char *)key;
tail->val = malloc(sizeof(*value));
strcpy(tail->val,value);
return true;
}
/**
* Remove given key and associated value from database.
* Return true on success, false on failure.
*
* Precondition: sdbm_has(key)
*/
bool sdbm_remove( const char *key ) {
if (!sdbm_has(key)) {
printf("Precondition !sdbm_has(%s) failed",key);
err = 7;
return false;
}
needNewDB = true;
if (beforeLastHas == NULL) {
head = lastHas->next;
}
else if (lastHas->next == NULL) {
tail = beforeLastHas;
}
else {
beforeLastHas->next = lastHas->next;
}
if (lastHas->val != NULL) {
free(lastHas->val);
}
free(lastHas->name);
free(lastHas);
return true;
}
There's a lot of errors in this code. To name just one:
filename = malloc(sizeof(*name));
*name is the first element of name, so it's a char, so sizeof(*name) == 1. To get the size of a string, use strlen(name) + 1. Better yet, use strdup if your system has it.
i would advise against global variables. you can not change the program (in the future) to use two of your databases in parallel.
so all your sdbm_xxx functions should get (or infer) all necessary values on their own.