web-dev-qa-db-fra.com

Obtenir la largeur du terminal en C?

Je cherchais un moyen d'obtenir la largeur du terminal à partir de mon programme C. Ce que je continue de proposer, c'est quelque chose comme:

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

Mais à chaque fois que j'essaye

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

Est-ce la meilleure façon de procéder ou existe-t-il une meilleure solution? Sinon, comment puis-je faire en sorte que cela fonctionne?

EDIT: le code fixe est

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

Avez-vous envisagé d'utiliser getenv () ? Il vous permet d'obtenir les variables d'environnement du système qui contiennent les colonnes et les lignes des terminaux.

Alternativement, en utilisant votre méthode, si vous voulez voir ce que le noyau voit comme la taille du terminal (mieux dans le cas où le terminal est redimensionné), vous devrez utiliser TIOCGWINSZ, par opposition à votre TIOCGSIZE, comme ceci:

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

et le code complet:

#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
}
115
John T

Cet exemple est un peu long, mais je pense que c'est la façon la plus portable de détecter les dimensions du terminal. Cela gère également les événements de redimensionnement.

Comme le suggèrent tim et rlbond, j'utilise ncurses. Il garantit une grande amélioration de la compatibilité des terminaux par rapport à la lecture directe des variables d'environnement.

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

Doit être compilé avec -ltermcap. Il existe de nombreuses autres informations utiles que vous pouvez obtenir en utilisant termcap. Consultez le manuel termcap à l'aide de info termcap pour plus de détails.

12
Juliano

Si ncurses est installé et que vous l'utilisez, vous pouvez utiliser getmaxyx() pour trouver les dimensions du terminal.

2
rlbond

Donc, ne suggérant pas de réponse ici, mais:

linux-pc:~/scratch$ echo $LINES

49

linux-pc:~/scratch$ printenv | grep LINES

linux-pc:~/scratch$

Ok, et je remarque que si je redimensionne le terminal GNOME, les variables LINES et COLUMNS suivent cela.

Il semble que le terminal GNOME crée lui-même ces variables d'environnement?

0
Scott Franco

En supposant que vous êtes sous Linux, je pense que vous souhaitez utiliser la bibliothèque ncurses à la place. Je suis à peu près sûr que le contenu que vous avez n'est pas dans stdlib.

0
tim