I have a program x, which I want to cleanly terminate.
You can run it by simply doing ./x and use the terminal to write lines to stdin directly and terminate it by writing exit.
However, if you use: cat file.txt | ./x, the stdin is now piped from the file and therefore you can never type exit.
The best way to end this program would be for it to automatically terminate once the last line was read from the file.
Alternatively, I'd like to re-route stdin back to the terminal if that is at all possible, to further allow manual input as before.
Here is some sample code:
int main() {
// ...
while (ongoing) {
size_t n = 0;
char* ln = NULL;
getline(&ln, &n, stdin);
strtok(ln, "\n");
strtok(ln, "\r");
if (strcmp("exit", ln) == 0) {
break;
}
//...
}
}
you're using getline to read your input. getline returns -1 on EOF. This makes it easy.
if (-1==getline(...))
break;
When you have read all the input from a pipe, EOF will be raised up to indicate that the full input has been reached.
In your example, this will be rougly equivalent with exit, so you can also check the return value of getline to see if the EOF has reached (in which case -1 will be returned).
Related
I can't seem to get this read loop to terminate.
#include <unistd.h>
char buffer[256];
int read_chars;
while((read_chars = read(STDIN_FILENO,buffer,sizeof(buffer))) > 0) {
//DO STUFF
}
However, when I hit enter in the terminal, it just hangs for the next read and never exits.
Any thoughts on this implementation is not correct ?
Here read will stop reading at the end of standard input, which a newline isn’t. Try doing Ctrl-D twice in your terminal while the program is reading and it should terminate. Ctrl-D once on an empty line or twice after some characters marks the end of standard input.
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.
I have this command line argument -
cat file_name | ./a.out
The problem is not reading from the cat command inside the C program as we can do that with read(), fgets(), fgetc() but the actual problem I am facing is after reading the data from cat I am not able to take input from user using fgets.
Here is my sample code
while(fgets(buffer, BUFSIZ, stdin ) != NULL )
puts( buffer ); // Here I have tried strtok( buffer, "\n" ) too.
memset( buffer, 0, BUFSIZ );`
The problem is after this line, it is not asking for the input like the below is not working-
puts("Name: ");
fgets( buffer, BUFSIZ, stdin );
Help me with what's wrong happening here?
When you do cat file_name | ./a.out the standard input of your program is tied to a pipe linking it to the output of cat. Your program will never get to see the user input - the very stream from where it would arrive has been replaced by the aforementioned pipe.
Mind you, I suspect that with some horrible POSIX-specific trickery you may be able to reopen it going straight for the tty device, but it's just bad design. If you need to both read from a file and accept interactive user input just accept the file as a command line argument and use stdin to interact with the user.
Edit
This is an example of the Unix-specific kludges that one can attempt, assuming that the process still has a controlling terminal. After reading all the original stdin, I'm opening /dev/tty (which is the controlling terminal of the process) and re-linking stdin to it.
Disclaimer: this is for entertainment purposes only, don't do this for real.
#include <stdio.h>
#include <stdlib.h>
void die(const char *msg) {
fprintf(stderr, "%s\n", msg);
fputs(msg, stderr);
exit(1);
}
int main() {
/* Read all of stdin and count the bytes read (just to do something with it) */
int ch;
unsigned long count = 0;
while((ch = getchar())!=EOF) {
count++;
}
printf("Read %lu bytes from stdin\n", count);
/* Open the controlling terminal and re-link it to the relevant C library FILE *
* Notice that the UNIX fd for stdin is still the old one (it's
* surprisingly complex to "reset" stdio stdin to a new UNIX fd) */
if(freopen("/dev/tty", "r", stdin) == NULL) {
die("Failed freopen");
}
/* Do something with this newly gained console */
puts("How old are you?");
fflush(stdout);
int age = -1;
if(scanf("%d", &age)!=1) {
die("Bad input");
}
printf("You are %d years old\n", age);
return 0;
}
(previously I had a solution that checked if stderr or stdout were still consoles, which was even more of a kludge; thanks #rici for reminding me of the fact that POSIX has the concept of "controlling terminal", which is accessible through /dev/tty)
If you need to use stdin for user interaction, then you need to use a different file descriptor for reading the input stream.
You could use a specific pre-opened file descriptor and document that (e.g. "the input stream should be connected to fd 3"), but the usual approach is to accept a file name as a command-line argument. You can then provide a named pipe as the argument; shells such as Bash provide process substitution to make that easy:
./a.out <(cat file_name)
When that is run interactively like that, stdin is still connected to the terminal, and can be used at the same time as the stream from the connected command.
(Obviously, if the command actually is cat with a single argument, then you could just provide the filename itself as the argument, but I'm assuming that's a placeholder for a more involved pipeline).
I am writing two c files that one is to write(by stdout) and another is read(by stdin).
But the read code is always hangs with read(), I have tried fread function but useless.
Can someone give advice?
Write example:
int main() {
char *a_string="Hello";
write(fileno(stdout), a_string, strlen(a_string)+1);
return 0;
}
Read example:
int main() {
char buffer[100];
read(fileno(stdin), buffer, 100-1);
printf("buffer=%s\n", buffer);
return 0;
}
The read code is always hangs with read(), I have tried fread function but useless.
This is because read and fread, unlike fgets and similar functions, do not quit reading when the user inputs a newline (presses Enter). It waits until EOF is read or until the specified bytes have been read.
To send EOF to read you must press Ctrl+D.
You need to input the EOF to stop, in Linux,it's Ctrl+D.
I am trying to get a basic understanding on how to use fputc in C. I have read some documentation that is out there and believed I had it right. But every time I try to use the script I wrote by executing ./fputc > test.txt where text.txt is a text file with one line of text.
This is my script:
int
main(int argc, char **argv){
int ch;
FILE *input;
input = fopen("text.txt", "w+");
while ((ch = getchar()) != EOF){
fputc(ch, input);
}
fclose(input);
return 0;
}
I get no errors on compilation and for some reason the script does not reach EOF at the end of the text file. Shouldn't the getchar return EOF when it reached the end of the text file?
The text (text.txt) file does not appear to be edited, although it is created. So somewhere in my while loop something is going wrong.
I am new to C programming (if you couldn't tell) and this little script has me befuddled.
Any help would be appreciated, or any links to sites with further detail would also be great.
Cheers,
S.
What you in essence say is:
Console: Run my_program and write anything it outputs to test.txt.
Program: Open text.txt and write any input to stdin to that file.
Your console normally have three standard streams stdin, stdout and stderr. These streams you can redirect. If you are on Windows also look at i.e. redirection.
When you say ./my_prog > test.txt, what you tell your console, (not my_prog), is to write anything my_prog writes to stdout to the file test.txt.
If you in your code say i.e. printf("Hello");, then Hello would be written to the file test.txt.
If you had turned your redirection around by saying ./my_prog < test.txt instead, would be; stream the file test.txt to my_prog. Which, in turn, if there was any text in test.txt would result in a copy of test.txt to text.txt.
Now in your code you say:
int main(void)
{
int ch;
FILE *input;
/* Here you open a handle to the file text.txt for reading and writing */
input = fopen("text.txt", "w+");
while ((ch = getchar()) != EOF) { /* get next char from stdin */
fputc(ch, input); /* write that char to the handle input */
}
fclose(input); /* close the handle */
return 0;
}
So what happens, the way you run it, is:
In your code:
Open text.txt
Wait for input (data entered to stdin) - typically user entering text to console, passed to program when Enter is pressed.
In console:
Redirect anything from my_prog to test.txt.
You say:
the script does not reach EOF
Well, as it reads from stdin it will only (not without exception) get EOF under two conditions.
If you redirect a file to your program. I.e. ./my_prog < foo.txt (notice <, not >).
- What would happen then is that my_prog would read the data from the file foo.txt and when that file ends your program would receive a EOF. And, hence quit.
If you manually enter EOF to stdin.
- On Linux and OSX Ctrl-D, on Windows Ctrl-Z
Now, if you test this by typing text to console remember that write actions like fputc()is buffered. What this mean is that the data is not written to the file right away, but only when a given amount of data is in buffer, fflush() is called, stream is closed, you turn off buffering, etc.
Also; if you run your program. Enter text, enter some more text, and then hit Ctrl-C to abort the program it is a big chance you end with no data in your text.txt.
The reason for this is that the program is killed and thereby fclose() never called, and hence no flush to file.
On your further endeavors in programming it would be a very good idea to make a habit of not presuming anything. I.e. do not presume fopen() is OK.
FILE *fh;
char *outfile = "foo.txt";
if ((fh = fopen(outfile, "w")) == NULL) {
fprintf(stderr,
"Unable to open file %s\n --",
outfile);
perror(" fopen() ");
return 1;
}
Most functions has a way to check if operation was a success. I.e:
if (fputc(ch, fh) != ch) { err ...
This will make your code a lot safer, give you hints on where it fails etc.
Some links:
Look at redirection links at top of post.
Look at the functions in stdio.h (good overview), stdio.h (examples etc.). I.e.:
stdin
stdout
stderr
fopen()
fflush()
setvbuf()
setbuf()
...
getchar returns the next character from the standard input (stdin).
It is equivalent to getc with stdin as its argument.
Hence, your code reads from standard input instead of FILE* input.
Use fgetc here.
fgetc returns the character currently pointed by the internal file position indicator of the specified stream. The internal file position indicator is then advanced by one character to point to the next character.
So, Use fgetc to read from a file:
while ((ch = fgetc(input)) != EOF)
your program and the shell are both writing the same file. you should remove the output redirection > test.txt from your command line