I'm trying to implement the ls command in C with a few parameters like -a, -l... or -la, but I'm having issues with the parsing, when I use the input I get Segmentation Fault, this is an example of the -a parameter:
int comparator(char *av) {
int i = 0;
if (my_strcmp((av[i]), "-a") == 0)
return 0;
else
return 1;
}
int my_ls_a(char *path) {
int comp = comparator(path);
DIR *pdirec = opendir(".");
struct dirent *direc;
direc = readdir(pdirec);
while (direc != NULL || comp == 0) {
my_printf("%s ", direc->d_name);
direc = readdir(pdirec);
}
if ((path = readdir(pdirec)) == NULL)
my_printf("\n");
if (pdirec == NULL)
return (84);
closedir(pdirec);
return (0);
}
And this is my main:
int main(int ac, char *av[]) {
if (ac == 1)
my_ls_a(av[0]);
return 0;
}
I already have all the #include in a .h by the way.
When I only use the main function it works but not when I add the parameter -a.
It's probably better to use getopt() for parameter parsing instead of writing your own parser.
You have undefined behavior in the function comparator in my_strcmp((av[i]), "-a") because av is defined as a char * so you are passing a character where my_strcmp probably expects a pointer.
You should compile with -Wall -Werror to avoid such silly mistakes.
It is unclear why you pass only a single argument to my_ls_a. You should pass both ac and the argument array av and iterate on the arguments to parse the options.
Related
I wish to use a c program repeatedly run the TCL interpreter many times. For reasons that are complicated, I need this to be a pure C program and not something that is embedded as a shared object. As an example, I wish to run this simple tcl program, tryMe.tcl, twice:
prtstr "Test from tryMe.tcl"
The prtstr is a TCL function that I have written that for right now just writes to stdout. Below is the c code that is attempting to interpret the tryMe.tcl program twice.
I compile the program below like this under linux:
$ gcc -c try.c; gcc -o try try.o -ltcl;
and run it like this:
$ ./try tryMe.tcl
And I get zero output. What am I doing wrong? Also are there steps required to reset the tcl interpreter so that it will be fresh each time.
#define _GNU_SOURCE
#include <tcl/tcl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int PrintStrObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
{
char *str;
int len;
Tcl_Obj *objPtr;
int i;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "value");
return TCL_ERROR;
}
objPtr = objv[1];
str = Tcl_GetStringFromObj(objPtr, &len);
if (str[0] == '\0')
return TCL_ERROR;
printf("len: %d, str: %s\n", len, str);
return TCL_OK;
}
int Tcl_AppInit(Tcl_Interp* interp)
{
if (Tcl_Init(interp) == TCL_ERROR)
return TCL_ERROR;
Tcl_CreateObjCommand(interp,"prtstr", PrintStrObjCmd, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
return TCL_OK;
}
int main(int argc, char *argv[])
{
char *cmd = NULL;
Tcl_Interp * interp = Tcl_CreateInterp();
Tcl_AppInit(interp);
asprintf(&cmd, "%s -x -y -z", argv[1]);
Tcl_Eval(interp, cmd);
free(cmd);
asprintf(&cmd, "%s -q -r -s 2", argv[1]);
Tcl_Eval(interp, cmd);
exit(0);
}
Thanks very much!
You should check out the Tcler's Wiki on this, as the pattern of embedding a Tcl interpreter in your application is a known and supported one. It includes a worked example that you can adapt (and no, I didn't write it; I prefer to extend standard Tcl interpreters).
The main problem you've got is that you're not calling Tcl_FindExecutable(). In modern Tcl, that initialises a number of key subsystems in the library (including its high-performance memory allocator!) so it's slightly vital. In your case, you've got a real argv available so you can use argv[0] with it:
Tcl_FindExecutable(argv[0]);
// NULL would also work as an argument, in a pinch at least
Once you've done that, you can call other Tcl API functions, specifically Tcl_CreateInterp().
You have a minor problem in that you are not testing the results of calls for failure. In C, this is essential as you don't have exceptions to do the heavy lifting of error handling for you.
Thanks for the pointer to TCLer's Wiki. That helped. I didn't understand that the script in Tcl_Eval(interp,script) was not a file name but a character string containing a tcl program. So this program uses TCL_Evalfile() I also wanted to be able to pass command line arguments to the tcl program. I found out how but diving into the TCL source for Tcl_MainEx(). Below is a program that does what I want. Also I discovered that calling Tcl_EvalFile more than one does retains the state so if I want a fresh value of the interpreter, I'll have to delete the old one and create a new one everytime.
#include <tcl/tcl.h>
#include <stdio.h>
#include <stdlib.h>
int PrintStrObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
{
char *str;
int len;
Tcl_Obj *objPtr;
int i;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "value");
return TCL_ERROR;
}
objPtr = objv[1];
str = Tcl_GetStringFromObj(objPtr, &len);
if (str[0] == '\0')
return TCL_ERROR;
printf("len: %d, str: %s\n", len, str);
return TCL_OK;
}
int Tcl_AppInit(Tcl_Interp* interp)
{
if (Tcl_Init(interp) == TCL_ERROR)
return TCL_ERROR;
Tcl_CreateObjCommand(interp,"prtstr", PrintStrObjCmd, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
return TCL_OK;
}
int main(int argc, char **argv)
{
char *script = argv[1];
Tcl_Obj *argvPtr;
Tcl_FindExecutable(script);
Tcl_Interp *interp = Tcl_CreateInterp();
if (interp == NULL) {
fprintf(stderr,"Cannot create TCL interpreter\n");
exit(-1);
}
if (Tcl_AppInit(interp) != TCL_OK)
return TCL_ERROR;
Tcl_SetVar2Ex(interp, "argv0", NULL, Tcl_NewStringObj(script,-1), TCL_GLOBAL_ONLY);
argc -= 2;
argv += 2;
Tcl_SetVar2Ex(interp, "argc", NULL, Tcl_NewIntObj(argc), TCL_GLOBAL_ONLY);
argvPtr = Tcl_NewListObj(0, NULL);
while (argc--)
Tcl_ListObjAppendElement(NULL, argvPtr, Tcl_NewStringObj(*argv++, -1));
Tcl_SetVar2Ex(interp, "argv", NULL, argvPtr, TCL_GLOBAL_ONLY);
if (Tcl_EvalFile(interp, script) != TCL_OK)
return TCL_ERROR;
exit(0);
}
I need to pass a 'key' as a parameter from terminal. It should run as ./a.out -k100101001
where 10011001 is the key and -k is the flag to specify it.
If I need to pass a filename along with the key it should run as ./a.out -k10011001 -iparameter.txt where parameter.txt is the filename and -i is the flag to specify that.
NOTE: I have several parameters to pass and parameter values are followed after the flag without space(-iparameter.txt), plus I don't know the order of the flags so doing something like this won't help.
int main(int argc, char **argv) {
if (argc == 2) {
if (!strcmp(argv[1], "-k")) something();
if (!strcmp(argv[1], "-i")) something();
}
Any suggestion for C? I'm using Ubuntu to run my program.
Thanks.
Using a loop through argv should do it.
int main(int argc, char *argv[])
{
int numArg;
for (numArg = 1; numArg < argc; numArg++)
{
if (argv[numArg][0] == '-')
{
switch (argv[numArg][1])
{
case 'k' : somethingAboutKey(argv[numArg] + 2); // The parameter's value is passed directly to the function
break;
case 'i' : somethingAboutFile(argv[numArg] + 2);
break;
}
}
}
}
I'm trying to call execv after manually saerching for the program to execute.
In my case,
c is a struct which has args as an array of strings having the arguments passed while receiving input. nargs is the number of arguments.
c->args[0] would contain "ls","cat" etc.
I tried printing the value of the args[0], fullPath etc. in my child process. They all show values like "/bin/ls","/bin/cat" etc. But when I call execv, it returns -1 with an errno of 2, which I understand is the error for "No such file or directory". But I'm sure the file is there because thats what my PathResolver is returning after checking all permissions.
Can anyone point where I might have made a mistake.
//The part happening inside child
char *fullPath = PathResolver(c->args[0],1,&permission);
printf("FullPath: %s -- Permission: %d\n",fullPath,permission);
if(permission==0)
{
fprintf(stderr, "%s: Command not found\n",c->args[0]);
}
else if(permission==-1)
{
fprintf(stderr, "%s: Permission denied\n",c->args[0]);
}
else
{
char* args[c->nargs+1];
int m=0;
for(m=0;m<c->nargs;m++)
{
strcpy(args[m],c->args[m]);
}
args[c->nargs] = NULL;
printf("%d\n",execv(args[0], args));
printf("errno: %d\n",errno);
}
PathResolver function
char* PathResolver(char *command, int ResolverMode, int *Permission)
{
*Permission = 0;
char *returnString;
returnString = malloc((sizeof(char)));
char *strPath = getenv("PATH");
char *del = ":";
char *strToken = strtok(strPath,del);
FILE *f;
while(strToken)
{
char filePath[100];
sprintf(filePath,"%s/%s",strToken,command);
if(access(filePath,F_OK)>=0)
{
if(access(filePath,X_OK)>=0)
{
*Permission = 1;
sprintf(returnString,"%s%s ",returnString,filePath);
if(ResolverMode == 1)
break;
}
else
{
*Permission = -1;
}
}
strToken = strtok(NULL,del);
}
sprintf(returnString,"%s\b",returnString);
return returnString;
}
strcpy(args[m],c->args[m]); is undefined behaviour, because args[m] is not a pointer to valid memory.
The following might be simpler:
char * args[c->nargs + 1];
for (size_t m = 0; m != c->nargs; ++m)
{
args[m] = c->args[m];
}
args[c->nargs] = NULL;
There's no need to copy the strings.
(This may not be your actual problem, but it certainly prevents your program from being correct.)
execv() expects the program name to be prefixed by a full path as 1st parameter.
To have PATH searched instead of providing a path use execvp().
Update:
Also this line
returnString = malloc((sizeof(char)));
does only allocate 1 byte to returnString, which is way to few for how you use returnString.
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 !
I've got an library which must read data from sqlite database by calling
extern int read(char** argv, int argc); // from header
it must process:
int read(char** argv, int argc) {
char* lineborder1;
char* lineborder2;
char* spaces1;
char* spaces2;
int maxl2 = 0, maxl1 = 0;
int i, maxi1, maxi2;
if (prelude() == -1) return -1;
// etc...
where prelude is inner procedure for sqlite connection:
int prelude() {
timefile = 0;
f = NULL;
#ifndef WIN32
char* temp = (char*)calloc(200, sizeof(char));
#endif
queries = (char**)malloc(sizeof(char*) * q_cnt);
for (x = 0; x < q_cnt; x++) {
queries[x] = (char*)malloc(sizeof(char) * q_size);
}
#ifdef WIN32
retval = sqlite3_open("todo.db3", &handle);
#else
home = (char*)getenv("HOME");
strcpy(temp, home);
retval = sqlite3_open(strcat(temp, "/.todo.db3"), &handle);
free(temp);
#endif
if (retval) {
printf("Database connection failed\n\r");
return -1;
}
return 0;
}
whole source is here : bitbucket: ctodo.c
I call this read from my application:
else if ((strcmp(argv[1], "read") == 0) || (strcmp(argv[1], "r") == 0)) {
return read(argv, argc);
but getting infinity cycle of this read call:
>>./todo r
Database connection failed
Database connection failed
Database connection failed
.... etc
here is how do I build it:
gcc -I . -c -o todo.a ctodo.c -lsqlite3 -O3
gcc -I . -o todo cctodo.c -lsqlite3 -O3 todo.a
help or version calls wrok fine and read works fine on windows, something specific to my linux build is here but I can't find a bug so far. what could call this read to run in infinity cycle like that?
The read function is defined in libc.so, and used to, you know, read data.
It is exceedingly likely that sqlite3_open() calls it.
By introducing your own function called read(), you've made your program enter infinite loop. If you wait long enough, your program will run out of stack and crash.
Doctor, it hurts when I do that. Well, don't do that :-)