用 C 表示终端宽度? ?

我一直在寻找一种方法,从我的 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;
}
100415 次浏览

你考虑过使用 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
}

假设您使用的是 Linux,我认为您希望使用 诅咒库 我很确定你的 ttysize 文件不在 stdlib 中。

如果您安装了 ncurses 并正在使用它,则可以使用 getmaxyx()查找终端的尺寸。

下面是对已经建议的环境变量的函数调用:

int lines = atoi(getenv("LINES"));
int columns = atoi(getenv("COLUMNS"));
#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 可以获得许多其他有用的信息。有关更多细节,请使用 info termcap查看 termcap 手册。

这个例子有点冗长,但我相信它是检测终端尺寸的最便携的方法。这也可以处理调整大小事件。

就像 Tim 和 rlbond 说的,我用的是护士咒语。与直接读取环境变量相比,它保证了终端的兼容性有很大的提高。

#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);
}

要添加一个更完整的答案,我发现可以使用@John _ T 的解决方案,从 罗塞塔密码中添加一些位,并进行一些解决依赖关系的故障排除。它可能有点低效,但是使用智能编程,您可以让它工作,而不是一直打开您的终端文件。

#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

My Version Is An extermination of the ioctl approach I am not allocating memory and passing the struct back by value I believe so no memory leaks here

头文件

#include <stdlib.h>
#include <sys/ioctl.h> // ioctl, TIOCGWINSZ


struct winsize get_screen_size();


unsigned short get_screen_width();
unsigned short get_screen_height();


void test_screen_size();

在实现中,我还添加了一个测试函数,它在终端中填充了一个由一个字符填充的框

/**
* Implementation of nos_utils signatures
*/


#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>   // doesnt seem to be needed for this
#include "nos_utils.h"


/**
* @return  struct winsize
*  unsigned short int ws_row;
*   unsigned short int ws_col;
*   unsigned short int ws_xpixel;
*   unsigned short int ws_ypixel;
*/
struct winsize get_screen_size() {
struct winsize ws;
int fd;


fd = open("/dev/tty", O_RDWR);
if (fd < 0 || ioctl(fd, TIOCGWINSZ, &ws) < 0) err(8, "/dev/tty");
close(fd); // dont forget to close files
return ws;
}


unsigned short get_screen_width() {
struct winsize ws = get_screen_size();
return ws.ws_col;
}


unsigned short get_screen_height() {
struct winsize ws = get_screen_size();
return ws.ws_row;
}


void test_screen_size() {
struct winsize ws = get_screen_size();
//    unsigned short  h = ws.ws_row;
//    unsigned short  w = ws.ws_col;
printf("The Teminal Size is\n rows: %zu  in %upx\n cols: %zu in %upx\n", ws.ws_row, ws.ws_ypixel, ws.ws_col,
ws.ws_xpixel);
    

unsigned short  h = get_screen_height();
unsigned short  w = get_screen_width();
h = h - 4; //for the 3 lines above + 1 fro new terminal line after :)
for (unsigned short  i = 0; i < h; i++) {// for each row
for (unsigned short  j = 0; j < w; j++) { // for each col
//new line if we are last char
if (j == w - 1) {
printf(" \n");
}//one space buffer around edge
else if (i == 0 || i == h - 1 || j == 0) {
printf(" ");
} //the up arrows
else if (i == 1) {
printf("^");
} else if (i == h - 2) {
printf("v");
} else if (j == 1) {
printf("<");
} else if (j == w - 2) {
printf(">");
} else {
printf("#");
}
}//end col
}//end row
}


int main(int argc, char** argv) {
test_screen_size();
return 0;
}


running test