HiveBrain v1.2.0
Get Started
← Back to all entries
patterncModerate

Non-curses pager in C

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
pagercursesnon

Problem

I have written a pager in C that is supposed to be used in systems where curses is not installed (or broken). It can also be used as a system-wide pager, it works with man pages (only on BSD, though). I want to spot any portability or output problems, as there may be some due to the dependence on buffered input:

#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.
 * Written by Daniel Roskams, in the public domain
 */

int
main(
    int argc,
    char *argv[])
{
    FILE *fp;
    int ch;

    if (argc < 2) {
        fp = stdin;
    } else if ((fp = fopen(argv[1], "r")) == NULL) {
        perror(argv[1]);
        return EXIT_FAILURE;
    }

    while ((ch = fgetc(fp)) != EOF) {
        if (ch == '\n') {
            getchar();
        } else {
            putchar(ch);
        }
    }

    if (ferror(fp)) {
        perror(argv[1]);
        return EXIT_FAILURE;
    }

    fclose(fp);
    return EXIT_SUCCESS;
}


I don't think there are any code problems themselves, since it compiles with the -Weverything flag with clang.

Solution

Bug

You're code has a bug-ish. When using this, if instead of hitting enter when asked to enter a character you enter some other letter and then you press enter, then next newline will be skipped and you will have two lines merged into one:

Fooa
BarHello, World!
Spama
Eggs


where the text file was:

Foo
Bar
Hello, World!
Spam
Eggs


To be honest, I'm not quite sure which line this is occurring on, but I think it has something to do with the getchar() call; when I pressed a, the next line was printed out.
Bug #2

Using the same file as above but this time passing it through STDIN like so:

./a.out < Foo


I got this as a result:

Fooarello, World!pamggs


I didn't touch the keyboard at all; it just flew through the file. I don't think this is intended.

However, this time, I think I know why. It's this line:

getchar();


When the end of a line is reached, then this is called. However, since the file you are reading is from stdin and getchar() also reads from stdin, then this call is going to remove the next character from the file.

See the input again, but with the characters removed by getchar:

FoobarHello, World!spameggs

The bolded characters are the characters that appeared after each newline.

Code Snippets

Fooa
BarHello, World!
Spama
Eggs
Foo
Bar
Hello, World!
Spam
Eggs
./a.out < Foo
Fooarello, World!pamggs

Context

StackExchange Code Review Q#113225, answer score: 12

Revisions (0)

No revisions yet.