what are approaches to work with settings - c

What are some approaches to work with custom setting files in C.
For example, I plan to do it like this.
Say I have file settings.ext and I want to store 3 string parameters
inside. What I will do is: assuming my string parameters are at most
32 bytes length, I will assume that my parameters inside file are stored
like this (in binary mode):
32 byte 32 byte 32 byte
---------------------------------------------
| 1 param || 2 param || 3 param |
Then if I want second string parameter, I will read 32 bytes starting from index: 32,
again in binary mode.
I think I will have separate file for string parameters and separate
file for int parameters (I will work with int parameters in similar manner).
Does this sound reasonable?
ps. I am programming on some embedded device

I wouldn't use a binary file for saving settings, of the top of my head there are the following reasons not to:
It's not very portable because of endianness etc.
It's not not very easy to extend, you might not need any extra config parameters right now, but you might do later.
It's hard to edit and read from other programs, it's nice to be able to install and configure your software with scripts.
Instead I'd use a plain text config file, and something like libconfig, there is no reason to reinvent the wheel, especially if make it worse ;-)

There are a couple of standard library functions which make parsing simple tag/value configuration files easy. Read about strtok and atoi/atof, and you might find that a simple configuration file like this easy to parse. You can comingle string and numeric values in your configuration, and support longer strings.
name1=value1
name2=value2
name3=value3
...
This offers the benefits that it is both easily read/edited by humans, and parsed by a fairly simple configuration parser. And passing a filename to read makes this fairly self-contained.
int
cfgparse(char *cfgname)
{
FILE* cfgfh;
if(!cfgname) return -1;
if( !(cfgfh=fopen(cfgname,"r")) ) {
printf("error: cannot open %s\n",cfgname);
return -2;
}
char buffer[256]; //pick an acceptable max size
while( fgets(buffer,sizeof(buffer),cfgfh) )
{
//check for comments, empty lines
char* tag = strtok(buffer,"=");
char* val = strtok(NULL,";\n");
//strip leading/trailing whitespace, handle empty lines,
//do something with tag, value here
Cfgadd(tag,value);
}
}
You can implement a simple configuration store in an array. A list would be dynamic, and a tree or hash would improve performance.
#define MaxKeyLen (200)
#define MaxValLen (200)
typedef struct
{
char* key; //a array would work here
char* value; //a union would allow string, int, and float
} ConfigObj;
#define CONFIGMAX (200)
const int ConfigMax=CONFIGMAX;
typedef struct
{
ConfigObj tab[CONFIGMAX]; //or make this a pointer or a list
int NextAvail;
} ConfigStoreObj;
ConfigStoreObj cfg; //or make this a pointer or a list
static int ConfigFind(ConfigStoreObj* cfg, char* key)
{
int n;
for( n=0; (n<cfg->NextAvail) && (cfg->tab[n].key); n++ )
{
if( strcmp(cfg->tab[n].key,key)==0 ) //found it
{
return n;
}
}
return -1;
}
const char* ConfigGet(ConfigStoreObj* cfg, char* key)
{
int n = ConfigFind(cfg,key);
if( n<0 ) return NULL; //or ""?
return cfg->tab[n].value;
}
int ConfigSet(ConfigStoreObj* cfg, char* key, char* value)
{
char* newvalue;
int n=ConfigFind(cfg,key);
if( n<0 ) return -1; //error
printf("dup(%s)\n",value); fflush(stdout);
if( !(newvalue = strndup(value,MaxValLen)) ) {
printf("error, cannot store %s:%s\n",key,value);
return -3;
}
{
if(cfg->tab[n].value) free(cfg->tab[n].value);
cfg->tab[n].value = newvalue;
}
//return cfg->tab[n].value;
return n;
}
int ConfigAdd(ConfigStoreObj* cfg, char*key, char*value)
{
char *newkey=NULL, *newvalue=NULL;
int n = ConfigFind(cfg,key);
if( n<0 )
{
if( n<ConfigMax )
{
n = cfg->NextAvail++;
printf("dup(%s)\n",key); fflush(stdout);
if( !(newkey = strndup(key,MaxKeyLen)) ) {
printf("error, cannot store %s:%s\n",key,value);
return -3;
}
}
else return -1;
}
printf("dup(%s)\n",value); fflush(stdout);
if( !(newvalue = strndup(value,MaxValLen)) ) {
printf("error, cannot store %s:%s\n",key,value);
if(newkey) free(newkey);
return -3;
}
{
if(cfg->tab[n].value) free(cfg->tab[n].value);
cfg->tab[n].value = newvalue;
}
//return cfg->tab[n].value;
return n;
}
You may also want,
ConfigStoreObj* ConfigStoreNew(int size);
char* ConfigDel(ConfigStoreObj* cfg, char*key);
int ConfigPrint(ConfigStoreObj* cfg);
Opening a config file for reading is fairly easy, as shown above. And here is a
main(int argc, char* argv[])
{
//...
char configname[200];
strcpy(configname,"yourconfigfilename.cfg");
cfgparse(configname); //of course, you need a ConfigStoreObj ...
//...
}
And there are libraries that make even complex configuration easy.

Related

Identify User Defined Function and Library Defined Function

I'm given a task to write a program that checks a piece of code, maximum of 20 lines of code, when the program runs you type in a function name, number of lines of code and type in the codes.
It's meant to search in the code and return if the function name you entered is a Library Function or User Defined Function or No Function if it doesn't find it, the code I've written is below, it doesn't work because I made mistakes and I've been trying to fix it but can't seem to figure it out, and I tried debugging to see where I made mistake, and I figured that in the function SearchRealisation it returns an error that
Run-Time Check Failure #2 - Stack around the variable 'buff' was
corrupted.
This program sample returns Library function instead of user defined function
type the function name: addition
Get count string in code: 9
int addition(int num1, int num2)
{
int result = num1 + num2; //trial
return result;
}
int main()
{
addition(8, 9);
}
Output is Library Function but correct output should be User Defined Function since it was defined in the code
void InputText(int length, char Text[MAX_STRINGS][MAX_COLUMNS])
{
//Repeat by Count String
gets_s(Text[0]);
for (int i = 0; i < length; i++)
gets_s(Text[i]);
//Output a string (starting with � zero and ending with Count String-1)
}
void OutMesseg(int param)
{
//Display one of three messages according to the parameter
if (param == -2)
printf("%s", "user defined function");
else if (param == -1)
printf("%s", "no function");
else
printf("%s", "library function");
}
char* DeleteComentsInString(char Text[MAX_STRINGS], char New[MAX_STRINGS])
{
char* a = strstr(Text, "//");
int len = strlen(Text);
if (a != NULL) len -= strlen(a);
strncpy(New, Text, len);
New[len] = '\0';
return New;
}
bool IsTypeC(char Word[MAX_STRINGS])
{
char ctype[6][MAX_STRINGS] =
{
"int",
"bool",
"char",
"float",
"double",
"void"
};
for (int i = 0; i < 6; i++)
{
if (strstr(Word, ctype[i]) != 0)
return true;
}
return false;
}
int SearchRealisation(int length, char Text[MAX_STRINGS][MAX_COLUMNS], int index_fanc, int& end)
{
int count = 0;
int start = -1;
end = -1;
char buff[MAX_STRINGS];
//Find first {
for (int i = index_fanc + 1; i < length && !count; i++)
{
if (strstr(DeleteComentsInString(Text[i], buff), "{") != NULL)
{
count++;
start = i;
}
}
//find last }
for (int i = start + 1; i < length && count; i++)
{
if (strstr(DeleteComentsInString(Text[i], buff), "{") != NULL)
count++;
else if (strstr(DeleteComentsInString(Text[i], buff), "}") != NULL)
count--;
if (!count)
end = i;
}
if (end == -1)
start = -1;
else
return start;
}
int SearchFunction(int length, char Text[MAX_STRINGS][MAX_COLUMNS], char FunctionName[MAX_COLUMNS], int& end)
{
//bool flag = false;
char commentDel[120];
int in;
for (int i = 0; i < length; ++i)
{
DeleteComentsInString(Text[i], commentDel);
if (strstr(commentDel, FunctionName) != NULL)
{
in = strlen(commentDel) - strlen(strstr(commentDel, FunctionName));
if ((in == 0 || (in != 0 && commentDel[in - 1] == ' ')) && (commentDel[in + strlen(FunctionName)] == ' ' || commentDel[in + strlen(FunctionName)] == '(') && strstr(commentDel, ";") == NULL)
{
return SearchRealisation(length, Text, i, end);
}
}
}
end = -1;
return -1;
}
int SearchResult(int length, char Text[MAX_STRINGS][MAX_COLUMNS], char FunctionName[MAX_COLUMNS])
{
int index;
int end;
int start = SearchFunction(length, Text, FunctionName, end);
if (start == -1)
return -1;
index = SearchFunction(length, Text, FunctionName, end);
if (index < 0)
return -2;
return index;
}
int findFunction(char string[MAX_STRINGS][MAX_COLUMNS], char* functName, int M)
{
return 0;
}
int main()
{
int length = 0;
char Code[MAX_STRINGS][MAX_COLUMNS] = { 0 };
char FunctionName[MAX_COLUMNS];
//char ConstantName[MAX_STRINGS];
printf("type the function name: ");
scanf("%s", &FunctionName);
printf("Get count string in code: ");
scanf("%d", &length);
InputText(length, Code);
printf("\n");
OutMesseg(SearchResult(length, Code, FunctionName));
return 0;
}
Well, you have been given a very difficult task:
There's no way to check this, as functions are resolved by a dynamic process that depends on your filesystem state, which is not available at runtime, after you have already compiled your program.
How do you distinguish a function that is compiled in a separate (but user defined) compilation unit from a system defined function? (e.g. double log(double);) that is defined in a math library? There is no way: the linker gets both from a different place (in the first case it gets it from the place you compiled the separate module, in the system case it gets it from a common library directory that has all the system related functions), but you don't have that information available at runtime).
In order to do this task feasible, you'd at least have the full set of source code files of your program. Preprocess them with the cpp(1) preprocessor (so you bypass all the macro expansion invocations) and then check for all function calls in the source code that are not provided in the full set of sources you have. This is quite similar to what the linker does. After compilation, the compiler leaves an object file with the compiled code, and a symbol table that identifies all the unresolved identifiers, and more important all the provided identifiers from this module. The linker then goes on all your modules trying to solve the unknowns, and for each that it doesn't have a solution in your code, it goes to the library directory to search for it. If it doesn't find it in either one, it fails telling you something is wrong.
In my opinion, you have been given a trap task, as the C language preprocess its input (this is something you should do, as many functions are hidden in the internals of macro bodies), then parse the code (for this, you need to write a C parser, which is no trivial task) to select which identifiers are defined in your code and which aren't. Finally you need to check all the calls you do in the code to divide the set in two groups, calls that are defined (and implemented) in your code, and calls that aren't (implemented, all the calls the compiler needs must be defined with some kind of prototype).
It's my opinion, but you have not a simple task, solvable in a short program (of perhaps one hundred lines) but a huge one.
Thanks a lot to everyone that answered I came up with a way to search the code for function definition and thereby return a value if its defined or not, or not even found, might not be the best solution to the task but works so far

How to check if a file exists in a given path in C?

I am trying to find the file(say marks.txt) in the particular path passed as argument to a function. Is it possible to give the filename and path as arguments to a function which checks if the file exists and prints out the path?
The below function only takes path as argument.
int fileexists(const char *path){
File *ptr = fopen(path, "r");
if (fptr == NULL)
return 0;
fclose(fptr);
return 1;
}
The required function prototype :
int fileexists(const char *path, const char *filename)
There are two parts to this question, and the right answers to them depend on what you're trying to do.
Concatenate a directory name and a file name to form a full path name.
Determine whether a file (referred to by a full path name) exists or not.
Concatenating a directory name and a file name is straightforward. Your friendsstrcpy and strcat will do most of the work. There are a few minor details to be careful of: (a) You'll need a big enough buffer for the full pathname, and you'll need to decide whether to use a fixed-size array (perhaps of size MAX_PATH), or a malloc'ed buffer; (b) you might need to insert an explicit '/' character (and it usually doesn't hurt to stick one in even if the directory string already ends in one); (c) under Windows you might want to use '\\' instead of '/'.
And then determining whether a file named by a full pathname exists is already well answered over at What's the best way to check if a file exists in C?. The big question to ask here is, are you asking whether the file exists in preparation to doing something with the file? If so, you have a serious vulnerability if you check for the file's existence, but then before you do the other thing, something else happens to cause the file to appear or disappear. So rather than checking-and-then-doing, it's usually better to just try doing the other thing, and deal gracefully with any errors.
The function you have checks if the file can be opened, but it will fail for some files that exist but you have no rights to open. I'd use stat instead. To concatenate the path and filename you can use string functions.
The usual Unix C APIs are dismal. It takes lots of effort to do the simplest of things correctly - and even then I'm not sure that I didn't forget some Unix-ism like signal handling or some obscure error cases. I.e. stuff that's rather trivial to get right in modern C++.
I wish someone designed a modern C system API and implemented it for at least Linux, so that our suffering would end...
Usually, string concatenation requires some higher level API to be done while maintaining a modicum of sanity. Thus, the example below uses a strbuilder class to build the string. This makes things vaguely readable and avoids most common mistakes.
#include <assert.h>
#include <errno.h>
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
struct strbuilder {
unsigned items, item;
size_t length, *lengths;
char *str, *dst;
};
bool strbuilder_pass(struct strbuilder *builder, int *rc);
void strcat_str(struct strbuilder *builder, const char *src);
void strcat_c_ifnone(struct strbuilder *builder, char c);
bool strbuilder_is_freed(const struct strbuilder *builder);
int fileExists(const char *path, const char *filename)
{
const char pathSep = '/';
int rc;
struct strbuilder bld = {0};
while (strbuilder_pass(&bld, &rc))
{
strcat_str(&bld, path);
strcat_c_ifnone(&bld, pathSep);
strcat_str(&bld, filename);
if (!rc)
{
struct stat statbuf;
printf("path = %s\n", bld.str);
rc = stat(bld.str, &statbuf);
}
}
assert(strbuilder_is_freed(&bld));
return rc;
}
int main()
{
int rc = fileExists("/", "dev");
assert(rc == 0);
return 0;
}
The string building is controlled by a strbuilder_pass function, which advances the string builder's state through five passes of operation:
Determine the number of items whose width has to be stored (avoids the need to call strlen twice).
Prepare the length storage vector. Determine the length of the buffer needed.
Prepare the output string buffer. Concatenate the elements into the buffer.
Use the output string buffer.
Free the output string buffer.
This API is not particularly special, but fits this use case. Some other ad-hoc approach would work too, but this is IMHO a bit more elegant.
void strbuilder_free(struct strbuilder *builder)
{
free(builder->lengths);
free(builder->str);
memset(builder, 0, sizeof(*builder));
}
bool strbuilder_pass(struct strbuilder *builder, int *rc)
{
if (!builder->length) {// start of pass 1
builder->length = 1; /*term*/
*rc = EAGAIN;
return true;
}
else if (!builder->lengths) // end of pass 1
{
builder->lengths = malloc(sizeof(*builder->lengths) * builder->items);
if (builder->lengths)
return true;
*rc = ENOMEM;
}
else if (!builder->str) // end of pass 2
{
builder->dst = (builder->str = malloc(builder->length));
builder->item = 0;
builder->length = 0;
if (builder->dst) {
*builder->dst = '\0';
return true;
}
*rc = ENOMEM;
}
else if (builder->dst) // end of pass 3
{
while (*builder->dst) { // include optional content
builder->dst++; // skip
builder->length++;
}
builder->dst = NULL;
*rc = 0;
return true;
}
else if (!builder->dst) // end of pass 4 (if any)
{}
else {
*rc = EINVAL;
}
strbuilder_free(builder);
return false;
}
void strcat_str(struct strbuilder *builder, const char *src)
{
if (!src)
return;
if (!builder->lengths) // pass 1
builder->items ++;
else if (!builder->str) // pass 2
{
size_t len = strlen(src);
builder->lengths[builder->item++] = len;
builder->length += len;
}
else if (builder->dst) // pass 3
{
size_t len = builder->lengths[builder->item++];
if (*builder->dst && (!len || *builder->dst != *src))
{
builder->dst++;
builder->length++;
}
memcpy(builder->dst, src, len);
builder->dst += len;
builder->length += len;
*builder->dst = '\0';
}
}
void strcat_c_ifnone(struct strbuilder *builder, char c)
{
if (!builder->lengths) {} // pass 1
else if (!builder->str) // pass 2
{
if (c) builder->length ++;
}
else if (builder->dst) // pass 3
{
if (!builder->length || builder->dst[-1] != c)
*(builder->dst) = c;
}
}
bool strbuilder_is_freed(const struct strbuilder *builder)
{
return !builder || (!builder->lengths && !builder->str);
}
You probably want something like this (no error checking for brevity):
...
#include <string.h> // for str* functions
#include <unistd.h> // for access
#include <stdlib.h> // for malloc
...
int fileexists(const char *path, const char *filename)
{
char *name= malloc(strlen(path) + strlen(filename) + 1);
strcpy(name, path);
strcat(name, filename);
int retval = access(name, F_OK) == 0;
free(name);
return retval;
}
Call like this:
if (fileexists("/some/path/", "somefilename.txt")) ...

C - should I use a variable array of function pointers

This question is about how to solve my problem on the level of how I design my program. For a school project, I'm building a shell, which has several built-in functions. One of these function's purpose (cmd_type) is to check to see if the argument provided is in that list of functions. Here is a partial implementation of it:
int cmd_type(int argc, char *argv[]) {
if (argc == 2) {
for (int i = 0; i < BUILTIN_FUNC_COUNT; i++) {
if (strcmp(cmds_name[i], argv[1]) == 0) {
printf("%s is a shell builtin\n", argv[1]);
return 0; // found it
}
}
// still need to search path, call stat(path/cmd)
errmsg("not implemented! type", 1);
} else {
err_msg("type", 1);
}
}
Defining manual if statements for every function my shell supports sounds like a bad choice because the list might expand over time, and I need to store the list of function names anyway. So originally, I planned to define an array of function names and an array of their pointers, like so:
char cmds_name[BUILTIN_FUNC_COUNT-1][16];
char (*cmds_ptr)(int,*char[])[BUILTIN_FUNC_COUNT-1];
// make list of built-in funcs
strcpy(cmds_name[0], "exit");
strcpy(cmds_name[1], "cd");
// make list of func pointers
cmds_ptr[0] = &cmd_exit;
cmds_ptr[1] = &cmd_cd;
They're accessed like so:
// try builtin cmds
for (int i = 0; i < BUILTIN_FUNC_COUNT; i++) {
if (strcmp(cmds_name[i], argv[0]) == 0) {
last_cmd_err = (*cmds_ptr[i])(argc, argv);
continue; // we found it, so next loop
}
}
Then they'd each happily take (int argc, char *argv[]) as arguments. But the cmd_path() needs access to the list in addition to those arguments, so I'd have to define it as a global, or define a global pointer to it... In the process of researching this, I found this answer, saying a similar approach was really bad style: https://stackoverflow.com/a/41425477/5537652
So my questions are: Is this a good way to solve this problem, or should I just do if/else statements/is there a better way? Would you recommend a global pointer to the array of function names?
I am going to propose a structure of cmd_name and function pointer like this:
typedef struct{
char cmds_name[16];
char (*cmds_ptr)(int,*char[]);
} cmd_type;
Now define a static table of this type for all your cmds:
static const cmd_type cmd_table[] = {
{"exit", &cmd_exit},
{"cd", &cmd_cd},
.......
.......
};
Finally access it like this:
for (int i = 0; i < BUILTIN_FUNC_COUNT; i++) {
if (strcmp(cmd_table[i].cmds_name, argv[0]) == 0) {
last_cmd_err = (*cmd_table[i].cmds_ptr)(argc, argv);
continue; // we found it, so next loop
}
}
The decision to choose between if-else vs a global table is a matter of personal taste and coding style. I would prefer the above solution simply because it improves ** code readability** and reduces clutter. There may be other constraints in your environment that can influence your decision - like if the no of table entries is huge and there is a limitation on global memory space - the if-else route would be a better choice..
HTH!
I would not go with if-else statements. There is nothing wrong with solution (2) proposed in https://stackoverflow.com/a/41425477/5537652.
You could have a table with a string and a function to service an entry:
typedef struct cmd_desc
{
char cmd[80];
int builtin_cmd(int argc, char **argv, void *extra);
} CMD_DESC;
static CMD_DESC descTable[] =
{
{ "exit", cmd_exit },
{ "cd", cmd_cd },
{ "$ON_OPEN_CMD", OnOpenCmd },
{ "$OPEN_EXTRA_CMD", OpenExtraCmd },
{ "$AC", ActionCmd },
{ "$AD", ActionDataCmd },
{ "$EC", ExtraCmd },
{ "$TC", TextCmd },
{ "", NULL }
};
int cmd_exit (int argc, char **argv, void *extra)
{
//...
}
Access/execution:
for (int tokenIndex=0; strcmp(descTable[tokenIndex].cmd,""); tokenIndex++) //search table
{
if ( strcmp( (descTable[tokenIndex]).cmd, argv[0] ) == 0 )
{
int ret = (*(descTable[tokenIndex]).builtin_cmd( argc, argv, extra);
}
}
I used the above approach in a my applications and it worked well for me.
The table can be easily expanded and the readability of the table is better than if/else chain.

Array of function pointer

Is it possible to replace all of these "if, else if ..." with an array of function pointers in this example of code ?
if (strncmp(buff, "ls\n", 3) == 0)
my_ls();
else if (strncmp(buff, "cd\n", 3) == 0)
my_cd();
else if (strncmp(buff, "user\n", 5) == 0)
my_user();
else if (strncmp(buff, "pwd\n", 4) == 0)
my_pwd();
else if (strncmp(buff, "quit\n", 5) == 0)
my_quit();
I'm trying to get something like this :
void (*tab[5]) (void);
tab[0] = &my_ls;
tab[1] = &my_cd;
tab[2] = &my_user;
tab[3] = &my_pwd;
tab[4] = &my_quit;
I created a code to illustrate what you wanted to do, because I it's pretty entertaining.
#include <stdio.h>
#include <string.h>
// your functions
void my_ls() { puts("fun:my_ls") ;}
void my_cd() { puts("fun:my_cd") ;}
void my_user(){ puts("fun:my_user");}
void my_pwd() { puts("fun:my_pwd") ;}
void my_quit(){ puts("fun:my_quit");}
int main(int argc, char const *argv[])
{
char* buff="ls\n"; // the string you have to compare
void (*tab[5]) (void)={my_ls,my_cd,my_user,my_pwd,my_quit};
char *names[5]={"ls\n","cd\n","user\n","pwd\n","quit\n"};
int i;
for (i=0; i<5; i++)
{
if(strncmp(buff,names[i],strlen(names[i]) )==0){
tab[i]();
return 0;
}
}
return 0;
}
There are other ways to write it. Actually my_function is the same as &my_function since a function name alone is converted to the adress of the function.
Also tab[i]() is equivalent to (*tab[i])()... Those are weird behaviours but I think it's specified by C standard
There's no problem with an array of function pointers, but you'd need to convert the sequence of boolean strncmp() results to a single index.
If the list is long, the hash table idea might be a winner. For compact, simple code and easy maintenance, I've used an array of structs:
typedef struct cmdtable_t
{
void (*fptr)();
unsigned char length
char name[11];
} cmdtable_t, *pcmdtable_t;
cmd_table_t commands = {
{ my_ls, 2, "ls"},
{ my_cd, 2, "cd" },
{ my_user, 4, "user" },
...etc.
};
That could also be what a hash table entry looks like, could be sorted in advance to allow a binary search, or simply sequentially searched for a KISS version until you find out whether this needs optimizing at all.
I think you want a dictionary or hashtable:
Use buff as string key
Use function pointer as values

User entered string run a particular function in c

Guys so I'm working on the web service assignment and I have the server dishing out random stuff and reading the uri but now i want to have the server run a different function depending on what it reads in the uri. I understand that we can do this with function pointers but i'm not exactly sure how to read char* and assign it to a function pointer and have it invoke that function.
Example of what I'm trying to do: http://pastebin.com/FadCVH0h
I could use a switch statement i believe but wondering if there's a better way.
For such a thing, you will need a table that maps char * strings to function pointers. The program segfaults when you assign a function pointer to string because technically, a function pointer is not a string.
Note: the following program is for demonstration purpose only. No bounds checking is involved, and it contains hard-coded values and magic numbers
Now:
void print1()
{
printf("here");
}
void print2()
{
printf("Hello world");
}
struct Table {
char ptr[100];
void (*funcptr)(void)
}table[100] = {
{"here", print1},
{"hw", helloWorld}
};
int main(int argc, char *argv[])
{
int i = 0;
for(i = 0; i < 2; i++){
if(!strcmp(argv[1],table[i].ptr) { table[i].funcptr(); return 0;}
}
return 0;
}
I'm gonna give you a quite simple example, that I think, is useful to understand how good can be functions pointers in C. (If for example you would like to make a shell)
For example if you had a struct like this:
typedef struct s_function_pointer
{
char* cmp_string;
int (*function)(char* line);
} t_function_pointer;
Then, you could set up a t_function_pointer array which you'll browse:
int ls_function(char* line)
{
// do whatever you want with your ls function to parse line
return 0;
}
int echo_function(char* line)
{
// do whatever you want with your echo function to parse line
return 0;
}
void treat_input(t_function_pointer* functions, char* line)
{
int counter;
int builtin_size;
builtin_size = 0;
counter = 0;
while (functions[counter].cmp_string != NULL)
{
builtin_size = strlen(functions[counter].cmp_string);
if (strncmp(functions[counter].cmp_string, line, builtin_size) == 0)
{
if (functions[counter].function(line + builtin_size) < 0)
printf("An error has occured\n");
}
counter = counter + 1;
}
}
int main(void)
{
t_function_pointer functions[] = {{"ls", &ls_function},
{"echo", &echo_function},
{NULL, NULL}};
// Of course i'm not gonna do the input treatment part, but just guess it was here, and you'd call treat_input with each line you receive.
treat_input(functions, "ls -laR");
treat_input(functions, "echo helloworld");
return 0;
}
Hope this helps !

Resources