Я искал способ получить ширину терминала из моей программы C. Я продолжаю придумывать что-то вроде:
#include <sys/ioctl.h>
#include <stdio.h>
int main (void)
{
struct ttysize ts;
ioctl(0, TIOCGSIZE, &ts);
printf ("lines %d\n", ts.ts_lines);
printf ("columns %d\n", ts.ts_cols);
}
Но каждый раз, когда я пытаюсь это сделать, я получаю
austin@:~$ gcc test.c -o test
test.c: In function ‘main’:
test.c:6: error: storage size of ‘ts’ isn’t known
test.c:7: error: ‘TIOCGSIZE’ undeclared (first use in this function)
test.c:7: error: (Each undeclared identifier is reported only once
test.c:7: error: for each function it appears in.)
Это лучший способ сделать это или есть лучший способ? Если нет, как я могу заставить это работать?
РЕДАКТИРОВАТЬ: фиксированный код
#include <sys/ioctl.h>
#include <stdio.h>
int main (void)
{
struct winsize w;
ioctl(0, TIOCGWINSZ, &w);
printf ("lines %d\n", w.ws_row);
printf ("columns %d\n", w.ws_col);
return 0;
}
Ответы:
Вы рассматривали возможность использования getenv () ? Это позволяет вам получить системные переменные среды, которые содержат столбцы и строки терминалов.
В качестве альтернативы, используя ваш метод, если вы хотите увидеть, что ядро видит в качестве размера терминала (лучше, если размер терминала изменен), вам нужно будет использовать TIOCGWINSZ, а не ваш TIOCGSIZE, например:
struct winsize w; ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
и полный код:
#include <sys/ioctl.h> #include <stdio.h> #include <unistd.h> int main (int argc, char **argv) { struct winsize w; ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); printf ("lines %d\n", w.ws_row); printf ("columns %d\n", w.ws_col); return 0; // make sure your main returns int }
источник
ws_xpixel
иws_ypixel
, но он просто печатает нули!Этот пример немного длинноват, но я считаю, что это наиболее удобный способ определения размеров терминала. Это также обрабатывает события изменения размера.
Как предлагают тим и rlbond, я использую ncurses. Это гарантирует значительное улучшение совместимости терминала по сравнению с прямым чтением переменных среды.
#include <ncurses.h> #include <string.h> #include <signal.h> // SIGWINCH is called when the window is resized. void handle_winch(int sig){ signal(SIGWINCH, SIG_IGN); // Reinitialize the window to update data structures. endwin(); initscr(); refresh(); clear(); char tmp[128]; sprintf(tmp, "%dx%d", COLS, LINES); // Approximate the center int x = COLS / 2 - strlen(tmp) / 2; int y = LINES / 2 - 1; mvaddstr(y, x, tmp); refresh(); signal(SIGWINCH, handle_winch); } int main(int argc, char *argv[]){ initscr(); // COLS/LINES are now set signal(SIGWINCH, handle_winch); while(getch() != 27){ /* Nada */ } endwin(); return(0); }
источник
man 7 signal
OK
иERR
. Как «добрые» с их стороны помочь нам заполнить этот пробел в нашей жизни :-(#include <stdio.h> #include <stdlib.h> #include <termcap.h> #include <error.h> static char termbuf[2048]; int main(void) { char *termtype = getenv("TERM"); if (tgetent(termbuf, termtype) < 0) { error(EXIT_FAILURE, 0, "Could not access the termcap data base.\n"); } int lines = tgetnum("li"); int columns = tgetnum("co"); printf("lines = %d; columns = %d.\n", lines, columns); return 0; }
Необходимо компилировать с
-ltermcap
. Есть много другой полезной информации, которую вы можете получить с помощью termcap. Обратитесь к руководству по termcapinfo termcap
для получения более подробной информации.источник
Если у вас установлен ncurses и вы его используете, вы можете использовать его
getmaxyx()
для определения размеров терминала.источник
Предполагая, что вы работаете в Linux, я думаю, вы захотите вместо этого использовать библиотеку ncurses . Я почти уверен, что у вас есть материал ttysize, которого нет в stdlib.
источник
ioctl
способ проще и чище, потому что вам не нужно инициализировать проклятия и т. Д.Так что не предлагая здесь ответа, но:
linux-pc:~/scratch$ echo $LINES
49
linux-pc:~/scratch$ printenv | grep LINES
linux-pc:~/scratch$
Хорошо, и я заметил, что если я изменю размер терминала GNOME, переменные LINES и COLUMNS последуют за этим.
Похоже, что терминал GNOME сам создает эти переменные среды?
источник
Чтобы добавить более полный ответ, я обнаружил, что для меня работает решение @ John_T с некоторыми битами, добавленными из кода Rosetta , а также с некоторыми устранениями неполадок, выясняющих зависимости. Это может быть немного неэффективно, но с умным программированием вы можете заставить его работать и не открывать файл терминала все время.
#include <stdio.h> #include <stdlib.h> #include <sys/ioctl.h> // ioctl, TIOCGWINSZ #include <err.h> // err #include <fcntl.h> // open #include <unistd.h> // close #include <termios.h> // don't remember, but it's needed size_t* get_screen_size() { size_t* result = malloc(sizeof(size_t) * 2); if(!result) err(1, "Memory Error"); struct winsize ws; int fd; fd = open("/dev/tty", 0_RDWR); if(fd < 0 || ioctl(fd, TIOCGWINSZ, &ws) < 0) err(8, "/dev/tty"); result[0] = ws.ws_row; result[1] = ws.ws_col; close(fd); return result; }
Если вы убедитесь, что не вызываете его все, но, возможно, время от времени все будет в порядке, он должен даже обновляться, когда пользователь изменяет размер окна терминала (потому что вы открываете файл и читаете его каждый раз).
Если вы не используете,
TIOCGWINSZ
см. Первый ответ в этой форме https://www.linuxquestions.org/questions/programming-9/get-width-height-of-a-terminal-window-in-c-810739/ .О, и не забывайте
free()
оresult
.источник
Вот вызовы функций для уже предложенной переменной окружения:
int lines = atoi(getenv("LINES")); int columns = atoi(getenv("COLUMNS"));
источник
SIGWINCH
сигнала, чтобы они могли поддерживать переменные в актуальном состоянии (они также нуждаются в этом, чтобы они выполняли надлежащий перенос строк в редакторе ввода).getenv()
возвращает ли NULL или нет, и это происходит в моем терминале Linux (потому что эти переменные не экспортируются). Также, даже если оболочка обновляет эти переменные, вы не увидите изменяется во время работы вашей программы (не без вашего собственногоSIGWINCH
обработчика).