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;
}
Related
The code below is a code that will track my product costs and remaining quantity.The problem I'm facing with is I can't search the code by
if(g[n].name == search[10])
The out put keep showing
"Item not found"
Im a beginner of c language and was hope to learn more. Please correct my code and send it here so that I can know why my code is wrong.
#include <stdio.h>
struct product
{
char name[10];
int quantity;
float costs;
};
void fn_search (struct product g[]);
int main ()
{
int n;
struct product g[4];
strcpy(g[0].name,"aa1");
g[0].quantity = 10;
g[0].costs = 1;
strcpy(g[1].name,"bb2");
g[1].quantity = 10;
g[1].costs = 2;
strcpy(g[2].name,"bb3");
g[2].quantity = 10;
g[2].costs = 3;
fn_search (g);
}
void fn_search (struct product g[10])
{
int n;
char search[10];
printf("Search>> ");
scanf("%s",&search[10]);
for (n=0;n<4;n++)
{
if(g[n].name == search[10])
{
printf ("\ncosts = NTD%.2f",g[n].costs);
printf ("\nquantity = %d\n",g[n].quantity);
}
else
{
printf("\nItem not found.");
break;
}
}
}
Two bugs:
Incorrect use of scanf :
scanf("%s",&search[10]); --> scanf("%9s", search);
Note: scanf("%9s", &search[0]); is also fine but the above is the common way.
Incorrect string compare :
if(g[n].name == search[10]) --> if(strcmp(g[n].name, search) == 0)
Also notice that you never initialized g[3] but fn_search checks it.
Then this part:
else
{
printf("\nItem not found.");
break;
}
means that you break the for loop as soon as an item doesn't match. In other words: Currently you only compare against g[0]
You don't want that! Check all items before printing "Item not found".
So the for loop should be more like:
for (n=0;n<4;n++)
{
if(strcmp(g[n].name, search) == 0)
{
printf ("\ncosts = NTD%.2f",g[n].costs);
printf ("\nquantity = %d\n",g[n].quantity);
return; // Exit function when match is found
}
}
// When execution arrives here, there was no matching element
printf("\nItem not found.");
Finally:
void fn_search (struct product g[10])
^^
why ??
Either do
void fn_search (struct product g[])
or
void fn_search (struct product *g)
I think this is written in C, honestly don't know how to identify (if someone could give some tips it would be great). When the command rpt dumpvars 1234 is run in the console it returns the variables of machine/node 1234 to the screen. I want the same data output to a variables.txt file. Is there a simple one liner that I can add to do this?
The file is located here.
The portion of the data I am trying to get can be found on lines 7590-7623 as pasted here:
/*
* Display a node's main channel variables from the command line
*/
static int rpt_do_showvars(int fd, int argc, char *argv[])
{
int i,thisRpt = -1;
struct ast_var_t *newvariable;
if (argc != 3) return RESULT_SHOWUSAGE;
for(i = 0; i < nrpts; i++)
{
if(!strcmp(argv[2], rpt_vars[i].name))
{
thisRpt = i;
break;
}
}
if (thisRpt < 0)
{
ast_cli(fd, "Unknown node number %s.\n", argv[2]);
return RESULT_FAILURE;
}
i = 0;
ast_cli(fd,"Variable listing for node %s:\n",argv[2]);
ast_channel_lock(rpt_vars[thisRpt].rxchannel);
AST_LIST_TRAVERSE (&rpt_vars[thisRpt].rxchannel->varshead, newvariable,
entries) {
i++;
ast_cli(fd," %s=%s\n", ast_var_name(newvariable),
ast_var_value(newvariable));
}
ast_channel_unlock(rpt_vars[thisRpt].rxchannel);
ast_cli(fd," -- %d variables\n", i);
return(0);
}
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.
I'm trying to print an array of structs that contain two strings. However my print function does not print more than two indices of the array. I am not sure why because it seems to me that the logic is correct.
This is the main function
const int MAX_LENGTH = 1024;
typedef struct song
{
char songName[MAX_LENGTH];
char artist[MAX_LENGTH];
} Song;
void getStringFromUserInput(char s[], int maxStrLength);
void printMusicLibrary(Song library[], int librarySize);
void printMusicLibraryTitle(void);
void printMusicLibrary (Song library[], int librarySize);
void printMusicLibraryEmpty(void);
int main(void) {
// Announce the start of the program
printf("%s", "Personal Music Library.\n\n");
printf("%s", "Commands are I (insert), S (sort by artist),\n"
"P (print), Q (quit).\n");
char response;
char input[MAX_LENGTH + 1];
int index = 0;
do {
printf("\nCommand?: ");
getStringFromUserInput(input, MAX_LENGTH);
// Response is the first character entered by user.
// Convert to uppercase to simplify later comparisons.
response = toupper(input[0]);
const int MAX_LIBRARY_SIZE = 100;
Song Library[MAX_LIBRARY_SIZE];
if (response == 'I') {
printf("Song name: ");
getStringFromUserInput(Library[index].songName, MAX_LENGTH);
printf("Artist: ");
getStringFromUserInput(Library[index].artist, MAX_LENGTH);
index++;
}
else if (response == 'P') {
// Print the music library.
int firstIndex = 0;
if (Library[firstIndex].songName[firstIndex] == '\0') {
printMusicLibraryEmpty();
} else {
printMusicLibraryTitle();
printMusicLibrary(Library, MAX_LIBRARY_SIZE);
}
This is my printing the library function
// This function will print the music library
void printMusicLibrary (Song library[], int librarySize) {
printf("\n");
bool empty = true;
for (int i = 0; (i < librarySize) && (!empty); i ++) {
empty = false;
if (library[i].songName[i] != '\0') {
printf("%s\n", library[i].songName);
printf("%s\n", library[i].artist);
printf("\n");
} else {
empty = true;
}
}
}
I think the problem is caused due to setting : empty = true outside the for loop and then checking (!empty) which will evaluate to false. What I am surprised by is how is it printing even two indices. You should set empty = false as you are already checking for the first index before the function call.
The logic has two ways to terminate the listing: 1) if the number of entries is reached, or 2) if any entry is empty.
I expect the second condition is stopping the listing before you expect. Probably the array wasn't built as expected (I didn't look at that part), or something is overwriting an early or middle entry.
you gave the definition as:
typedef struct song
{
char songName[MAX_LENGTH];
char artist[MAX_LENGTH];
}Song;
the later, you write if (library[i].songName[i] != '\0') which really seems strange: why would you index the songname string with the same index that the lib?
so I would naturally expect your print function to be:
// This function will print the music library
void printMusicLibrary (Song library[], int librarySize) {
for (int i = 0; i < librarySize; i ++) {
printf("%s\n%s\n\n", library[i].songName,
library[i].artist);
}
}
note that you may skip empty song names by testing library[i].songName[0] != '\0' (pay attention to the 0), but I think it would be better not to add them in the list (does an empty song name make sens?)
(If you decide to fix that, note that you have an other fishy place: if (Library[firstIndex].songName[firstIndex] == '\0') with the same pattern)
I am trying (and having trouble) to write a program (In C) that accepts a string in the command line (eg. $ test.out "This is a string") and looks through the string to find verbs (and nouns, but if I figure out verbs, I can do nouns on my own).
A list of aplphabetically sorted verbs is given in the file lexicon.h, and is what I am supposed to use as my dictionary.
I know how to accept the string from the command line and use that input to create an array of strings, each string itself being a separate word, and I already have a working program that can do that, and that I hope to use part of for this one.
I am supposed to create a function called binary_search(...stuffgoeshere...) and use that to search through the lexicon file and find the verb.
I would like some suggestions or guidance on how to create a function (binary_search) that can check to see if an already separated word matches any on the list in lexicon.h. I do not want someone to just write an answer, I would like to know why you are suggesting what you do. Hopefully I can learn something fun out of this!
I know it's messy, but this is what I have so far.
Also note that lexicon's verb array has 637 values (as seen when I make int size = 637)
This program does not compile anymore, as I have not yet figured out how to make the binary_search function work yet. I am trying to modify a binary search function used in an example for class, however, that one sorted numbers in a text file, not strings of characters.
If there is anything else I should include, let me know. Thank you for your help!
#include <stdio.h>
#include <string.h>
#include "lexicon.h"
int binary_search(char word[], char verbs[][], int size);
int
main(int argc, char*argv[])
{
char word[80];
char str[80],
args[80][80];
int counter = 0,
a = 0,
i = 0,
index = 0,
t = 0;
while(str[a] != '\0')
{
if(str[a] == ' ')
{
args[index][i] = '\0';
i = 0;
a++;
index ++;
counter ++;
}
args[index][i++] = str[a++];
}
args[index][i] = '\0';
counter = counter + 1;
printf("\nThe verbs were: ");
int verbposition= -1;
int size = 637;
while(t<counter)
{
strcpy(word, args[t]);
verbposition = binary_search(word, verbs, size);
if(verbposition > -1)
printf("%s", args[t]);
t++;
}
return 0;
}
int
binary_search(char word[], char &verbs[][], int size)
{
int bottom = 0,
top = size - 1,
found = 0,
middle;
while(bottom <= top && !found)
{
middle = (bottom + top) / 2;
if(strcmp(word, verbs[middle]))
{
found = 1;
return = middle;
}
if(strcmp(word, verbs[middle]) > 0)
{
top = middle - 1;
}
else
bottom = middle + 1;
}
return -1;
}
You are on the right track. I would highly suggest you to use print statements as you will have a clear idea of where you are going wrong.