termsize/termsize.c

125 lines
2.3 KiB
C

/* -*- Mode: C ; c-basic-offset: 2 -*- */
/* termsize - Adjust rows and cols of /dev/tty
to match the size of attached terminal (emulator) */
/* SPDX-FileCopyrightText: Copyright © 2023 Nedko Arnaudov */
/* SPDX-License-Identifier: GPL-3 */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <stdbool.h>
#include <stdlib.h>
#include <limits.h>
#include <errno.h>
int fd;
char buf[256];
struct curpos
{
int row;
int col;
};
void write_asciiz(const char * str)
{
ssize_t sret;
size_t len;
len = strlen(str);
loop:
sret = write(fd, str, len);
if (sret == -1) abort();
str += (size_t)sret;
len -= (size_t)sret;
if (len > 0) goto loop;
}
void get_cursor_position(struct curpos * pos)
{
int i;
char * p;
ssize_t sret;
write_asciiz("\033[6n");
i = 0;
loop:
if (i == sizeof(buf)) abort();
sret = read(fd, buf + i, 1);
if (sret == -1)
{
if (errno == EINTR) goto loop;
abort();
}
if (sret == 0) goto loop;
if (sret != 1) abort();
if (buf[i] == 'R')
{
buf[i] = 0;
if (buf[0] != '\e' || buf[1] != '[') abort();
p = strchr(buf + 2, ';');
if (p == NULL) abort();
*p++ = 0;
pos->row = atoi(buf + 2);
pos->col = atoi(p);
if (pos->row == 0 || pos->col == 0) abort();
return;
}
i++;
goto loop;
}
void set_cursor_position(const struct curpos * pos)
{
sprintf(buf, "\033[%d;%dH", pos->row, pos->col);
write_asciiz(buf);
}
void get_terminal_size(struct curpos * size)
{
struct curpos oldpos;
get_cursor_position(&oldpos);
// TIOCSWINSZ cannot set sizes more than USHRT_MAX anyway
size->row = size->col = USHRT_MAX;
set_cursor_position(size);
get_cursor_position(size);
set_cursor_position(&oldpos);
}
int main(void)
{
struct termios tty_save;
struct termios tty;
struct curpos size;
struct winsize winsize;
fd = open("/dev/tty", O_RDWR);
tcgetattr(fd, &tty_save);
tty = tty_save;
tty.c_lflag &= ~(ICANON|ECHO);
tcsetattr(fd, TCSANOW, &tty);
get_terminal_size(&size);
tcsetattr(fd, TCSANOW, &tty_save);
printf("%d rows, %d cols\n", size.row, size.col);
winsize.ws_row = (unsigned short)size.row;
winsize.ws_col = (unsigned short)size.col;
ioctl(fd, TIOCSWINSZ, &winsize);
}