Terminal de salida

Usando la estructura termios, tendrá control sobre las entradas a través del teclado, pero sería conveniente tener el mismo nivel de control sobre el modo de presentación en pantalla de las salidas de un programa. Al principio del capítulo usamos printf para mostrar los caracteres en la pantalla, pero con ese método no podíamos colocar los datos en una posición determinada en la pantalla.

TIPO DE TERMINAL

Muchos sistemas UNIX se usan con terminales, aunque actualmente, la mayoría de veces, a los terminales se les refiere como un ordenador que ejecuta un programa de emulación de terminal o a una aplicación de terminal en un entorno conformado por ventanas como xterm en X11.

Casi todos los tipos de terminales utilizan una secuencias de escape (una cadena de caracteres que empiezan con un carácter de escape) para proporcionar control sobre la posición del cursor y de otros atributos, como la negrita y el cursor parpadeante, pero no suelen seguir una estandarización adecuada para hacerlo. Otras terminales más antiguas disponen de otras opciones de desplazamiento que pueden o no desaparecer cuando se envía el retroceso de espacios, etc.

terminalSalida_notaEsta variedad de terminales de hardware representa un gran problema a la hora de hacer programas que escriben algún software que controle la pantalla y que se ejecute en varios tipos de terminal. Por ejemplo, la terminal ANSII usa la secuencia de escape, [A, para subir el cursor una línea. La terminal ADM-3a (muy común hace unos años) usa el carácter de control único CTRL-K.

Para no tener que hacer diferentes códigos fuentes para cada terminal, existe la solución en un paquete llamado terminfo. En lugar de descargarnos cada programa de todas las terminales posibles, el programa busca una base de datos con tipos de terminales para obtener la información correcta. En los sistemas UNIX/Linux, el paquete ha sido integrado con otro llamado curses, que estudiaremos en el próximo capítulo.

Para poder usar las funciones terminfo, habrá que incluir el archivo de cabecera curses, curses.h, y el propio archivo de cabecera de terminfo, term.h. En algunos sistemas Linux, es posible que tenga que usar implementaciones de curses conocidas como ncurses, e incluir ncurses.h para proporcionar prototipos para sus funciones terminfo.

IDENTIFICAR EL TIPO DE TERMINAL

 El entorno Linux dispone de una variable, TERM, que contiene el tipo de terminal que se está usando. El sistema lo configura cuando se registra. El administrador de sistema puede establecer un tipo de terminal predeterminado para cada una de las terminales que se conecten directamente y puede pedir que se solicite  a los usuarios remotos y conectados en red un tipo de terminal. El valor TERM se puede negociar a través de telnet y lo transmite rlogin.

Un usuario puede pedir a la shell que descubra qué terminal cree el sistema que está usando.

tipoterminal.En este caso, la shell se está ejecutando desde un programa llamado xterm, un emulador de terminal para el sistema X Windows, o un programa que proporciona una funcionalidad similar a la KDES Konsole o a la terminal GNOME.

El paquete terminfo contiene una base de datos de prestaciones y secuencias de escape para un gran número de terminales y proporciona una interfaz de programación que se beneficiará de las terminales futuras a medida que se amplia la base de datos, y así cada aplicación no tendrá que proporcionar soporte para las diferentes terminales.

Las prestaciones terminfo son descritas por los atributos. Se guardan en un conjunto de archivos terminfo compilados, que se suelen encontrar en /usr/lib/terminfo o en /usr/share/terminfo. Para cada terminal (y muchas impresoras que también se pueden especificar en terminfo) existe un archivo que define sus prestaciones y cómo se puede acceder a sus características. Para no tener que crear un directorio muy extenso, los archivos reales se guardan en subdirectorios, y el nombre de dicho subdirectorio es la primera letra del tipo de terminal. De manera que la definición VT100 se encuentra en ...terminfo/v/vt100.

 Se escribe un archivo terminfo por cada tipo de terminal en un formato fuente que es legible, después se compila, usando el comando tic, en un formato más compacto y eficiente que pueden usar los programas de aplicaciones. Curiosamente, la especificación X/Open hace referencia a las definiciones de formatos fuente y de los formatos compilados, pero no menciona el comando tic necesario para pasar del formato fuente al compilado. Puede usar el programa infocmp para visualizar una versión una versión legible de una entrada terminfo compilada.

A continuación vemos un ejemplo del archivo terminfo para la terminal VT100:

infocmpCada definición está compuesta de tres tipos de entradas. Cada entrada se denomina capname y define la prestación de la terminal.

infocmp_2infocmp_3La cosa se complica cuando la secuencia de escape necesita más parámetros. La mayoría de terminales pueden mover el cursor a una fila y a una columna en particular. Evidentemente, es muy poco práctico tener una prestación diferente para cada posible ubicación, por eso se usa una cadena de prestación genérica, con parámetros que definen los valores que han de insertarse cuando se usan las cadenas.

terminfo5El significado es el siguiente:

  • \E.- Envía escape.
  • [.- Envía el carácter [.
  • %i.- Incrementa los argumentos.
  • %p1.- Coloca el primer argumento en la pila.
  • %d.- Envía el número de la pila a modo de número decimal.
  • ;.- Envía el carácter ;.
  • %p2.- Coloca el segundo argumento en la pila.
  • %d.- Envía el número de pila como un número decimal.
  • H.- Envía el carácter H.

Parece complejo, pero permite que los parámetros aparezcan en un orden determinado, independientemente del orden en el que se espera encontrarlos la terminal en la secuencia de escape final. %i para aumentar los argumentos es necesario porque especifica que el direccionamiento de cursor estándar comienza en (0,0) en la parte superior izquierda de la pantalla, pero para la terminal VT100 esta ubicación es (1,1). El $<5> final indica que es necesario un retraso equivalente a cinco tiempos de caracteres de salida para que la terminal puede procesar el movimiento del cursor.

terminfo_nota6Uso de las prestaciones de terminfo

Ahora que ya sabe cómo definir prestaciones, tiene que aprender a acceder a ellas. Cuando esté usando terminfo, lo primero que tiene que hacer es configurar el tipo de terminal  llamando a setupterm. De esta manera se inicializará una estructura TERMINAL para el tipo de terminal actual. después ya podrá solicitar prestaciones para la terminal y usar sus opciones. Para hacerlo use la llamada setupterm:

terminfo_sintaxisLa función de biblioteca setupterm configura el tipo de terminal actual según lo especificado por el parámetro term.

setupterm_1Si term es un indicador nulo, se usará la variable de entorno TERM.

Tenemos que transmitir a fd un descriptor de archivo abierto que se va a usar para escribir a la terminal.

setupterm_2La función resultante se almacena en la variable entera señalada por errret, si no es un indicador nulo. El valor escrito será:

  • -1: No hay una base de datos terminfo.
  • 0: No existe entrada de correspondencia en la base de datos terminfo.
  • 1: Éxito.

setupterm_3La función setupterm envía la constante OK si tiene éxito y ERR si falla. Si errrt está configurada con un indicador nulo, setupterm mostrará un mensaje de diagnóstico y saldrá del programa si falla, veamos el ejemplo: badterm_listadoLa salida de ejecución de este programa puede variar con lo aquí expuesto (sistema Fedora 19), pero el significado debería ser claro. Done. No se muestra, porque setupterm hizo que el programa se saliese cuando falló.

badterm_terminalTenga en cuenta la línea de compilación del ejemplo: en los sistemas Linux usamos la implementación ncurses de la biblioteca curses con un archivo de cabecera estándar, que está disponible en la ubicación estandar. En dichos sistemas puede incluir simplemente curses.h y especificar -lncurses para la biblioteca.

terminfo_tux_salidaPara la función de elección de menú, lo ideal sería vaciar la pantalla, mover el cursor alrededor de la pantalla , y escribir en diferentes lugares de la pantalla. Una vez que haya llamado a setupterm, podría acceder a las prestaciones terminfo con tres llamadas a funciones, una por cada tipo de prestación:

tiget_1Estas tres funciones envían el valor de la prestación terminfo:

tigetflag_booleanotigetnum_numericotigetstr_cadenaPodemos usar la base de datos terminfo para descubrir el tamaño de la terminal mediante la recuperación de las prestaciones cols y lines con este programa, sizeterm.c:

sizeterm_listadoSi ejecutamos el programa dentro de una ventana en una estación de trabajo, obtendrá la respuesta que refleja el tamaño de la actual ventana:

sizeterm_salida_terminalsizeterm_salida_terminal_2sizetermi_salida_trminal_3Si utiliza tigetstr para recuperar la capacidad de movimiento del cursor (cup) del tipo de terminal cterm, obtendrá una respuesta con parámetros: \E[%p1%d; %p2%dH.

Esta prestación requiere dos parámetros: una fila y una columna donde colocar el cursor. Ambas coordenadas se miden empezando desde cero desde la esquina superior superior izquierda de la pantalla.

Puede sustituir los parámetros de una prestación con valores reales usando la función tparm. Se pueden llegar a sustituir nueve parámetros y se enviará una secuencia de escape utilizable.

tparm_1Una vez que haya construido la secuencia de escape de terminal con tparm, debe enviarla a la terminal. Para procesarlo correctamente, no debería enviar la cadena a la terminal con printf. En su lugar use las funciones especiales proporcionadas que procesan correctamente todfos los retrasos necesarios mientras la terminal completa una operación. Estas funciones son:

putp_tputsSi tiene éxito, putp envía OK, si falla envía ERR. La función putp adopta la cadena de control de terminal y la envía a stdout.

De manera que para colocarse en la fila 5, columna 30 de la pantalla, puede usar un bloque de código de este tipo:

cursor

tputs_1putp_2putp_3 De hecho, putp (string) equivale a tputs (string, 1, putchar).

atras

Una respuesta a Terminal de salida

  1. galileo dijo:

    Muy bueno, como instalo los ncurses en mi ubuntu?

    Me gusta

Deja un comentario

Este sitio utiliza Akismet para reducir el spam. Conoce cómo se procesan los datos de tus comentarios.