Programmare con la Libreria Ncurses

L’interfaccia utente di un programma Linux appartiene a una di queste categorie:

  • linea di comando
  • testuale
  • grafica

Nel primo caso l’utente può interagire con il programma quasi esclusivamente passandogli una serie di parametri ( ls, cp, rm, mv, … ). I programmi del secondo tipo sono quelli che sfruttano la console corredata di accorgimenti grafici come colore e possibilità di spostare il cursore su vari campi ( vi, nano, … ). Il terzo tipo sono tutti quelli che sfruttano il pixel e non più il carattere ( firefox, gedit, vim-gtk, … ). Per un utilizzatore la semplicità migliora passando dalla prima alle successive, mentre per il programmatore avviene il processo inverso, la difficoltà aumenta all’aumentare delle caratteristiche grafiche. Un programma a linea di comando è molto più semplice da creare perché evita la programmazione dell’interfaccia utente. La difficoltà in Linux aumenta perché esistono vari tipi di terminale, tutti con dei propri comandi e sono incompatibili tra loro. La libreria ncurses nasce proprio per questa esigenza, cercando di uniformare la programmazione per programmi testuali su terminale. L’uso di un tipo di programmazione di questo genere sembrerebbe superato, ma è ancora un ottimo compromesso tra la semplicità della linea di comando e la complicazione dell’interfaccia grafica completa, pensiamo ai server Linux da amministrare tramite ssh. Come ambiente di sviluppo prenderemo una Linux Ubuntu 10.04 su macchina virtuale, il compilatore GCC versione 4.4.3 ed il pacchetto ncursesw-dev installato. Ncurses è nata come implementazione free di curses, presente in UNIX versione System V a sua volta nata come miglioramento della curses BSD. Il suo sviluppo è avvenuto in ambiente Linux anche se ogni ambiente UNIX-like dovrebbe compilarla. La presenza di una libreria come ncurses appare chiara dalla storia di UNIX; all’inizio c’era solo l’unità centrale con tanti terminali seriali collegati e la console dell’amministratore. I tipi di terminali erano molteplici ed ognuno di essi necessitava di comandi specifici, ad esempio per spostare il cursore o pulire lo schermo. Nei terminali compatibili VT100 il comando ESC+{2J cancella lo schermo, ESC+{2K cancella la riga corrente o ESC+c che resetta il terminale.
Nacque così il database termcap, un file ASCII presente in /etc/termcap. La sigla termcap significa Terminal Capabilities ed ogni record descrive i comandi per ogni modello di terminale, grazie a termcap è quindi possibile scrivere programmi indipendenti dal tipo, basta inserire il proprio terminale nella variabile d’ambiente TERM. Ncurses in realtà non usa termcap, ma una sua implementazione più moderna: terminfo. Il database terminfo ha gli stessi compiti di quello termcap, ma è più efficiente e permette di descrivere meglio i terminali, in Linux Ubuntu 10.04 si trova in /usr/share/terminfo ed è organizzato in directory ed utilizza un formato binario e non ASCII. Visto che esistono funzioni per interfacciarsi direttamente ai database termcap o terminfo, perché creare ncurses? La libreria ncurses è ottimizzata per la velocità di visualizzazione dei caratteri sullo schermo, oggi non molto importante, ma un tempo si, pensate che per aggiornare una schermata su un vecchio terminale occorrevano anche una decina di secondi e talvolta anche più. Oltre all’ottimizzazione della velocità di output  alcune caratteristiche salienti di ncurses sono:

  • gestione delle finestre, ovvero di porzioni rettangolari dello schermo che racchiudono informazioni
  • gestione dei colori, se supportati dal terminale
  • gestione del mouse attraverso gpm nelle console testuali o anche all’interno di xterm nell’ambiente grafico X

Nel nostro ambiente di sviluppo che ho citato in precedenza, per utilizzare e programmare con la libreria ncurses dobbiamo includere il file curses.h che risiede nella directory /usr/include/ncursesw ed inoltre dobbiamo compilare con l’opzione -lncursesw per includere la libreria nel compilatore.
Ncurses opera su porzioni rettangolari di schermo dette finestre, che possono essere due:

  • curscr – rappresenta cosa c’è al momento sullo schermo del terminale e non dovrebbe essere mai utilizzata dal programmatore
  • stdscr – rappresenta il contenuto che dovrà essere mostrato al prossimo aggiornamento

Tutte le funzioni che utilizzeremo lavorano quindi su stdscr e durante l’aggiornamento dello schermo ncurses confronterà stdscr con curscr per trasmettere al terminale solo le porzioni differenti, cercando di ottimizzare il numero di caratteri inviati. Ricordo che scrivendo su stdscr non verrà visualizzato nulla sullo schermo, ma questo avverrà richiamando la funzione refresh(), inoltre non è possibile mischiare funzioni tipo printf del C che operano sullo schermo, ncurses possiede delle proprie funzioni similari a quelle standard.
Le funzioni della libreria si possono suddividere in quattro grandi categorie:

  • inizializzazione
  • output
  • input
  • chiusura

Per utilizzare le funzioni della libreria occorre allocare lo spazio per i vari buffer, come quelli delle finestre, con la funzione initscr(), per chiudere ncurses e ritornare alla modalità predefinita basta richiamare la funzione endwin().

// File ncur.c

#include "ncursesw/curses.h"

void main()
{
     initscr();
     addstr("Hello World con Ncurses!\n\n");
     addstr("Premere un tasto, per uscire da Ncurses...");
     getch();
     refresh();
     endwin();
}

Per compilare questo piccolo programma occorre dare il comando:

gcc -o ncur ncur.c -lncursesw

Nell’esempio ho inizializzato la libreria, ho aggiunto due stringhe su stdscr e poi ho richiesto un carattere ed infine ho fatto fare il refresh della finestra e chiuso la libreria.

#include "ncursesw/curses.h"

void main()
{
    initscr();
    if (has_colors())
    {
         start_color();
         init_pair(1, COLOR_WHITE, COLOR_WHITE);
         bkgd(COLOR_PAIR(1));
         init_pair(2, COLOR_BLUE, COLOR_WHITE);
         init_pair(3, COLOR_RED, COLOR_WHITE);
         attron(COLOR_PAIR(2));
    }
    addstr("Hello World con Ncurses!\n\n");
    if (has_colors())
       attron(COLOR_PAIR(3));

    addstr("Premere un tasto, per uscire da Ncurses...");
    getch();
    endwin();
}

Per usare i colori occorre chiamare la funzione start_color() e poi crearli con init_pair(n, f, b) che ha un numero che va da 1 a n ( il numero 0 è bianco su nero ) inserendo i colori del testo ed il background. La funzione attron(n) consente di inserire l’attributo di colore creato in precedenza.
Per spiegare tutte le funzioni e le caratteristiche della libreria ncurses occorre più di un articolo, qui ho spiegato le basi dell’uso della programmazione in C su terminali grafici, ma se alcuni di voi hanno interesse sull’argomento, posso continuare spiegando altre caratteristiche della libreria. Potete contattarmi tramite il forum su Linux ( link in alto a destra del blog ) oppure inserire un commento in fondo all’articolo.

Lezione Successiva >>

Pubblicato
Categorie: Linux Taggato

Di Giampaolo Rossi

Sviluppatore software da oltre 16 anni.

3 commenti

  1. Grande articolo, complimenti! Saranno sicuramente apprezzati approfondimenti dei vari aspetti di ncurses 😉

  2. Grazie. Benissimo, allora preparerò un nuovo articolo sui colori e le zone dello schermo.

I commenti sono chiusi.