#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/ioctl.h>

struct termios  saved_attributes;
int             saved_fl;

void tty_raw()
{
    struct termios tattr;

    fcntl(0,F_GETFL,&saved_fl);
    tcgetattr(0, &saved_attributes);

    fcntl(0,F_SETFL,O_NONBLOCK);
    memcpy(&tattr,&saved_attributes,sizeof(struct termios));
    tattr.c_lflag &= ~(ICANON|ECHO);
    tattr.c_cc[VMIN] = 1;
    tattr.c_cc[VTIME] = 0;
    tcsetattr(0, TCSAFLUSH, &tattr);
}

void tty_restore()
{
    fcntl(0,F_SETFL,saved_fl);
    tcsetattr(0, TCSANOW, &saved_attributes);
}

int select_wait()
{
    struct timeval  tv;
    fd_set          se;

    FD_ZERO(&se);
    FD_SET(0,&se);
    tv.tv_sec = 3;
    tv.tv_usec = 0;
    return select(1,&se,NULL,NULL,&tv);
}

int main(int argc, char **argv)
{
    // as a side effect, the scrolling region is set to the entire screen
    static char *teststr = "\e7\e[r\e[999E\e[999C";
    static char *cleanup = "\e8";
    static char *getpos  = "\033[6n";
    char retstr[16];
    int pos,rc,row,col;
    struct winsize ws;

    if (!isatty(0) || !isatty(1))
        exit(2);

    tty_raw();
    write(1,teststr,strlen(teststr));
    write(1,getpos,strlen(getpos));
    for (pos = 0; pos < sizeof(retstr)-1;)
    {
        if (0 == select_wait())
            break;
        if (-1 == (rc = read(0,retstr+pos,sizeof(retstr)-1-pos)))
        {
            perror("read");
            exit(2);
        }
        pos += rc;
        if (retstr[pos-1] == 'R')
            break;
    }
    retstr[pos] = 0;
    write(1,cleanup,strlen(cleanup));
    tty_restore();

    rc = sscanf(retstr,"\033[%d;%dR",&row,&col);
    printf("Terminal size: %dx%d\n", col, row);
    memset(&ws, 0, sizeof(struct winsize));
    ioctl(1,TIOCGWINSZ,&ws);
    ws.ws_row=row;
    ws.ws_col=col;
    ioctl(1,TIOCSWINSZ,&ws);
    exit(0);
}
