Nested Lua Metatables in C - c

In a 3D scene, I have an Object that has a position that I would like to move using Lua.
eg. box.position.x = 10
box has a metatable ("Object") and so has position ("Vec"). Object has __newindex and __index set to call C functions NewIndexObject and IndexObject respectively. Same with Vec (NewIndexVec and IndexVec).
Object has an id so it can be identified in a list that is stored in the scene and when box.position is accessed all is fine, the C function IndexObject is called and I can extract the id from the stack, it's just when box.position.x = 10 is executed 'NewIndexVec' is called and the only thing on the stack is {table, x, 10} so no way of identifying the object to change its x position.
Is there anyway of pushing values onto a local state? Help!
UPDATE: thank you for getting back to me quickly, below I have distilled the code as much as possible. If you run this code it'll appear to work but I have comments where I'm stuck, it's just getting the first object in the array but I need to choose it by it's ID, Thanks in advance
struct Obj
{
std::string id;
int x,y,z;
Obj()
{
x = 10; y = 20; z = 30;
id = "12345";
}
};
//array of external objects
std::vector<Obj> objects;
int NewObject(lua_State * L)
{
Obj obj;
objects.push_back(obj);
lua_newtable(L);
luaL_getmetatable(L, "MT_Object");
lua_setmetatable(L, -2);
lua_pushstring(L, "id");
lua_pushstring(L, obj.id.c_str());
lua_settable(L, 1);
lua_newtable(L);
luaL_getmetatable(L, "MT_Vec");
lua_setmetatable(L, -2);
lua_pushinteger(L, obj.x);
lua_setfield(L, -2, "x");
lua_pushinteger(L, obj.y);
lua_setfield(L, -2, "y");
lua_pushinteger(L, obj.z);
lua_setfield(L, -2, "z");
lua_setfield(L, -2, "position");
return 1;
}
int IndexVec(lua_State * L)
{
// How do I get the correct object so I can pass its value back
Obj &dunnoObj = objects[0];
std::string key = luaL_checkstring(L,-1);
if(key == "x")
lua_pushinteger(L,dunnoObj.x);
else if(key == "y")
lua_pushinteger(L,dunnoObj.y);
else if(key == "z")
lua_pushinteger(L,dunnoObj.z);
return 1;
}
int NewIndexVec(lua_State * L)
{
// How do I know which object's value to update
Obj &dunnoObj = objects[0];
std::string key = luaL_checkstring(L,-2);
int value = luaL_checkinteger(L,-1);
if(key == "x")
dunnoObj.x = value;
else if(key == "y")
dunnoObj.y = value;
else if(key == "z")
dunnoObj.z = value;
return 0;
}
int main()
{
lua_State * L = luaL_newstate();
luaL_openlibs(L);
luaL_Reg objreg[] =
{
{ "new", NewObject },
{ NULL, NULL }
};
luaL_newmetatable(L, "MT_Object");
luaL_register(L, 0, objreg);
lua_setglobal(L, "Object");
luaL_Reg reg[] =
{
{ "__index", IndexVec },
{ "__newindex", NewIndexVec },
{ NULL, NULL }
};
luaL_newmetatable(L, "MT_Vec");
luaL_register(L, 0, reg);
lua_setglobal(L, "Vec");
int res = luaL_dostring(L, "box = Object.new() box.position.x = 1000 print(box.id .. \" , \" ..box.position.x .. \" , \" .. box.position.y .. \" , \" .. box.position.z)");
if(res)
printf("Error: %s\n", lua_tostring(L, -1));
lua_close(L);
return 0;
}

If I understand you correctly, you don't have to do anything. Tables are tracked by reference, so NewIndexVec doesn't need to know anything about box if its first argument is box.position.
If this answer can't work for some reason, then I'd need more information about your data structure to understand your problem.
Basically, box.position needs to return some obj for which obj.x = 10 is a valid operation and changes exactly what you want it to change.
The problem is that you're trying to keep the same data in two separate places. Keep all the data in the C++ struct, then have NewObject return a userdata that pretends to be a table. Both the Object and the position field should be the same Obj*, but they may have different metatables to simulate different sets of fields.

Thanks, I've posted the code that works
struct Obj
{
unsigned int id;
int x,y,z;
Obj()
{
x = 10; y = 20; z = 30;
id = rand();
}
};
//array of external objects
std::map<unsigned int,Obj> objects;
int NewObject(lua_State * L)
{
Obj obj;
objects[obj.id] = obj;
lua_pushinteger(L, obj.id);
luaL_getmetatable(L, "MT_Object");
lua_setmetatable(L, -2);
return 1;
}
int IndexObj(lua_State * L)
{
unsigned int objid = luaL_checkinteger(L,1);
std::string key = luaL_checkstring(L,-1);
if(key == "position" )
{
Obj *a = (Obj *)lua_newuserdata(L, sizeof(Obj));
*a = objects[objid];
luaL_getmetatable(L, "MT_Vec");
lua_setmetatable(L, -2);
}
else if(key == "id")
lua_pushinteger(L, objid);
else
lua_pushnil(L);
StackDump(L);
return 1;
}
int IndexVec(lua_State * L)
{
Obj *a = (Obj *)lua_touserdata(L, 1);
std::string key = luaL_checkstring(L,-1);
if(key == "x")
lua_pushinteger(L,a->x);
else if(key == "y")
lua_pushinteger(L,a->y);
else if(key == "z")
lua_pushinteger(L,a->z);
return 1;
}
int NewIndexVec(lua_State * L)
{
Obj *a = (Obj *)lua_touserdata(L, 1);
Obj &objRef = objects[a->id];
std::string key = luaL_checkstring(L,-2);
int value = luaL_checkinteger(L,-1);
if(key == "x")
objRef.x = value;
else if(key == "y")
objRef.y = value;
else if(key == "z")
objRef.z = value;
return 0;
}
int main()
{
lua_State * L = luaL_newstate();
luaL_openlibs(L);
luaL_Reg objreg[] =
{
{ "new", NewObject },
{ "__index", IndexObj },
{ "__newindex", NewIndexObj },
{ NULL, NULL }
};
luaL_newmetatable(L, "MT_Object");
luaL_register(L, 0, objreg);
lua_setglobal(L, "Object");
luaL_Reg reg[] =
{
{ "__index", IndexVec },
{ "__newindex", NewIndexVec },
{ NULL, NULL }
};
luaL_newmetatable(L, "MT_Vec");
luaL_register(L, 0, reg);
lua_setglobal(L, "Vec");
int res = luaL_dostring(L, "box = Object.new() box.position.x = 1000 "
"print(box.id .. \" , \" ..box.position.x .. \" , \" .. box.position.y .. \" , \" .. box.position.z)");
if(res)
printf("Error: %s\n", lua_tostring(L, -1));
lua_close(L);
return 0;
}

Related

create tree with static and pre-determined elements in c

I have a problem that I decided to solve using binary tree, however:
I can't think of a way to fill the tree with predetermined elements so that it looks like the following in the image
I used a vector as follows, and then I inserted it into the tree, I don't know if I just leave it in the order the tree will be assembled as in the image, but what I did was the following:
char* dict[] = {
"Mamifero","aves","repteis",
"quadrupede", "bipede", "voadores", "aquaticos",
"nao-voadoras", "nadadoras", "de rapina", "com casco", "carnivoros", "sem patas",
"carnivoro", "herbivoro", "onivoro", "afrutifero", "tropical", "polar",
"leao", "cavalo", "homem", "macaco", "morcego", "baleia", "avestruz", "pinguim",
"pato", "aguia", "tartaruga", "crocodilo", "cobra"
};
typedef struct Animal *animalptr;
typedef struct Animal {
char *str;
animalptr left, right;
} Animal;
typedef int (*compare)(const char*, const char*);
void insert (char* key, Animal** leaf, compare cmp) {
int res;
if (*leaf == NULL) {
*leaf = (Animal*) malloc(sizeof(Animal));
(*leaf)->str = malloc(strlen(key) + 1);
strcpy ((*leaf)->str, key);
(*leaf)->left = NULL;
(*leaf)->right = NULL;
// printf("\nnew node for %s", key);
}
else {
// printf("%d\n", res);
res = cmp (key, (*leaf)->str);
if (res < 0) insert (key, &(*leaf)->left, cmp);
else if (res > 0) insert (key, &(*leaf)->right, cmp);
else printf("key '%s' already in tree\n", key);
}
}
int cmpStr (const char* a, const char* b) {
// printf("a = %d\n b = %d", strlen(a), strlen(b));
return (strcmp (a,b));
}
fill it in as follows:
int main () {
Animal *parent = NULL;
char q;
// printf("%ld\n", sizeof(dict));
// insert(dict[0], &parent, (compare)cmpStr);
// printTree(parent);
for (int i = 0; i < NUM_NODES; i++) {
insert(dict[i], &parent, (compare)cmpStr);
}
printf ("%s", search(parent, "", (compare)cmpStr)->str);
// printTree(parent);
// do {
// // scanf("%c", &q);
// // printf("%s?", dict[rand() % 32]);
// // }while (q != 'q');
return 0;
}
so now my saga would be how to apply some weight to each word, to direct it to one side or the other, the exercise I'm trying to solve in this way is this:
Build a program that is able to conclude which of the following animals
was chosen through questions and answers. Possible animals: lion, horse, man,
monkey, whale, ostrich, penguin, duck, eagle, turtle, crocodile and snake.
teste
Each word can be marked with a parent-child relationship, weight = parent's weight + own serial number under the same parent, like
Mamifero => "1"
aves => "2"
repteis => "3"
bipede => "12" (second child under Mamifero)
afrutifero => "122" (second child under bipede)
If the prefixes are the same, it means that there is a parent-child relationship, insert it on the right side of the tree, otherwise insert it on the left side of the tree
Please see the modified code
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct words {
char *weight;
char *name;
} Words;
Words dict[] = {
{"1", "Mamifero"},
{"2", "aves"},
{"3", "repteis"},
{"11", "quadrupede"},
{"12", "bipede"},
{"13", "voadores"},
{"14", "aquaticos"},
{"21", "nao-voadoras"},
{"22", "nadadoras"},
{"23", "de rapina"},
{"31", "com casco"},
{"32", "carnivoros"},
{"33", "sem patas"},
{"111", "carnivoro"},
{"112", "herbivoro"},
{"121", "onivoro"},
{"122", "afrutifero"},
{"211", "tropical"},
{"212", "polar"},
{"1111", "leao"},
{"1121", "cavalo"},
{"1211", "homem"},
{"1221", "macaco"},
{"131", "morcego"},
{"141", "baleia"},
{"2111", "avestruz"},
{"2121", "pinguim"},
{"221", "pato"},
{"231", "aguia"},
{"311", "tartaruga"},
{"321", "crocodilo"},
{"331", "cobra"}
};
#define NUM_NODES (sizeof(dict)/sizeof(*dict))
typedef struct Animal *animalptr;
typedef struct Animal {
char *weight;
char *str;
animalptr left, right;
} Animal;
typedef int (*compare)(const char *, const char *);
void insert(Words *key, Animal **leaf, compare cmp)
{
int res;
if (*leaf == NULL) {
*leaf = (Animal *) malloc(sizeof(Animal));
(*leaf)->str = strdup(key->name);
(*leaf)->weight = strdup(key->weight);
(*leaf)->left = NULL;
(*leaf)->right = NULL;
} else {
res = cmp(key->weight, (*leaf)->weight);
if (res < 0) insert(key, &(*leaf)->left, cmp);
else if (res > 0) insert(key, &(*leaf)->right, cmp);
else printf("key '%s' already in tree\n", key->name);
}
}
int cmpStr(const char *a, const char *b)
{
if (strcmp(a, b) == 0)
return 0;
// If the prefixes are the same, it means a is a child of b, insert on the right
if (strncmp(a, b, strlen(b)) == 0)
return 1;
// Otherwise insert left
return -1;
}
char *search(Animal *leaf)
{
char *ret = "";
char buf[16];
while (leaf) {
if (!leaf->right && !leaf->left) {
ret = leaf->str;
break;
}
// guess
printf("É %s (yes,no): ", leaf->str);
fgets(buf, sizeof(buf), stdin);
if ((*buf == 'q') || (*buf == 'Q'))
break;
// If yes, go to the right
if ((*buf == 'y') || (*buf == 'Y'))
leaf = leaf->right;
// Otherwise, left
else if ((*buf == 'n') || (*buf == 'N'))
leaf = leaf->left;
}
return ret;
}
int main()
{
Animal *parent = NULL;
for (int i = 0; i < NUM_NODES; i++) {
insert(&dict[i], &parent, (compare)cmpStr);
}
printf("%s\n", search(parent));
return 0;
}

Anyone know why this code gives wrong output in leet code and works fine in vs code

so basically i am trying to solve a leet code problem called [two sum II] using hashing
but i am getting error in this test case 1,2,3,4,4,9,56,90 where i have to find two index those elements sum is equal to target 8
well the answer of this test case is 4,5 because the sum of index4 and index5 in array[1-8] is 8
Here the problem is when i compiled this below code in vs code it works perfectly fine and gives correct output 4,5
but during leet code submission it throws wrong answer and showing output 1,3 instead of 4,5
// here is my hash implemention code
#include <stdio.h>
#include <stdlib.h>
typedef struct Hash {
int value;
int index;
struct Hash *next;
} hash;
hash *Hashes[10];
int hashify(int value) { return abs(value) % 10; }
void insert(int value, int index) {
int key = hashify(value);
if (Hashes[key] == NULL) {
Hashes[key] = malloc(sizeof(hash));
Hashes[key]->value = value;
Hashes[key]->index = index;
Hashes[key]->next = NULL;
return;
}
hash *ptr = Hashes[key];
while (ptr->next != NULL) ptr = ptr->next;
ptr->next = malloc(sizeof(hash));
ptr->next->value = value;
ptr->next->index = index;
ptr->next->next = NULL;
return;
}
int search(int value) {
int key = hashify(value);
if (Hashes[key] == NULL) return -1;
if (Hashes[key]->value == value)
return Hashes[key]->index;
else {
hash *ptr = Hashes[key]->next;
while (ptr != NULL) {
if (ptr->value == value) return ptr->index;
ptr = ptr->next;
}
return -1;
}
}
// here is hash_free function
void Hash_free() {
for (int i = 0; i < 10; i++) {
if (Hashes[i] == NULL)
continue;
else {
if (Hashes[i]->next == NULL) {
free(Hashes[i]);
Hashes[i] = NULL;
} else {
hash *ptr;
while (ptr != NULL) {
ptr = Hashes[i]->next;
free(Hashes[i]);
Hashes[i] = ptr;
}
}
}
}
}
// here is two sum function code
int *twoSum(int *numbers, int numbersSize, int target, int *returnSize) {
int *result;
if (numbersSize == 2) {
result = malloc(2 * sizeof(int));
result[0] = 1;
result[1] = 2;
*returnSize = 2;
return result;
} else {
int val, element;
for (int i = 0; i < numbersSize; i++) {
val = target - numbers[i];
element = search(val);
if (element != -1) {
result = malloc(2 * sizeof(int));
if (element < i) {
result[0] = element + 1;
result[1] = i + 1;
} else {
result[0] = i + 1;
result[1] = element + 1;
}
*returnSize = 2;
Hash_free();
return result;
}
insert(numbers[i], i);
}
}
return NULL;
}
// here is main code
int main() {
int numbers[] = {1, 2, 3, 4, 4, 9, 56, 90};
int target = 8;
int numberSize = sizeof(numbers) / sizeof(int);
int returnSize;
int *res = twoSum(numbers, numberSize, target, &returnSize);
for (int i = 0; i < returnSize; i++) {
printf("%d ", res[i]);
}
free(res);
return 0;
}
Your "hash" variable is global, so it keeps preserving data of previous testcase executed. I have faced the same when using global variable.
Solution:
Just clear your hash or initialize it, in your main function( or the entry point function), so that it will ensure a fresh start for each of the test cases those are executed.

Postgresql custom c aggregate function throw a segmentation fault

I am trying to create an aggregate function which returns the value of a column in the row which has the least/greatest timestamp. Below is the code which throws a segmentation fault for some large input.
PG_FUNCTION_INFO_V1(minmax);
Datum minmax(PG_FUNCTION_ARGS) {
if(PG_ARGISNULL(1) || PG_ARGISNULL(2) || PG_ARGISNULL(3)) {
if(PG_ARGISNULL(0)) {
PG_RETURN_NULL();
}
else {
PG_RETURN_HEAPTUPLEHEADER(PG_GETARG_HEAPTUPLEHEADER(0));
}
}
Timestamp epoch = PG_GETARG_TIMESTAMP(1);
Datum col = PG_GETARG_DATUM(2);
Oid element_type = get_fn_expr_argtype(fcinfo->flinfo, 2);
bool is_min = PG_GETARG_BOOL(3);
Timestamp minmax_epoch = is_min ? LONG_MAX : LONG_MIN;
Datum minmax_col;
if(PG_ARGISNULL(0)) {
// first call
minmax_epoch = epoch;
minmax_col = col;
}
else {
// state
HeapTupleHeader hth_state = PG_GETARG_HEAPTUPLEHEADER(0);
bool isnull_state_minmax_timestamp;
Datum d_state_minmax_timestamp = GetAttributeByNum(hth_state, (AttrNumber) 1, &isnull_state_minmax_timestamp);
minmax_epoch = DatumGetInt64(d_state_minmax_timestamp);
if((is_min && epoch < minmax_epoch) || (!is_min && epoch > minmax_epoch)) {
minmax_epoch = epoch;
minmax_col = col;
}
else {
PG_RETURN_HEAPTUPLEHEADER(hth_state);
}
}
// return state
TupleDesc tupdesc;
Datum values[2];
bool nulls[2];
MemSet(values, 0, sizeof(values));
MemSet(nulls, 0, sizeof(nulls));
tupdesc = CreateTemplateTupleDesc(2, false);
TupleDescInitEntry(tupdesc, (AttrNumber) 1, "minmax_timestamp", INT8OID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber) 2, "minmax_col", element_type, -1, 0);
tupdesc = BlessTupleDesc(tupdesc);
values[0] = Int64GetDatum(minmax_epoch);
values[1] = minmax_col;
HeapTuple rettuple = heap_form_tuple(tupdesc, values, nulls);
PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
}
PG_FUNCTION_INFO_V1(get_minmax);
Datum get_minmax(PG_FUNCTION_ARGS) {
if(PG_ARGISNULL(0)) {
PG_RETURN_NULL();
}
else {
// state
//error here
HeapTupleHeader hth_state = PG_GETARG_HEAPTUPLEHEADER(0);
bool isnull_state_minmax_col;
Datum d_state_minmax_col = GetAttributeByNum(hth_state, (AttrNumber) 2, &isnull_state_minmax_col);
PG_RETURN_DATUM(d_state_minmax_col);
}
}
The seg fault seems to be in the function get_minmax getting the PG_GETARG_HEAPTUPLEHEADER argument. May be I am not building it properly in minmax function.
Doesn't seem to be anything wrong with the above code. I was using the aggregate function in greenplum and not postgresql. For those writing aggregate functions in greenplum and implementing PREFUNC, make sure to check if both the arguments are NULL and handle accordingly.
Experts do suggest if any improvements can be made to the above function in terms of memory usage, etc

How to create AVL

I enter several numbers(2,1,4,5,9,3,6,7),after I enter the number '3', there something wrong,the function can not return correctly.
#include <stdio.h>
#include <stdlib.h>
typedef struct AVLNode
{
int data;
int height;
struct AVLNode *LChild;
struct AVLNode *RChild;
}*AVLTree;
typedef struct AVLNode *Position;
static int Height(Position T)
{
if (T == NULL)
return -1;
else
return T->height;
}
static Position SingleLeft(Position k2)
{
Position k1;
k1 = k2->LChild;
k2->LChild = k1->RChild;
k1->RChild = k2;
k2->height = max(Height(k2->LChild), Height(k2->RChild)) + 1;
k1->height = max(Height(k1->LChild), Height(k1->RChild)) + 1;
return k1;
}
static Position SingleRight(Position k1)
{
Position k2;
k2 = k1->RChild;
k1->RChild = k2->LChild;
k2->LChild = k1;
k1->height = max(Height(k1->LChild), Height(k1->RChild)) + 1;
k2->height = max(Height(k2->LChild), Height(k2->RChild)) + 1;
return k2;
}
static Position DoubleLeft(Position k3)
{
k3->LChild = SingleRight(k3->LChild);
return SingleLeft(k3);
}
static Position DoubleRight(Position k1)
{
k1->RChild = SingleLeft(k1->RChild);
return SingleRight(k1);
}
void PrePrint(AVLTree T)
{
if (T != NULL)
{
printf("%d ", T->data);
PrePrint(T->LChild);
PrePrint(T->RChild);
}
}
AVLTree Insert(int x, AVLTree T)
{
if (T == NULL)
{
T = (AVLTree)malloc(sizeof(struct AVLNode));
T->data = x;
T->LChild = T->RChild = NULL;
}
else if (x < T->data)
{
T->LChild = Insert(x, T->LChild);
if (Height(T->LChild) - Height(T->RChild) == 2)
{
if (x<T->LChild->data)
T = SingleLeft(T);
else
T = DoubleLeft(T);
}
}
else if (x > T->data)
{
T->RChild = Insert(x, T->RChild);
if (Height(T->RChild) - Height(T->LChild) == 2)
{
if (x>T->RChild->data)
T = SingleRight(T);
else
T = DoubleRight(T);
}
}
T->height = max(Height(T->LChild), Height(T->RChild)) + 1;
return T;
}
I think there is something wrong in my main function, I think I shouldn't write
T=(AVLTree)malloc(sizeof(struct AVLNode));
T->LChild = T->RChild = NULL;
those code in mian function, I try to add a 'Init' function, but it doesn't work. It always said "'T' is being used without initialized"
int main()
{
AVLTree T;
T=(AVLTree)malloc(sizeof(struct AVLNode));I think there is wrong
T->LChild = T->RChild = NULL;
int x;
printf("please enter the data(0 to quit):");
scanf("%d", &x);
T->data = x;
while (x != 0)
{
Insert(x, T);
printf("enter a number(0 to quit):");
scanf("%d", &x);
}
PrePrint(T);
}
When your insertion makes a new root node, this fact is not propagated back to main in any way. The value of T inside the Insert function changes, but main has its own variable called T that isn't changed, and that's the one that you then use to print out the tree.
I notice that your Insert function returns an AVLTree, but when main calls it it doesn't do anything with the return value.
(This is not the only thing that's amiss in your code, but it would be a good place to start.)

xmlNewChild not always writing the value of the element

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.

Resources