Multi line input from stdin using fgets() - c

I am trying to input something like this
line 1
this is line 2
now line 3
Using fgets and from the user stdin
My snippet:
char *line;
while ((line = fgets(text, BUF_SIZE, stdin)) != NULL) {
//save and process line
However, upon runnnig this I am stuck at stdin until I do Ctrl+C force quit.
How do I check the 2-enter key aka '\n' using this? so that the code can proceed to the next lines following the 'read from stdin section'
I am open to using getc or getline() if that is a simpler solution.

You can check for '\n' and break while loop
your while loop should look something like this
while ((line = fgets(text, 100, stdin)) != NULL) {
if(text[0] == '\n'){
break;
}
/* do your work here */
}

fgets returns NULL when it hits the end of file marker aka EOF. However, unlike a standard text file, stdin doesn't automatically encounter the EOF marker since there is no pre-designated end of file location that will be automatically run into like a standard text file. If you want to send the end of file marker to stdin, you have to type in a command unique to each operating system. For example, on windows you enter Crtl-Z to send EOF to stdin. Anytime you are stuck on something like this, try to look up the documentation of the function you're using (in this case fgets).
Also, there's no need to save the return value of fgets into "line". You can just compare the return value of the function directly to NULL like
while (fgets(text, BUF_SIZE, stdin) != NULL) {
// do stuff
}

Related

fgets function and file handling in C

I am trying to make a program which will store the data entered by the user in a text file whose name is provided by the user. Program will terminate when the user enters exit. strcmp function of string.h is used for string comparison and fgets() is used to read data from stdin.
Here is my code.
#include<stdio.h>
#include<string.h>
void main()
{
char file[60]; // will store file name
printf("Enter file name: ");
fgets(file, 59, stdin);
FILE *fp = fopen(file, "a+"); // open file in append mode
if(fp == NULL){
printf("File not found !");
return;
}
char data[100];
printf("Enter some data to add to file(exit to terminate): ");
fgets(data, 99, stdin);
int flag = strcmp(data, "exit");
while(flag != 0){
fputs(data, fp);
fgets(data, 59, stdin);
flag = strcmp(data, "exit");
printf("%d\n", flag); // for checking whether string are correctly comapred or not
}
printf("Bye");
}
Program does not terminate even if i enter exit. I have also tried concatenating "\n" at the end of string input by user but that also doesn't help. Although, gets() function works fine, but i know it is not preferred to use to I shifted to fgets() but it doesn't work for me.
Check the man page for fgets(), it reads and stores the newline (caused by pressing ENTER) after the entered input. Thus, the strcmp() fails.
You have to manually strip the input buffer off the newline, before you can compare the input. A simple yet elegant way of doing that would be
data[strcspn(data, "\n")] = 0;
fgets reads in a complete "line", i.e. a sequence of characters until (and including!) a new line character. Hence, when a user presses "Enter", the new line will be part of the string read in and a strcmp(data,"exit") will evaluate to "not equal".
So either strip off the new line before comparison, or compare with a string literal including a new line. Since you write the data as is(i.e. including the new lines) to a file, it seems cumbersome to first strip the new line off and add it then in the output manually. So I'd actually suggest the second approach:
fgets(data, 100, stdin);
flag = strcmp(data, "exit\n");
An alternative would be to use strstr if excess characters do not matter (i.e. your program would exit if the user types "exit" or "asdfexitasdf". - both of which contain "exit".)
So
int flag = strstr(data, "exit");
if(flag != NULL)
//exit the program
else
//stay in the program

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.

How to add text at the end of line

for example I have test.txt with
test1
test2
at the end of each line I would like to add some text
my code is:
fp = fopen("test.txt", "w");
while ((ch=getc(fp)) != EOF)
if (ch == '\n')
fprintf(fp, "newText");
my output is:
test1
newText
The outcome should be:
test1newText
test2newText
You cannot do it with a single file.
Here is what you need to do:
Open an auxiliary file for temporary output
Read the actual file line by line
For each line write the copy of the line into the auxiliary output
After writing the line write the suffix that you would like to append
Go to the next line until you process the whole file
Once you finished processing the whole file, close both files, and move the auxiliary file in place of the original input.
How to avoid a new line?, I successfully copy [the text] but when I try to add some text at the end of each line, it starts from new line
This is because you include the end-of-line character in your copied text.
If you read character-by-character, do not copy '\n's when you see them; if you read with fgets, check the last character, and skip it if it happens to be '\n' (fgets includes it in its return value).
You can’t read from your output file like that. It is possible to open a file for reading and writing, but it’s an advanced topic and isn’t really appropriate for text files.
The normal approach is to write to another file, and then replace the original if desired. Note that you’ll have to emit all the characters you read and your extra text.
If this is the whole function of the program, consider making it a filter (by using the standard streams); this is what’s expected by experienced users and saves some error checking.
eventually, I have succeed
if (!strcmp(fileName, SWM_DEBUG))
{
fp = fopen(fileName, "r");
fpOut = fopen("tmp.txt", "w");
while ((ch = fgetc(fp)) != EOF)
{
if (ch == '\n')
fprintf(fpOut, "TEST");
fputc(ch, fpOut);
}
}
Thanks for your support ☺
You need to change the fopen call to read from the file and use the fputc function to re-output the character you read, like this:
fp = fopen("test.txt", "r");
while ((ch=fgetc(stdin)) != EOF) {
if (ch == '\n') {
fprintf(fp, "newText");
}
fputc(ch, fp);
}
fprintf(fp, "newText");
As pointed out elsewhere, you can't simultaneously read and write a file in the way you were trying to do, so i've changed it to read from stdin to illustrate the code

Remove empty new line at the end of a file

I have a file that's storing strings from the user's input (stdin)
However there are 2 situations
If I read it normally, my file will have an empty line at its end due to the newline from the last string the user introduced.
If I remove the \n from the input string, the file stores all strings in the same line, which is not wanted.
How can I simply remove that newline from the end of the file?
I can edit and provide some of my code if required.
EDIT: Let's say the last line of a file I already have is "cards"
when the cursor is in front of "cards", if I press the down arrow it doesn't go on to the next line, while in this case it can happen once.
For my code to function perfectly I can't let that happen,
Here's an example of what I have:
f=fopen(somefile, "w");
do
{
fgets(hobby, 50, stdin);
fprintf(f, "%s", hobby)
} while(strcmp(hobby,"\n") != 0);
The newline character1 at the end of the file is part of the last line. Removing it is possible but makes the last line incomplete, which will break many programs. For example, concatenating another file at the end of this file will cause the last line to be merged with the first line of the concatenated file.
A Yuri Laguardia commented, if you later reopen this file in append mode to write more lines, the first one added would be concatenated at the end of this last incomplete line. Probably not the intended behavior.
If you do not want the file to contain empty lines, check user input before writing the line into the file:
void input_file_contents(FILE *fp) {
char userinput[80];
printf("enter file contents:\n");
while (fgets(userinput, sizeof userinput, stdin)) {
if (*userinput != '\n') {
fputs(userinput, fp);
}
}
}
EDIT:
Your code does not test for termination at the right place: you write the empty line before the test. Do not use a do / while loop:
f = fopen(somefile, "w");
if (f != NULL) {
/* read lines until end of file or empty line */
while (fgets(hobby, 50, stdin) != NULL && *hobby != '\n') {
fputs(hobby, f);
}
}
1 The newline character is actually a pair of bytes <CR><LF> on legacy systems.

How to return to previous scanf and keep the flow

I'm programming this code (personal software) for a spa which is still in a beta version but I encounter a issue well is more like an idea than an issues let me explain you:
Source code:
fflush(stdin);
gets(NC1.Customer_Nameandlastname);
fflush(stdin);
printf("provide the customer's age\n\t");
fflush(stdin);
scanf("%d",&NC1.Customer_Age);
fflush(stdin);
this is just part of the source code but what I want to do when the program is running is this:
If the the person that is typing the information makes a mistake or wants to retype the same information but the next command line is already waiting for the input data the question is how would I do to go back to the previous line and then after I finish continue to the next line?
So it is like how would I return to the previous scanf() if I already type that information and then the system is waiting for the next line.
Please help me because I dont really know what yo do I am seeking how to do it but I still not able to find it.
You cannot portably flush input from stdin with fflush(stdin);. It invokes undefined behavior.
You can read the rest of an offending line from stdin with this function:
void flush_line(FILE *fp) {
int c;
while ((c = getc(fp)) != EOF && c != '\n')
continue;
}
Furthermore, do not use gets(). This unsafe function (you cannot provide the size of the destination array, so any properly crafted input may cause undefined behavior, a flaw that can be used by an attacker to compromise your program). The function was finally removed from the C Standard in 2011. Use fgets() and remove the trailing linefeed if any this way:
if (fgets(line, sizeof line, stdin)) {
line[strcspn(line, "\n")] = '\0';
...
}
You cannot restart a failed scanf(). The return value gives you some information as to where it failed, but not enough to restart the parse reliably. A better way to parse standard input is to read line by line and use sscanf() to parse the lines. Example:
/* read the customer's age. Keep prompting in case of invalid input */
for (;;) {
char line[80];
printf("provide the customer's age\n\t");
/* force flush of stdout for systems that do not do it
automatically upon reading from stdin */
fflush(stdout);
if (!fgets(line, sizeof line, stdin)) {
/* end of file reached */
return -1;
}
if (sscanf(line, "%d", &NC1.Customer_Age) == 1) {
/* input parsed correctly, break out to the next question */
break;
}
/* parse failed, output an appropriate message and restart */
printf("bad input, please type a number\n");
}
This is really a basic problem, what you want is a loop like this
while (fgets(buffer, SIZE_OF_BUFFER, stdin) != NULL) {
if (is_input_valid(buffer) == 1)
break;
/* Or else, go again */
}
After asking the user for all the details, ask something like
Do you want to store this record in the database?
Instruct the user that if he makes a mistake, he should enter garbage for the following fields, and answer "no, I want to discard this record".
Maybe the user will understand by himself that this is what he should do, because asking for such confirmation is a pretty standard practice.

Resources