C: Catch empty Input and print command prompt - c

Sorry for the bad title, but i didn't know a better one!
Target: I'm trying to make an command handler. So I'm printing out via printf("cmd: ") and listing on stdin via fgets(). If theres an Input I'm check on commands via if .. else if. So my Problem now: If there is no input on stdin it should repeat the function and print cmd!
int cmd_handler()
{
printf("cmd: ");
char command[LINE_MAX];
fgets(command, LINE_MAX, stdin);
if(command != NULL)
{
if(strcmp(command, "xyz"))
{
xyz();
}
}
return 0;
}
I really don't know how i can arrange that. simple call cmd_handler() on else isn't working. Maybe someone can give me a tip how to solve it.
EDIT:
It should look like this, if there is no input(2x for example) on stdin:
cmd:
cmd:
cmd:
THIS CODE ISN'T THE REAL ONE!
regards

You need a loop. I would suggest a while loop with an exit condition, perhaps set by an "exit" command.
int run = 1;
while (run) {
printf("cmd: ");
...
else if (strcmp(command, "exit") == 0) {
run = 0;
}
}

You need to check whether fgets() returns NULL, not whether command is NULL:
if (fgets(command, LINE_MAX, stdin) != NULL)
Then you can add an 'else' clause to handle the error condition, as you were trying to do.

The way you check for empty string is not going to work.
if(command != NULL)
This condition will always evaluate to true as command, in the expression, gets converted to a pointer and is always non-null.
To check if there are any alpha-numeric characters, use isalnum() from <ctype.h> and ensure there's no whitespace characters in command. You seem to want to use recursion whereas a loop is probably more suited.
char command[LINE_MAX];
int alnum=0;
while(1) {
alnum=0;
printf("cmd: ");
fgets(command, LINE_MAX, stdin);
for(i=0;i<strlen(command);i++)
if(isalnum(command[i])) {
alnum=1;
break;
}
if(!alnum) continue;
if(strcmp(command, "xyz"))
{
xyz();
}
....
break;
}
This way, you can ensure it handles any whitespace you may input. But rest of your strcmp(command"xyy") will fail if user inputs " xyz". So it may suffice to check whether user simply hits ENTER:
if(command[0] == '\n') continue;
instead of the above check using alnum().

Related

Shell endlessly loops when EOF is entered C

I am a new C programmer who is attempting to create their own shell. The shell itself works well and processes my commands correctly, but when the user enters the EOF character as input into the command line, my shell just infinite loops. My code is posted below as well as what I've already attempted (I'm also new to using GDB and Valgrind but neither is seeming to help me locate the issue).
What I have tried already:
The current implementation below attempts to capture the return value of getline and handle the case where it returns -1 (when EOF is read). However this just causes the shell to endlessly loop the prompt
I replaced my function call completely with:
if (fgets(command_line, MAX_CANON, stdin) == NULL) {
printf("\nTo quit, please use the exit command: exit.\n");
}
To my knowledge the above replacement should handle an EOF character input by the user. However this implementation using fgets also causes an endless command prompt loop.
Below is my current implementation which is referred to in #1 above:
Function called in main to read input from user:
char *read_command_line(void)
{
//Declare an integer to hold the length of the string, a line to hold our output, and a variable getline can use to hold the generated buffer
int len;
char *line = NULL;
ssize_t bufsize = 0;
//Get the line from stdin
int retval = getline(&line, &bufsize, stdin);
if(retval == -1)
{
line = NULL;
return line;
}
//Determine the length of the line and set a null terminating byte to end the string and get rid of the trailing return
len = strlen(line);
line[len - 1] = '\0';
//Finally return the read in line
return line;
}
Beginning of my shell while loop where line is read in:
//BEGIN SHELL
while (go)
{
//Signals are handled in the main.c
//Print the prompt
char cwd_loop[max_buf_size];
getcwd(cwd_loop, sizeof(cwd_loop));
printf("\n%s [%s]:> ", prompt_prefix, cwd_loop);
commandline = read_command_line();
if(commandline == NULL)
{
continue;
}
From your code
commandline = read_command_line();
if(commandline == NULL)
{
continue;
}
If read_command_line returns a null pointer, which it does if there's an error like EOF, then you continue the loop, letting it iterate again. This time read_command_line will again return a null pointer, and you continue like that forever.
You should break out of the loop if read_command_line returns a null pointer.
You should not continue to prompt and read further input when the input stream has been closed as indicated by getline() returning -1 or fgets() returning NULL. Just break out of the loop as if an exit command had been entered.

Ignoring leading newline("\n") in c

I am currently working on an practice. My program is working and I just want to make it more robust and foolproof. The code is of the following:
printf("Enter Name : ");
memset(userinput, '\0', 50);
fgets(userinput, 50, stdin);
I accidentally hit the enter key(newline) and for my program, the system just dangle there and couldn't accept anymore inputs. I am only allowed to use fgets. So is there any way of rejecting \n from being entered as a field?
One way you could do it is to check if the first character is a newline:
do {
printf("Enter Name : ");
memset(userinput, '\0', 50);
fgets(userinput, 50, stdin);
}
while ( userinput[0] == '\n');
printf("Hello %s", userinput);
This would still leave you up to space + newline, but its a first start.
So is there any way of rejecting \n from being entered as a field?
... to make it more robust and foolproof.
Code should not prevent '\n' from being read via fgets(). Instead, code should assess that input for validity. A leading '\n' is likely only 1 concern. Make code easy to update as certainly the criteria for a valid name will evolve.
I recommend a separate name test.
bool ValidNameInputTest(const char *userinput) {
if (*userinput == '\n') return false; // fail
// add other tests as needed
return true;
}
In a loop, test and repeat as needed. Code should exit the loop on success. When an end-of-file or input error occurs, code should detect/handle that too.
...
char userinput[50];
do {
printf("Enter Name : ");
fflush(stdout); // add to insure above output is seen before reading input
//memset(userinput, '\0', 50);// Commented out as not needed - although useful for debug
// Check return value and used a derived size
//fgets(userinput, 50, stdin);
if (fgets(userinput, sizeof userinput, stdin) == NULL) {
Handle_EndOfFile_or_Error();
}
} while (!ValidNameInputTest(userinput));

How do i take an unwanted character off the end of a file in C?

So i have some code that will allow the user to write anywhere they want inside a text file, thanks to the answers from How do I write to a specific line of file in c? , However i have hit a new obstacle, whenever i write back to the file an annoying random character will always appear at the end of the last word, and if it's on the first line a new line is created before it.
I know this has something to do with the file copy but i don't know where, can someone please help?
int main()
{
FILE *fp,*fc;
int lineNum;
int count=0;
int ch=0;
int edited=0;
char t[16];
fp=fopen("start.txt","r");
fc=fopen("end.txt","w");
if(fp==NULL||fc==NULL)
{
printf("\nError...cannot open/create files");
return 1;
}
printf("\nEnter Line Number Which You Want 2 edit: ");
scanf("%d",&lineNum);
while((ch=fgetc(fp))!=EOF)
{
if(ch=='\n')
count++;
if(count==lineNum-1 && edited==0)
{
printf("\nEnter input to store at line %d:",lineNum);
scanf(" %s[^\n]",t);
fprintf(fc,"\n%s\n",t); /
edited=1;
while( (ch=fgetc(fp))!=EOF )
{
if(ch=='\n')
break;
}
}
else
fprintf(fc,"%c",ch);
}
fclose(fp);
fclose(fc);
if(edited==1)
{
printf("\nCongrates...Error Edited Successfully.");
FILE *fp1,*fp2;
char a;
system("cls");
fp1=fopen("end.txt","r");
if(fp1==NULL)
{
puts("This computer is terrible and won't open end");
exit(1);
}
fp2=fopen("start.txt","w");
if(fp2==NULL)
{
puts("Can't open start for some reason...");
fclose(fp1);
exit(1);
}
do
{
a=fgetc(fp1);
fputc(a,fp2);
}
while(a!=EOF);
fclose(fp1);
fclose(fp2);
getch();
}
else
printf("\nLine Not Found");
return 0;
}
(Sorry about ident, i'm in a rush)
Try changing your do-while loop like,
while((a=fgetc(fp1))!=EOF)
fputc(a,fp2);
I guess it will solve your problem.
do
{
a=fgetc(fp1);
fputc(a,fp2);
}
while(a!=EOF);
A do-while loop evaluates its condition after performing the body of the loop. In other words, this loop is writing EOF to the file, which you shouldn't be doing. EOF isn't actually a character, it's just something that gets returned by the OS when it's finished reading a file. I'm not sure what would be the end result of actually writing EOF to a file, but I'd hazard a guess this is what's causing the "annoying random character" you're talking about.
Invert the loop into a normal while loop, as follows, so that you're checking for EOF before writing anything:
while ((a=fgetc(fp1))!=EOF)
{
fputc(a,fp2);
}
1) As you said "and if it's on the first line a new line is created before it"
To solve this problem you have to optimize the use of fprintf(fc,"\n%s\n",t); statement.
Replace this fprintf(fc,"\n%s\n",t); with below code.
if(count==0) //if its the first line to edit..
fprintf(fc,"%s\n",t) //watch closely,no '\n' before %s,This will copy wihtout creating new line at beginning of line or file.
else
fprintf(fc,"\n%s\n",t);
2) And Your statement scanf(" %s[^\n]",t); will not work properly if you give multiple-words input.You have tried to use both ScanSet and %s fromat specifer. You should only use any one of them.
Lets understand with a code snippet:-
char t[16]="\0";
scanf(" %s[^\n]",t); //Assume that you gave input "abc efg" from keyboard
printf("%s",t); // This will output only "abc" on moniter.
You should change it to some thing like this:-
char t[16]="\0";
scanf(" %15[^\n]",t);//here 15 is sizeof(array)-1. one left to accomadate '\0'.
printf("%s",t); //this will successfully output "abc efg" (if given)

Breaking while loop by EOF

I am trying to solve this problem and I need your help.
I have this code...
while(a != EOF){
scanf("%f",&a);
...
}
...and I want to terminate this loop by pressing CTRL+D. It works but I need to press it two times. I tried to use this
while(getchar() != EOF){
scanf("%f",&a);
...
}
but the same result. Is there any way to end this loop by pressing CTRL+D only once?
Thank you for any response.
You can check for EOF directly in scanf:
while (scanf("%f",&a) != EOF) {
...
}
For more information, read the docs on scanf (an example of them).
You should be checking the result of the call to scanf, not just for EOF, but also to ensure that the value parsed correctly. scanf returns the number of items that were successfully scanned, in your particular case, it will return 1 if it successfully scanned one float. If the parse was unsuccessful, then you can't rely on the value of a after that.
int result;
do
{
while ((result = scanf("%f", &a)) != EOF)
if (result == 1)
{
// scan was successful, you can safely use the value of "a"
}
else
{
// scan was unsuccessful
// you can skip to the next line, produce an error, etc.
}
}
You have at least two solution:
I.
while (scanf("%f",&a) != EOF) {
...
}
II.
get a from File Descriptor
Try testing the return from scanf(): if your stream has ended it'll return EOF.
Try this, this may help for you:
while(1) {
scanf("%f",&a);
if(a==EOF)
break;
......
}

My chdir() function will not work. Why?

I am writing a program that asks the user for a linux bash command and then stores them in pointer arrays (kind of like char *argv[]). The program must then make a check if this command is a normal bash command or a cd (change directory) command. If its a cd command then it should use something like chdir(). If the command is anything else I wanna use some variation of the exec() system call to execute that command.
However I am not succeeding with the first part (chdir()).
int ii=-1
printf("Enter the command: ");
fgets(command, 100, stdin);
command[strlen(command)-1]=0;
printf("Command = %s\n", command);
if (command[0]=='c' && command[1]=='d' && command[2]==' ')
{
printf("I am inside CD now.\n");
cd_dump[0] = strtok(command," ");
while(sub_string[++ii]=strtok(NULL, " ") != NULL)
{
printf("%s\n", sub_string[0]);
}
chdir(sub_string[0]);
}
Edit:
I have also tried the following if statement without luck.
if (command[0]=='c' && command[1]=='d' && command[2]==' ')
{
printf("I am inside CD now.\n");
chdir(command+3);
}
Sadly the program isnĀ“t doing what I want it to, and even after hours trying to solve the issue I have no idea why. What have I done wrong? Also if I input cd /home/ why does the output result in sub_string[0] end up with an extra "Enter key" on the output? Does strtok save the Enter key into the string?
Any help on the subject is very much appreciated.
Calling chdir() only affects the current process, not its parent process.
If you chdir() and exit immediately, it is pointless - the shell you call it from keeps its old cwd. That's why cd is always a shell builtin.
Use
char buffer[PATH_MAX];
if (getcwd(buffer, sizeof buffer) >= 0) {
printf("Old wd: %s\n", buffer);
}
chdir(command+3);
if (getcwd(buffer, sizeof buffer) >= 0) {
printf("New wd: %s\n", buffer);
}
to verify chdir() works correctly.
I think I'd do something like this:
if (command[0]=='c' && command[1]=='d' && command[2]==' ')
{
for(i=2, i++, command[i]!=' '); /* Skip to nonspace */
chdir(command+i);
}

Resources