Home Tecnica Programmazione GNU readline: un tool indispensabile per la linea di comando

In evidenza

SMAU a Bologna con Research to Business

SMAU a Bologna con Research to Business

Il 6 e 7 giugno il Roadshow Smau Business torna a far tappa al Padiglione 33 della Fiera di Bologna e...
Gli articolisti del Portale

Gli articolisti del Portale

Abbiamo deciso di dare più visibilità a tutti coloro che hanno pubblicato articoli per noi, questo perché...
SMAU festeggia il suo quinto anno nel NordEst a Padova

SMAU festeggia il suo quinto anno nel NordEst a Padova

Il 18 e 19 aprile al padiglione 5 di Padova Fiere si terrà la prossima tappa di SMAU Business Roadshow. All'evento...
SMAU risale l’Italia e arriva a Roma

SMAU risale l’Italia e arriva a Roma

Il 21 e 22 marzo nella Nuova Fiera di Roma si terrà la prossima tappa di SMAU Business Roadshow. L'evento...

Bandi di Concorso

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

Avviso per incarico ad ingegnere informatico alla Provincia di Bergamo

Nell'ambito del progetto denominato "SOS badanti: la rete provinciale di sportelli per assistenti e collaboratori familiari” nell'ambito del programma "SAP - Servizi alla Persona" è stato pubblicato la Provincia di Bergamo ha pubblicato l'avviso per il reclutamento di una unità per incarico di...

21 Mag 2012 - Letture:1

Esperto di servizi e tecnologie cloud al Digit PA

Procedura comparativa per il conferimento di un incarico di collaborazione coordinata e continuativa per un profilo senior di “Esperto di servizi e tecnologie cloud”, nell’ambito del progetto europeo “Open Dai” presso l' Ente nazionale per la digitalizzazione della Pubblica Amministrazione...

18 Apr 2012 - Letture:34

Selezione per addetto servizi informatici all'Autorità Portuale di Brindisi

Avviso di selezione pubblica per titoli e prova orale per l’assunzione di n. 1 “addetto ai servizi informatici”, a tempo pieno ed determinato triennale, previo periodo di prova, da inquadrare nell’Area Amministrativa. (Inquadramento al III Livello del C.C.N.L. dei Lavoratori...

12 Feb 2012 - Letture:435

Concorso pubblico per informatico alla Corte dei Conti

E' indetto un concorso pubblico, per   esami,   per   il reclutamento di tre unità di informatici da inquadrare nella III area, fascia retributiva F1, da destinare agli Uffici della Corte dei Conti con sede in Roma. Requisiti: laurea triennale in scienze e...

05 Feb 2012 - Letture:306

Istruttore informatico L.68/1999 al Comune di Potenza

Concorso pubblico, per esami, per la copertura di n. 2 posti di Istruttore Informatico, categoria C, posizione economica C1, a tempo pieno e indeterminato, con riserva assoluta alle categorie dilavoratori di cui all'art. 1 della legge n. 68/1999 (norme per...

21 Gen 2012 - Letture:244

Senior Business Consultant presso Lombardia Informatica

Selezione per figura Senior Business Consultant presso Lombardia Informatica. Il collaboratore dovrà fornire consulenza strategica e di business sulle tematiche verticali della Socio-Sanità. Requisiti di ammissione: Laurea in Ingegneria, Economia e Commercio o Scienze dell’Informazione; Percorsi di formazione professionale in ambito sanitario e socio-sanitario, su...

11 Gen 2012 - Letture:284

Bando progetto TAG (Toscana Area Giovani) per giovani talenti digitali

UPI Toscana ha indetto un avviso pubblico per la selezione di 20 giovani (2 per ciascuna delle 10 province della Toscana), da impiegare come formatori all'interno del Progetto TAG (Toscana Area Giovani). Il bando è finalizzato a valorizzare al meglio i...

03 Gen 2012 - Letture:271

I più attivi

Dati e punteggi dell'ultimo anno

Giovanna Casamassima Giovanna Casamassima
47 articoli
16,501 punti totali
Rodolfo Giometti Rodolfo Giometti
49 articoli
5,153 punti totali
Vittorio D'Aversa Vittorio D'Aversa
33 articoli
3,445 punti totali
Fulvio Lucchetti Fulvio Lucchetti
9 articoli
0,279 punti totali
Luigi Carbone Luigi Carbone
10 articoli
0,262 punti totali

Ci hanno visitato

Oggi:1315
Ieri:2110
Totali (14/04/09):1170490

I nostri numeri

Articoli pubblicati: 552
Iscritti al portale: 768
Iscritti all'Elenco: 184
Iscritti ML Discussioni: 351
Iscritti ML Articoli: 30
Iscritti ML Lavoro: 166
 

OpenWRT: la distribuzione piccola e versatile

In queste ultime settimane ho avuto modo di vedere da vicino OpenWRT, una distri...

Il NAS D-Link DNS-343

Grazie alla D-Link azienda produttrice di apparecchiature di rete e non solo v...

Boxee Box: la TV facile di D-Link

Grazie alla D-Link possiamo presentare un nuovo gioiello della tecnologia: il me...

Server Linux: tutti i trucchi per farlo al meglio

Volete fare un server Linux per la vostra impresa, ufficio o semplicemente per c...

Clonare una macchina vera in 30 minuti con VirtualBox

Essendo uno sviluppatore mi son reso conto che la virtualizzazione di una macchi...

Universal USB Installer 1.8.04 e Ubuntu Linux 10.10

Rilasciata il 10.10(.2010) la nuova versione di Ubuntu Linux (la data corrispond...

Sviluppare codice per Arduino dalla command line

Arduino Uno è un micro controllore basato su CPU ATmega328; si alimenta via alim...

Forno a microonde: analisi emissioni EME

Nell'immaginario collettivo c'è una forte paura per i danni che posso generare s...

AVG Live CD Rescue: l'antivirus live!

Qualche giorno fa mi sono reso conto che in azienda sta per scadere la licenza d...

Aggiungere programmi all'N900 con Maemo SDK

Abbiamo già visto come sia facile installare nuove applicazioni sul Nokia N900, ...

Arduracing: come realizzare una robot-car intelligente con Arduino

Arduracing è un progetto realizzato con Arduino in collaborazione con il Lucccal...

Cluster VMWARE

In questo articolo vediamo come realizzare un cluster di macchine virtuali con u...

Come creare un NFS server ridondante

Quelli che mi conoscono sanno che il mio ambito lavorativo è nei sistemi embedde...

I-Memo: le password personali sempre con te

Prodotto dalla MensTecnica, una giovane azienda della Basilicata fondata nel 200...

Programmare in C sull'N900

In questo articolo vedremo come sia semplice programmare in C sull'N900. In part...

Implementare una LIM con Linux

Come promesso rieccomi qui per illustrare come realizzare una LIM (che ricordo s...

LIM: la lavagna multimediale con il wiimote

LIM sta per Lavagna Interattiva Multimediale, ed è un progetto che, tramite l'...

Socat: quando i dati passano via rete

Lavorando coi sistemi embedded molte volte mi capita di dovermi arrangiare su di...

Virtualizzazione di Windows XP o altri SO su Ubuntu con Qemu

I pc odierni sono sempre più potenti e molto spesso sotto sfruttati, la virtua...

Intervista esclusiva a Mageia Linux

La Presidente dell'Associazione MAGEIA.ORG, Anne Nicolas, in questa intervi...

AccessPoint: la scelta ottimale del canale di trasmissione

Realizzare una rete Wireless outdoor (ma anche indoor) pone il problema della sc...

Generare un file pieno di 0xff

Per generare in file da 16Kbyte pieno di zeri su di un sistema UNIX/GNU-Linux si...

Controllare MAME con Wiimote su N900!

Ecco un'altra dimostrazione delle potenzialità di questo telefono (se vogliamo c...

SUN Wiki Publisher: scrivere facilmente su Wikipedia

Personalmente uso parecchio Mediawiki (il motore di Wikipedia); lo ritengo un ot...

Openembedded: la distribuzione «ristretta» per Linux

Quando le risorse di un sistema sono limitate non è possibile usare una distribu...

Rete lenta? Vediamo chi consuma...

Molte volte capita di trovarsi la rete molto lenta e magari non abbiamo a dispos...

F-Droid, e il FOSS su Android è servito!

Come Software Libre Evangelist mi son spesso trovato ad incoraggiare l'uso del s...

Sabayon Linux 5.4 (32 e 64 bit)

E' stata rilasciata online la nuova versione 5.4 di Sabayon Linux, una tra ...

Generare un file da 10GB in 2 millisecondi!

Chi ha a che fare con le macchine virtuali o deve generare delle immagini di fil...

Installazioni di Linux su sistemi non convenzionali

Un'ottica convenzionale vede l'informatica come un insieme di applicazioni e sis...

Linutop OS 4.0: Internet, Chiosco Multimediale e non solo!

Presentata negli ultimi giorni nella capitale francese la nuova distribuzione LI...

Android: se non hai il telefono usa l'emulatore!

In questi giorni sto valutando di comprare un cellulare basato su Linux. Inizial...

WODE, l'emulatore DVD per la Wii

Qualche giorno fa mi è capitato di sfidare mio cognato ad una partitella a tenni...

Come ti controllo i tassi di interesse con Linux

In questi giorni sto cercando di fare una surruga per il mutuo di casa mia. Tra ...

Cloud Money

Discorrendo con un collega di cloud computing, si è finito, come al solito, a pa...

Gimp, OpenOffice & C. su N900? Semplice con Debian!

Che Maemo fosse versatile me ne sono accorto subito, ma l'idea di poter installa...

Odroid: la piattaforma di gioco libera

Si chiama Odroid ed e basata su Android, è la prima piattaforma di gioco interam...

Demolinux: l'automazione industriale con Linux

Qualche tempo fa il mio ex istituto superiore mi aveva chiesto di fare una picco...

ettercap: il man-in-the-middle facile

Troppo spesso mi rendo conto che molti considerano la rete aziendale o quella ...

Multi puntatore su Ubuntu 10.4: ecco come

Tempo fa ebbi modo di dare un'occhiata al progetto MPX per un cliente. La cosa n...

ASUS U36SD il notebook in soli 19mm

La concorrenza al più blasonato della “mela” si fa agguerrita specie nell'ultimo...

NBTempo: una GUI per le timeline

Svolgendo alcuni casi in cui serviva creare delle timeline per verificare l'att...

Snom 870: il telefono con Linux

Definirlo solo telefono è sicuramente riduttivo, infatti lo Snom 870 è sicuramen...

Il settore danneggiato e l'acquisizione forense

Se si deve acquisire un hard disk in maniera forense, ossia con tutti i crismi n...

Gobby: l'editor collaborativo

Quante volte vi sarà capitato di dover dire come modificare un file di testo ad ...

L'SMS autoprodotto!

Tempo fa sulla mailing list di CFI ho provato a lanciare l'idea di effettuare un...

Installare strace su Android

Quando si programma è importante avere buoni tool di debug e uno dei più importa...

Linutop4 PC

Il produttore francese Linutop, con sede a Parigi, ha annunciato il nuovo modell...

Lion desktop: finalmente una distribuzione mirata alle aziende!

Chi è abituato a lavorare con Linux, ed in particolare ha provato a lavorare con...

Boot from SAN

Intendiamoci, non è l’ultima briciola tecnologica caduta da un banchetto alla NA...

Come gestire una presentazione con il Wiimote

Capitandomi spesso si tenere conferenze e workshop mi trovo sempre il problema d...

GNU readline: un tool indispensabile per la linea di comando

Chiunque di voi abbia avuto a che fare con la linea di comando avrà senz'altro a...

Come saltare il proxy «blocca-tutto» aziendale

Mi capita spesso, ma non sempre, di andare da dei miei clienti e non potermi con...

busybox & Android: la command line facile

Nei precedenti articoli abbiamo visto due tecniche per aggiungere nuovi programm...

Mageia 1 alpha1 è tra noi

Finalmente è stata rilasciata la tanto attesa versione alpha1 principalmente riv...

XMount finalmente liberi di virtualizzare!

Cosa succede dopo che abbiamo acquisito un disco in bitstream su file immagine? ...

"Impronte digitali" anche per le macchine fotografiche

Da www.hwupgrade.it: Una ricerca della Binghamton University ha messo a punto u...

Linaro, la no-profit che produce distribuzioni Linux/ARM

Il progetto Linaro presentato nel 2010 da colossi del calibro di Freescale Semic...

Multistrap: come ti creo un rootfs Debian dal nulla

Una volta c'era debootstrap, un tool fantastico che permetteva di creare un root...

Installare Linux su una USB key: ecco come!

L’installazione  e l'avvio di una distribuzione Linux Live da un supporto U...

GNU readline: un tool indispensabile per la linea di comando Stampa E-mail
(1 voto, media 5.00 di 5)
Area Tecnica - Programmazione
Scritto da Rodolfo Giometti   
Domenica 03 Gennaio 2010 19:50
Articolo letto 1416 volte

Chiunque di voi abbia avuto a che fare con la linea di comando avrà senz'altro apprezzato due cose: la possibilità di ridare un comando già digitato semplicemente cercandolo con le freccie «su» e «giù» e la possibilità di completare un comando con la doppia pressione del tasto «TAB».

Quelli più esperti poi apprezzeranno la possibilità di muovere il cursore più velocemente spostandolo direttamente da una parola all'altra, oppure la possibilità di cancellare parte della linea di comando con una combinazione di tasti particolare, ecc.. Bene, vi sieti mai chiesti come e ossibile questo? E perché queste funzionalità alle volte si trovano anche in altri programmi? No? Beh, ve lo dico io! Dipende tutto dalla libreria readline.

Questa libreria, che fa parte del progetto GNU, è alla base di molte interfacce di testo di diversi programmi a cominciare, ovviamente, delle shell. In questo articoletto vedremo molto brevemente come poter utilizzare questa libreria per realizzare un piccolo programma che possa essere utilizzato, ad esempio, per ottenere una serie di informazioni da un ipotetico dispositivo installato sul nostro sistema. Ovviamente, poiché nella realtà il dispositivo non esiste, metteremo del codice ad hoc per simularne il funzionamento.

L'interfaccia di base

Come tutte le librerie che si rispettino anche la readline ha una propria interfaccia verso le applicazioni che intendono utilizzarla. Anche se la readline è molto complessa, ha però una interfaccia di base molto semplice. In questo articolo ci limiteremo alle funzonalità di base che però, come vedremo, sono già abbastanza interessanti da utilizzare.

Ma vediamo subito un semplice corpo di una funzione main() che implementa le funzionalità di base:

printf("TEST shell - version " VERSION "\n");                          
printf("Copyright (C) 2005 - Rodolfo Giometti \n");
 
initialize_readline();  
                                               
/* Loop reading and executing lines until the user quits. */           
while (1) {                                                            
        /* Read the command line */                                         
        line = readline(prompt);                                            
 
        if (!line)                                                          
                 break;       

        /* Remove leading and trailing whitespace from the line.            
         * Then, if there is anything left, add it to the history list      
         * and execute it
         */                                                
        s = strip_blanks(line);                                             
        if (*s) {                                                           
                add_history(s);
                execute_line(s);
        }

 

        free(line);
}         

 

return 0;
                                                           

Come si vede la cosa è abbastanza semplice, la funzione readline() una volta invocata restituisce una stringa che contiene proprio quello che l'utente ha inserito dalla linea di comando, mentre nella variabile prompt è contenuta la stringa che rappresenta (appunto) il prompt da mostrare all'utente. Tutta le gestione dell'editing della linea di comando viene quindi gestita della libreria readline!

Una volta che si è controllato se la stringa è non vuota (altrimenti si esce perché vuol dire che l'utente ha inserito un End-Of-File) la si ripulisce dagli spazi in testa ed in cosa, e se il risultato è non nullo allora lo si passa alla funzione add_history() e quindi alla funzione execute_line().

La funzione add_history() è un'altra funzione propria della libreria readline (anche se in realtà, ad essere pignoli, essa fa parte della libreria history, ma questo è un altro discorso) che permette di gestire la possibilità di rieseguire un comando già dato semplicemente cercandolo con le freccie, mentre la fuzione execute_line() è una funzione ad hoc che si incarica di eseguire il comando che l'utente ci ha appena inserito dalla linea di comando.

E' abbastanza evidente allora che di per se la cosa è abbastanza semplice, ma andiamo avanti nell'esposizione perché occorre chiarire altri punti essenziali della questione.

Scendiamo più a fondo

Vediamo ora come si realizza la funzione forse più interessante ed utile di readline: il completamento dei comandi. Ritorniamo al codice appena presentato e vediamo cosa contiene la funzione initialize_readline():

static void initialize_readline(void)                      
{                                                          
        /* Allow conditional parsing of the ~/.inputrc file */  
        rl_readline_name = NAME;   
                             
 
        /* Tell the completer that we want a crack first */     
        rl_attempted_completion_function = commands_completion;
}                                                           


Questa funzione inizializza le variabili rl_readline_name e rl_attempted_completion_function.

La prima funzione serve per definire il nome dell'applicazione per il sistema di parsing del file .inputrc, che e quello che definisce la configurazione di base del funzionamento della libreria stessa. Questo file è lo stesso per tutte le applicazioni che usano la libreria readline e per poter differenziare il funzionamento della libreria a seconda dell'applicazione che la sta utilizzando possiamo appunto utilizzare questo parametro.

Ad esempio, se nel nostro codice definiamo la define NAME come testsh allora è possibile specificare nel file .inputrc una configurazione speciale con:

$if testsh                                       
        # Put here special configuration for "testsh"
        ...                                           
$endif                                           


Non mi addentro di più nella cosa perché è al di fuori dello scopo di questo articolo ma rimando il lettore curioso alle pagine del manuale della libreria.

Con la variabile rl_attempted_completion_function invece si definisce la funzione che permette di impostare le modalità di completamento dei comandi. Questa è la funzione che ci interessa ed è qui che le cose si complicano... :)

Completare un comando

Come appena detto occorre definire la funzione rl_attempted_completion_function la quale viene chiamata da readline ogni qual volta essa ha bisogno di completare un comando e non sa come. In parole povere se l'utente preme il tasto «TAB» per chiedere il completamento del comando allora questa funzione viene attivata.

Vediamo un esempio di come questa potrebbe essere implementata:

static char **commands_completion(const char *text, int start, int end)
{                                                                       
        const char delimiters[] = " \t";                                     
        char *token, *cp;                                                    
        int i;        
 
        /* We start from the commands' tree root */                          
        cmds_level = cmds_root;                                              
 
        cp = strndupa(rl_line_buffer, end); 
        while ((token = strtok(cp, delimiters)) != NULL) {                   
                if (token == NULL)
                        break;
                cp = NULL;      
 
                for (i = 0; cmds_level[i].name != NULL; i++)
                        if (strcmp(token, cmds_level[i].name) == 0) {
                                cmds_level = cmds_level[i].sub;
                                if (cmds_level == NULL)
                                        goto out;
                        }
        }
 
out :                                                                   
        if (cmds_level != NULL)                                              
                return rl_completion_matches(text, command_generator);
 
        return NULL;                                                         
}

C'è da dire subito che in questo esempio abbiamo utilizzato la struttura seguente per definire la variabile cmds_root:

struct commands_s {
         char *name;                          /* command name */
        int (*func)(struct commands_s *cmd,
                    int argc, char *argv[]); /* function to call to do the job */
        char *usage;                         /* command usage */
        char *help;                          /* command help */
        struct commands_s *sub;              /* subcommands list */
};
                                                                                      

La struttura è semplice, con name si definisce il nome del comando, con func la funzione che esegue il comando stesso, con usage una stringa che ne definisce la sintassi di uso e con help una stringa che riporta un messaggio di aiuto su cosa fa il comando. L'ultima variabile, sub, definisce una lista di sotto comandi disponibili e riferiti al comando stesso.

Un esempio di come questa struttura si riferisca ad un comando tipo help è il seguente: 

{                                             
        "help",                   /* the "help" */
        func_help,                                 
        "help ",                          
        "show a little commands' help",            
        cmds_root                                  
},

Si noti come la lista dei sottocomandi di help corrisponda in realtà alla lista di tutti i comandi disponibili...

Ma ritorniamo a noi e supponiamo allora di voler realizzare una piccola interfaccia a linea di comando verso un dispositivo che riporta lo stato di alcune grandezze notevoli e supponiamo anche che tale interfaccia possegga un comando del tipo: 

show --+--> status  --+--> temperatures
       |              |                 
       |              +--> voltages     
       |              |                 
       |              +--> IOs          
       |                                
       +--> version --+--> shell        
                      |                 
                      +--> driver       
                      |                 
                      +--> hardware   

 

Cioè dando show status voltages si ottengono le letture delle tensioni, mentre dando show version hardware si ottiene la versione dell'hardware controllato. In pratica, come ben si vede, la struttura di tutti i comandi è correlata ad una struttura ad albero, dove, nel nostro caso, la variabile cmds_root è appunto la radice; in particolare abbiamo definito, per quanto riguarda il primo livello di comandi: 

cmds_root --+--> exit/quit
            |              
            +--> help      
            |              
            +--> reset     
            |              
            +--> show

 

Bene, detto questo se ritorniamo alla nostra funzione commands_completion() possiamo ora capire cosa questa fa: sostanzialmente, partendo dalla radice dei comandi disponibili scorre il contenuto della variabile rl_line_buffer (che contiene il comando inserito dall'utente fino alla sua invocazione) cercando di capire quale particolare percorso di comandi possibili l'utente vuole utilizzare.

Se il percorso si trova, allora si ritorna alla readline il valore di ritorno della funzione rl_completion_matches() che, a sua volta, ha il compito di invocare più volte la funzione command_generator() la quale, ad ogni invocazione, deve ritornare un possibile comando di completamento del comando dell'utente (se questo esiste, ovviamente).

La funzione command_generator() è la seguente:

static char *command_generator(const char *text, int state)                 
{                                                                           
        static int i, len;
        char *name;
 
        if (state == 0) {
                i = 0;
                len = strlen(text);
        }

        /* Return the next name which partially matches from the
         * command list
         */
        while ((name = cmds_level[i++].name) != NULL)
                if (strncmp(name, text, len) == 0)
                        return dupstr(name);
 
        /* If no names matched, then return NULL. */
        return NULL;
}


e come di vede è una funzione a stati, nel senso che essa, ogni volta che viene invocata, restituisce un nuovo possibile comando che completa quello dell'utente.

Un esempio: se l'utente scrive show version e poi preme due volte il tasto «TAB» otterrà una lista di comandi possibili, e cioè driver, hardware e shell, questo grazie al fatto che la funzione command_generator() restituisce uno di questi valori ogni volta che viene invocata.

Un esempio pratico

Facciamo ora un esempio pratico per fissare un po' le idee (posso immaginare che la cosa sia un po' «ingarbugliata» ma se analizzate bene il tutto vedrete che non è poi impossibile capire come funziona).

Per coloro che vogliono ben capire il funzionamento del codice che sto utilizzando io possono scaricarsi il tutto dal mio FTP anonimo all'indirizzo: http://ftp.enneenne.com/pub/misc/readline/.

Prima di proseguire vediamo però come sia possibile definire le strutture dati che definisco i vari comandi.

I comandi principali possono essere definiti come segue:

struct commands_s cmds_root[] = {                  
        {                                               
                "exit",           /* "quit" alias */
                func_quit,                                   
                "exit",                                      
                "quit the program",                          
                NO_SUBCOMMANDS                               
        }, {                                               
                "help",           /* the "help" */   
                func_help,                                   
                "help ",                            
                "show a little commands' help",              
                cmds_root                                    
        }, {                                               
                "reset",                                     
                func_reset,                                  
                "reset ...",                                 
                "reset the device",                          
                cmds_reset                                   
        }, {                                               
                "show",                                      
                func_show,                                   
                "show ...",                                  
                "show status data",                          
                cmds_show                                    
        }, {                                               
                "quit",                                      
                func_quit,                                   
                "quit",                                      
                "quit the program",                          
                NO_SUBCOMMANDS                               
        },                                              
        END_LIST,                                       
};

Si noti come la funzione che esegue il comando exit è la stessa del comando quit (i due comandi sono quindi sinonimi) e come la lista dei sottocomandi del comando help sia appunto la lista dei comandi principali, questo perché è possibile dare comandi del tipo: help help o help reset ecc..

Per completezza vediamo anche come potrebbe essere il corpo di una funzione che ha il compito di eseguire un comando dell'utente:

int func_show(struct commands_s *cmd, int argc, char *argv[])
{                                                             
        struct commands_s *command;

        /* Check command line */
        if (argc < 2) {
                cmd_usage(cmd);
                return -1;
        }

        /* Find the subcommand */
        command = find_command(cmd->sub, argv[1]);
        if (command == NULL) {
                printf("%s: no such subcommand\n", argv[1]);
                cmd_usage(cmd);
                return -1;
        }

        /* Execute the command */
        return command->func(command, --argc, ++argv);
}

 

Come si nota il corpo della funzione è molto simile ad una funzione main(), ed esso ha semplicemente il compito di cercare, sempre nella stessa struttura ad albero, i sottocomandi del comando show e quindi di eseguire il tutto.

Ma facciamo ora l'esempio compilando il nostro codice:

giometti@zaigor:~/readline$ make
cc -Wall -D_GNU_SOURCE -I../ -O -ggdb -M main.c cmds_tree.c misc.c func_quit.c func_help.c func_reset.c func_show.c > .depend
cc -Wall -D_GNU_SOURCE -I../ -O -ggdb   -c -o main.o main.c
cc -Wall -D_GNU_SOURCE -I../ -O -ggdb   -c -o cmds_tree.o cmds_tree.c
cc -Wall -D_GNU_SOURCE -I../ -O -ggdb   -c -o misc.o misc.c
cc -Wall -D_GNU_SOURCE -I../ -O -ggdb   -c -o func_quit.o func_quit.c
cc -Wall -D_GNU_SOURCE -I../ -O -ggdb   -c -o func_help.o func_help.c
cc -Wall -D_GNU_SOURCE -I../ -O -ggdb   -c -o func_reset.o func_reset.c
cc -Wall -D_GNU_SOURCE -I../ -O -ggdb   -c -o func_show.o func_show.c
cc -s -rdynamic -lm -ldl -lreadline  main.o cmds_tree.o misc.o func_quit.o func_help.o func_reset.o func_show.o  -o testsh

Si noti che per compilare il programma di test c'è bisogno della libreria readline installata sul vostro sistema: necessitate sia dei file binarii sia dei file sorgenti necessari per la compilazione e lo sviluppo.

Se comunque il tutto va bene, date il comando:

giometti@zaigor:~/Projects/enneenne/readline$ ./testsh    
TEST shell - version 0.90.0                               
Copyright (C) 2005 - Rodolfo Giometti
testsh>                                                   


A questo punto proviamo subito il completamento dei comandi, scrivete show e quindi date il doppio «TAB»:

testsh> show       
status   version   
testsh> show       


Come vedere il programma vi propone i sottocomandi disponibili del comando principale show, ora scrivete il carattere s e quindi date il solito doppio «TAB»:

testsh> show status


Ecco che readline vi completa il comando. Se poi proviamo a dare un comando completo:

testsh> show status temperatures  
 32.500000*C, 33.800000*C          


ecco che questo viene eseguito!

Provate ora a dare un po' di comandi e quindi premete le freccie «su» e «giù» e vedrete che scorreranno i vari comandi che avete già dato in precedenza! Bello no? ;)

Bon direi che possiamo fermarci qua. Vi consiglio di continuare a provare ad utilizzare questo programmino di esempio.

E' interessante secondo me vedere come è stato implementato il comando help, infatti se ad esempio date il solo comando help otterrete:

testsh> help                                                        
--- usage ---                                                       
help                                                       
   exit                 - quit the program                          
   help                  - show a little commands' help    
      exit                 - quit the program                       
      help                  - show a little commands' help
      reset ...                 - reset the device                  
      show ...                 - show status data                   
      quit                 - quit the program                       
   reset ...                 - reset the device                     
      reset hard                 - hard reset the board             
      reset soft                 - soft reset (init) the board      
   show ...                 - show status data                      
      show status ...                 - show status of ...          
      show version ...                 - show version of ...        
   quit                 - quit the program                          


Ma se date help show allora otterrete:

testsh> help show                                            

--- help ---                                                 
show status data                                             
--- usage ---                                                
show ...                                                     
   show status ...                 - show status of ...      
      temperatures                 - show temperatures state
      voltages                 - show voltages state         
      IOs                 - show IOs state                   
   show version ...                 - show version of ...    
      shell                 - show shell version             
      driver                 - show driver version           
      hardware                 - show hardware version       


Secondo voi, come mai? Beh, buono studio! ;

 
 

In primo piano

Simons Voss: un mondo senza chiavi

Simons Voss: un mondo senza chiavi

Il sistema di gestione e di controllo degli accessi 3060 si presenta come un’alternativa con enormi vantaggi...
Pubblicità mirata dei prodotti

Pubblicità mirata dei prodotti

Hai un prodotto o un servizio da pubblicizzare? Fallo su consulenti-ict.it! Pubblicizzare un prodotto...
Recensioni sul Portale

Recensioni sul Portale

Hai un prodotto hardware/software o un libro riguardante uno dei temi dell'ICT? Vuoi farlo conoscere...

Offerte di lavoro

Visualizza Topic »

Eventi

Non ci sono eventi in programma
Novembre 2005
D L M M G V S
30 31 1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 1 2 3
Dicembre 2005
D L M M G V S
27 28 29 30 1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31

Sondaggi

busyCaricamento Sondaggio...