patterncMinor
Non-curses pager in C (revision 2)
Viewed 0 times
pagercursesrevisionnon
Problem
In this revision (follow-up of this post) I've fixed reading from stdin, and also tried to minimise the damage caused by typing additional characters. You might want to see my original post on this.
Some questions:
#include
#include
/*
* A very SIMPLE pager that does not require curses. If your curses library
* is broken, this is practically the only portable one you can easily get.
*/
int
main(
int argc,
char *argv[])
{
FILE *fp;
FILE *tty;
int ch;
if (argc < 2) {
fp = stdin;
} else if ((fp = fopen(argv[1], "r")) == NULL) {
perror(argv[1]);
return EXIT_FAILURE;
}
if ((tty = fopen("/dev/tty", "r")) == NULL) {
perror("/dev/tty");
return EXIT_FAILURE;
}
while ((ch = fgetc(fp)) != EOF) {
if (ch == '\n') {
while (fgetc(tty) != '\n');
} else {
putchar(ch);
}
}
if (ferror(fp)) {
perror(argv[1]);
return EXIT_FAILURE;
}
fclose(fp);
return EXIT_SUCCESS;
}Some questions:
- How can I avoid having to read from /dev/tty? I know that the device file is available on practically all Unixes, but it won't work on Windows.
- Also, I want to avoid dependency on any library except standard C.
Solution
Making the code portable again
You did a fine job cleaning up last code's bugs. My answer will be fairly short this time.
How can I avoid having to read from /dev/tty? I know that the device
file is available on practically all Unixes, but it won't work on
Windows.
Well, I have some good news and some bad news.
Bad News
The bad news is that I'm pretty sure the only way you aren't going to get that bug where you substitute the file for
You can stop now. As a quick and smart fix, you can drop support for reading from STDIN (I mean, who would use a pager to read something they are typing into STDIN?). Or, if you want you can read on for the good news.
Good News
There's a solution that allows you to keep on reading from
Now, you may think to just include the
An easy fix is to use the pre-processor:
This will make sure to only include the
Then, in the section where you would normally open and read from the
and the Windows code in the respective pre-processor statements.
As for what actually goes inside the Windows code sections, I am unsure. Through some quick searching, I came across
You did a fine job cleaning up last code's bugs. My answer will be fairly short this time.
How can I avoid having to read from /dev/tty? I know that the device
file is available on practically all Unixes, but it won't work on
Windows.
Well, I have some good news and some bad news.
Bad News
The bad news is that I'm pretty sure the only way you aren't going to get that bug where you substitute the file for
STDIN is if you continue reading from /dev/tty. After all, you can't possibly read from STDIN because that's where the file is.You can stop now. As a quick and smart fix, you can drop support for reading from STDIN (I mean, who would use a pager to read something they are typing into STDIN?). Or, if you want you can read on for the good news.
Good News
There's a solution that allows you to keep on reading from
/dev/tty and that is to use the amazing Windows API. Luckily, you can do that in C because Windows provides a header file windows.h that gives you full access to the Windows API in your C/C++ code.Now, you may think to just include the
windows.h file in your code and use whatever the API has to read the keyboard. Well, you can't quite do that because if you try compiling that on *nix, you'll get an error saying that the windows.h could not be found.An easy fix is to use the pre-processor:
#include
#include
#ifdef _WIN32
#include
#endifThis will make sure to only include the
windows.h file if the operating system is a Windows one.Then, in the section where you would normally open and read from the
/dev/tty file, you would encase that in:#ifdef linux
...
#endifand the Windows code in the respective pre-processor statements.
As for what actually goes inside the Windows code sections, I am unsure. Through some quick searching, I came across
ReadConsole in the API index. However, I have not tested it out. If that does not work, feel free to explore the API for other possibilities.Code Snippets
#include <stdio.h>
#include <stdlib.h>
#ifdef _WIN32
#include <windows.h>
#endif#ifdef linux
...
#endifContext
StackExchange Code Review Q#113229, answer score: 2
Revisions (0)
No revisions yet.