domingo, 16 de septiembre de 2007

GBM 1.52 o de la timidez de SSI

Heiko Nitzsche ha actualizado su versión mejorada de GBM (Generalised Bitmap Module) una librería y una serie de utilidades para trabajar con diversos formatos de imagen de mapa de bits (como los formatos JPEG, GIF o PNG). La última versión anterior al trabajo de Nitzsche de la dll (GBM.DLL) forma parte de eComStation 1.2; el procedimiento multimedia para ver ficheros JPEG (un reemplazo del original hecho por IBM, programado por Chris Wolgemuth) depende de esa biblioteca.

El trabajo de Nitzsche no es moco de pavo: ha añadido nuevos formatos y mejorado el soporte de los formatos ya existentes, ha actualizado los visualizadores de imagen, ha añadido un plugin para Firefox (y familia) y otro para Lucide, así como un API que permite previsualizar las imágenes en los diálogos de apertura de ficheros y una extensión que permite acceder a todas estas funcionalidades desde REXX y además todo esto lo hace utilizando compiladores modernos (OpenWatcom 1.7).

De hecho, el conjunto de procedimientos multimedia parte de eSchemes Deluxe denominado Imagination que añade nuevos formatos de imagen al sistema multimedia de OS/2 está basado en el trabajo de Nitzsche.

Y ahora pasamos a Serenity Systems International, los responsables de eComStation y los listados de características de las betas de la próxima versión de su distribución de OS/2 (eComStation 2.0): en ningún lugar se habla de la inclusión de la versión de GBM mejorada por Nitzsche.

Y eso me hace preguntarme por qué SSI realiza tan timidamente muchas modificaciones al sistema operativo (las referentes a ACPI, controladores de tarjetas de red y demás controladores podría decirse que son por necesidad). Hay docenas de programas que podrían ser incluidos y GBM es solamente un ejemplo: programas de grabación de CDs y DVDs (Audio/Data-CD-Creator, dvddao, cdrtools, All2Iso), clientes para compartir archivos (ctorrent -del que parece existir un front-end-), clientes de correo (está incluido Thunderbird, pero RexxMail ¡es tan WPS...!), gestores de descargas (las últimas versiones de wget y el maravilloso Auto WGet Daemon), utilidades varias (la utilidad para el portapapeles ClipView), extensiones REXX (rxu, por mencionar el ejemplo más notable)...

Además, uno supone que no debería ser difícil para SSI sustituir el visor de imágenes incluido en OS/2 por algo más moderno (al estilo del de Windows XP), hacer un conversor de formatos de imagen, un editor de imágenes (al estilo del MS Paint) e incluir un capturador de imágenes sencillo (Gotcha es un punto de partida para hacer uno bien integrado con el sistema, el visor de GBM incluye otro capturador)... por mencionar solamente uno de los tipos de datos que puede manejar un sistema operativo.

¿Por qué no lo hacen? ¿Miedo a que el sistema pierda estabilidad? ¿Falta de recursos económicos y humanos (invertidos en el corazón del sistema, que es esencial para que todo lo demás funcione)? ¿Implicaciones legales? ¿Falta de ideas?

sábado, 15 de septiembre de 2007

Como averiguar si un script está en una consola

En un mundo en el que las interfaces gráficas de usuario en general y los entornos de escritorio son algo omnipresente no deja de resultar muy curioso el hecho de que cada sistema operativo ha optado por métodos muy diferentes a la hora de ejecutar sus scripts diseñados para la consola desde el entorno de escritorio. Es decir, cuando hacemos doble click sobre el icono correspondiente al script.

Windows y OS/2, por ejemplo, abren una consola cada vez que se ejecuta un fichero bat o cmd (en el caso de OS/2, los ficheros cmd pueden ser programas escritos en REXX o incluso pueden ser programas escritos en Python o Perl no simples ficheros de proceso por lotes). Windows no ofrece muchas facilidades para ocultar la ventana de la consola. OS/2 ofrece bastantes alternativas para ocultarlo si es necesario y modos de ejecutar pequeños diálogos gráficos cuando la consola está oculta.

BeOS nunca abre una consola cuando se ejecuta un script. Tradicionalmente en BeOS todo aquel script que estuviese pensado para el escritorio utilizaba el comando alert de BeOS que permitía mostrar al usuario pequeños diálogos con sus correspondientes mensajes y botones.

Con los entornos de escritorio usuales en Linux (Gnome y KDE, aunque haya docenas más con muy buenas ideas, por cierto) lo habitual es que el comportamiento fuese el mismo que en BeOS. Actualmente lo usual en Gnome (por ejemplo) es que cuando un usuario hace doble click sobre un script aparezca un diálogo que le pide confirmar si quiere ejecutarlo, ejecutarlo abriendo una terminal, editarlo o cancelar la apertura.

Ocasionalmente puede ser interesante que un script averigüe si se está ejecutando en una consola o no y para ello el comando tty nos puede servir muy bien puesto que la salida de ese comando nos indica el número de terminal en el primer caso o nos dice "not a tty" en caso contrario. Así podemos hacer de forma sencilla lo siguiente:
  #!/bin/bash

if [ "$(tty)" = "not a tty" ]; then
echo "No es una terminal"
else
echo "Sí es una terminal"
fi

exit 0

Lo que en REXX quedaría como:
  /*bin/true;exec rexx "$0" "$@";exit # REXX */

'tty | rxqueue'
parse pull tty

if tty = 'not a tty' then
say 'No es una terminal'
else
say 'Sí es una terminal'

exit 0

El código de retorno del comando nos da la misma información:
  #!/bin/bash

tty=$(tty)

if [ $? = 1 ]; then
echo "No es una terminal"
else
echo "Sí es una terminal" # $? es igual a 0
fi

exit 0

En REXX:
  /*bin/true;exec rexx "$0" "$@";exit # REXX */

'tty > /dev/null'

if rc = 1 then
say 'No es una terminal'
else
say 'Sí es una terminal' /* rc es igual a 0 */

exit 0

Esto nos permite, por ejemplo, forzar la ejecución del programa en una terminal:
  #!/bin/sh
# Ejemplo para BeOS
# Cada entorno de escritorio tiene su propio ejecutable
# para la terminal.
myself=$0
if [ "$(tty)" = "not a tty" ]; then
Terminal -t "Ejemplo" /bin/sh -c "$myself"
else
echo 'Sí una terminal'
fi

Con kdialog, zenity o xdialog podemos hacer pequeños scripts interactivos como en el siguiente caso:
  /*bin/true;exec rexx "$0" "$@";exit # REXX */

current_date = date('S')

'tty > /dev/null'

gui = rc

if gui = 1 then do
'zenity --title "Escoja su fecha de nacimiento"' ||,
' --calendar --date-format %Y%m%d | rxqueue'
pull birthday_date
if rc = 1 then
exit 1 /* Pulsado el botón "Cancelar" */
end
else do
say 'Introduzca su fecha de cumpleaños (19770223):'
parse pull birthday_date
end

age_in_days = say date('B', current_date, 'S'),
- date('B', birthday_date, 'S')

if gui = 1 then do
'zenity --warning --text "Su edad en días es:',
age_in_days '"'
else do
say 'Su edad en días es' age_in_days

exit 0

jueves, 13 de septiembre de 2007

La máquina expendedora de ooRexx

David Ashley, uno de los líderes del desarrollo del intérprete Open Object REXX (también conocido como ooRexx) anuncia hoy en comp.lang.rexx que el servidor de compilación de Open Object REXX está listo y la página asociada para acceder a él, también lo está. Tal como estaba previsto hace ya bastantes meses y como al parecer se comentó en el simposio internacional de este año. Básicamente ese servidor es una máquina con un Fedora Core 6 y un conjunto de sistemas operativos ejecutados como invitados a través de un VMware Server 1.0.3. Por ahora las elecciones no son muy variadas: Fedora 7, Ubuntu 7, Windows 2000 y Windows XP. Esto deja fuera otros sistemas para los que ya existen versiones oficiales del intérprete (AIX, Mac OS X y Solaris) y versiones no oficiales (FreeBSD). Lo que más me llama la atención de esta iniciativa es la enorme conexión que establece entre un lenguaje que deriva de REXX y SmallTalk (y que por lo tanto tiene una tradición tan larga que hace que sea fácil tacharlo de antigüedad) y algo tan en boga y de moda como son las máquinas virtuales. La máquinas virtuales no son el único punto de conexión de ooRexx con cosas que no están nada trasnochadas: gracias a Rony Flatscher y sus alumnos tenemos BSF4Rexx que permite ejecutar código Java desde REXX (desde Object REXX de forma completamente transparente) y código REXX desde Java; gracias también a Rony se puede acceder a OpenOffice y su sistema de componentes UNO desde Open Object REXX permitiendo el control externo de la aplicación, así como el escribir macros en ooRexx; gracias a David Ashley también disponemos de una mod_rexx apto para las últimas versiones del servidor Apache; René Vincent Jansen insinua en su blog que la integración entre ooRexx y el sistema de scripting de Mac OS X es cada vez mejor... En definitiva, la comunidad de viejos dinosaurios se mueve aun y se moderniza. Que el equipo de desarrolladores pongan al servicio de la comunidad esta máquina expendedora que escupe la versión binaria más reciente correspondiente al código almacenado en los depósitos Subversion resulta (al menos desde el punto de vista intelectual) muy estimulante.

martes, 11 de septiembre de 2007

Free Pascal Compiler 2.2.0 en OS/2 y eComStation

Ayer me enteré a través de Barrapunto de la salida de la versión 2.2.0 de Free Pascal Compiler, un compilador de Pascal y Object Pascal de código abierto multiplataforma (OS/2, Linux -versiones de 32 y 64 así como para arm-, FreeBSD, Windows -incluidos Vista y CE-...) y me llama bastante la atención que no se haya mencionado nada todavía en ninguno de los portales dedicados a OS/2.

Y me llama la atención porque Pascal, sus dialectos y sus derivados siempre han dado un buen puñado de programas populares y útiles para OS/2 (dejamos de lado el hecho de que en otros sistemas operativos uno de mis programas favoritos de todos los tiempos esté hecho en Delphi: Total Commander de Christian Ghisler).

Por poner un ejemplo, en este mismo instante estas líneas las escribo en el editor de texto de eComStation, el AE de Aaron Lawrence, que está hecho en Sibyl (una especie de Delphi para OS/2), mientras tengo un cliente IRC hecho con Virtual Pascal (Virtual IRC) conectado y escucho esa deliciosa excentricidad de Mike Oldfield llamada Amarok con el reproductor Z! hecho con Virtual Pascal. Y hay cientos de ejemplos así:
  • En Virtual Pascal: el reproductor MP3 en modo texto Z! (también disponible para Windows), Web/2 (un estupendo servidor web, ligero y sencillo también disponible para Windows), Virtual IRC (un cliente IRC), Normal Player (un reproductor que usa el sistema multimedia de OS/2)...
  • En Sibyl o su variante GPL WDSibyl (disponible para Windows): NewView (el nuevo visor de ayuda que es componente de eComStation), AE (el editor de texto que es componente de eComStation), el USB Resource Manager, el programa de configuración de TCP/IP de Reinhard Berger...
  • En Modula, un lenguaje derivado de Pascal: FTPServer (un estupendo servidor FTP) y Weasel (un estupendo servidor de correo) ambos de Peter Moylan.
  • En Oberon, otro derivado de Pascal, DrDialog (una herramienta gratuita de desarrollo RAD en REXX).

Viendo la tradición de Pascal en OS/2, me llama la atención que la comunidad en torno a este sistema operativo no se haya hecho hecho eco de la noticia de esta nueva versión del compilador FPC.

Como nota curiosa, he descubierto que el cliente IRC está programado con Virtual Pascal cuando mi amiga Nerea ha intentado pasarme un fichero a través de DCC y el cliente ha dado un típico fallo en tiempo de ejecución de los que dan los programas hechos con ese compilador. Y el fallo era por una razón bastante peculiar: ¡me había quedado sin espacio en mi partición de OS/2!

domingo, 9 de septiembre de 2007

Macros REXX en IBM Works

Mientras intento recuperarme de la impresión de ver 300, la adaptación del cómic de Frank Miller al cine (Miller, aunque algunos no le perdonemos aun el guion de Robocop 2, parece tener bastante más suerte en esto que el pobre de Alan Moore), me gustaría hablar de cómo estaban implementadas las macros en una aplicación que ya tiene más de 10 años: IBM Works.

Las macros, desde el punto de vista de un usuario final, son conjuntos de acciones que permiten ahorrar trabajo al usuario en un programa concreto. Ejecutando la macro al pulsar una combinación de teclas, pulsar un elemento de un menú, seleccionarla en un diálogo o como permita el programa, el usuario puede evitar realizar tareas repetitivas como inserta el carácter hebreo aleph, selecciona el párrafo y dale otro formato...

Ocasionalmente, las macros pueden tener una lógica interna más allá de una secuencia de tareas repetitivas y entonces el modo de realizarlas es a través de un lenguaje de programación de macros. Y son de estas macros de las que quiero hablar.

El problema que siempre ha existido con los lenguajes de programación de macros es que son específicos de la aplicación: el cliente IRC mIRC tiene su lenguaje de macros, Microsoft Office hasta ahora ha utilizado una variante de BASIC (Visual Basic for Applications), Open Office ha utilizado otra variante de BASIC, Lotus SmartSuite utiliza LotusScript, el editor de audio Audacity usa su propio lenguaje...

Esto quiere decir que si el usuario desea aprender un lenguaje de macros, probablemente no pueda reutilizar sus conocimientos en otro sitio. Además, en algunos casos, la complejidad del lenguaje de macros para el tipo de tarea que desea el usuario puede resultarle excesiva (se encuentra con tipos de variables, declaraciones, módulos, objetos, métodos, sistemas de componentes y similares incluso para las macros más sencillas).

Cuando hace más de 25 años, Mike Cowlishaw creó el lenguaje de programación REXX, uno de sus propósitos era que fácilmente pudiera ser utilizado como un lenguaje de macros. Y cuando IBM empezó a introducirlo como lenguaje de scripts de todos sus sistemas operativos, también empezó a convertirse en el lenguaje de macros de muchas aplicaciones para esos sistemas.

En el mundo de la informática personal, dos sistemas operativos (uno ajeno a IBM) escogieron implementaciones de REXX como su lenguaje de macros preferido: OS/2 y Amiga OS.

En OS/2 existía un pequeño paquete de oficina llamado IBM Works cuya hoja de cálculo utiliza macros REXX aunque apenas aproveche las posibilidades de esto.




Como puede verse en la segunda imagen, la primera columna corresponde a nombres de personas, la segunda a un NIF (Número de Identificación Fiscal) y la tercera muestra una comprobación de la validez del NIF utilizando una función de la hoja de cálculo IBM Works: =rexx("isValidNIF.fnc",1,1,B4). La función rexx de IBM Works busca un fichero indicado en el primer parámetro (isValidNIF.fnc), decide que el valor de la celda será texto (si tuviésemos 0 en lugar de 1 tras la primera coma, trataría la celda como número) y lo ejecuta pasándole el número de parámetros indicado en el tercero de sus parámetros (en este caso uno)... Y el código de la macro no puede ser más sencillo:
/* isValidNIF.fnc */
parse arg nif
letras = 'TRWAGMYFPDXBNJZSQVHLCKE'
numeros = '0123456789'

letra = right(nif, 1)
dni = left(nif, length(nif) - 1)

select
when pos(letra, letras) = 0 then
ret = 'ERROR: Último carácter no es una letra'
when verify(dni,'1234567890') <> 0 then
ret = 'ERROR: El NIF debe comenzar por un número válido'
when letra = substr(letras, dni//23 + 1, 1) then
ret = 'NIF válido'
otherwise
ret = 'ERROR: La letra no corresponde al DNI'
end

return ret

En esta aplicación concreta, la utilización de REXX como lenguaje de macros se ve reducida a su mínima expresión (al contrario que en casos como gnuplot, gdb, Photo>Graphics, GoServe, EPM...) y a pesar de ello se aprecia la sencillez.

Esto no solventa uno de los problemas de los sistemas de lenguajes de macros: la dependencia de un lenguaje concreto.
Microsoft intentó eliminar la dependencia del lenguaje a través de su sistema de componentes COM que permite utilizar cualquier lenguaje para el que exista un WSE (Windows Scripting Engine) en cualquier aplicación que funcione como WSH (Windows Scripting Host) como son Internet Explorer o IIS, por ejemplo (y no es Microsoft Office, curiosamente), pero el sistema es incómodo para un no iniciado. OpenOffice desde sus últimas versiones permite ejecutar macros en más de un lenguaje, pero el sistema es tan barroco como el caso de los sistemas de Microsoft.
Quizás la aproximación que dando independencia de lenguaje conserva la sencillez es una de las que siguen virtualmente todos los servidores web y algunos editores de texto: la macro se ejecuta por el intérprete deseado y coge la információn necesaria de la entrada estándar, los parámetros y las variables de entorno y devuelve la información a la aplicación a través de su salida estándar. Así es como funcionan los CGIs en los servidores web y las macros en el editor de texto para programadores TextMate (aunque en este caso, la documentación del editor restringe el concepto de macro), por ejemplo.

Es una pena que a veces las cosas sean innecesariamente complejas.

Incidentalmente: en la distribución del intérprete newLISP para Windows puede encontrarse un ejemplo de fichero de Excel que incluye una macro en Visual Basic que define una función que permite ejecutar código newLISP en cualquier fórmula de Excel de un modo muy similar al ejemplo de IBM Works. Y el mismo sistema puede utilizarse para ejecutar código de otros lenguajes.

Synergy en OS/2

,a href="http://www.netlabs.org":Netlabs,/a: cumple 10 aos, lo que es un buen motivo de celebracin... No es que me haya equivocado de tecla, es que estoy usando el teclado y el ratn del porttil de mi hermana (Windows) en mi ordenador de sobremesa (eComStation). Y que nadie piense que he sido tan bruto como para despedazar el porttil y hacer una chapuza, simplemente estoy usando Synergy a travs de la red. Pero volvamos a mi teclado...

Hace unos días, Netlabs cumplía 10 años y explorando el directorio incoming en su servidor FTP como hago de vez en cuando me tropecé con un misterioso fichero llamado synergybart.zip. El bart me sugería quién era probablemente el autor (Bart van Leeuwen), pero el synergy me dejó descolocado y como la curiosidad extrema es uno de mis numerosos defectos, descargué el fichero y le eché un vistazo para encontrarme... que no llevaba ninguna documentación.

Una rápida búsqueda a través de Google permite ver que Synergy es un programa libre multiplataforma (hay versiones para Windows, Linux y Mac OS X) que permite usar el teclado y el ratón de un ordenador concreto (el servidor) en varios ordenadores conectados en una red. Es decir, podemos tener tres monitores correspondientes a tres CPUs distintas y controlar todos desde el mismo teclado y ratón. Moviendo el puntero a los bordes de un monitor, pasamos al siguiente...

El que comparte el teclado y el ratón funciona como servidor ejecutando synergys.exe con la configuración y los parámetros adecuados. En mi caso, el fichero de configuración synergy.conf es así:
section: screens
salva:
fran:
end
section: links
salva:
right = fran
fran:
left = salva
end
section: options
screenSaverSync = false
end

En él se indican los nombres de los monitores y además la posición relativa de los mismos (fran está a la derecha de salva y salva está a la izquierda de fran).

Si mi máquina tiene mi como IP la 192.168.0.3 y la de mi hermana tiene como IP la 192.168.0.1 y la mía funciona como servidor, debo ejecutar synergys.exe --config synergy.conf --name salva en mi máquina y synergyc.exe --name fran 192.168.0.3 en el portátil de mi hermana. Mientras que en el caso en el que el servidor es el portátil, debo ejecutar synergys.exe --config synergy.conf --name fran en el portátil y synergyc.exe --name salva 192.168.0.1 en mi ordenador.

La versión de OS/2 del servidor parece no funcionar bien; solamente consigo que el puntero en el portátil se mueva, pero renqueando y sin que funcionen los botones y el teclado envía la señal al servidor en lugar de al cliente. (Digo parece porque puede ser culpa de la configuración.) La versión de OS/2 del cliente parece funcionar bien, salvo por lo que queda patente en el primer párrafo de la entrada.

De hecho, lo más espectacular es ver cómo se copia y pega texto del clipboard (portapapeles) de forma completamente transparente entre una máquina y otra. (ClipView, la utilidad de Dave Saville también permite compartir el portapapeles entre dos máquinas a través de la red.)

sábado, 8 de septiembre de 2007

La sentencia parse version

La instrucción parse de REXX permite, entre muchas otras cosas, saber con qué intérprete y qué versión del mismo estamos trabajando. A través de la sentencia parse version rexxVersion, el intérprete da a la variable un valor que indica el nombre del intérprete, el nivel del lenguaje y la fecha del intérprete.

Así, por ejemplo, si es el intérprete de REXX clásico de eComStation el que interpreta el código, la variable valdrá REXXSAA 4.00 3 Feb 1999. Si es Regina, puede resultar algo como REXX-Regina_3.3(MT) 5.00 25 Apr 2004 en las versiones más recientes o REXX-Regina_3.0 4.95 25 Apr 2002 en versiones anteriores. Si es Reginald, puede devolver REXX-Reginald_4.6 4.00 13 Aug 2005, por ejemplo. Si es Open Object REXX, el resultado podría ser REXX-ooRexx_3.0(MT) 6.00 28 Mar 2005.

En el primer ejemplo, REXXSAA identifica el intérprete REXX como el que forma parte de OS/2 y eComStation (si bien el intérprete REXX que forma parte del sistema operativo PC-DOS de IBM también se identifica a sí mismo como REXXSAA como probablemente le ocurra a alguna implementación más de IBM). El número 4.00 corresponde al nivel del lenguaje: el 4.00 corresponde al definido por la segunda edición de The REXX Language de Mike Cowlishaw, el nivel 5.00 corresponde al definido por el estándar ANSI de 1996 y el 6.00 corresponde al superconjunto de REXX clásico que es Object REXX. Y la fecha se supone que indica la fecha del intérprete en el mismo formato que date().

El estándar ANSI especifica que el nombre del intérprete debe ser la palabra REXX en mayúsculas seguida del nombre del intérprete en si mismo. Pero en algunos casos, el intérprete no sigue esa norma, como en el caso del Object REXX de IBM, que devuelve OBJREXX 6.00 18 May 1999, o BRexx, que devuelve brexx 2.1.0 Mar 11 2003 (debe apreciarse que en este caso BRexx tampoco indica el nivel del lenguaje, sino su versión y que el formato de fecha no es el que se considera correcto por el estándar ANSI).

Entre los intépretes más modernos se ha extendido la costumbre de indicar la versión del intérprete y la indicación de si es o no multithreaded (multihilo):
  • Regina (multihilo): REXX-Regina_3.3(MT) 5.00 25 Apr 2004
  • Regina (ejecutable estático): REXX-Regina_3.3 5.00 25 Apr 2004
  • Reginald: REXX-Reginald_5.0 4.00 9 Apr 2006
  • Reginald Lite: REXX-RegLite_5.0 4.00 3 Apr 2006
  • Open Object REXX: REXX-ooRexx_3.0(MT) 6.00 28 Mar 2005

El distinguir que intérprete y/o que nivel del lenguaje ejecuta nuestro código nos permite aprovechar características de un intérprete concreto o un nivel del lenguaje sin dejar a los otros fuera.

El manejo de ficheros en REXX es una de las cosas que más cambian de una implementación a otra del lenguaje. Utilizando parse version podemos hacer lo siguiente:
parse version rxInterpreter rxLevel rxDate
select
when rxLevel < 4 then
IO_routines = 'EXECIO'
when rxLevel < 5 then
IO_routines = 'ANSI'
when rxLevel >= 5 then
IO_routines = '.STREAM'
otherwise
nop
end
para decidir si usamos el comando EXECIO de los mainframes como sistema de manejo de ficheros, las funciones del estándar ANSI (stream, charin, lineout...) o el objeto Stream propio de Object REXX. O, si queremos dar soporte a BRexx y AREXX:
parse version rxInterpreter rxLevel rxDate
select
when rxInterpreter = 'AREXX' then
IO_routines = 'AREXX'
when rxInterpreter = 'brexx' then
IO_routines = 'BREXX'
when rxLevel < 4 then
IO_routines = 'EXECIO'
when rxLevel < 5 then
IO_routines = 'ANSI'
when rxLevel >= 5 then
IO_routines = '.STREAM'
otherwise
nop
end

En ese ejemplo, consultando la variable IO_routines, podemos decidir qué código queremos ejecutar.

Evidentemente este sistema es de utilidad limitada. Hay tantos intérpretes REXX para tantas plataformas que es imposible para cualquier programador conseguir que un programa de mediana envergadura se aproveche de parse version para que se ejecute en todos ellos.

viernes, 7 de septiembre de 2007

Salvando datos a través de FTP

Un cliente nos trajo hace muy poquito un portátil HP al que deseaba que le realizásemos un formateo y una reinstalación del sistema operativo (un Windows XP Home Edition) sin borrarle sus ficheros y directorios de la partición de datos.

El procedimiento no sería difícil de no ser por tres puntos esenciales:
  1. El sistema operativo no arranca ni en modo seguro.

  2. El cliente ha destruido la partición de recuperación de HP

  3. Un Windows XP Home Edition Service Pack 2 ordinario no reconoce el disco duro SATA del citado portátil.

La partición de recuperación que suelen incluir la mayor parte de los fabricantes que venden equipos preinstalados (HP, Dell, Acer...) generalmente es accesible a través de algún tipo de obscuro atajo de teclado en el arranque del PC. El PC arranca el sistema desde la partición de recuperación y normalmente puede recuperarse la partición del sistema tal como venía "de fábrica" sin tocar para nada la partición de los datos.
En el peor de los casos, cuando desconocemos el atajo de teclado o éste no funciona, podemos establecer con una herramienta de particionado de disco duro (como DFSee no como Partition Magic) la partición de recuperación como partición de arranque, dejar que recupere el sistema y volver a establecer la partición del sistema como partición activa.

Al no tener partición de recuperación se puede optar por instalar desde un CD ordinario (dado que no tenemos los discos de recuperación del sistema y aunque los tuviésemos, no tenemos garantías de que respeten la partición de datos), pero se da la circunstancia de que Windows XP Home SP2 no tiene los drivers necesarios para detectar el disco SATA y como el portátil no tiene disquetera (y no, una disquetera USB NO sirve) y por lo tanto no podemos instalar.

Entonces es evidente que es necesario sacar los datos de algún modo del portátil. Un CD arrancable y un disco duro externo por USB parecen una buena opción, hasta que es patente que el único disco duro externo que tenemos no tiene suficiente espacio libre (y en ese momento no podemos liberar el espacio ocupado).

Pienso un poquito y decido montar un servidor FTP con Filezilla en uno de nuestros ordenadores. Entonces inicio el portátil desde CD con un Puppy Linux (esa distribución es una verdadera joya en cuanto a ligereza y funcionalidad), configuro la red y con el cliente FTP que incluye (gFTP) transfiero todos los datos.

Si los clientes fuesen conscientes de los malabarismos que a veces tenemos que hacer para proteger sus datos, quizás nos mirasen con otros ojos...

jueves, 6 de septiembre de 2007

Multifunción que bloquea el arranque de un PC

Esta tarde me he enfrentado a uno de esos momentos tan poco gratificantes que se encuentran las personas demasiado a menudo en el mundo de la informática cuando un ordenador nuevecito, montado hacía apenas 24 horas, se negaba a arrancar.

Puede ser bonito saber que el ordenador lleva en su interior una WinFast, pero cuando el logotipo permanece en la pantalla durante cinco minutos seguidos sin inmutarse por mucho que se pulsen las teclas (primero de uno de estos detestables teclados inalámbricos por USB -detestables por inalámbricos y por USB- y después con un teclado PS/2 de toda la vida) uno desea sacar un lanzagranadas y volar por los aires todo el equipo informático. Un equipo completamente nuevo.

De todos modos, en estos casos se impone el sentido común antes que la ira y uno piensa que tal vez algún dispositivo externo o un extraíble está causando el problema aunque solamente sea porque ya ha visto cómo ordenadores se han bloqueado en el arranque al tener un llavero USB pinchado. Y un rápido vistazo permite comprobar que lo único inusual que tiene pinchado el PC es una multifunción Lexmark.

En cuanto se despincha la multifunción, el ordenador arranca con completa normalidad.

Presumiblemente el problema reside en el mismo punto que el caso de los llaveros USB pinchados en el momento del arranque, dado que la multifunción tiene un lector de tarjetas digitales que es tratado por el PC como un simple MSD (Mass Storage Device, es decir, un dispositivo de almacenamiento masivo).

Si alguien piensa que apagando la impresora se soluciona el problema, lamento decepcionarle. Si alguien está pensando que basta con desactivar en la BIOS la búsqueda de arranque en removables (extraíbles), lamento decepcionarle.

La solución más sencilla es quitar el cable de la multifunción y pincharla exclusivamente cuando el ordenador esté encendido.

Sería interesante probar con distintas combinaciones de placas y multifunciones (conozco muchos casos de gente con multifunciones de HP que no tienen este tipo de problemas, desafortunadamente no sé si alguna de esos ordenadores tiene una WinFast) para ver cuáles dan este problema. Pero que no cuenten conmigo para ello.

miércoles, 5 de septiembre de 2007

Precisión arbitraria en la aritmética REXX

Una de las características de la familia REXX (REXX clásico, Object REXX, NetREXX y otras variaciones) que la diferencia de otros lenguajes de programación más extendidos es su aritmética.

En ella no nos encontramos cosas como los clásicos conceptos de variables numéricas de tipo int, float o double... pero de lo que quisiera hablar hoy es de una característica concreta de la aritmética REXX: la precisión arbitraria.

¿Qué queremos decir con precisión arbitraria?

El siguiente código imprime el resultado del cociente de 1 entre 3:

say 1/3

es decir: 0.333333333. Cualquiera que tenga claras ciertas nociones de matemáticas básicas sabrá que en realidad eso no es 1/3, sino simplemente una aproximación con 9 cifras significativas a 1/3 porque la representación decimal de 1/3 tiene infinitos decimales.

REXX nos da el resultado con 9 cifras significativas porque es el número de cifras con el que trabaja.

Si hacemos lo siguiente:

say 1000000000 + 1

obtendremos 1.00000000E+9. Es decir, que perdemos ese 1 que hemos sumado. Puede que bajo ciertas circunstancias nos interesase ese dígito, pero dado que el lenguaje trabaja con 9 cifras significativas y que ese dígito extra sobrepasa los 9 parece que debamos quedarnos sin el mismo. Y aquí es donde entra en juego el carácter arbitrario de la precisión:

numeric digits 100
say 1000000000 + 1


Con esta sentencia nueva en el código, el resultado se convierte en 1000000001. Y en el caso anterior de 1/3 obtendríamos una ristra de cien cifras significativas (es decir, cien bonitos números 3 uno detrás del otro). La instrucción numeric digits nos permite variar el número de cifras significativas.

Consideremos la clásica función factorial escrita iterativamente:

factorial: procedure
parse arg n
factorial = 1
do i = 1 for n
factorial = factorial * i
end
return factorial


Si ejecutamos:

say factorial(100)

el resultado es 9.33262137E+157. Mientras que si ejecutamos:

numeric digits 1000
say factorial(100)


el resultado es exactamente el factorial de 100:

93326215443944152681
69923885626670049071
59682643816214685929
63895217599993229915
60894146397615651828
62536979208272237582
51185210916864000000
000000000000000000.

Intentad haced esto utilizando exclusivamente la aritmética básica de otro lenguaje de programación y probablemente descubrais que no podeis o es terriblemente más complicado. Esto no significa que REXX sea mejor, simplemente que es diferente.

martes, 4 de septiembre de 2007

¡Contagie su ordenador a través de USB en tres sencillos pasos!

Esta misma mañana he invertido varias horas entre otras cosas en limpiar de malware (esto es, de software malintencionado como son los virus, los troyanos y los gusanos) unos cinco ordenadores de sobremesa, tres portátiles, seis llaveros USB y cuatro tarjetas de memoria (MMC y SD). Si bien no todos estaban infectados, era necesario comprobarlo uno a uno porque estaba claro cuál había sido el sistema de propagación de la mayoría de las infecciones presentes: los llaveros USB.

Últimamente es algo muy común ver llaveros USB que transmiten virus de un ordenador a otro como si fuesen el mosquito anófeles transmitiendo la malaria. Y por lo que he podido ver, es algo que se produce con cierta frecuencia en centros públicos como colegios e institutos donde los usuarios llevan su información de un ordenador a otro. Sospecho que en estos casos la propagación es especialmente rápida y en una semana probablemente casi todos los ordenadores estén infectados.

El modo en el que funciona el contagio es enormemente sencillo y se basa en lo que ya hace muchos años era para mí un fallo de diseño y seguridad de Windows 98: el autorun.

Cada vez que se inserta un dispositivo extraíble como un CD, un DVD o un sistema de almacenamiento como una llave USB, Windows busca en la raiz de esa unidad un fichero de texto llamado autorun.inf. Ese fichero de texto indica a Windows cosas como el icono con el que debe aparecer en Mi PC, las acciones que deben agregarse al menú contextual de la unidad (el menú que aparece al pinchar con el botón derecho del ratón) y lo que debe pasar automaticamente al detectarse la unidad. Generalmente esto es utilizado en CDs y DVDs para iniciar algún tipo de asistente de instalación aunque yo mismo en un arranque de malicia hace años grabé algunos CDs con un autorun.inf que apagaba el ordenador en el se introdujese y esa característica de Windows estuviese activada.

Los CDs, que eran comunes como medio de transporte de información hace cinco años, y los DVDs (que para el caso podemos considerar como CDs grandes) son dispositivos de sólo lectura. No podemos arrastrar ficheros a ellos para copiarlos en ellos, no podemos modificar ficheros existentes y es IMPOSIBLE añadir nada al CD si está finalizado. No son un modo cómodo de propagación para el malware.

Pero desde que los llaveros USB y similares han desplazado casi completamente a los disquetes el malware tiene un método de propagación nuevo puesto que son dispositivos de lectura y escritura. Y ahí tenemos el primero de los pasos: si se pincha un llavero en un ordenador infectado por cierto tipo de malware, éste puede crear una o varias copias en el llavero y un fichero autorun.inf con instrucciones para ejecutar alguna de las copias. El segundo paso consiste en que el usuario lleva el llavero USB a otra máquina. Y en el tercero, al pinchar el llavero infectado en un ordenador limpio, si la característica de autorun está activada del modo adecuado, se ejecutará la copia del malware que se copiará a sí misma en el disco duro del ordenador obligándole a ejecutarla cada vez que lo encendamos.

Un método sencillo, simple y efectivo.

Evitar el contagio no es sencillo pero hay algunas cosas que probablemente ayuden:

  • Si la llave USB lleva un método de bloqueo (los reproductores MP3 suelen llevar algún sistema de bloqueo generalmente etiquetado como hold y otro tanto ocurre con muchas tarjetas digitales) y simplemente nos interesa llevar algo a un ordenador que no es de confianza (y el que lea esto debe pensar como un paranoico que, en el mejor de los casos, solamente su ordenador es de confianza) lo activamos y así el dispositivo no podrá ser infectado.

  • Desactivar algunas de las características del autorun en nuestro Windows para que nada se ejecute automáticamente sin nuestro permiso (para ello, buscad información en Internet).

  • Darnos cuenta de que cuando en la ventana emergente que aparece al pinchar dispositivos extraíbles en Windows XP hay indicadores extraños sobre la lista de acciones con el nombre de "Programa", es probable que el llavero USB esté infectado y debamos someter a un escaneo tanto el llavero como el equipo.


Todo lo dicho solamente es aplicable a usuarios de Microsoft Windows. Aquellos que utiliceis otro sistema operativo (Linux, BeOS, Mac OS X, OS/2, FreeBSD... el que sea) podeis estar razonablemente seguros de que este sistema de infección no os afectará.

lunes, 3 de septiembre de 2007

Reimplementando BIFs en REXX

En REXX es frecuente referirse oficiosamente a toda función que forma parte del núcleo del lenguaje como BIF: Built-In Function. El estándar ANSI de 1996 define una serie de funciones dentro de esta categoría como por ejemplo abbrev, words, date o address. En general las implementaciones del lenguaje tienen todas las BIFs definidas en el estándar, añadiendo aportaciones propias o tal vez careciendo de alguna concreta.

Lo peculiar del caso es que REXX permite que el programador defina las funciones internas de su programa (aquellas que se incluyen dentro del mismo fichero) utilizando los mismos nombres que alguna BIF y aun así seguir utilizando la BIF cuyo nombre hemos utilizado.


/* words.rex */

parse pull frase
say words(frase)

exit


Este sencillo ejemplo se limita a contar el número de palabras que tiene una cadena que introduce el usuario utilizando la BIF words. La línea con la sentencia parse pull frase se limita a meter la entrada del usuario en la variable frase. Y la siguiente línea nos dice la salida de la función words aplicada sobre la variable frase, es decir, muestra en pantalla el número de palabras.

Si el programador introduce una función en el código como en el siguiente caso:


/* words.rex */

parse pull frase
say words(frase)

exit

words: procedure
return 'No me apetece contar palabras'


El resultado es que en lugar de ejecutarse la BIF words, se ejecuta nuestra función. Es decir, que sea cual sea la entrada del usuario, el programa siempre imprimirá que no le apetece contar palabras.

A pesar de tener ocupado el nombre de la BIF words, podemos seguir accediendo a ella llamandola por su nombre en mayúsculas entrecomillado (por comillas simples). Así, en el siguiente ejemplo, se imprime siempre que no le apetece contar palabras e inmediatamente después el número de palabras tal como lo cuenta la BIF words:


/* words.rex */

parse pull frase
say words(frase)
say 'WORDS'(frase)

exit

words: procedure
return 'No me apetece contar palabras'


Evidentemente podemos ejecutar la BIF desde dentro de nuestra función:


/* words.rex */

parse pull frase
say words(frase)

exit

words: procedure
parse arg cadena
return 'WORDS'(cadena)


Esto nos permite cierto número de posibilidades como cambiar el comportamiento de las BIFs de nuestro intérprete. Esto puede ser interesante, por ejemplo, cuando un intérprete no implementa una BIF como estamos acostumbrados a utilizar. Imaginemos que un programador acostumbrado a las características de la BIF date para hacer aritmética de fechas propias del estándar y presentes en Object REXX y Regina desea que su código funcione en REXX clásico en OS/2 (que carece de esa característica). Si hace una función date que supla esas características ausentes en ese intérprete, solamente tiene que añadir esa función en la versión de su programa para OS/2 y no tendrá que tocar ninguna línea más de código.

Lo interesante es que podemos reimplementar muchas de las BIFs orientadas a manejo de cadenas solamente utilizando bucles condicionales y la instrucción PARSE. En el caso que nos ocupa, podríamos hacer:


words: procedure
parse arg string
n = 0
do while string <> ''
parse var string . string
n = n + 1
end
return n


parse coge el argumento de la función que hemos escrito y lo introduce en la variable string, mientras la variable string no esté vacía parse coge la primera palabra de la variable string y la descarta (.) metiendo el resto en string. Cada vez que descarta una palabra, aumenta el contador, y cuando las ha descartado todas, nos devuelve el valor de ese contador, es decir, del número de palabras. (Podríamos habernos ahorrado un par de líneas, pero he preferido dejarlo así por claridad.)

Como ejercicio para principiantes, el intentar reimplementar BIFs sin utilizar BIFs es algo, creo yo, muy educativo. Permite apreciar el valor de la instrucción parse y familiarizarse con las BIFs orientadas a cadenas.

Solamente podemos "redefinir" las BIFs a través de funciones internas de nuestro programa. Las funciones externas no nos valdrán y tampoco aquellas que estén en el macroespacio (si la implementación lo tiene). Pero cuando la BIF no está definida en nuestro intérprete (como ocurre con countstr en REXX clásico para OS/2), entonces podemos implementarla como una función externa y cargarla en el macroespacio...

Pero, como decía Jack Lemmon en Irma la dulce: Eso es otra historia.

domingo, 2 de septiembre de 2007

mplayer en OS/2 y eComStation

Aún recuerdo cómo hace años el proyecto mplayer puso en su lista negra a WarpVision, que por aquel entonces era practicamente el único reproductor de vídeo para OS/2 con cierta funcionalidad, porque había utilizado código fuente de mplayer (código bajo la licencia GPL) y se trataba de un programa comercial.

Tras el paso de los años el proyecto WarpVision cambió de tutela y pasó a Netlabs que liberó su código fuente. Y lo que hace años era un prometedor reproductor multimedia para una plataforma de software virtualmente abandonada, ahora sigue siendo exactamente eso: un proyecto prometedor.

Y precisamente el hecho de que las funcionalidades del programa y su estabilidad hayan mejorado tan poco significativamente resulta enormemente frustrante (como el mismo Adrian Gschwend, responsable de Netlabs, comentaba no hace muchos meses ante la decisión de despedir al desarrollador del programa). WarpVision no sigue un esquema de numerado de versiones claro y resulta muy difícil decidir qué versión utilizar porque hay características que dejan de funcionar en una versión nueva que ha corregido algún problema que tenía la versión anterior.

En el transcurso de estos años el panorama ha cambiado en OS/2 de un modo curioso; toda una serie de personas individuales y comunidades han aportado una serie de herramientas de desarrollo que mantienen vivo a un sistema operativo que lleva muerto ya más de media década: Knut St. Osmundsen es el responsable de las versiones del compilador GCC y la biblioteca libc más actuales existentes para la plataforma (con características nuevas de las que carecen los equivalentes anteriores: EMX); Doodle ha portado SDL y Cairo; Dmitry A. Kuminov ha portado QT3; la comunidad OpenWatcom ha sacado recientemente la versión 1.7 de su compilador de C, C++ y Fortran; varias personas mantienen todos los programas de la familia de productos Mozilla al día...

En estas circunstancias en las que el software libre da una inyección de vitalidad al sistema, varias personas, probablemente insatisfechas con WarpVision, han mirado hacia afuera para ver qué podían traer hacia el sistema. Ese bendito australiano llamado Paul Smedley portó ffplay (el reproductor basado en ffmpeg) y mplayer utilizando SDL con resultados discretos. El coreano KO Myung-Hun, basandose probablemente en el trabajo de Paul, ha hecho sus propias versiones de estos programas eliminando la dependencia de la biblioteca SDL y activando aceleración 2D a través de WarpOverlay y en el caso de mplayer ha creado una verdadera joya.

Mi máquina es muy modesta en recursos: un AMD K6-2 a 450 MHz, una tarjeta gráfica de tan solo 8 megas, una RAM de unos 500 megas... y en muchos casos no conseguía reproducir la mayor parte de los vídeos (aun en mis restantes sistemas operativos). Por poner un ejemplo: no conseguía ver los capítulos de Naruto Shipuuden de ningún modo, no importaba el sistema operativo o el reproductor que utilizase o lo que jugase con las opciones de reproducción.

Hasta el port de mplayer de KO Myung-Hun.

Hasta ahora ha resultado extraordinariamente estable, me ha permitido ver casi todos los vídeos que he probado (hasta ahora solamente se le resisten los FLV bajados de YouTube y los WMV), carga y sincroniza correctamente ficheros de subtítulos externos, reproduce DVDs sin problemas... y si un vídeo me da problemas con su resolución completa, con la opción "-lavdopts lowres=1:fast:skiploopfilter=all" puedo verlo en baja resolución sin inconvenientes (salvo, claro está, la resolución misma).

Le faltan pequeñas cosas como reproducir VCD, ocultar el puntero de ratón en pantalla completa, desactivar el salvapantallas mientras está reproduciendo, que el ejecutable y la ventana de reproducción tenga un icono (es sorprendente lo que me importa una nimiedad como esa, teniendo en cuenta lo poco que suele importarme la estética)... Tal vez una interfaz gráfica sería deseable y dado que el trabajo de Myung-Hun incluye un modo esclavo que es necesario para hacer un front-end (con el que he intentado jugar sin éxito alguno) ya existe todo lo necesario para ello (de hecho, el front-end multiplataforma SMPlayer, basado en QT es un buen candidato a port).

Pero mientras llegan esas cosas que no son vitales, ¡qué irónico es que OS/2 se haya convertido en el sistema que he de usar para ver vídeos!