I have a basic C program that needs to read input from stdin.
First, it reads from an input file by using
./Program <input
and then it loops through to read that until there's no more
while(scanf("%s",command)!=EOF){
printf("%s\n",command);
}
After that I need to read from the keyboard again, but it continues infinitely to spam read the last line from my input file, not letting me use my keyboard for input.
while(1){
scanf("%s",command);
if(!strcasecmp(command,"exit"))
exitProg();
else if(!strcasecmp(command,"help"))
helpMess();
else
printf("Command \"%s\" not recognized, use command \"help\" for a list.\n",command);
}
Read the documentation for scanf, specifically the part about the return value, excerpted below:
Return Value
On success, the function returns the number of items successfully read. This count can match the expected number of readings or fewer, even zero, if a matching failure happens.
In the case of an input failure before any data could be successfully read, EOF is returned.
The problem you're having is that once the file runs out of data, the program's standard-in does not revert back to the controlling terminal, it stays at the end of the empty file. Your scanf call is silently failing, leaving the contents of command unmodified. If you want to be able to read from both, you'd need to find another way of handling that.
It might be possible that your shell supports this functionality.
Related
I am trying to make a program that can process sentences in C in the POSIX environment. Assume that my program's name is "test". If the user entered just "./test", then my program will ask the user to enter some sentences. This one so far is easy.
However, if the user entered "./test < file.txt", the program should get the characters from that txt file. I do not know how I can get the characters of the file in C. I tried something like file = open(argv[2]);, but it did not work.
I will really appreciate it if you give me the answer to this question.
TL;DR: If you start your program like
./test
and you have to type in the input, then exactly the same program will read from file.txt if you start it as
./test < file.txt
Longer explanation starts here. (The following explanation is not 100% precise, but shall help to get an understanding what is going on in principle.)
In a C program you can open files with fopen. As a return value, fopen gives you a FILE pointer. However, when you start a program under Unix, three FILE pointers are already available. These default FILE pointers are stored in variables named stdin, stdout and stderr.
Of these, stdin can be used to read from, stdout and stderr can be written to. And, stdin is used as default in several C library calls, like, gets or scanf. Similarly, stdout is used by default for calls like printf.
Now, although they are called FILE pointers, they can in fact represent other things than just files. stdin could be a file, but it can also be a console where you can type in stuff.
This latter scenario is what you observe when you start your test program from the shell with the command
./test
In this case, the test process will be started with stdin just using the console from the shell from which you started the test program. Therefore, if in your test program you call, say, gets(), then your program will implicitly read from stdin, which represents the console input that was inherited from the shell. Consequently, in this case the user has to provide input by typing it in.
Now let's look at what happens if you start your process from the shell in the following way:
./test < file.txt
Here, the shell does a bit of extra work before it actually creates your test process. This is because the < file.txt part of your command line is interpreted by the shell - this is not passed as arguments to your program. Instead, what the shell does is, to open the file.txt and, when the test process is started, hand the opened file.txt over to the process such that in your test process stdin is connected to file.txt.
Then, the call to gets() in your program will again read from stdin, but this time stdin is not the console. This time stdin really corresponds to a file, that is, file.txt.
I am having issues with handling the arguments that are passed to my program. The user should have the ability to provide his own arguments or to provide a JSON file containing the arguments at launch.
The individual can enter their own arguments at the launch. For example:
prog --x 1 --y 2
The individual can also send the arguments through a file input (JSON).
prog < arguments.json
The issue I am having is trying to get to recognize if a file has been passed through stdin. More specifically, if the user runs the program without any arguments or file input.
I can easily find out if any arguments have been passed by checking argc, but then my program gets stuck at verifying if anything has been passed in stdin by going through this ;
[...]
char str[150];
char c;
while ((c = fgetc(stdin)) != EOF) {
strncat(str, &c, sizeof(char));
}
[...]
After launching the program with no arguments, it sits in the terminal waiting for my input (which it should not be doing since there is no file input). The problem is only when the user has put in no arguments at launch, and the program tries to check the stdin. Is there anyway for me to check if stdin is empty before using fgetc?
Not easily. There are two immediate problems.
As mentioned, it's not that easy to detect if the standard input is tied to a file. You could possibly use isatty but there may be perfectly valid reasons why you wish to send a file with real input to your program, not options.
As foreshadowed in the preceding point, if you use standard input for passing in arguments, that rather stops you from also using it for "proper" input. Now it may be that your program expects no input in which case that's fine. But, if you want to provide a file with options and allow input, things start to get difficult.
The way this is usually handled is to not use standard input for the options, rather you provide another option which will specify a file to be used.
For example, the file my.options could contain --x 1 --y 2 and you would run your program as one of:
prog --opts-file=my_options.json
prog -o my_options.json
That requires an extra level of indirection in that you have to handle both command line options and options read in from the file but it leaves standard input for what ${DEITY} intended :-)
I have created an auto typing bot which simulate characters of string given by user.
My code is this:
printf("Enter speed (wpm) (1 to 11750):");
scanf("%d", &speed);
if(speed < 1 || speed > 11750)
{
printf("\nPlease provide CORRECT DATA\n");
return -1;
}
printf("Paste the String : \n");
gets(exaArray);
exaArrayLength = strlen(exaArray);
relation = (int)11750/speed;
printf("typing will start in 2 sec-\n");
Sleep(2000);
i=pos=0;
while(i<=exaArrayLength)
{
Sleep(relation);
if((exaArray[pos]>96) && (exaArray[pos]<123)) //small letters
{
keycode=0x41 + (exaArray[pos]%97);
smallLetter(keycode); //function for key simulation
}
.....
I am taking input using gets function. This program works fine when I paste text which does not contain Enter. So this program works fine with one paragraph.
But if the user provides more than one paragraph, then it simulates only the first paragraph.
Because gets terminates at '\n'. Which function could take multiple paragraph input and assign it to a string.
This is actually a very hard and complex problem, and not easy to solve in an automated way.
It would seem like reading in a loop would be a good solution, but then you come to the point when there is no more input and the reading function just blocks waiting for more input. The easiest way out of this is to have the user enter the "end of file" key combination (CTRL-D on POSIX systems like Linux or OSX, CTRL-Z on Windows), but the user must then be told to do that.
The problem stems from that your program simply have no idea how much data it is expected to read, and there is no function which is able to, basically, read the users mind when the user thinks "that's it, no more data".
Besides the above solution to have the user give an "end of file", you can use other sequences or special keys or even phrases of input to mark the end, but it all comes down to this: Read input in a loop until users says "no more input".
Well, there is no way for the computer to make a difference between the user pressing enter and the "pasted" string containing newlines. (Technically, pasting something into the console is like typing it.)
If you just don't want the problem to exit after one paragraph but continue, you can do it as commenter alk suggested (loop around the reading function) - then you would need Ctrl+C to exit the program and then there would technically still be one paragraph at a time written. Depends on what you further want to do with the program.
On the other hand, if you want a way for the user to input all text at once and only then process it, you would need to define something other than "newline" as "end of input" marker, for example something like ESC.
You would do this by using getchar instead of gets and manually concatenating each char which is entered this way to a string buffer, and if the character has the value 27 (escape key) for instance, you would end the input loop and start outputting.
i am writing a terminal chat and would like to reprint the content the user has typed in, if a new message from another user has arrived asynchronously.
if a new message arrives i print "\x1B[2K" to stdout (ANSI ESCAPE CODE for erasing the current line) to clear the current line, then i print "\r" to move the cursor to the leftmost position, then i print the received message with a newline
now i would like to reprint the characters the user has typed - i found out that there is a special character VREPRINT (http://www.gnu.org/software/libc/manual/html_node/Editing-Characters.html) that can be used and if a hit CTRL-R it actually works... but if print the character to stdout using the character placed in c_cc[VREPRINT] of a struct termios, it does not work - is it even possible to do it that way?
I do not want to use any other libraries like readline or ncurses, since this would be plain overkill... i just would like to make my solution work using ICANON terminal mode if possible
Thanks in advance!
While it is possible to write to the same tty device that you are reading from, this doesn't mean that the characters that appear will be processed as input characters.
You can test this yourself, using two separate shell sessions (using screen, tmux, or, if you are on MacOSX, iTERM.app sessions).
in Session 1, get the current tty name:
tty
Let's assume the tty name of Session 1 is /dev/ttys000.
Then enter the following, without a return or newline -- just leave it pending:
echo abc def-
In Session 2 (using the tty name from Session 1), enter the following command:
echo foo >/dev/ttys000
The string foo should appear on the pending line in Session 1, like this:
echo abc def-foo
Now, go back to Session 1, and hit an "enter" (or return), causing the input buffer to be completed and sent to the shell, which will parse the first word as the echo command, with the subsequent arguments as text to be printed.
You should see the string "abc def-" echoed -- but not the foo.
This test makes it clear that the string foo was never placed into the input buffer, even though it was sent to the same tty being used for input (and output).
You can try to see if special control characters are recognized and processed; but they won't be. These characters are only being output to the terminal, but not processed.
In order for the special characters to be processed, they have to be received via the socket connected to the input device.
To accomplish what you are trying to do, you'll have to go non-canonical (stty -icanon) and process every character in your code, in order to collect the pending input and also be able to produce asynchronous output.
Alternatively, using nurses is not hard at all, and if you are writing a terminal-based chat program, I would suggest creating at least two panels: a "chat" panel for all output, and an "input" panel for user input. This allows output from other users, as well as the completed commands from the "input" panel, to be received and written to the "chat" panel asynchronously without disturbing the current command in progress by the user in the "input" panel.
This problem maybe a little bit hard to state. For example, a program receive a string from stdin, but it need a interactive input from user, like this:
echo "Some text to handle later after command is specified" | a.out
And in the beginning of the program:
printf("Please input command first");
scanf("%s", &cmd);
/* Some Code Here */
/* process "Some text to handle later after command is specified" */
Is there a way to "suspend" previous input stream and wait for the scanf's ones?
The standard does not specify any way to get interactive user input besides reading from stdin. Since your stdin is occupied with a pipe, you need to tread an implementation-specific path.
For Unix-like systems that would be a special file named /dev/tty. fopen it and use normal stdio functions.
On Windows you probably need to call Console API.
Threre's no guarantee a program is attached to any interactive device, so prepare to fail.
Note that it's considered bad style to write programs this way. If there's any user input expected, a well-witten program should just use stdin. All other input streams should then be passed as filenames via command-line arguments.
When using pipes, the shell sets up the programs stdin to be from the output of the previous command. So reading should not be a problem.
The problem here is that you should not print any output if the input is from a pipe (or redirection). This can be done by checking the result of the isatty function:
if (isatty(fileno(stdin)))
{
/* Only print prompt if input is an interactive terminal */
printf(...);
}
scanf(...);
Or am I misreading you, in that you want to read both from the user, and from the pipe? Then you probably have to open a direct connection to the terminal.
For this you could use ttyname to get the name of the TTY device of stdout and open that device for input to read the user input. That won't work if the stdout is leading to a pipe (or is being redirected) as well.