viernes, 20 de julio de 2007

Uso de readline y history

Para mejorar el interfaz de usuario de la aplicación de control del maestro se han usado las librerías libreadline y libhistory para poder editar fácilmente los comandos y tener una historia de los comandos introducidos anteriormente.

Lo primero que hemos hecho es instalar el paquete de desarrollo de las librerías:

sudo apt-get install libreadline5-dev

El paquete anterior incluye ambas liberías.

El siguiente paso es adaptar nuestro programa para usar ambas liberías. Para ello hay que tener en cuenta lo siguiente:

Para leer una línea de entrada, en lugar de gets o fgets se usará readline. El prototipo de esta función es:

char *readline (const char *prompt);

La función recibe como argumento una cadena que se usará como prompt, aunque si no se necesita se puede usar NULL. readline permitirá que el usuario introduzca su comando facilitando la edición de éste. Cuando el usuario pulse enter, la función devuelve un puntero a una cadena con el comando introducido, pero sin el \n. La función asigna memoria dinámicamente para la cadena, por lo que cuando terminemos de usarla tendremos que liberarla con un free().

Para almacenar un comando en el histórico se usa la función:

void add_history (const char *string);

Esta función almacena la cadena string en el histórico.

El proceso a seguir es por tanto leer la cadena con el comando, almacenarla en el histórico, usarla (interpretándola y ejecutando el comando correspondiente) y luego liberar la memoria asignada. Lo más apropiado en este caso es hacer una función que se encarge de realizar todo el proceso anterior salvo la interpretación del comando. Esta función será un sustituto de gets. El código de esta función es el siguiente:

/* Lee una línea usando libreadline y libhistory para permitir
editar la línea y tener una historia de los comandos tecleados
*/

char *rl_gets(void)
{
static char *plinea=(char *)NULL; /* Para guardar la línea devuelta por
readline */
if(plinea!=NULL){/* En la llamada anterior se devolvió una línea válida.
Como ya no la necesitamos liberamos la memoria.*/
free(plinea);
plinea = (char *)NULL;
}

plinea = readline("Comando > ");
if(plinea != NULL && plinea[0] != '\0'){
/* Se ha introducido una línea válida*/
add_history(plinea);
}

return plinea;
}

El modo de llamar a esta función es el siguiente:

#include
#include

main()
{
char *pcomando;

do{
pcomando = rl_gets();
InterpretaComando(pcomando);
}while(strcmp(pcomando, "quit")!=0);
}

Por ello rl_gets lo primero que hace es liberar la memoria de la cadena de la ejecución anterior de rl_gets, salvo que sea la primera ejecución o que haya devuelto NULL (devuelve un NULL si sólo lee como entrada un EOF). Luego lee la siguiente línea y si se ha leído correctamente (no es NULL) y contiene algún carácter (plinea[0] no es el caracter nulo) se almacena dicha línea en el histórico.

Por último, para compilar el programa no hay que olvidar de decirle al linker que incluya las librerías:

gcc -o prog prog.c -lreadline -lhistory

Más información


La información mostrada aquí está obtenida de la siguiente página:
Programming with GNU Readline

También tiene más información en las páginas del manual.

  • man readline

  • man history

No hay comentarios: