2009-06-21 20 views
75

He estado buscando una manera de obtener el ancho del terminal desde mi programa C. Lo que sigo viniendo para arriba es algo a lo largo de las líneas de:Obtener el ancho del terminal en 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); 
} 

Pero cada vez que intento que consigo

[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.) 

¿Es esta la mejor manera de hacer esto, o hay una mejor manera? Si no, ¿cómo puedo hacer que esto funcione?

EDIT: fijo código es

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

Respuesta

101

¿Ha considerado el uso de getenv()? Le permite obtener las variables de entorno del sistema que contienen las columnas y líneas de los terminales.

alternativa mediante su método, si usted quiere ver lo que ve el núcleo como el tamaño del terminal (mejor en la terminal caso se cambia el tamaño), que tendría que utilizar TIOCGWINSZ, en contraposición a su TIOCGSIZE, así:

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

y el código completo:

#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

sí, pero el término ancho no es una variable ambiental, es estático para el término. – austin

+4

No le proporciona el tamaño del terminal _corrent_, si alguien cambia el tamaño del terminal durante la ejecución del programa. –

+0

Sí, estaba agregando eso :) –

0

Suponiendo que está en Linux, creo que desea utilizar la biblioteca ncurses lugar. Estoy bastante seguro de que las cosas que tienes no están en stdlib.

+0

bueno, lo que estoy haciendo realmente no vale la pena configurar ncurses para – austin

+0

ncurses tampoco está en stdlib. Ambos están estandarizados en POSIX, pero el modo 'ioctl' es más simple y más limpio, porque no tiene que inicializar las maldiciones, etc. – Gandaro

2

Si tiene ncurses instalado y lo está usando, puede usar getmaxyx() para encontrar las dimensiones del terminal.

+1

Sí, y tenga en cuenta que la Y es la primera y luego la X. – Daniel

-1

Estas son las llamadas de función de la variable ambiental que ya se ha sugerido:

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

Las variables de entorno no son de confianza.Estos valores son establecidos por el shell, por lo que no se garantiza que existan. Además, no estarán actualizados si el usuario cambia el tamaño del terminal. – Juliano

+0

Muchos shells establecen un controlador para la señal 'SIGWINCH', por lo que pueden mantener las variables actualizadas (también lo necesitan para que puedan realizar el ajuste de línea correcto en el editor de entrada). – Barmar

+1

Es muy posible que lo hagan, pero el entorno de un programa no se actualizará mientras se está ejecutando. – 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; 
} 

necesita ser compilado con -ltermcap. Hay mucha otra información útil que puede obtener usando termcap. Consulte el manual de termcap usando info termcap para más detalles.

+0

Puedes compilarlo con -lcurses también. – Kambus

+0

No puedo incluir termcap en Ubuntu 14.04 y tampoco puedo encontrarlo en los repositorios. :/ –

+1

Sé que este comentario viene 6 años después del hecho, pero por favor explique su número mágico de 2048 ... – einpoklum

15

Este ejemplo es un poco largo, pero creo que es la manera más portátil de detectar las dimensiones de la terminal. Esto también maneja eventos de cambio de tamaño.

Como sugieren tim y rlbond, estoy usando ncurses. Garantiza una gran mejora en la compatibilidad del terminal en comparación con las variables del entorno de lectura directamente.

#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

¿Pero es realmente seguro llamar a initscr y endwin desde un manejador de señal? Por lo menos no están enlistados entre las API de señal asíncrona segura en 'man 7 signal' – nav

+1

Ese es un buen punto @nav, ¡nunca * he pensado * en eso! ¿Sería una mejor solución que el manejador de señal levantara una bandera y luego realizara el resto de las operaciones en el ciclo principal? – gamen

+1

@gamen, sí, eso sería mejor;) - también sería mejor usar también sigaction en lugar de señal. –

Cuestiones relacionadas