2009-06-21 26 views
75

Tôi đã tìm kiếm một cách để có được chiều rộng thiết bị đầu cuối từ bên trong chương trình C của tôi. một cái gì đó dọc theo dòng của những gì tôi giữ đến với là:Lấy chiều rộng đầu cuối trong 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); 
} 

Nhưng mọi tôi cố gắng mà tôi nhận được

[email protected]:~$ 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.) 

Đây có phải là cách tốt nhất để làm điều này, hoặc là có một cách tốt hơn? Nếu không làm thế nào tôi có thể làm điều này để làm việc?

EDIT: cố định đang

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

Trả lời

101

bạn đã xem xét sử dụng getenv()? Nó cho phép bạn có được các biến môi trường của hệ thống chứa các cột và dòng đầu cuối.

Ngoài ra sử dụng phương pháp của bạn, nếu bạn muốn xem những gì các hạt nhân xem như kích thước thiết bị đầu cuối (tốt hơn trong trường hợp thiết bị đầu cuối được thay đổi kích cỡ), bạn sẽ cần phải sử dụng TIOCGWINSZ, như trái ngược với TIOCGSIZE của bạn, như vậy:

struct winsize w; 
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); 

và mã đầy đủ:

#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 
} 
+4

vâng nhưng độ dài cụm không phải là biến môi trường, tĩnh của thuật ngữ đó theo thuật ngữ. – austin

+4

Nó không cung cấp cho bạn kích thước thiết bị đầu cuối _current_, nếu ai đó định lại kích thước thiết bị đầu cuối trong quá trình thực thi chương trình. –

+0

vâng, đã thêm rằng :) –

0

Giả sử bạn đang trên Linux, tôi nghĩ rằng bạn muốn sử dụng thư viện ncurses để thay thế. Tôi khá chắc chắn các công cụ ttysize bạn có không phải là trong stdlib.

+0

tốt, những gì tôi đang làm là không thực sự đáng giá thiết lập ncurses cho – austin

+0

ncurses không phải là trong stdlib hoặc. Cả hai đều được chuẩn hóa trong POSIX, nhưng cách 'ioctl' đơn giản và rõ ràng hơn, bởi vì bạn không phải khởi tạo các lời nguyền, v.v. – Gandaro

2

Nếu bạn đã cài đặt và sử dụng ncurses, bạn có thể sử dụng getmaxyx() để tìm kích thước của thiết bị đầu cuối.

+1

Có, và lưu ý rằng Y đến trước và sau đó biến môi trường X. – Daniel

-1

Sau đây là các chức năng đòi hỏi phải điều biến môi trường đã đề nghị:

int lines = atoi(getenv("LINES")); 
int columns = atoi(getenv("COLUMNS")); 
+8

không đáng tin cậy.Các giá trị này được đặt bởi trình bao, do đó chúng không được bảo đảm để tồn tại. Ngoài ra, chúng sẽ không được cập nhật nếu người dùng thay đổi kích thước thiết bị đầu cuối. – Juliano

+0

Nhiều shell thiết lập một trình xử lý cho tín hiệu 'SIGWINCH', vì vậy chúng có thể giữ cho các biến được cập nhật (chúng cũng cần nó để chúng có thể thực hiện gói dòng thích hợp trong trình soạn thảo đầu vào). – Barmar

+1

Họ cũng có thể làm điều đó, nhưng môi trường của chương trình sẽ không được cập nhật khi nó đang chạy. – Functino

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

Cần phải được biên soạn với -ltermcap. Có rất nhiều thông tin hữu ích khác mà bạn có thể sử dụng termcap. Kiểm tra sổ tay termcap bằng cách sử dụng info termcap để biết thêm chi tiết.

+0

Bạn cũng có thể biên dịch nó với các -lý do. – Kambus

+0

Tôi không thể bao gồm termcap trong Ubuntu 14.04 và không thể tìm thấy nó trong kho lưu trữ. :/ –

+1

Tôi biết nhận xét này đến 6 năm sau khi thực tế, nhưng hãy giải thích số ma thuật của bạn 2048 ... – einpoklum

15

Ví dụ này hơi lệch về phía dài, nhưng tôi tin rằng đó là cách di động nhất để phát hiện thứ nguyên thiết bị đầu cuối. Điều này cũng xử lý các sự kiện thay đổi kích thước.

Vì tim và rlbond gợi ý, tôi đang sử dụng ncurses. Nó đảm bảo một sự cải tiến tuyệt vời trong tính tương thích thiết bị đầu cuối so với các biến môi trường đọc trực tiếp.

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

Nhưng nó thực sự an toàn để gọi initscr và endwin từ một bộ xử lý tín hiệu? Chúng ít nhất không được liệt kê trong số các API async-signal-safe trong 'man 7 signal' – nav

+1

Đó là một điểm tốt @nav, tôi đã * không bao giờ * nghĩ về điều đó! Sẽ là một giải pháp tốt hơn có lẽ là để có xử lý tín hiệu nâng cao một lá cờ, và sau đó thực hiện phần còn lại của các hoạt động trong vòng lặp chính? – gamen

+1

@ gamen, vâng, điều đó sẽ tốt hơn;) - cũng sử dụng sigaction thay vì tín hiệu cũng sẽ tốt hơn. –

Các vấn đề liên quan