G A C E T A   D E   L I N U X
...haciendo a Linux un poco más divertido!
Descrifando el enigma:
Como trabajan las fuentes de la consola Linux

Por En D Loozzr
Traducción al español por Isaac Uribe
el día 30 de Junio 2003, para La Gaceta de Linux
 

EL CONTROLADOR DE LA CONSOLA

Hasta el momento, con Linux 2.4.x, el kernel incluye un controlador de consola subdivido en un controlador de teclado y otro de pantalla. El controlador de consola está siendo completamente reescrito para Linux 2.6.0 pero en este instante, básicamente, el controlador del teclado envía caracteres a una aplicación, la aplicación hace su trabajo y solicita del controlador de pantalla alguna salida a la misma. El controlador de consola se complementa con el paquete kbd, que normalmente se encuentra en '/usr/share/kbd/' o en '/usr/lib/kbd/'.

Durante el camino entre el controlador de teclado a la aplicación y hacia el controlador de pantalla, los caracteres no son más que códigos (números hexadecimales). Y ya que al final queremos ver sus pequeñas imágenes (glyphs) en la pantalla, debe haber alguna de asociar los glyphs con estos códigos.

Éste artículo se enfocará sólamente en el controlador de pantalla, dando por sentado que algo ocurre entre el teclado y la aplicación. Necesitaremos conocer algunas cosas básicas sobre las fuentes. También ten a mano la página del manual (man) de la utilería 'setfont'. Este artículo está basado en material de:

ftp://win.tue.nl/pub/linux-local/utils/kbd/
ftp://ftp.debian.org/debian/pool/main/c/console-tools/
http://qrczak.home.ml.org/programy/linux/fonty/


UNICODE

Tradicionalmente, las codificaciones de caracteres utilizan 8 bits, por lo que están limitados a 2^8=256 caracteres, lo cual es insuficiente. Por supuesto, hubo una vez hace mucho tiempo cuando las impresoras y monitores no se tenían que preocupar por símbolos diacríticos (acentos, diéresis, etc.), solo manejaban mayúsculas y en ocasiones minúsculas. Esos tiempos pertenecen a la historia, y ahora con la internacionalización (i18n), 256 caracteres no son más que un "aperitivo".

El "Conjunto Universal de Caracteres" (UCS - Universal Character Set), también conocido como Unicode, fué creado para manejar y mezclar todos los lenguajes del mundo, incluyendo aquellos ideográficos de China, Korea, Japón. Tiene más de 65000 caracteres para empezar, pero puede alcanzar hasta 2^31, intenta imaginarlo...

UCS es una codificación de 32-bit/4-byte. Está normalizado por ISO como el stándard 10646-1. Los caracteres más comúnmente utilizados de UCS están contenidos en el subrango UCS-2 16-bit. Este es el subrango utlizado ahora por la consola Linux. El conjunto de caracteres que utiliza Linux por defecto para N y S America, W Europa y Africa se conoce como latin1 o ISO 8859-1.

Por comodidad, una codificación llamada UTF-8 fué diseñada para tener compatibilidad hacia atrás con ASCII. Todos los caracteres que tienen una codificación UCS pueden ser expresados como una secuencia UTF-8, y viceversa. No obstante, UTF-8 y Unicode son distintas codificaciones.

En modo UTF-8, el controlador de la consola trata al rango ASCII exactamente como antes, de manera que visores de texto antiguos pueden continuar desplegando ASCII. Los caracteres fuera del rango ASCII son convertidos a una secuencia de bytes de longitud variable (hasta 6 bytes por caracter), UTF significa en realidad Unicode Transformation Format (Formato de Transformación Unicode), y UTF-8 cubre la conversión de caracteres de 8-bit - que era el rango utilizado por los conjuntos de caracteres tradicionales.

Unicode es complejo. Sólo ten presente que nos permite asignar un código a cualquier caracter. Éste código tiene 4 bytes en su forma completa, y 2 bytes en el subconjunto UCS-2, y aquí el código unicode se vé, por ejemplo 0x2502 también se puede escribir como U+2502. Si conoces este código, puedes seleccionar el glyph (imágen) para ese caracter de alguna fuente adecuada. En realidad, aún los nombres de los glyphs están estandarizados y todos están en mayúsculas, por ejemplo:

FEMININE ORDINAL INDICATOR (INDICADOR ORDINAL FEMENINO)

¿Todo claro hasta ahora?

Problema 1: Encontrar el nombre oficial para un unicode dado.

Problema 2: Obtener el glyph para el unicode dado.

El Problema 1 no es crítico, al menos en lo que concierne al controlador de consola Linux. Los nombres más comunes pueden ser encontrados en algunos archivos '*.trans' en el directorio kbd '../consoletrans' o en algunos archivos '*.uni' en el directorio kbd '../unimaps'. Para más información:
http://partners.adobe.com/asn/developer/typeforum/unicodegn.html
El verdadero lío está en el problema 2.

GLYPHS

A pesar de que ya hemos estado hablando de glyphs, y creo que por intuición nos queda claro que es lo que son, aquí tenemos algunos comentarios adicionales.

Ejecuta tu editor de texto winword o su equivalente y escribe la letra 'a' varias veces, cambiando el tipo de fuente y el tamaño en cada una de ellas. Todas esas 'a'es se ven parecidas, aunque difieren en forma y tamaño. Lo que tienen en común es que todas ellas representas el mismo glyph, el caracter 'a'.

La referencia a un glyph es sólo una abstracción de la fuente particular que necesariamente estarás utilizando para poder ver algo.

Una fuente a es una colección de glyphs de una forma particular. Mientras que en modo gráfico se enfatiza la forma de la fuente (typeface), en modo consola nos debemos ocupar acerca de qué glyphs están incluidas o no - y quizás acerca del tamaño de los mismos. Una fuente por software para la consola viene en un archivo binario con series de bits para cada glyph. Y hay una fuente por hardware en la ROM del adaptador VGA. Ésta es la fuente que verás, si no hay fuentes por software cargadas al momento de arrancar.

UNIMAP

El mapa de fuentes de la pantalla nos da, para cada posición de la fuente de la consola, la lista de caracteres que va a desplegar. En Linux 2.4.x, el controlador de pantalla está basado en la codificación UCS-2.

El mapa de fuentes de la pantalla es conocido también como "Mapa Unicode" (Unicode Map) o "Unimap" o "Mapa de Consola" (Console Map) o "Mapa de Pantalla" (Screen Map) o "Tabla psf" (psf table), como sea. La terminología varía mucho y no contribuye para una fácil comprensión. Sobre todo porque todos estos términos tenían diferentes significados antes de que llegara Unicode. Y especialmente ya que archivos que sirven para el mismo propósito y tienen el mismo formato están nombrados con diferentes extensiones. Al parecer esto se está esparciendo, y como suena bastante diferente, vamos a ceñirnos al término "unimap" y a sus archivos '*.uni'. Si te encuentras revisando/utilizando diversas utilerías de consola, diferentes del paquete kbd, ten en cuenta este "enredo" de terminologías.

Siempre hay un unimap. Se incluye con la fuente o se carga de un archivo diferente, o como último recurso tenemos el mapeo "derecho-a-la-fuente" (straight-to-font), "directo-a-la-fuente" (direct-to-font), "trivial", "directo", "nulo", "idem" o "de identidad". Otra vez terminología que no está estandarizada y que entorpece el fortalecimiento del usuario. Mapeo "idem" significa que la petición de un caracter por ejemplo 0xB3 es recibida y el glyph en la posición 0xB3 en la fuente es seleccionado directamente. Para enrededar más esto, el mapeo "derecho-a-la-fuente" (straight-to-font) no se considera de alguna manera un unimap. Preferimos decir que siempre hay un unimap, aún que setfont del paquete kbd diga lo contrario. Ellos utilizan la opción

setfont -u none
para forzar "derecho-a-la-fuente" (straight-to-font). mapscrn, ahora incorporado dentro de setfont, llamaba "derecho-a-la-fuente" (straight-to-font) un unimap especial. Esta es la opción mas sensata, nos apegaremos a esta.

Un glyph nos puede servir para diferentes unicodes. ¿Cómo es esto? Bueno, en ocaciones glyphs idénticos tienen diferentes nombre, por ejemplo, la letra mayúscula 'A' está disponible en Ruso y en Español con diferentes nombre. Pero una fuente que cubra ambos idiomas no necesita este glyph dos veces. Así que dos unicodes nos dan en este caso el mismo resultado visual.

También puede ocurrir que dos glyphs son diferentes pero muy parecidos visualmente, así que sólo se incluye uno en la fuente para ahorrar espacio, y funciona como sustituto del otro. Esto es análogo a los viejos hábitos de la era de la mecanografía. Por ejemplo, las comillas para citar textualmente, se abrían y cerraban con el mismo glyph, aunque tipográficamente fueran distintos.

Estas alternativas están formalizadas mediante las entradas de reserva (fallback). Una entrada de reserva es una serie de dos o más códigos UCS-2, separados por un espacio en blanco. El primero es el unicode para el que queremos el glyph. Los siguientes son aquellos de los que usaremos sus respectivos glyphs en caso de que no tengamos disponible uno diseñado para el primero. El orden de códigos define el orden de prioridad (glyph propio disponible, si no el segundo, si no el tercero, etc).

Las entradas de reserva están habilitadas si se incluye en el unimap una línea como esta:

0x04a U+20AC U+004A
(Que significa: para el caracter 0x04a queremos el símbolo del Euro. Si no está disponible, tomamos el símbolo de moneda).

MODOS DE PANTALLA

Hay dos modos de pantalla, modo de byte único (hasta hace poco el valor por defecto más ampliamente utilizado) y el modo UTF-8. Cambiando la pantalla a UTF-8 y viceversa se realiza con las secuencias de escape '\e%G' y '\e%@' en el prompt. Utilizando:

unicode_start
unicode_stop
cambias el teclado y la consola a UTF-8 y viceversa.

En modo UTF-8, los bytes recibidos de la aplicación y los que serán escritos a la pantalla son interpretados como secuencias UTF-8, convertidas a unicodes y luego buscados en el unimap para determinar el glyph a utilizar.

El modo de byte único aplica un mapeo intermedio adicional a los bytes enviados por la aplicación antes de utilizar el unimap.

Éste mapeo intermedio, se llamaba el "Mapa de Caracteres de Aplicación" (Application Charset Map) o "Mapa de Aplicación de Consola" (Application Console Map) - ACM or acm. Desfortunádamente, esta es la terminología de las utilerías de consola que silenciosamente a quedado en el olvido.

El paquete kbd no le dá ningún nombre especial al mapa, se refiere a éste como una "tabla de traducción" y lo coloca en archivos con extensión '.trans'. La página del manual lo llama "Mapa de Consola Unicode" (Unicode console map) que es bastante ambiguo, ya que nos recuerda al Mapa Unicode (unimap). Llamémoslo "cmap", una abreviación utilizada aquí y allá.

Aquí tenemos un diagrama simple de los dos modos:


    Modo byte único :
        aplicación ->      cmap ->         unimap -> pantalla
                     (bytes)      (UCS-2)

    Modo UTF-8:
        aplicación ->                      unimap -> pantalla
                     (UTF-8 / UCS-2)


Memoriza este diagrama ya que es la clave para entender esta confusión de términos en la documentación. Asegúrate que puedes distinguir entre cmap y unimap: ¿Qué es lo que hace cmap?

¿QUÉ ES LO QUE HACE CMAP?

Hay varios formatos para cmap, y sólo uno que nos permite entender lo que realmente hace cmap. Por ejemplo, echa un vistazo al archivo 'cp437_to_iso01.trans' en el directorio '../consoletrans' del paquete kbd. El código de página 437 viene de los tiempos del primer DOS y aún es la fuente en la ROM de cualquier adaptador VGA.

El archivo tiene dos columnas de números hexadecimales. La primera columna es una enumeración de las entradas en la fuente, 256 como máximo. Solamente 256 pueden ser manejadas por cmap.

La segunda columna es la traducción. El archivo en cuestión hace posible utilizar una fuente cp437 como si fuera una fuente latin1. La traducción no es perfecta, pero funciona, por ejemplo:

0xA1 0xAD
El carácter 0xA1 en cp437 es una vocal acentuada que nos es correcto para este código en latin1. Así que cmap está informando al controlador de consola que responda como si la petición de carácter fuera para 0xAD. El controlador de consola va al unimap "derecho-a-la-fuente" (straight-to-font) y lee la posición unicode 0xAD. Lo que resulta ser U+00a1, el símbolo de exclamación invertido. La siguiente parada es la fuente donde el glyph para U+00a1 debe ser seleccionado. En resumen, tuvimos una petición para 0xA1 pero no recibimos el carácter en esa posición en cp437, obtuvimos el símbolo invertido de exclamación de la posición 0xA1 en latin1. Nuestro cp437 se comporta como una fuente latin1 gracias a cmap. Este ejemplo funciona sin problemas, pero en otros casos, ya que cp437 y latin1 son muy diferentes, obtendríamos un símbolo inapropiado, representado por algún carácter de sustitución genérico. O una aproximación, una alternativa, por ejemplo, obtienes una 'A' mayúscula donde necesitabas la misma letra con un acento circunflejo sobre ella.

Cuando utilizamos fuentes de 256 caracteres, un cmap que realmente traduce significa que da alternativas. Cuando no se necesitan alternativas, el cmap es "derecho-a-la-fuente" (straight-to-font): cada carácter se traduce a su mismo código, solamente el unimap es relevante. Este es el más natural y común caso.

Sin embargo, una fuente puede estar diseñada para abarcar más de un rango de caracteres. Esto es evidente para las fuentes de 512 caracteres pero hay en realidad fuentes de 256 caracteres que pueden manejar más de un rango de caracteres (claro que parcialmente). Si utilizas esa clase de fuentes, el cmap te permite seleccionar uno de los rangos cubiertos. Un ejemplo (lat1-16.psfu) se discute a continuación.

LEYENDAS G0/G1

Aunque solamente hay un cmap activo en un momento dado, el kernel maneja cuatro de ellos. Tres de ellos son empotrados y nunca cambian. Estos definen el código de página IBM 437 de las primeros versiones de DOS con caracteres de caja, el conjunto de caracteres DEC VT100 también con caracteres de caja, y el conjunto ISO latin1. El cuarto conjunto de caracteres del kernel está definido por el usuario, por defecto el mapeo "derecho-a-la-fuente" (straight-to-font), y sólo puede ser cambiado cargando una fuente por software.

El controlador de consola tiene dos entradas etiquetadas G0 y G1, cada una referenciando a alguno de los conjuntos de caracteres del kernel. G0 y G1 pueden variar de consola a consola mientras que apunten a cp437, vt100, latin1. Si pones un cmap diferente de estos tres en cualquier entrada G0 o G1 en cualquier consola, todas las demás consolas cambiarán al mismo conjunto de caracteres definido por el usuario. Por defecto, G0 apunta a latin1 y G1 apunta a vt100. G0 y G1 pueden ser manipulados con secuencias de escape en la consola. Y a pesar de que son mencionados frecuentemente, mejor los dejas tal cual. ¿Por qué?

Si cargas una fuente por software y envías secuencias de escape para cambiar de conjuntos de caracteres del kernel, podrías estar aplicando a tu fuente por software una traducción que produce bastante basura. El cmap que selecciones debe ser adecuado para tu fuente y ser un "jugador del equipo" con el unimap actual. La única garantía que tienes al respecto es confiar en 'setfont' y controlar cmap y unimap. Si comienzas a mezclar comandos 'setfont' con secuencias de escape a la consola, los cuales se basan parcialmente en los valores por defecto, podrías (¡seguramente!) terminar perdiendo el rumbo. Para mantener cmap y unimap bajo control, utiliza fuentes que tengan un unimap incluido y utiliza

setfont -m none mi_nueva_y_hermosa_fuente.psfu
Cuando cargues una fuente por software de 256 caracteres. Esto nos da una buena garantía de no interferencia si no estás experimentando con utilerías de teclado al mismo tiempo, ya que estas podrían afectar las fuentes de la consola. Para fuentes de 512 letras, debes saber lo que hay adentro, y debes conocer los nombres de los conjuntos cubiertos (por ejemplo los archivos '*.trans' correspondientes) de otro manera no podrás cambiar entre ellas.

¿Y qué acerca de los conjuntos definidos por el usuario? Si le has echado un vistazo a una fuente por software (y siempre que ejecutas 'setfont' cargas una fuente por software, a excepción de cuando estás guardando la fuente actual a disco), la secuencia de escape para seleccionar el conjunto de caracteres definido por el usuario del kernel activa ésa fuente por software con el conjunto de caracteres implícito a su cmap y no tienes manera de revertirlo a la fuente de la ROM. Si revisas el código fuente de 'setfont', te darás cuenta que están activando la fuente por software de todos modos. Olvídate del conjunto definido por el usuario, no es de tu incumbencia, deja esto a 'setfont'.

Por otro lado, si ejecutas la fuente de la ROM y no has cargado una fuente por software, solicitar el conjunto definido por el usuario solamente hará que cambies a cp437, la razón por la que el conjunto definido por el usuario tiene "derecho-a-la-fuente" (straight-to-font) como valor por defecto. Por ejemplo, asúmamos que escogiste vt100 que no tiene letras minúsculas e inmediatamente nos desplegará basura, envía la secuencia de escape para el conjunto definido por el usuario (que no ha sido definido aún, por lo que contiene el valor por defecto): la basura desaparece y tenemos las minúsculas de nuevo.

Hay, sin embargo, una fuente por software que ha sido explícitamente hecha para lidiar con los conjuntos del kernel. Esta fuente se llama

lat1-16.psfu
y no es una fuente latin1 como sugiere su nombre, es un híbrido. Con el cmap puesto a cp437 trabajará con la mayoría de los cp437 (todos los elementos de bloque y caja), con el cmap puesto a latin1 trabajará con latin1. Y también trabajará vt100, si es que a alguien le interesa. Solitar el cmap definido por el usuario nos revela que la fuente utiliza los rangos de control normalmente vacios (0-31, 128-159) para almacenar juntos los caracteres de cp437 y latin1.

Advertencia: Si estás en una región donde latin1 no es adecuado, mantente con la fuente proveida por tu distribución (y seguramente despídete de los elementos de dibujo caja). Si latin1 funciona, utiliza lat1-16.psfu. Esto te dará los caracteres latin1 además de las lineas-caja de tu administrador de archivos.

DOCUMENTACIÓN O LA FALTA DE ELLA

Los problemas sobre las fuentes para la consola Linux están pobremente documentados. Las páginas del manual (man) son muy densas, la terminología es ambigua, y los COMOs (HOWTO's) que vienen con el paquete kbd son un desastre, me pregunto si la gente que los recomienda alguna vez a intentado leerlos.

Todo lo presentado en este artículo es elemental y aún así tomó su esfuerzo para hilarlo. Vamos a resumirlo desde un punto de vista diferente, no nos afectará en lo más mínimo.

(i) La fuente de la ROM (Siempre 256 caracteres) (ii) Fuentes de consola por software
(a) 256 caracteres como máximo (b) 257-512 caracteres
Alguien se encuentra trabajando en un nuevo controlador de consola para Linux 2.6.0. ¿Podemos hacer alguna orden? Algún truco para utilizar fuentes de consola mayores a 512 caracteres; cada consola con su propia fuente; sin interferencias de fuentes grandes con colores. Muchas gracias.

PREGUNTAS Y RESPUESTAS

¿Cómo forzo la fuente de la ROM en la consola?

Debe haber alguna utilería en algún lugar, pero no está en el paquete kbd. Sin una utilería como esa, la única manera de forzar la fuente de la ROM es arrancar con la fuente de la ROM. Revisa tus scripts init y asegúrate de que no se carguen fuentes por software. Si no lo encuentras, renombra el directorio donde se encuentra la fuente por software, de manera que no se pueda encontrar/cargar al momento de arrancar.
¿Cómo guardo la fuente de la ROM a un archivo?
Mientras estés utilizando la fuente de la ROM, intenta:

echo -ne '\e(U'
setfont -o cp437-16.psf

en el prompt. El archivo cp437-16.psf contiene la fuente de la ROM. Esta fuente tiene una altura de 16 pixeles.

¿Cómo sé que fuente está utilizando la consola?
Si te refieres a qué nombre tiene la fuente, revisa los scripts de arranque y/o el log del shell para saber que fuente por software fué cargada la última ocasión (quizás ninguna, lo que significa que la fuente de la ROM está activa). Si quieres ver los caracteres de la fuente de acuerdo con su arreglo actual, ejecuta:

echo -ne '\e(K'
setfont -om fuente_actual.trans

y revisa el archivo 'fuente_actual.trans' con algún editor. Esto no funciona al 100% ya que ciertos rangos de caracteres (0-31 y 128-159) no son desplegados de manera correcta aunque probablemente estén almacenando glyphs. Si la fuente tiene un unimap, este enlistará todos los caracteres con sus nombres oficiales. Lo cual seguramente nos dará una idea del glyph.

Creé mi propia fuente en base a latin1 añadiendo elementos-caja en el rango no utilizado 128-159. Funciona, pero las lineas horizontales tienen espacios pequeños. ¿A qué se debe?
Los caracteres son de 8 pixeles de ancho, pero el hardware VGA añade una novena columna en blanco para desplegarlos a una pequeña distancia unos de otros. Eso es bastante apropiado para la mayoría de los caracteres, pero no para los segmentos de linea horizontales que deberían aparecer completamente pegados. Por esta razón el hardware VGA hace una excepción para los elementos-caja: en lugar de insertar espacios vacíos repite la octava columna de pixeles. Hasta ahí vamos bien, pero ¿De qué manera el hardware VGA distingue dónde pusimos nuestros elementos-caja? No hay forma, así que o pones estos elementos en el mismo rango donde se encontraban en cp437 o vas a tener esos espacios.
¿De qué manera utilizo una fuente de 512 caracteres y conservo los colores?
Necesitas arrancar con el framebuffer, para detalles revisa el Framebuffer-HOWTO.html. Las opiniones acerca del framebuffer están divididas, Mandrake arranca en él por defecto, SuSE advierte sobre esto. Desconozco la posición oficial de Red Hat's pero ellos no lo utilizan a pesar de que utilizan una fuente con un conjunto de 512 caracteres, lo cual deshabilita los colores.
lati1-16.psfu es una fuente con 256 caracteres y aún así cubre más de un conjunto. ¿Cómo es esto posible?
Sólo es posible debido a que cubre solamente en parte cada conjunto o a que cubre conjuntos menores de 256 caracteres. cp437 está hasta el tope, tiene exactamente 256 caracteres, de manera que lat1-16.psfu lo cubre parcialmente. Por otro lado, latin1 mantiene el rango de caracteres de control (0-31 y 128-159) vacío, de manera que sólo contiene 192 caracteres. vt100 es manejada como un conjunto de 128 caracteres pero complementada con latin1 en el rango 160-255. De manera que en esencia lo que hace lat1-16.psfu es mantener los elementos caja-bloque en donde se encontraban usualmente en cp437 y mover los caracteres latin1 a algún otro lugar. De esta manera todo cabe dentro del conjunto de 256 caracteres. Bien hecho.
¿Es la fuente de la consola única para todas las consolas o puede variar de una a otra?
La fuente de la consola es la misma para todas las consolas, lo que puede variar es el conjunto de caracteres (cmaps) utilizado en cada una de ellas.

 


Copyright © 2003, En D Loozzr. Licencia de copia http://www.linuxgazette.com/copying.html
Publicado en el número 91 de Linux Gazette, Junio 2003