Lua nested table from Lua to C - c

I miserably fail to convert nested Lua table into C json object. I'm using LuaTableToJson (see code here after) where "index" is the parameter index to retrieve and PopOneArg the routine to process a value depending on its type.
When having a nested table I would like to call LuaTableToJson recursively, but with index=-1 it does not work.
Question: could please someone point on working sample to retreive nested table passed as argument from Lua to C. Alternatively could someone explain the stack structure when passing nested table from Lua to C.
Thank you
Note: for C->Lua I have a solution.
STATIC json_object *LuaTableToJson (lua_State* luaState, int index) {
int idx;
json_object *tableJ= json_object_new_object();
const char *key;
char number[3];
lua_pushnil(luaState); // 1st key
for (idx=1; lua_next(luaState, index) != 0; idx++) {
// uses 'key' (at index -2) and 'value' (at index -1)
if (lua_type(luaState,-2) == LUA_TSTRING) key= lua_tostring(luaState, -2);
else {
snprintf(number, sizeof(number),"%d", idx);
key=number;
}
json_object *argJ= PopOneArg(luaState, -1);
json_object_object_add(tableJ, key, argJ);
lua_pop(luaState, 1); // removes 'value'; keeps 'key' for next iteration
}
// Query is empty free empty json object
if (idx == 1) {
json_object_put(tableJ);
return NULL;
}
return tableJ;
}
STATIC json_object *PopOneArg (lua_State* luaState, int idx) {
json_object *value=NULL;
int luaType = lua_type(luaState, idx);
switch(luaType) {
case LUA_TNUMBER: {
lua_Number number= lua_tonumber(luaState, idx);;
int nombre = (int)number; // evil trick to determine wether n fits in an integer. (stolen from ltcl.c)
if (number == nombre) {
value= json_object_new_int((int)number);
} else {
value= json_object_new_double(number);
}
break;
}
case LUA_TBOOLEAN:
value= json_object_new_boolean(lua_toboolean(luaState, idx));
break;
case LUA_TSTRING:
value= json_object_new_string(lua_tostring(luaState, idx));
break;
case LUA_TTABLE: {
if (idx > 0) {
value= LuaTableToJson(luaState, idx);
} else {
value= json_object_new_string("UNSUPPORTED_Lua_Nested_Table");
}
break;
}
case LUA_TNIL:
value=json_object_new_string("nil") ;
break;
default:
AFB_NOTICE ("PopOneArg: script returned Unknown/Unsupported idx=%d type:%d/%s", idx, luaType, lua_typename(luaState, luaType));
value=NULL;
}
return value;
}
static json_object *LuaPopArgs (lua_State* luaState, int start) {
json_object *responseJ;
int stop = lua_gettop(luaState);
if(stop-start <0) return NULL;
// start at 2 because we are using a function array lib
if (start == stop) {
responseJ=PopOneArg (luaState, start);
} else {
// loop on remaining return arguments
responseJ= json_object_new_array();
for (int idx=start; idx <= stop; idx++) {
json_object *argJ=PopOneArg (luaState, idx);
if (!argJ) goto OnErrorExit;
json_object_array_add(responseJ, argJ);
}
}
return responseJ;
OnErrorExit:
return NULL;
}

For a packaged solution, check my code here
Essentially, when parsing a nested table, you should be parsing at a negative index. In this case, lua_next will mess up the stack relative to the index you're tracking, so you need to decrement it.
You can try
if (index < 0) index--; // change to -- as in your code
When parsing tables. It should work with your code, but I can't promise there's not another problem I'm missing.
My code works for sure to any level of nesting, so I'd recommend following it as an example and posting your final code as an answer once it works.

Related

Waiting for character in string

I am currently working on a project that will be used to test whether an instrument is within tolerance or not. My test equipment will put the DUT (Device Under Test) into a "Test Mode" where it will repeatedly send a string of data every 200ms. I want to receive that data, check is is within tolerance and give it a pass or fail.
My code so far (I've edited a few things out like .h files and some work related bits!):
void GetData();
void CheckData();
char Data[100];
int deviceId;
float a;
float b;
float c;
void ParseString(const char* stringValue)
{
char* token = NULL;
int tokenPlace = 0;
token = strtok((char *) stringValue, ",");
while (token != NULL) {
switch (tokenPlace) {
case 0:
deviceId = atoi(token);
break;
case 1:
a= ((float)atoi(token)) / 10.0f;
break;
case 2:
b= ((float)atoi(token)) / 100.0f;
break;
case 3:
c= ((float)atoi(token)) / 10.0f;
break;
}
tokenPlace++;
token = strtok(NULL, ",");
}
}
void GetData()
{
int x = UART.scanf("%s,",Data);
ParseString(Data);
if (x !=0) {
UART.printf("Device ID = %i\n\r", deviceId);
UART.printf("a= %.1f\n\r", a);
UART.printf("s= %.2f\n\r", b);
UART.printf("c= %.1f\n\n\r", c);
}
if (deviceId <= 2) {
CheckData();
} else {
pc.printf("Device ID not recognised\n\n\r");
}
}
void CheckData()
{
if (a >= 49.9f && a< = 50.1f) {
pc.printf("a Pass\n\r");
} else {
pc.printf("a Fail\n\r");
}
if (b >= 2.08f && b <= 2.12f) {
pc.printf("b Pass\n\r");
} else {
pc.printf("b Fail\n\r");
}
if (c >= 20.0f && c <= 25.0f) {
pc.printf("c Pass\n\n\r");
} else {
pc.printf("c Fail\n\n\r");
}
if (deviceId == 0) {
(routine1);
} else if (deviceId == 1) {
(routine2);
} else if (deviceId == 2) {
(Routine3);
}
}
int main()
{
while(1) {
if(START == 0) {
wait(0.1);
GetData();
}
}
}
And this works absolutely fine. I am only printing the results to a serial terminal so I can check the data is correct to make sure it is passing and failing correctly.
My issue is every now and then the START button happens to be pressed during the time the string is sent and the data can be corrupt, so the deviceId fails and it will say not recognised. This means I then have to press the start button again and have another go. A the moment, it's a rare occurrence but I'd like to get rid of it if possible. I have tried adding a special character at the beginning of the string but this again gets missed sometimes.
Ideally, when the start button is pressed, I would like it to wait for this special character so it knows it is at the beginning of the string, then the data would be read correctly, but I am unsure how to go about it.
I have been unsuccessful in my attempts so far but I have a feeling I am overthinking it and there is a nice easy way to do it. Probably been staring at it too long now!
My microcontroller is STM32F103RB and I am using the STM Nucleo with the mBed IDE as it's easy and convenient to test the code while I work on it.
You can use ParseString to return a status indicating whether a complete string is read or not.
int ParseString(const char* stringValue)
{
/* ... your original code ... */
/* String is complete if 4 tokens are read */
return (tokenPlace == 4);
}
Then in GetData use the ParseString return value to determine whether to skip the string or not.
void GetData()
{
int x = UART.scanf("%s,",Data);
int result = ParseString(Data);
if (!result) {
/* Did not get complete string - just skip processing */
return;
}
/* ... the rest of your original code ... */
}

If I can't define a variable inside an if-condition, how can I reduce searching through my array multiple times in this code?

I have a function who's body looks a lot like this:
if (contains(array, element1) > -1){
// do something
} else if (contains(array, element2) > -1) {
// do something
} else if (contains(array, element3) > -1) {
// do someting
}...
The function contains will loop through my array and check to see if it contains an element that I pass to it and return either its position if it exists, or -1 if it doesn't.
In my // do something portion, I need the position of this element in the array. There are a couple of different ways I can do this:
I can call my contains() function once more to get the position.
I can define several variables that are defined as the return of the contain function, and then check them in my if-else block. So something like:
int element1Loc = contains(array, element1);
int element2Loc = contains(array, element2);
int element3Loc = contains(array, element3);
if (element1Loc > -1){
// do something
} else if (element2Loc > -1) {
// do something
} else if (element3Loc > -1) {
// do someting
}...
I can perhaps modify contain to return an int array[2], with array[0] equal to 0 or 1 whether the element is in it or not, and then array[1] qwould equal the actual location, making the code look like thiss:
if (contains(array, element1)[0] > -1){
// do something
} else if (contains(array, element2)[0] > -1) {
// do something
} else if (contains(array, element3)[0] > -1) {
// do something
}...
I can say screw the if-else block, save the return of contains in a variable and run several if-statements.
Solution one will search through my array at least twice. Solution two will search at least as many times as there are elements I'm looking for. Solution 3 is perhaps the best, but maybe not the most elegant. Solution 4 will run each if statement...
What is the best way to search just once? Should I make a function that takes all the things I am looking for and returns an array with the position of each element? Am I overthinking it?
I would modify contains to only use the return value to indicate the error/success of the find, and, if the parameter was found, output the parameter by reference.
int contains(int *data, int value, int *loc)
{
for(int i = 0; i < SIZE; i++)
{
if(data[i]==value)
{
*loc = i;
return 1; // success
}
}
*loc = -1;
return 0; // failure
}
Now, you can just do:
int elem1loc, elem2loc, elem3loc;
if(contains(data, val1, &elem1loc))
// use elem1loc...
if(contains(data, val2, &elem2loc))
// use elem2loc...
You could pass a pointer to say int which would be populated when the contains function finds an element. Then inside your if block you would be assured that pos is the correct index.
Example:
int pos;
if (contains(array, element1, &pos) > -1) {
// Here you can check pos for the position
} else if (contains(array, element2, &pos) > -1) {
// Here you can check pos as well...
}
Here's a solution that doesn't require you to modify contains at all:
int pos;
if ((pos = contains(array, element1)) > -1) {
// do something with pos
} else if ((pos = contains(array, element2)) > -1) {
// do something with pos
} else if ((pos = contains(array, element3)) > -1) {
// do something with pos
}
This works because variable assignment in most imperative languages is an expression.

Dynamically enumerate keys in libconfig

in libconfig - is it possible to dymanically enumerate keys?
As an example, in this example config file from their repo - if someone invented more days in the hours section, could the code dynamically enumerate them and print them out?
Looking at the docs, I see lots of code to get a specific string, or list out an array, but I can't find an example where it enumerates the keys of a config section.
Edit
Received some downvotes, so thought I'd have another crack at being more specific.
I'd like to use libconfig to track some state in my application, read in the last known state when the app starts, and write it out again when it exits. My app stores things in a tree (of depth 2) - so this could be niceley represented as an associative array in a libconfig compatible file as below. The point is that the list of Ids (1234/4567) can change. I could track them in another array, but if I could just enumerate the 'keys' in the ids array below - that would be neater.
so
ids = {
"1234" = [1,2,3]
"4567" = [9,10,11,23]
}
e.g (psuedocode)
foreach $key(config_get_keys_under(&configroot)){
config_get_String($key)
}
I can't see anything obvious in the header file.
You can use config_setting_get_elem function to get n-th element of the group, array or list, and then (if it's group) use config_setting_name to get it's name. But AFAIK you can't use digits in key names. So consider following config structure:
ids = (
{
key = "1234";
value = [1, 2, 3];
},
{
key = "4567";
value = [9, 10, 11, 23];
}
);
Then you can easily enumerate through all members of the ids getting the values you want using the following code:
#include <stdio.h>
#include <libconfig.h>
int main(int argc, char **argv) {
struct config_t cfg;
char *file = "config.cfg";
config_init(&cfg);
/* Load the file */
printf("loading [%s]...\n", file);
if (!config_read_file(&cfg, file)) {
printf("failed\n");
return 1;
}
config_setting_t *setting, *member, *array;
setting = config_lookup(&cfg, "ids");
if (setting == NULL) {
printf("no ids\n");
return 2;
}
int n = 0, k, v;
char const *str;
while (1) {
member = config_setting_get_elem(setting, n);
if (member == NULL) {
break;
}
printf("element %d\n", n);
if (config_setting_lookup_string(member, "key", &str)) {
printf(" key = %s\n", str);
}
array = config_setting_get_member(member, "value");
k = 0;
if (array) {
printf(" values = [ ");
while (1) {
if (config_setting_get_elem(array, k) == NULL) {
break;
}
v = config_setting_get_int_elem(array, k);
printf("%s%d", k == 0 ? "" : ", ", v);
++k;
}
printf(" ]\n");
}
++n;
}
printf("done\n");
/* Free the configuration */
config_destroy(&cfg);
return 0;
}

Data by reference instead of value

I am trying to make a program that has a menu and it has an option to set the "current" date. I can define the date and it will stay until the program shuts down. I've got another method to get the date, by asking the user the date when linking a person to it, the problem is that it wont go on the main data on the main menu. It will only be the data for the .date on the person structure, I guess I explained it well. I've tried many ways and I really can't figure it out, if someone can help me out...
typeData readData() {
int val;
typeData data;
do {
printf("Day: ");
data.day = readInteger(MIN_DAYS, MAX_DAYS);
printf("Month: ");
data.month = readInteger(MIN_MONTH, MAX_MONTH);
printf("Year: ");
data.year = readInteger(MIN_YEAR, MAX_YEAR);
val = validateData(data);
if(val == 0) {
printf("The data is not valid.\n");
}
} while (val == 0);
return data;
}
I think I need to get it by reference but I'm trying for some time already and can't do it. Thanks everyone.
While it's legal C, passing structs by value and returning them is usually not the best way. Consider:
void
readData(typeData *data)
{
int val;
do {
printf("Day: ");
data->day = readInteger(MIN_DAYS, MAX_DAYS);
printf("Month: ");
data->month = readInteger(MIN_MONTH, MAX_MONTH);
printf("Year: ");
data->year = readInteger(MIN_YEAR, MAX_YEAR);
val = validateData(data);
if (val == 0) {
printf("The data is not valid.\n");
}
} while (val == 0);
}
UPDATE:
Here is a sample main program plus sample changes to validateData:
int
validateData(typeData *data)
{
int data_valid = 1;
// check for error
// this is whatever checks you already do ...
if (data->... != ...)
data_valid = 0;
return data_valid;
}
int
main(int argc,char **argv)
{
typeData main_data;
readData(&main_data);
// do something useful with the data [or transform it, etc]
processData(&main_data);
// print some results
printData(&main_data);
return 0;
}
UPDATE #2:
Here's a modified [partial] program, based on your latest example. I had to guess at the overall organization, but, at least it has the necessary changes to menuPrincipal:
int
validateData(typeData *data)
{
int data_valid = 1;
// check for error
// this is whatever checks you already do ...
if (data->... != ...)
data_valid = 0;
return data_valid;
}
char
menuPrincipal(typeDate *date)
{
char option;
if (date->day == 0 && date->month == 0 && data->year == 0) {
printf("Date not set yet.\n");
}
else {
printf("Date: %d/%d/%d", date->day, date->month, date->year);
}
// more stuff
return option;
}
int
main(int argc,char **argv)
{
typeData main_data;
char option;
while (1) {
readData(&main_data);
option = menuPrincipal(&main_data);
switch (option) {
case 'a': // do something
break;
case 'b': // do something else
break;
default:
printf("unknown option: '%c'\n",option);
break;
}
}
return 0;
}
UPDATE #3:
Based on your latest comment, I think I see what you're having trouble with. I've taken your latest code snippet and updated:
// your original code -- this no longer works because readData is now void
if (data->ano == 0 && data->mes == 0 && data->dia == 0) {
Blah[*Bleh].date = readData(*data);
}
// one possibility -- but it does _not_ update "data"
if (data->ano == 0 && data->mes == 0 && data->dia == 0) {
readData(&Blah[*Bleh].date);
}
// this is more likely what you want -- it updates _both_:
if (data->ano == 0 && data->mes == 0 && data->dia == 0) {
readData(data);
Blah[*Bleh].date = *data;
}
It works now, I was using
val = validateDate(&date)
on the original function for readData, now I changed it to
val = validateDate(date)
and it works!
I just don't know why I need to use date instead of &date, I thought that if I was passing the parameters by reference I needed a '&' symbol.

Returning error when traversing through a tree

I am trying to calculate the frequency of each node as I add them to the tree, instead of inserting a new element. For some reason when a comparing a new key to every element in the current tree, the if statement will not return 1 if they are both identical. BUT, the function will still add 1 to the frequency of the existing node. This is very puzzling to me, as I don't know why it would skip over the return 1, and continue searching through the tree. Thank you for help/advice in advance.
struct:
typedef struct node {
char* key;
struct node *left;
struct node *right;
int height;
int frequency;
}node;
This is my parsing function:
while(fgets(str, 100, textFile)) {
token = strtok(str," \n");
while (token != NULL)
{
key = strdup(token);
if((sameFrequency(root, key)==1)&&root!=NULL) {
printf("%s", key);
free(key);
token = strtok (NULL, " \n");
}
else {
root = insert(root, key);
//printf("%s\n", key);
free(key);
token = strtok (NULL, " \n");
}
}
if(ferror(textFile))
{
printf("you done messed up a-a-ron");
return(0);
}
}
Function to check the frequency of each node:
int sameFrequency(node *node, char* key) {
if (node != NULL) {
if(strcmp(key, node->key)==0){ //This statement is true in some cases, but will not return the 1
node->frequency = node->frequency+1;
printf("%d\n",node->frequency);
return 1;
}
sameFrequency(node->left, key);
sameFrequency(node->right, key);
}
else return 0;
}
Input would look something like this:
wrn69 flr830 flr662 flr830 flr830
flr231
The output (after printing in preOrder):
key: wrn69, frequency: 1
key: flr830, frequency: 3
key: flr662, frequency: 1
key: flr231, frequency: 1
key: flr830, frequency: 1
key: flr830, frequency: 1
I want this to print everything shown, but I don't want the same key to be inserted into the tree, just incremement its frequency by 1.
TL;DR: Function skipping over return value, but still running code in the if statement, have no idea whats wrong, even after debugging.
I'm not sure what your code is trying to do, since you do not define your node struct, however your function int sameFrequency(node *node, char* key) has an obvious bug: not all code paths return a value. Reformatting a bit for clarity, you can see that if strcmp(key, key)!=0 then the return is undefined:
int sameFrequency(node *node, char* key) {
if (node != NULL) {
if(strcmp(key, node->key)==0){
node->frequency = node->frequency+1;
printf("%d\n",node->frequency);
return 1;
}
else {
sameFrequency(node->left, key);
sameFrequency(node->right, key);
// Continue on out of the "if" statements without returning anything.
}
}
else {
return 0;
}
// NO RETURN STATEMENT HERE
}
My compiler generates a warning for this:
warning C4715: 'sameFrequency' : not all control paths return a value
Surely yours must be doing so as well, unless you intentionally disabled them. Such warnings are important, and should always be cleared up before finishing your code.
I'm guessing you want to do something like this, perhaps?
int sameFrequency(node *node, char* key) {
if (node != NULL) {
if(strcmp(key, node->key)==0){
node->frequency = node->frequency+1;
printf("%d\n",node->frequency);
return 1;
}
else {
int found;
if ((found = sameFrequency(node->left, key)) != 0)
return found;
if ((found = sameFrequency(node->right, key)) != 0)
return found;
return 0;
}
}
else {
return 0;
}
}
This clears the compiler warning.
Incidentally, the following if statement is probably in the wrong order:
if((sameFrequency(root, key)==1)&&root!=NULL) {
Since && statements in C execute left to right the following makes more sense:
if(root!=NULL && (sameFrequency(root, key)==1)) {

Resources