Processeur de commandes
- typedef list shell;
Un type shell
est une liste de commandes.
- extern shell shell_new( void );
- extern void shell_free( shell this );
- extern shell shell_help( shell this, char *input );
- extern void shell_inputline( shell this, char *input_line );
- extern void shell_input( shell this, char *prompt );
- extern shell shell_addcmd( shell this, char *name, char *help, void (*f)( int argc, char **argv ) );
- extern shell shell_delcmd( shell this, char *name );
shell_new
retourne une nouvelle instance du type shell
.
shell_free
désalloue l'espace mémoire occupé par le shell.
shell_help
affiche un résumé de toutes les commandes disponibles.
shell_inputline
interprète une ligne de texte et exécute la fonction correspondante.
shell_input
lit une ligne de texte, la passe à shell_inputline
et affiche un message d'invite.
shell_addcmd
ajoute une commande au processeur.
shell_delcmd
retire une commande du processeur.
- typedef struct _shell_keyword {
- char *name, *help;
- void (*f)( int argc, char **argv );
- } *shell_keyword;
Le type shell_keyword
définit une commande. name
spécifie son nom, comment elle est appelée. help
donne l'usage de la commande qui est affiché par shell_help
. f
est un pointeur sur la fonction appelée pour exécuter la commande.
- static shell_keyword shell_keyword_alloc( void ) {
- return (shell_keyword)calloc( 1, sizeof ( struct _shell_keyword ));
- }
- static shell_keyword shell_keyword_init( shell_keyword this, char *name, char *help, void (*f)( int argc, char **argv ) ) {
- this->name = name;
- this->help = help;
- this->f = f;
- return this;
- }
- static shell_keyword shell_keyword_new( char *name, char *help, void (*f)( int argc, char **argv ) ) {
- return shell_keyword_init( shell_keyword_alloc(), name, help, f );
- }
- static void shell_keyword_free( shell_keyword this ) {
- free( this );
- }
- shell shell_alloc( void ) {
- return list_alloc();
- }
- shell shell_init( shell this ) {
- return this;
- }
- shell shell_new( void ) {
- return shell_init( shell_alloc() );
- }
- void shell_free( shell this ) {
- int i, len = list_length( this );
- for ( i = 0; i < len; i++ )
- shell_keyword_free( list_get( this, i ));
- list_free( this );
- }
- shell shell_help( shell this, char *input ) {
- shell_keyword kw;
- int i, len = list_length( this );
- unsigned lin = input ? strlen( input ) : 0;
- for ( i = 0; i < len; i++ ) {
- kw = (shell_keyword)list_get( this, i );
- if ( !lin || strncmp( kw->name, input, lin ) == 0 )
- fprintf( stderr, "%s\n", kw->help );
- }
- return this;
- }
- static shell_keyword shell_match( shell this, char *input ) {
- shell_keyword kw, found = 0;
- int i, len = list_length( this );
- unsigned lin = input ? strlen( input ) : 0;
- for ( i = 0; i < len; i++ ) {
- kw = (shell_keyword)list_get( this, i );
- if ( strncmp( kw->name, input, lin ) == 0 ) {
- if ( !found )
- found = kw;
- else { /* ambiguous input */
- shell_help( this, input );
- return 0 ;
- }
- }
- }
- if ( !found )
- shell_help( this, 0 ); /* help user */
- return found;
- }
- static int parse( char *s, char ***argv ) {
- register char *p;
- int argc;
- int i;
- /* count tokens */
- for ( argc = 0, p = s; *p; ) {
- while ( isspace( *p ))
- p++; /* skip spaces between tokens */
- if ( *p == '\0' )
- break; /* end of line */
- argc++; /* one more token */
- while ( *p && !isspace( *p ))
- p++; /* goto to end of token */
- }
- /* return 0 if empty */
- if ( argc == 0 )
- return 0;
- /* allocate space for array of arg pointers */
- *argv = (char **)calloc( argc + 1, sizeof( char * ));
- /* fill array of pointers */
- for ( i = 0, p = s; *p; ) {
- while ( isspace( *p ))
- p++; /* skip spaces between tokens */
- if ( *p == '\0' )
- break;
- (*argv)[ i++ ] = p; /* put token address in argv */
- while ( *p && !isspace( *p ))
- p++; /* go to end of token */
- if ( *p )
- *p++ = '\0';
- }
- return argc;
- }
- void shell_inputline( shell this, char *input_line ) {
- shell_keyword kw;
- int argc;
- char **argv;
- if ( (argc = parse( input_line, &argv )) ) {
- if ( (kw = shell_match( this, argv[ 0 ] ))) {
- argv[ 0 ] = kw->name; /* full name */
- (kw->f)( argc, argv );
- }
- free( argv );
- }
- }
- void shell_input( shell this, char *prompt ) {
- char *input_line;
- if ( (input_line = readline( prompt )) ) {
- shell_inputline( this, input_line );
- free( input_line );
- }
- }
- void shell_input( shell this, char *prompt ) {
- char input_line[ 4096 ];
- if ( fgets( input_line, sizeof ( input_line ), stdin )) {
- shell_inputline( this, input_line );
- if ( prompt ) {
- fprintf( stdout, "%s", prompt );
- fflush( stdout );
- }
- }
- }
- shell shell_addcmd( shell this, char *name, char *help, void (*f)( int argc, char **argv ) ) {
- list_put( this, -1, shell_keyword_new( name, help, f ));
- return this;
- }
- shell shell_delcmd( shell this, char *name ) {
- shell_keyword kw;
- int i, len = list_length( this );
- for ( i = 0; i < len; i++ ) {
- kw = (shell_keyword)list_get( this, i );
- if ( strcmp( kw->name, name ) == 0 ) {
- list_delete( this, i );
- break;
- }
- }
- return this;
- }
- #if defined( STANDALONE )
- #include <time.h>
- struct _app {
- shell sh;
- } app;
- static void cmd_echo( int argc, char **argv ) {
- while ( --argc )
- printf( argc > 1 ? "%s " : "%s\n", *++argv );
- }
- static void cmd_date( int argc, char **argv ) {
- time_t clock = time( (time_t *)0 );
- fprintf( stdout, "%s", ctime( &clock ));
- }
- static void cmd_time( int argc, char **argv ) {
- time_t clock = time( (time_t *)0 );
- struct tm *tm = localtime( &clock );
- fprintf( stdout, "%02d:%02d:%02d\n", tm->tm_hour, tm->tm_min, tm->tm_sec );
- }
- static void cmd_quit( int argc, char **argv ) {
- shell_free( app.sh );
- exit( 0 );
- }
- int main( void ) {
- char *prompt = "? ";
- app.sh = shell_new( );
- shell_addcmd( app.sh, "echo", "echo word...", cmd_echo );
- shell_addcmd( app.sh, "date", "date", cmd_date );
- shell_addcmd( app.sh, "time", "time", cmd_time );
- shell_addcmd( app.sh, "quit", "quit | exit", cmd_quit );
- shell_addcmd( app.sh, "exit", "exit | quit", cmd_quit );
- setbuf( stdout, 0 ); /* interactive */
- #ifndef READLINE
- fprintf( stdout, "%s", prompt );
- #endif
- for ( ;; ) /* exit with a command */
- shell_input( app.sh, prompt );
- }
- #endif
Installez la librairie libreadline
si nécessaire :
$ apt-get install libreadline-dev
NOTE : Si vous ne voulez pas utiliser readline
, supprimez la ligne qui définit READLINE dans le fichier shell.c et n'ajoutez pas l'option -lreadline
quand vous liez un programme avec le toolkit.
Pour fabriquer le programme de test, compilez list.c séparément puis shell.c avec -DSTANDALONE
:
$ gcc -Wall -DDEBUG -c list.o
$ gcc -Wall -DDEBUG -DSTANDALONE -c shell.c -o test-shell.o
$ gcc test-shell.o list.o -o test-shell -lreadline
Essayez le programme :
$ ./test-shell
?
Demandez de l'aide :
? ?
echo word...
date
time
quit | exit
exit | quit
?
Affichez la date et l'heure :
? date
Wed May 26 13:02:48 2010
? time
13:02:50
?
Essayez une commande avec un nombre variable d'arguments :
? echo Hello my dear Frasq!
Hello my dear Frasq!
?
Vérifiez ce qui se passe quand le nom d'une commande est ambigu :
? e
echo word...
exit | quit
?
Quittez le programme :
? q
$
Commentaires