#include <err.h>
#include <signal.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <sys/ioctl.h>

static void
print_winsize(int fd)
{
	struct winsize size;
	if (ioctl(fd, TIOCGWINSZ, (char *) &size) < 0)
		err(EXIT_FAILURE, "ioctl(TIOCGWINSZ)");
	printf("%d %d\n", size.ws_row, size.ws_col);
}

static sig_atomic_t should_exit;

static void
handler(int signo)
{
	if (signo == SIGHUP)
		should_exit = 1;
}

int main(void)
{
	if (!isatty(STDIN_FILENO))
		errx(EXIT_FAILURE, "stdin must be a tty");

	// Block SIGWINCH and SIGHUP until we explicitly unblock with `sigsuspend`.
        sigset_t mask;
        sigemptyset(&mask);
        sigaddset(&mask, SIGHUP);
        sigaddset(&mask, SIGWINCH);
        if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0)
            err(EXIT_FAILURE, "sigprocmask(SIG_BLOCK, ..)");

	// Register a signal handler for SIGWINCH. The default disposition for
	// SIGWINCH is to ignore it. We set up an empty handler that will break
	// us out of the sigsuspend, which is different than ignoring the
	// signal.
	struct sigaction sa;
	sa.sa_handler = handler;
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = 0;
	if (sigaction(SIGWINCH, &sa, NULL) < 0)
		err(EXIT_FAILURE, "sigaction");

	// Register a signal handler for SIGHUP. This will tell us when to exit.
	if (sigaction(SIGHUP, &sa, NULL) < 0)
		err(EXIT_FAILURE, "sigaction");

	// Loop printing the window size when it changes. We print the window
	// size the first time through to signal the test that it can change
	// the window size. We initialize `mask` with the empty mask, then call
	// `sigsuspend`. This is like `pause`, except it unblocks signals. In
	// this case, we unblock SIGWINCH. Importantly, SIGWINCH will be
	// re-blocked when the signal handler is called, and also when
	// sigsuspend returns. Since we don't print the window size again until
	// after SIGWINCH has already been blocked, we know the test won't
	// resize the window until the signal is blocked.
	sigemptyset(&mask);
	while (!should_exit) {
	    print_winsize(STDIN_FILENO);
            sigsuspend(&mask);
        }
}
