Skip to content

Instantly share code, notes, and snippets.

@samrat samrat/pager.c
Last active Oct 29, 2019

Embed
What would you like to do?
#include <unistd.h>
#include <stdio.h>
#include <sys/wait.h>
#include <errno.h>
#include <stdlib.h>
/* Usage:
$ clang -o pager main.c
$ ./pager 200
*/
#define READ_END 0
#define WRITE_END 1
void perror_die(char* msg) {
perror(msg);
exit(EXIT_FAILURE);
}
void print_n_lines(int n) {
for (int i = 0; i < n; i++) {
printf("%d\n", i);
}
}
int main(int argc, char *argv[]) {
int fds[2];
if (pipe(fds) == -1) {
perror_die("pipe");
}
int child_pid = fork();
switch (child_pid) {
case -1: {
/* fork failed */
perror_die("fork");
break;
}
case 0: { /* Child(pager) */
/* Pager process doesn't write to pipe */
close(fds[WRITE_END]);
/* Make READ_END of pipe pager's STDIN */
dup2(fds[READ_END], STDIN_FILENO);
/* F -> quit-if-one-screen */
/* R -> preserve color formatting */
/* X -> don't send some special instructions eg. to clear terminal screen before starting */
char *less_argv[] = {"less", "-FRX", NULL};
int exec_status = execvp(less_argv[0], less_argv);
fprintf(stderr,
"execvp failed with status: %d and errno: %d\n", exec_status, errno);
break;
}
default: { /* Parent */
/* STDOUT is now fds[WRITE_END] */
dup2(fds[WRITE_END], STDOUT_FILENO);
/* parent doesn't read from pipe */
close(fds[READ_END]);
/* "Business" logic which determines what to actually print */
int num_lines = 1024;
if (argc > 1) {
num_lines = atoi(argv[1]);
}
print_n_lines(num_lines);
fflush(stdout);
/* Signal EOF to the pager process */
close(STDOUT_FILENO);
int stat_loc;
waitpid(child_pid, &stat_loc, 0);
break;
}
}
}
@The-King-of-Toasters

This comment has been minimized.

Copy link

The-King-of-Toasters commented Oct 29, 2019

This example didn't work for me until I flushed all output in the buffer before the call to close(2).
fflush(stdout) did the trick.

@samrat

This comment has been minimized.

Copy link
Owner Author

samrat commented Oct 29, 2019

Thanks, fixed.

@The-King-of-Toasters

This comment has been minimized.

Copy link

The-King-of-Toasters commented Oct 29, 2019

Actually, for this purpose it's better to call fdopen() for fds[1], use that for fprintf and call fclose at the end.

I experimented with this here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.