My program is supposed to let the user edit a line of a file. The user edits the line and sends it back by pressing enter. Therefore I would like to print the current line which is about to be edited, but kind of print it on stdin instead of stdout.
The only problem I don't know how to solve is how I can prefill the stdin. I've already tried this:
char cprefill[] = {"You may edit this line"};
char cbuffer[100];
fprintf(stdin, cprefill);
fgets(cbuffer, 100, stdin);
This seems to be the simplest solution, but is probably too simple to work. The fprintf doesn't print anything to stdin. What is the correct way?
Edit:
This is how it is supposed to look like. Please mind the cursor which can be moved.
The C language has no notion of terminal nor of line edition, so it cannot be done in a portable way. You can either rely on a library like [n]curses to get an almost portable solution, or if you only need that on one single OS use low level OS primitives.
For exemple on Windows, you could feed the input buffer by simulating key strokes into the appropriate window (for example by sending WM_CHAR messages) just before reading, but that would be highly non portable - and in the end is no longer a C but a Windows solution...
First you need the libreadline developer package. (You might also need the libreadline if it's not already available on your system)
On Debian / Ubuntu that's apt install libreadline-dev (plus libreadline6 if you need the binaries also - 6 might be different on your platform)
Then you can add an history to readline, like this
#include <stdio.h>
#include <readline/readline.h>
#include <readline/history.h>
...
char cprefill[] = {"You may edit this line"};
add_history(cprefill);
char *buf = readline("Line: ");
printf("Edited line is %s\n", buf);
// free the line allocated by readline
free(buf);
User is prompted "Line: ", and has to do UP ARROW to get and edit the history, i.e. the cprefill line.
Note that you have to compile/link with -lreadline
readline prints the prompt given as argument, then waits for user interaction, allowing line edition, and arrows to load lines stored in the history.
The char * returned by readline has then to be freed (since that function allocates a buffer with malloc()).
You could use GNU Readline. It calls the function that rl_startup_hook points to when starting, where we use rl_insert_text to put our text in the line buffer.
#include <stdio.h>
#include <stdlib.h>
#include <readline/readline.h>
int prefill(void)
{
rl_insert_text("You may edit this line");
return 0;
}
int main(void)
{
char *cbuffer;
puts("Please edit the following line");
rl_startup_hook = prefill;
if ((cbuffer = readline(NULL)) == NULL) /* if the user sends EOF, readline will return NULL */
return 1;
printf("You entered: %s\n", cbuffer);
free(cbuffer);
return 0;
}
For more information, see the GNU Readline manual.
Related
When you read from stdin using getchar, fgets or some similar function, if you type some text and then put an eof (control+d in linux) you cannot delete the previous text. For example, if I type 'program' and then enter eof by pressing control+d, I can't delete what I typed before, i.e. program.
#include<string.h>
#include<stdlib.h>
int main() {
char buffer[1024] = "";
printf("> ");
if(fgets(buffer,sizeof(buffer),stdin) == NULL){
puts("eof");
}
else{
puts(buffer);
}
return 0;
}
How can this be avoided?
The readline function of The GNU Readline Library I think is my best option to do the job. It's pretty simple to use but it uses dynamic memory to host the string so you have to use the free function to free up the memory. You can find more information by opening a terminal and typing 'man readline'.
The code would look like this:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include <readline/readline.h>
int main() {
char *ptr = readline("> ");
if(!ptr){
puts("eof");
}
else{
puts(ptr);
}
free(ptr);
return 0;
}
To be able to use readline with gcc you must pass it -lreadline
When fgets reads a line, what will happen is that it will read characters from the specified stream until it encounters a '\n' or EOF, until it has read the specified maximum size to read or a read error occurs. It does not see what you are doing on your keyboard at all. It only sees the stream, but it is the terminal that sends the data to the stream.
What's happening when you are editing the input has absolutely nothing to do with fgets. That's the terminals job.
As Eric Postpischil wrote in the comments:
Pressing control-D in Linux does not signal EOF. It actually means “Complete the current read operation.” At that point, if characters have been typed, they are immediately sent to the program, whereas the system would usually wait until Enter is pressed. If no characters have been typed, the read operation completes with zero characters read, which some I/O routines treat as an EOF, and that is why programs may seem to receive an EOF when control-D is pressed at the start of a line of input. Since the data is sent to the program, of course there is no way to undo it—it has already been sent.
I guess there is some way to alter the behavior of pressing C-d, but then you need to decide what it should do instead. If you want it to do "nothing" instead of sending the data to stdin I cannot really see what you have won. The only use case I can see with this is if you for some reason are having a problem with accidentally pressing C-d from time to time.
One thing you could do is to take complete control of every keystroke. Then you would have to write code to move the cursor every time the user presses a key, and also write code to remove characters when the user is pressing backspace. You can use a library like ncurses for this.
It can't be avoided. Simply put, Ctrl+D ends the current read operation.
If you want to ignore this, make your own fgets based on fgetc and have it ignore end-of-file.
How can I remove a character on the terminal before the cursor in Linux? In the past I used something like this:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define KEY_BACKSPACE 127
int main(){
printf("%s", "abc"); // add something so we can see if delete works
char * buf = malloc(3*sizeof(char));
*(buf+0)=KEY_BACKSPACE;
*(buf+1)=' ';
*(buf+2)=KEY_BACKSPACE;
write(1,buf,3);
free(buf);
}
This is only a small example demonstrating this technique. In the original program I disabled canonical mode and handled every keystroke myself. That's why I needed to remove characters.
Writing backspace, space, backspace worked fine in my original program. Now when I run same program after a few years, it didn't remove anything. What changed? What can I do to fix this?
As I noted in a comment, you need to use backspace instead of '\177' (or '\x7F') to move backwards. You also have to worry about buffering of standard I/O. It's often best not to use a mixture of standard I/O and file descriptor I/O on the same stream — standard output in this example. Use one or the other, but not both.
This works:
#include <unistd.h>
int main(void)
{
char buff1[] = "abc";
char buff2[] = "\b \b";
write(STDOUT_FILENO, buff1, sizeof(buff1) - 1);
sleep(2);
write(STDOUT_FILENO, buff2, sizeof(buff2) - 1);
sleep(2);
write(STDOUT_FILENO, "\n", 1);
return 0;
}
It shows first (for 2 seconds):
abc
then (for another 2 seconds):
ab
then it exits. The cursor is after c at first, then after b.
As explained by Jonathan Leffler in the comment, your code needs two modifications:
The rubout character understood by the typical terminal (emulator) is '\b' (or 8), not 127.
printf() is line-buffered by default when writing to a TTY. This means that you need to call fflush(stdout) between calls to printf() and write(). Without flushing abc will only be printed at program exit, so the deletion sequence will be emitted before the contents it is supposed to delete, which renders it inoperative.
I am working on a school project in which we have to do some operations (select, min, max) on a table saved in .txt file.
The problem is that we can't use common functions such as fopen, fscanf, fclose.
The program will be launched from command line like this: .\project.exe select parameters <table.txt
Do you have some ideas how to get content of the .txt file to stdin without using fopen?
Thanks.
You do not need to open the file - the operating environment will do it for you.
When your program is called with <table.txt, your standard input is switched to read from that file instead of the keyboard. You can use scanf to read the data, and do not worry about opening and closing the file.
Same goes for the output of your program and the >table_out.txt redirection: rather than printing to the screen, printfs in your program would be writing to a file, which would be automatically closed upon your program's exit. Of course if you need to print something to the screen when your output is redirected, you can do so by printing to stderr (e.g. fprintf(stderr, "Invalid table format\n").
There are few ways to acomplish this.
Reading STDIN
I guess the teacher wants this method in particular. The idea is reading standard input rather than particular file.
In C++ you can simply read the stdin object. Here's an example:
#include <stdio.h>
#include <string.h>
int main(void)
{
char str[80];
int i;
printf("Enter a string: ");
fgets(str, 10, stdin);
/* remove newline, if present */
i = strlen(str)-1;
if( str[ i ] == '\n')
str[i] = '\0';
printf("This is your string: %s", str);
return 0;
}
Source: http://www.java2s.com/Code/C/Console/Usefgetstoreadstringfromstandardinput.htm
Using system utils
You can call "type" util # Windows (not sure about it) or "cat" util in Linux as a subprocess to read some partticular file. But this is rather a "hack", so I do not recommend using this one.
My program has to read just ONE character from the standard input, and so I use read(0, buffer, 1).
But if the user insert more than one single character, they remain in some buffer and when I call a read again they are still there.
So, how can I discard these characters?
I want that when I call a read again, the buffer is filled with the new character, not with the old ones.
An example:
I've a read(0, buffer, 1) and the user writes abcde. My buffer contains a (and it's right), but then I call read(0, buffer, 1) again and I want the next character written by the user from now, and not the b written before.
The POSIX answer is tcflush(): flush non-transmitted output data, non-read input data, or both. There is also tcdrain() which waits for output to be transmitted. They've been in POSIX since there was a POSIX standard (1988 for the trial-use version), though I don't recall ever using them directly.
Example program
Compile this code so the resulting program is called tcflush:
#include <stdio.h>
#include <unistd.h>
#include <termios.h>
int main(void)
{
char buffer[20] = "";
read(0, buffer, 1);
printf("%c\n", buffer[0]);
tcflush(0, TCIFLUSH);
read(0, buffer, 1);
printf("%c\n", buffer[0]);
tcflush(0, TCIFLUSH);
return 0;
}
Example dialog
$ ./tcflush
abc
a
def
d
$
Looks like what the doctor ordered. Without the second tcflush(), the shell complains that it can't find a command ef. You can place a tcflush() before the first read if you like. It wasn't necessary for my simple testing, but if I'd used sleep 10; ./tcflush and then typed ahead, it would make a difference.
Tested on RHEL 5 Linux on an x86/64 machine, and also on Mac OS X 10.7.4.
When your program wants to start reading characters, it must drain the buffer of existing characters and then wait to read the character.
Otherwise, it will read the last character entered, not the last character entered after right now.
Naturally, you do not need to do anything with the read characters; but, you do need to read them.
I'm using C. I wrote a very simpe program which prints back the input, using getchar() and putchar() or printf(). Is there any way to make it so as soon as the user types one key, the program registers it, without waiting for an Enter? Let me show:
Currently, if the user types "abc" and then presses Enter, the program prints "abc" and a newline and keeps waiting for more input. I want to make it so as soon as the user types "a", the program prints "a" and waits for more input. I'm not sure whether this has to be done inside the source code or if something has to be changed in the Windows command line.
Just in case, here's the source code:
#include <stdio.h>
int main()
{
int c;
while ((c = getchar()) != EOF) {
putchar(c);
}
return 0;
}
if you are using Visual Studio, there is a library called conio (#include <conio.h>) which defines a kbhit() function and getch().
otherwise, on Windows, there is still the possibility of using functions from the Windows SDK (ReadConsoleInput() and the like), but that would require a little bit more code (although, once done and if done properly, it can be reused any time you want)
If you're using Visual Studio, you can use getch().
In this simple case, the other answers should suit you fine.
The general solution is to disable line buffering. This depends on the particular console; the following example is Windows-only (untested):
#include <windows.h>
int main() {
HANDLE hConsole = GetStdHandle(STD_INPUT_HANDLE);
DWORD mode;
GetConsoleMode(hConsole, &mode);
SetConsoleMode(hConsole, mode & ~ENABLE_LINE_INPUT);
// ...
}
I assume that the standard C library functions are implemented in terms of ReadConsole and friends; if not, this might not even work. (I'm currently on Linux, so I cannot test this.)
On Linux you can take over the terminal:
#include <stdio.h>
#include <ctype.h>
#include <termios.h>
system("stty raw"); /* raw output to terminal, direct feedback */
system("clear"); /* clear screen */
printf("Press a key");
answer = getchar();
system("stty cooked"); /* revert back*/