Repeat prompting for correct number of arguments - c

I need to keep prompting the user until they give me 1 argument. I have a while(1) loop with a break statement inside but it exits early when it is run with 2 arguments. How do I continue prompting instead of exiting? I want to do something like this:
bool flag = true;
while(flag)
{
// ..code
flag = false;
}
but that does not work in C. This is what I have so far.
int main(int argc, char* argv[])
{
while(1)
{
if(argc == 2)
{
reverse(argv[1]);
printf("Reversed string: %s\n", argv[1]);
}
else
{
printf("Error, wrong number of arguments. Please provide only one argument");
}
break;
}
return 0;
}
I tried deleting the break statement and got an infinite loop, as expected, but no "pause" of execution for the input argument.

You cannot do that. Command line arguments are passed to a program when it is started. You can't ask for more arguments just like that. The best you can do is notify the user to run the program with one argument only. I recommend simply ignoring the second argument if it is not needed, but still notifying the user that it was not needed.

Related

How do you generally scan/parse commands in interactive REPL programs in C, is there a standard way?

I am writing an interactive REPL program in c.
Some examples of commands (lines starting with >) I would like to handle are:
$ ./my_program // run the program
> add user
id: 123 // this is the output of above command
> update user 123 name "somename"
> remove user 123
> quit
So basically the command is a line with multiple strings.
This is how I am trying to handle the commands.
scan the whole line
parse the command and get a corresponding int value unique to command
do whatever needs to be done for the command
#include <stdio.h>
int parse_cmd(const char *buffer)
{
// parse command
}
int main(int argc, const char **argv)
{
// init code
char buffer[100];
int cmd;
while (1) {
printf("> ");
scanf("%[^\n]%*c", buffer);
cmd = parse_cmd(buffer);
if (cmd < 0) {
printf("error: invalid command\n");
continue;
}
switch (cmd) {
// handle commands
}
}
// deinit code
}
There are a lot of cli programs I have seen that take command inputs in similar way.
I wonder if there is a general way of writing cli programs?
I can write code to parse the commands, just wanted to know the standard approach for such situations?
While there's no real standard way, quite a lot of opensource console tools with an interactive mode use the GNU readline library (https://tiswww.case.edu/php/chet/readline/rltop.html).
It's actually quite easy to use, even simpler than implementing everything 100% correctly by yourself.
Your example rebased on readline:
int main(int argc, const char **argv)
{
// init code
int cmd;
char* line;
while (1) {
line = readline("> ");
if (line) {
cmd = parse_cmd(line);
switch (cmd) {
// handle commands
default:
printf("error: invalid command\n");
}
free(line);
} else {
break;
}
}
// deinit code
}
This isn't any more complex than your example, but you immediately gain:
command line editing at the interactive prompt, with correct handling of each and every possible terminal
correct handling of EOF (important if stdin is redirected)
unlimited input line size
And it's not very hard to add a command history, with arrow-up and down to repeat previous lines, incremental search, optionally persisted to a file, et et.
There's not really a standard way to do it. This is not a 100% fair comparison, but your question is kind of like if there is a standard way to construct a compiler, because you are in fact constructing a language, although a very simple one.
But one reasonably common way that works fairly well for simple programs is this approach. Let's assume that we have two commands add and del. Create a function for both these commands. First we search for one of the strings "add " or "del ". Notice the spaces. Put a pointer on the next character and call the corresponding function with the rest of the line as argument and allow them to determine things.
Here is some pseudo:
parse(bufferptr)
word = getFirstWord(bufferptr)
ptr = bufferptr + strlen(word)
if word == "add"
return add(ptr)
else if word == "del"
return del(ptr)
return -1
add(bufferptr)
word = getFirstWord(bufferptr)
if userExist(word)
return -1
else
return addUser(word)
del(bufferptr)
word = getFirstWord(bufferptr)
if not userExist(word)
return -1
else
return delUser(word)
buffer = input()
int res = parse(buffer)

basic CLI program in C

Okay so overall im trying to complete a basic CLI C program which will complete functions such as clear, quit, cd, ls, help (bring up the unix man) etc.. i altered my code and so far i have this, im getting segmination error when trying to execute the cd command part of the program, (im very new to c btw);
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
int main (int argc, char *argv[])
{
char input[] = " ";
char *argument;
while(strcmp(input, "quit")!= 0)
{
printf("$");
scanf ("%s", input);
if(strcmp(input,"clear") == 0)
{
printf("\e[1;1H\e[2J");
}
else if(strcmp(argv[1],"cd") == 0)
{
if(chdir(argv[2]) == -1)
{
printf("\n directory does not exists");
}
}
else if(strcmp(input, "echo") == 0)
{
char str[50];
scanf("%[^\n]+", str);
printf(" %s", str);
}
}
}
input is declared as a ' ' (space) character. It will never match 'cd'.
This is probably more along the lines of what you want to achieve, where the first parameter is the command (cd), and the second will be the directory:
int main (int argc, char *argv[])
{
char *argument;
if(strcmp(argv[1],"cd") == 0)
{
if(chdir(argv[2]) == -1)
{
printf("\n directory does not exists");
}
}
Edit Also please note that there is no need for the else satement. If chdir does not return an error, it will change the directory, thus no need to call it again in an else.
Additionally, another tip for using system calls in general, it would be of great help if you print the error number returned by the system upon a failure in system call. This will make things easier when things start going wrong. To do this simply include <errno.h>' and modify the printf to printerrno` which gives specific details about the error:
printf("Chdir error: %d", errno);
For instance chdir() does not only return an error when the directory does not exist, but also for example if you do not have permissions to view the contents of the directory. See the man page for a list of possible errors.
To implement your own shell, you need to take input directly from stdin, not from command-line arguments (argv) from another shell. The basic pattern is like this:
Read input
Execute command
Print results
Loop back to step 1

creating a shell like program in C

I am trying to create a simple c program that takes user input, passes it to underlying shell and return the ouput of the user command. For eg: pwd will give the present working directory.
I want to do this using fork() and exec() in an infinite loop but I am facing two problems:
My loop terminates after first run
It only takes first argument. 'ls -ltr' will give me the output of 'ls' and not 'ls -ltr'
int runit(char*);
void main() {
int pid=0;
char command[50];
while(1)
{
int d=0;
printf("Please enter your command!\n");
scanf("%s", &command);
switch (pid = fork())
{
case 0: // a fork returns 0 to the child
printf("Child process \n");
d=runit(command);
if(d==-1){
printf("command not found \n");}
break;
default:
wait(5); // a fork returns a pid to the parent
printf("Parent process \n");
break;
case -1: //if something went wrong
perror("fork");
exit(1);
}
}
}
int runit(char* command) { //executing the command
char path[50]="/bin/";
int d = execl(strcat(path,command),command,NULL,NULL);
return(d);
}
Can somebody tell me what I am doing wrong or guide me how to correct this.
This input reading
scanf("%s", &command);
would stop at the first whitespace (unless input failure occurs -- you should check the return value of scanf() in any case). So, when you input ls -ltr, command will have just ls. You need to read lines. For example, use fgets() to read input (and make sure to handle the trailing newline):
fgets(command, sizeof command, stdin);
command[strcspn(command, "\n")] = 0; /* to remove \n if present */
And the next problem is that execl() takes multiple arguments. That means
this usage:
int d = execl(strcat(path,command),command,NULL,NULL);
is broken. You need to split the input command into multiple strings and pass each arguments to execl(). A better option to store the individual strings in an array and use execv() instead.
Another thing you need to be aware of is exec*() family functions do not return on success. So, the return code check isn't very useful - instead you can just use perror() to know why it failed if it failed.

Real time input/output (chat-like)

I'm trying to make a little chat program after reading Beej's guide to programming.
And then I was thinking about the basics of the program itself, and I don't know how to print output of recv() and get input for send() at the same time, because the client can always write something and send, but how is it possible to also print something while he's trying to input ?
I thought about threads, and I learned a little bit about them, and I created 2 simple threads: The first one, prints a sentence every 3 seconds, and the second one get input, this little program of-course had a lot of issues, for ex. if you started typing, and the other thread needs to print something, it will simply take what you wrote, and print it with itself output.
Here is the code, I tried to recreate it, I hope you guys can help me ..
pthread_t tid[2];
void* printse();
void* getinput();
int main(int argc, char *argv[])
{
int error;
error = pthread_create(&(tid[1]), NULL, &getinput, NULL);
if(error != 0)
{
printf("ERROR\n");
} else {
printf("NOERROR\n");
}
error = pthread_create(&(tid[2]), NULL, &printse, NULL);
if(error != 0)
{
printf("ERROR\n");
} else {
printf("NOERROR\n");
}
sleep(5000);
return 0;
}
void* printse()
{
while(1)
{
printf("POTATO\n");
sleep(3);
}
return NULL;
}
void* getinput()
{
char *input;
while(scanf("%s", input) != EOF)
{
printf("-%s\n", input);
}
return NULL;
}
You have undefined behavior in your code: You haven an uninitialized pointer input in getinput.
Uninitialized (non-static) local variables have an indeterminate value, and it will seem to be random. As the value is indeterminate (and seemingly random) the scanf call will write to some unknown place in memory, overwriting whatever was there.
You could easily solve this by making input an array.

how to put the whole program in a infinite loop controlled by command line arguments

Programming Language : C
I'd like to put my program in a infinite loop controlled by command line arguments..
I mean, unless I enter "quit" it should keep on executing based upon the arguments I enter to do..
Without knowing anything about your target platform, it is hard to make specific recommendations. But one way you can do it is with a "state machine." Here is a rather nice stackoverflow question that can give you some ideas. In particular look at this answer.
Try this:
#include <stdio.h>
int main(int argc,char *argv[]);
{
char cmd = '\0';
char quit = 0;
while(quit==0) {
cmd = fgetc(stdin);
switch(cmd) {
case 'q':
{
quit =1;
break;
}
// process other cases.
}
}
fprintf(stdout,"Quiting\n");
}
If I am not mistaken you can use the following function : system() in stdlib.h
where the syntax is as follows:
int system(const char *command);
here you can pass any shell command as a string argument

Resources