parsing a .conf file in c - c

Perhaps this bridge likely has been crossed many times and in many ways... reading a simple text .conf file and acting upon its entries.
In my case, the file format is simple.. a series of tokens and assignments, as in:
token_name_1 value
with a tab character as the field delimiter and a unix line-ending for each the record.
The .conf file directly alters certain program configurations, all of them stored in a single structure. Variables of types Integer, float, char[], and *char are represented in the structure.
A quick but boring approach involves, for example:
if (strcasecmp(token,"token_name_1")==0)
token_name_1=value;
But I determined that it would be sweet to do the deed in a nice tight loop. In C.
So it seemed best to construct an array which provides pointers to each of the structure variables I wish to expose; another that provides the name of the variable; and a third which describes the stored data type and a desired default value.
These look like this:
const char* allowed_tokens[] =
{
"loglevel",
"debugecho",
"errorSqlDisable",
"ClearErrorDbOnExit",
"\0" // terminates list
}
int *varpointers[] =
{
&appinfo.nLogLevel,
&appinfo.debugEcho,
&appinfo.OWFSLogLevel,
&appinfo.OWFSLogEchoToDisplay,
0 // terminates list
};
char *varDatatypes_defaults[] =
{
"I|6", // for LOG_INFO
"B|false",
"I|0",
"B|true",
"\0" // terminates list
};
The loop looks like this (pseudocode):
row=0;
while (read a line of the .conf file into cLine)
{
get the token_name and value from cLine
check if allowed_tokens[row]==0 and if true, exit the loop
// example cLine= "debugecho false"
find match to "debugecho" in allowed_tokens. This provides an offset into varpointers and varDatatypes.
get the default data type and default value tokens from varDattypes_defaults[row]
Do the assignment. For example, if the data type=="I":
*varpointers[row]=atoi(value);
++row;
}
This technique works fine, but there are two problems.
It would be preferable to combine the three arrays into a single array. Is there a best practice here?
The array of pointers (varpointers[]) is defined as *int. I did so as I want it to hold pointers. However if the variable pointed to is not an integer data type, warning: initialization from incompatible pointer type is triggered. Of course, char * and int * cannot be mixed... so how otherwise could this be done such that a single pointer array is used?
I realize I can do all this in c++. This luxury is not an option at this point.

You can combine them into one array by structs, e.g.
typedef struct { char *token; void *var; char *defaults; } the_type;
the_type the_data[] = { { "loglevel", (void*)&appinfo.nLogLevel, "I|6" },
{ "debugecho", (void*)&appinfo.debugEcho, "B|false" },
...
};
The generic pointer type is void *. Your code has to ensure you use the correct type when actually writing to the variable being pointed to, e.g. *(int*)the_data[0] = 42;.

I would use an enumeration to specify the types so you don't have to parse a string. The values could be stored in an union.
typedef enum {
BOOLEAN,
INTEGER,
} type_t;
typedef union value {
bool boolean;
int integer;
} value_t;
typedef struct token {
char *name;
type_t type;
value_t value;
} token_t;
Now you can define your defaults like so:
token_t data[] = {
{ "loglevel", INTEGER, { 6 } },
{ "debugecho", BOOLEAN, { false } },
{ "errorSqlDisable", INTEGER, { 0 } },
{ "ClearErrorDbOnExit", BOOLEAN, { true } },
{ 0 }
};
This will get pretty cumbersome if the number of configuration keys gets large. You might want to think about storing the configuration in a hash table or a tree.
Here is a short example that seems to accomplish what you want.

If we are talking about the same data type, use double pointers (you get an array of arrays)
Declare a struct holding your pointers, then use a pointer to your struct to work on.
For declaring a general pointer, you can use void instead of int. But then every time you have to cast the pointer to use it properly.

Related

What is the purpose of an array with undefined length but only one int element?

I have a headerfile which declares these arrays:
int stVal_On[] = {2};
int stVal_Off[] ={1};
int subVal_On[]={1};
int subMss[]={1};
int subVal_Off[]={0};
The dereferenced arrays are then used in structs that are declared:
Definition of WriteData struct:
/* Write structure used in loop for Read- and Write Tests */
typedef struct WriteData {
char* name; // MMS object name
const VOID* data; // Data to write
const SINT32 localFormat; // SVI type (on server)
const SINT32 dataLength; // length of data to write/read
const SINT32 NbrofElmnts; // Number of elements to write/read
char* description; // SVI type as String (on server)
char* SVI_Name; // SVI address of the SVI mapped on server
UINT32 svi_Length; // length of SVI variable on server (used for readback)
} WriteData;
What is the purpose of this int arr[] = {1}; idiom? Why use arrays at all if only one value is assigned?
Well, one reason I can think of has to do with code organization. If you write your code in a tabular form:
struct {
char const *file_name;
uint16_t flags;
// Other data
} table [] = {
{ .file_name = "/usr/bin/foo", .flags = 0x0 },
};
for (size_t i = 0; i < sizeof(table)/sizeof(table[0]); ++i) {
// do something meaningful with a table row table[i]
}
While it's just an array of 1 now, if you need to add more cases, your code is already written well for it. You'd just need to add another "row' to the table initializer.
All the definitions create arrays with only one element, true. The actual use case may vary.
One commonly used scenario is, this variable can be passed as a function argument and it will be possible to change the content of the array (the only element value) from the called function, which in case of a non-array variable is not possible. This maybe not the very smart way, but still, it's possible and someone chose to use it.
Also, as always, array size determined by the supplied initializer leaves the room for expansion without requiring major code changes.

Comparing Char* to Enum variable in C

So I'm trying to utilize Enumerated types in C for the first time. So I have an Enumerated "variable?" declared and I also have a struct which has a variable of the Enumerated type(among other things). Finally I have a static array for which there is an element containing each of the enum "types?" in the same order they were declared. I am hoping to use the enum type to act as an index for the array.
So my problem is that I need to somehow relate a char* variable to the enumerated type. If I KNOW that the Char* variable is one of the enum types, is there some way to assert that without having to look at each char to determine which specific enum"option" it is?
Example:
enum example = {abc,def}
struct _strExample {
enum example letters;
....
};
typedef struct _strExample strEx;
static strEx Table[2] = {
{abc,...}
{def,...}
};
//Given char* "abc" , want either example.abc or 0 ( correct index of table)
So given the char* "abc"(does not need to be char*), is there a simple way to get either the correct enum "type?"(abc or def)or the correct index of the table? I know that I could check all the individual chars in the char* and manually determine which enumerated "type?" it is, but I am going to be working with a very large set of enumerated variables and this kind of thing is exactly what I was trying to avoid. any help or advice you guys could give on enumerated types and/or my design would be most appreciated.
Use a an array of strings where the index into the array is the enum value. If the strings are all short, or all about the same length, storing the string in the array makes sense. Otherwise, use a char* pointer.
typedef enum enum_t { plugh, plover, xyzzy, y0 } enum_t;
const char *etable = { "plugh", "plover", "xyxxy", "y0", NULL };
With that, you can convert with a simple search like:
enum_t find_enum(char *sval)
{
enum_t result=plugh; /* value corresponding to etable[0] */
int i=0;
for (i=0; etable[i]!=NULL; ++i, ++result)
if (0==strcmp(sval, etable[i])) return result;
return -1;
}
The enum-to-string converstion is simply etable[e-plugh]. Those allow for a different definition of enum_t where the first meaningful value may not be 0, but the values are sequentially assigned thereafter.
No, you can't lookup any scalar value from a character array. You have to iterate over a set of strings to compare and find the relation to the enum member.
You can use an array of structs
typedef struct { int value; const char * name; } lookup_t;
lookup_t lookup[] = {
{ 1, "One"},
{ 0, NULL} // end tag, alternatively use the _countof(lookup) to get the number of elements
};
and compare your char* with the name member. Then you use the value on match.
Use if :
char *ex = "abc";
strEx strex;
if(!(strcmp("abc",ex))) {
strex.letters = abc;
}
else {
strex.letters = def;
}

Quick check to see if structure of function pointers is NULL in C99

In C99 is there an easier way of check if a structure of function pointers is NULL, other than checking each individual pointer?
What I currently have is similar to the following:
typedef struct {
void* (*foo)(int a);
int (*bar)(int a, int b);
} funcs;
void *funcs_dll;
funcs_dll = dlopen("my_funcs_dll.so", RTLD_GLOBAL);
if (funcs_dll == NULL) {
THROW_ERROR;
}
funs.foo = dlsym(funcs_dll, "foo");
funcs.bar = dlsym(funcs_dll, "bar");
if (!funcs.foo || !funcs.bar) {
THROW_ERROR;
}
What I am looking to do is reduce the second if check, so that I do not need to check each individual function. Any suggestions would be helpful.
Not directly, no.
You can't use memcmp() to compare to some constant buffer, since there might be padding inside the structure which will have "random" values. If you can make sure that the size of the structure is exactly the sum of the function pointer fields, you can perhaps go that way.
You can also use a proxy, by i.e. declaring an initial uint32_t member that is a bitset representing which function pointer(s) are valid. Then you can check up to 32 (or 64 with uint64_t) proxy bits in parallel.
If you only want to do this once, my suggestion would be a data-driven approach. Define a table of function names to look for, and process that in a loop, exiting as soon as a dlsym() call fails.
Something like:
const struct {
const char *name;
size_t offset;
} functions[] = {
{ "foo", offsetof(funcs, foo) },
{ "bar", offsetof(funcs, bar) },
};
Data-driven code like this is very powerful, and often very fast.
Make wrapper function for dlsym which will set error flag, if return value is NULL.

Initializing an array of structs in C then dereference later

I'm trying to build a serial command interpreter, so I want to store my commands in an array. I want each command to have a name and a function pointer so that I can compare the command name to what I typed into and then call the function. I'm not that good with C, so please help! Here is what I have so far.
The command array will be an array of structs. Each struct will have a string and a function pointer. There are errors here, but I don't know how to fix them. These are done before main.
typedef struct cmdStruct {
char cmd[16];
void (*cmdFuncPtr)(void);
}CmdStruct;
void (*ledFuncPtr)(void);
void (*cmd2FuncPtr)(void);
// assign pointers to functions
ledFuncPtr = &LedFunction;
cmd2FuncPtr = &Cmd2Function;
//build array of structs
CmdStruct cmdStructArray[] = cmdStructArray = { {"led", ledFuncPtr },
{"cmd2", cmd2FuncPtr }, };
Later on, I will go through the struct array to compare it to the received command.
// go through the struct array to do string comparison on each struct's string member
for (int i = 0; i < sizeof(cmdStructArray); i++) {
// string comparison of received command and string of struct
if(strcmp(cmdStructArray[i].cmd, receivedCmd)==0) {
// dereference function pointer
(*cmdStructArray[i].cmdFuncPtr)(void);
}
}
What parts am I doing wrong, and how do I fix them?
sizeof(cmdStructArray) is not in elements, but rather in bytes.
Use sizeof(cmdStructArray)/sizeof(cmdStructArray[0]).
As it has already been noted, your cycle makes wrong number of iterations. sizeof array does give you the number of elements in the array, but rather the number of bytes in the array. You have to calculate sizeof array / sizeof *array to get the number of elements.
Also, your function call syntax is invalid
(*cmdStructArray[i].cmdFuncPtr)(void);
The above will not compile. You cannot specify void as an argument in function call. (void) syntax can only be used in function declarations. If the function accepts no parameters, the call should look as
(*cmdStructArray[i].cmdFuncPtr)();
Also, this will not compile as well
CmdStruct cmdStructArray[] = cmdStructArray = { {"led", ledFuncPtr },
{"cmd2", cmd2FuncPtr }, };
Why are you mentioning cmdStructArray in this declaration twice?
Some additional, essentially cosmetic remarks:
Firstly, since your commands are probably going to be string literals known at compile time, you can declare the first member of your struct as a const char * pointer instead of char array
typedef struct cmdStruct {
const char *cmd;
void (*cmdFuncPtr)(void);
} CmdStruct;
The initialization syntax does not change. This will relieve you of the need to worry about the size of the array (16 that you currently have there).
Secondly, it is not clear why you had to declare intermediate pointers to functions ledFuncPtr and cmd2FuncPtr instead of initializing your array directly. What was the purpose of this
void (*ledFuncPtr)(void);
void (*cmd2FuncPtr)(void);
// assign pointers to functions
ledFuncPtr = &LedFunction;
cmd2FuncPtr = &Cmd2Function;
CmdStruct cmdStructArray[] = { {"led", ledFuncPtr },
{"cmd2", cmd2FuncPtr }, };
when you could simply do this
CmdStruct cmdStructArray[] = { {"led", &LedFunction },
{"cmd2", &Cmd2Function }, };
(without introducing ledFuncPtr and cmd2FuncPtr at all)?
Thirdly, you don't have to use * and & operators with function pointers. This will work too
CmdStruct cmdStructArray[] = { {"led", LedFunction },
{"cmd2", Cmd2Function }, };
and
cmdStructArray[i].cmdFuncPtr();
Anyway, this is a purely cosmetic issue, a matter of personal preference.

2D array using strings

I'm stuck on some homework which isn't graded (its meant for practice).
I have to create a function called find_name that takes 2 arguments. The first argument is a 2D array of names (strings), and the second is a character string which is used to find the name in the 2D array, the function must return 1 if found else 0.
When i call the function (which is empty right now), I get this warning: passing argument 1 of 'find_name' from incompatible pointer type
Here is the important bits.
In Main
char strNameList[][2] = { { "Luca","Daniel"} ,{"Vivan","Desmond"},{"Abdul","Justin"}, {"Nina","Marlene"},{"Donny","Kathlene"} };
char strFindName[] = "\0";
printf("Please enter a name to look for: ");
gets(strFindName);
nSearch = find_name(strNameList, strFindName);
The Function
int find_name(char strNameList[][2], char strLookUp[])
I'm new to C (I'm a student), and I'm completely confused about strings (string arrays etc).
I'm assuming you want a 2D array of char pointers. Your declaration of strNameList is incorrect in both locations in your program. You have:
char strNameList[][2] = { { "Luca","Daniel"} ,{"Vivan","Desmond"},{"Abdul","Justin"}, {"Nina","Marlene"},{"Donny","Kathlene"} };
But char[][N] is declaring a 2D array of chars, not char* Therefore you're being warned by the compiler you're assigning a raft of pointer values to items of type char
Change both your declarations (your variable and your function parameter) to:
const char *strNameList[][2]
which declares an array of unknown length of arrays of two char*, which now matches your initialization lists. Also, the const is added because (a) I'm assuming you are not planning on modify that name list in your function, and (b) writable string literal declarations assigned to char* via initializer is undefined behavior in C, and officially deprecated in C++, so you should not be using it regardless. Likewise, your lookup-name is probably not being modified either, so also declare it const.
Result:
const char * strNameList[][2] = {
{"Luca","Daniel"} ,
{"Vivan","Desmond"},
{"Abdul","Justin"},
{"Nina","Marlene"},
{"Donny","Kathlene"}
};
and in your function:
int find_name(const char * strNameList[][2], const char strLookUp[])
Last but certainly not least, unless you have a crystal ball your find_name() function has no way of knowing with the given information how many names are in the name list being passed. I'd rather you see this now rather than wonder what happened later. you need to either (a) terminate the list with a token-value that find_name() knows about, or (b) pass the number of names in the list to find_name(). To each their own, but I prefer the latter of these:
int find_name(const char * strNameList[][2], size_t nNameListSize, const char strLookUp[])
and invoke it on your caller side by:
find_name(strNameList, sizeof(strNameList)/sizeof(strNameList[0]), strFindName)
Do it this way:
#define STOPPER_NAMELIST NULL
char * strNameList[][2] = {
{ "Luca","Daniel"},
{"Vivan","Desmond"},
{"Abdul","Justin"},
{"Nina","Marlene"},
{"Donny","Kathlene"}
{STOPPER_NAMELIST, STOPPER_NAMELIST}
};
size_t sizeNameList(const char * strNameList[][2])
{
size_t size = 0;
while ((strNameList[size][0] != STOPPER_NAMELIST) &&
(strNameList[size][0] != STOPPER_NAMELIST))
++ size;
return size;
}
int find_name(char * strNameList[][2], char strLookUp[])
{
size_t size = sizeNameList(strNameList);
...
}
...
nSearch = find_name(strNameList, strFindName);
This approach uses an open array ([]) of char * arrays with 2 entries.
Update:
You could add a stopper element to the array carring the names, then there is no need to pass around the array's size along with array itself, as the size could alway be determined by scanning the array members until the stopper is found.
Your function find_name() is looking for a 2-D array of characters ie:
char arr[][2] = { { 'a', 'b'}, ...
if you want to make them strings you need:
char *arr[][2] = { {"John", "Smith"}, ...
Then in the function parameter list you need:
void find_name(char *something[][2])
{
printf("first name: %s, second name: %s\n", something[0][0], something[0][1]);
And in your main() function call it just by:
find_name(arr);

Resources