Temas dependientes de la plataforma para Euphoria


1. Introducción

Rapid Deployment Software soporta actualmente a Euphoria en cuatro plataformas distintas. En el futuro se agregarán varias más.

La primera plataforma se llama DOS32, que está basado en el sistema operativo DOS, pero con la CPU operando en modo protegido de 32 bits.

La segunda plataforma se llama WIN32, en el que el sistema operativo subyacente es Microsoft Windows, particularmente, las versiones de 32 bits de Windows que se usan en Windows 95/98/ME, tanto como NT/2000/XP y sistemas posteriores.

La tercera plataforma es Linux. Linux está basado en el sistema operativo UNIX. Recientemente se ha hecho muy popular entre los usuarios de PC. Hay varios distribuidores de Linux como Red Hat, Debian, Caldera, etc. Linux es un sistema operativo de código abierto y se puede obtener comprando un CD de muy bajo precio.

La cuarta plataforma es FreeBSD. FreeBSD también está basado en el sistema operativo UNIX, es muy popular como servidor de Internet y, al igual que Linux, también es de código abierto.

Algunos usuarios que compraron el código fuente de Euphoria, portaron Euphoria a otras plataformas tales como el UNIX de HP y el UNIX de Sun.

La instalación de Euphoria para DOS32+WIN32 contiene dos archivos .exe. El primero se llama ex.exe. Este corre programas de Euphoria en la plataforma DOS32. El segundo es exw.exe. Este, en cambio, ejecuta programas de Euphoria en WIN32. Los programas de Euphoria programs que están hechos para correr en WIN32 son archivos de extensión .exw, mientras que aquellos hechos para DOS32 tienen extensión .ex.

El archivo .tar de Euphoria para Linux contiene solamente exu. Corre programas Euphoria en la plataforma Linux. Los programas Euphoria desarrollados para Linux o FreeBSD tienen extensión .exu.

Para instalar la versión FreeBSD de Euphoria, primero hay que instalar la versión para Linux, y luego reemplazando exu para Linux, por la versión de exu para FreeBSD.

Muchos programas de Euphoria pueden correr en dos, tres o las cuatro plataformas sin cambios. La extensión debería indicar la plataforma preferida del programa. Cualquier intérprete Euphoria puede intentar ejecutar cualquier archivo Euphoria, pero hay que especificar el nombre completo del archivo, incluida la extensión que cada intérprete busca para identificar su tipo de archivo (.ex, .exw or .exu).

Algunas veces verá que la mayor parte del código es el mismo para todas las plataformas, pero hay pequeñas partes que se escriben especialmente para cada una de ellas. Use la función platform() para determinar la plataforma en la que se está ejecutando. Observe que platform() devuelve el mismo valor (3) tanto en Linux como FreeBSD, ya que ambos sistemas son muy similares.


2. La plataforma DOS32

Si es novato en programación, debería comenzar con ex.exe en la plataforma DOS32. Debería intentar comprender lo fundamental de Euphoria, antes de meterse en la programación GUI de Windows. Todas las versiones de Windows (aún XP), le permiten abrir la ventana de texto Símbolo del Sistema y ejecutar programas DOS.

Los programas Euphoria corren en modo protegido de 32 bits y tienen acceso a toda la memoria instalada en la máquina. Muchos lenguajes de programación para DOS lo limitan al modo real de 16 bits. Esto hace imposible a acceder a más memoria que 640K. Su máquina puede tener instalados 256 Mb de memoria, pero su programa se quedará sin memoria después de haber agotado los 640K. QBasic es aún peor; lo limita a solamente 160K.

Los programas DOS32 pueden alternar entre el modo de texto y el modo gráfico de píxel, y Euphoria provee rutinas de librería para ambos modos. Raramente necesitará llamar al DOS directamente, pero puede hacerlo usando la rutina dos_interrupt(). También puede acceder a posiciones especiales de memoria, mediante peek() y poke(), para ejecutar gráficos de alta velocidad o para acceder a detalles de bajo nivel del sistema.

Bajo DOS32 para Windows 95 y sistemas posteriores, los archivos Euphoria pueden tener nombres largos, lo mismo que los archivos que estos programas abran para lectura y escritura, pero no podrá crear archivos nuevos con esta característica.

Bajo DOS puro, fuera de Windows, no hay un sistema de archivo de intercambio, por lo que el expansor DOS incluido en ex.exe creará uno para que lo use su programa. Este archivo se crea cuando inicia su programa Euphoria bajo DOS, y se borra cuando termina el programa. Comienza como un archivo de 0 bytes y crece solamente cuando es necesario. Se crea en el directorio del disco rígido apuntado por la variable de entorno TEMP o TMP. Si ninguna de esas variables existiera, se crea en el directorio que contiene a ex.exe o en el que está su archivo Euphoria enlazado (.exe). Puede forzar su creación en un directorio en especial, estableciendo la variable de entorno CAUSEWAY del siguiente modo:

        SET CAUSEWAY=SWAP:path
donde path es la ruta completa del directorio. Puede evitar la creación del archivo de intercambio con:
        SET CAUSEWAY=NOVM

Mientras se desarrolla el intercambio de información con la memoria virtual en disco, su programa sigue funcionando pero más lentamente. Una mejor aproximación es podría ser liberar más memoria extendida, restándosela al SMARTDRV y otros programas que reservan grandes cantidades de memoria para usos propios.

El archivo de intercambio no se creará si el espacio vacío del disco es menor que la cantidad de memoria RAM instalada en su máquina.


3. La plataforma WIN32

Euphoria para WIN32 (exw.exe) tiene mucho en común con Euphoria para DOS32. Con WIN32 también tiene acceso a toda la memoria de su máquina. La mayoría de las rutinas de librería trabajan del mismo modo en cada una de las plataformas. Muchos programas DOS32 de modo de texto se pueden ejecutar usando exw sin ningún cambio. Con exw puede ejecutar programas desde la línea de comandos y mostrar texto en una ventana DOS estándar (comúnmente de 25 líneas x 80 columnas). En la terminología Windows, la ventana DOS se conoce como consola. Euphoria hace trivial la transición desde la programación de modo de texto de DOS32 a la programación de consola de WIN32.Puede agregar llamadas a funciones de C en WIN32, y luego si lo desea, crear verdaderas ventanas GUI de Windows.

Cuando su programa Euphoria escriba algo en pantalla o lea desde el teclado, automáticamente se creará una ventana de consola. También verá una ventana de consola cuando lea desde la entrada estándar o escriba hacia la salida estándar, aún cuando hayan sido redireccionadas a archivos. La consola desaparecerá cuando finalice la ejecución del programa, o mediante una llamada a free_console(). Si hay algo en la consola que quiere que el usuario lea, debería avisarle y esperar su respuesta antes de terminar. Para evitar la desaparición rápida de la consola, podría incluir una sentencia como:

        if getc(0) then
        end if
que espera que el usuario ingrese alguna cosa.

Si quiere ejecutar programas Euphoria sin lanzar una nueva ventana de consola, puede hacer una versión de exw.exe que use la ventana de consola actual, como cuando un programa DOS usa ex.exe. Para hacer esta versión alternativa de exw.exe, necesita ejecutar la utilidad makecon.exw que está en euphoria\bin. Para ahorrar espacio en el archivo de instalación, no hemos creado este archivo .exe. También hay una utilidad llamada make40.exw que creará una versión alternativa de exw.exe que usa una versión más reciente (versión 4.0) de la interfaz gráfica de usuario de Windows.

Bajo WIN32, están completamente soportados los nombres largos de archivos, tamto para lectura, como para escritura.


3.1 Programación WIN32 de alto nivel

Gracias a David Cuny, Derek Parnell, Judith Evans y algunos otros, hay un paquete llamado Win32Lib con el que se pueden desarrollar aplicaciones Windows GUI en Euphoria. Es notoriamente sencillo de aprender y de usar, y viene con una buena documentación y algunos pequeños programas de ejemplo. Puede descargar Win32Lib y el entorno de desarrollo de Judith desde el Sitio Web de Euphoria. Recientemente, Andrea Cini ha desarrollado otro similar, un paquete algo más pequeño llamado EuWinGUI. También está disponible en nuestro sitio.


3.2 Programación WIN32 de bajo nivel

Para permitir el acceso a WIN32 de bajo nivel, Euphoria provee un mecanismo para llamar a cualquier función de C en cualquier archivo .dll del API de WIN32, o cualquier otro archivo .dll de Windows de 32 bits que usted cree o que otro haya creado. También existe un mecanismo de call-back que le permite a Windows llamar a sus rutinas de Euphoria. Las call-backs son necesarias para crear interfaces gráficas de usuario.

Para hacer completo uso de la plataforma WIN32, necesitará documentación para programación de Windows de 32 bits, en especial la Interfaz de Programación de Aplicaciones (API) de WIN32, incluyendo las estructuras de Cdefinidas por la API. Hay un extenso archivo WIN32.HLP © de Microsoft que está disponible con muchas herramientas de programación para Windows. Hay numerosos libros al respecto de la programación WIN32 para C/C++. Mucho de lo que encuentra en esos libros, lo puede adaptar para el mundo de la programación Euphoria para WIN32. Un buen libro es:

Programming Windows
de Charles Petzold
Microsoft Press

Se puede descargar desde el sitio de Borland un archivo de ayuda del API de WIN32 (8 Mb):
ftp://ftp.inprise.com/pub/delphi/techpubs/delphi2/win32.zip

También vea la página Web Archivo - "documentación" de Euphoria.


4. Las plataformas Linux y FreeBSD

Euphoria para Linux, y Euphoria para FreeBSD comparten ciertas características con Euphoria para DOS32, y algunas otras con Euphoria para WIN32.

Como en WIN32 y DOS32, puede escribir texto en una consola, o en la ventana xterm, en varios colores y en cualquier línea o columna.

Como en WIN32, puede llamar rutinas de C en librerías compartidas y código C puede llamar a sus rutinas (call-back).

Euphoria para Linux y FreeBSD no tienen soporte integrado para gráficos de píxel como DOS32, pero Pete Eberlein creó una interfaz Euphoria para svgalib.

Actualmente, la programación de interfaz gráfico del usuario Xwindows es más fácil usando la interfaz de Irv Mullin para la librería GTK GUI.

Al portar código desde DOS o Windows a Linux o FreeBSD, notará las siguientes diferencias:

  • Alguno de los números asignados a los 16 colores principales en graphics.e son distintos. Si usa las constantes definidas en graphics.e bo tendrá problemas; si en cambio, escribe los números de color literalmente dentro del código, notará que el azul y el rojo habrán cambiado.

  • Los códigos para teclas especiales como Inicio, Fin, teclas de flechas, son diferentes y hay algunas diferencias adicionales cuando ejecuta bajo XTERM.

  • La tecla Enter tiene el código 10 (avance de línea) en Linux, mientras que en DOS/Windows tiene el 13 (retorno de carro).

  • Linux y FreeBSD usan '/' en sus rutas. DOS/Windows usan '\\'.

  • Cosas altamente especializadas como dos_interrupt(), obviamente no funcionan en Linux o FreeBSD.

  • Las llamadas a system() y system_exec() que contienen comandos DOS, cambiarán obviamente a los correspondientes comendos de Linux o FreeBSD. Por ejemplo, "DEL" se convierte en "rm", y "MOVE" en "mv".


5. Interfacing con código C (WIN32, Linux, FreeBSD)

En WIN32, Linux y FreeBSD es posible relacionar código Euphoria con código de C. Su programa Euphoria puede llamar rutinas de C y leer y escribir variables. Las rutinas de C pueden igualmente llamar ("callback") a sus rutinas Euphoria. El código de C tiene que estar en una librería de enlace dinámico de WIN32 (archivo .dll), en una librería compartida de Linux o FreeBSD (archivo .so). Al conectarse con las .dll o las .so, puede acceder completamente a las interfacesde programación de esos sistemas.

Usando el Traductor Euphoria a C, puede traducir las rutinas Euphoria a C, y compilarlas dentro de archivos .dll o .so. Puede pasar átomos y secuencias Euphoria a esas rutinas Euphoria compiladas, y recibir datos Euphoria como resultado. Comúnmente, las rutinas traducidas/compiladas se ejecutan mucho más rápido que las rutinas interpretadas. Para obtener más información, vea el Traductor.


5.1 Llamando Funciones de C

Para llamar una función de C en un archivo .dll o .so, tiene que seguir los suientes pasos:
1.
Abrir el archivo .dll o .so que tiene la función de C, llamando a open_dll() en euphoria\include\dll.e.
2.
Definir la función de C, llamando a define_c_func() o define_c_proc() en dll.e. Esto le dice a Euphoria la cantidad y tipo de argumentos, tanto como el tipo del valor de retorno.

Euphoria soporta actualmente todos los tipos enteros y punteros de C, como argumentos y valores de retorno. También soporta para los mismos casos de tipo punto flotante (tipo double de C). Actualmente noes posible pasar estructuras de C por valor y recibir una estrctura como función resultado, aunque puede pasar un puntero a la estructura y obtener un puntero a la estructura como valor de retorno. Pasar estructuras de C por valor es un requerimento raramente solicitado por las llamadas del sistema operativo.

Euphoria también soporta todas las formas de datos de Euphoria - átomos y secuencias arbitrariamente complejas, como argumentos para rutinas Euphoria traducidas/compiladas.

3. Llamar la función de C, invocando a c_func() o c_proc().

Ejemplo:
include dll.e

atom user32
integer LoadIcon, icon

user32 = open_dll("user32.dll")

-- el nombre de la rutina en user32.dll es "LoadIconA".
-- Toma como argumentos un puntero y un entero, y devuelve un entero.
LoadIcon = define_c_func(user32, "LoadIconA", {C_POINTER, C_INT}, C_INT)
icon = c_func(LoadIcon, {NULL, IDI_APPLICATION})

Ver en library.doc - Llamando funciones de C las descripciones de c_func(), c_proc(), define_c_func(), define_c_proc(), open_dll(), etc. Ver los programas de ejemplo en demo\win32 o demo\linux.

En Windows hay más de una convención de llamadas. Las rutinas de la API de Windows usan la convención __stdcall. Sin embargo, la mayoría de los compiladores de C tienen __cdecl establecida por defecto. __cdecl permite pasar una cantidad variable de argumentos. Euphoria asume __stdcall, pero si necesita llamar una rutina de C que usa __cdecl, puede poner un signo '+' al comienzo del nombre de la rutina en define_c_proc() y define_c_func(). En el ejemplo de más arriba, tendría "+LoadIconA", en lugar de "LoadIconA".

Puede examinar un archivo .dll haciendo click derecho sobre él y eligiendo "vista rápida" (si existe en su sistema). Verá la lista de todas las rutinas de C que el .dll exporta.

Ejecute euphoria\demo\win32\dsearch.exw para determinar el archivo .dll contiene una función C WIN32 en especial.


5.2 Accediendo a Variables de C

Puede obtener la dirección de una variable de C, usando define_c_var(). Luego, puede usar poke() y peek() para acceder al valor de la variable.


5.3 Accediendo a estructuras de C

Muchas rutinas de C necesitan que les pase punteros a estructuras. Puede simular las estructuras de C asignando bloques de memoria. La dirección devuelta por allocate() se puede pasar como si fuera un puntero de C.

Puede leer y escribir los miembros de las estructuras de C usando peek() y poke(), o peek4u(), peek4s(), y poke4(). Puede asignar espacio para las estructuras usando allocate(). Tiene que calcular el offset de un miembro de una estructura de C. Normalmente esto es sencillo, porque cualquier cosa en C que necesite 4 bytes, se asignará 4 bytes en la estructura. Así, los "int" de C, los "char", los "unsigned int" , punteros a lo que sea, etc. todos tomarán 4 bytes. Si la declaración C se ve como:

        // Warning C code ahead!

        struct ejemplo {
            int a;           // offset  0
            char *b;         // offset  4
            char c;          // offset  8
            long d;          // offset 12
        };

Para reservar espacio para "struct ejemplo", necesitará:

        atom p

        p = allocate(16) -- tamaño de "struct ejemplo"

La dirección que obtiene de allocate() es siempre de al menos 4 bytes alineados. Esto es provechoso, ya que las estructuras de WIN32 are supposed to start on a 4-byte boundary. Fields within a C structure that are 4-bytes or more in size must start on a 4-byte boundary in memory. 2-byte fields must start on a 2-byte boundary. Para hacer esto, tiene que dejar pequeños huecos dentro de la estructura. En la práctica no es difícil alinear la mayoría de las estructuras, ya que el 90% de los campos son punteros de 4 bytes o enteros de 4 bytes.

Puede asignar los campos, usando algo como:

        poke4(p + 0, a)
        poke4(p + 4, b)
        poke4(p + 8, c)
        poke4(p +12, d)
Puede leer un campo con algo como:
        d = peek4(p+12)
Consejo:
Por legibilidad, utilice offsets para declarar sus constantes Euphoria. Ver el ejemplo siguiente:
Ejemplo:
constant RECT_LEFT = 0,
         RECT_TOP  = 4,
         RECT_RIGHT = 8,
         RECT_BOTTOM = 12
         
atom rect
rect = allocate(16)

poke4(rect + RECT_LEFT,    10)
poke4(rect + RECT_TOP,     20)
poke4(rect + RECT_RIGHT,   90)
poke4(rect + RECT_BOTTOM, 100)
     
-- pasa rect como un puntero a una estructura de C
-- hWnd es un "handle" para la ventana
if not c_func(InvalidateRect, {hWnd, rect, 1}) then
    puts(2, "Falló InvalidateRect\n")
end if

El código Euphoria que accede a las rutinas de C y las estructuras de datos, puede verse un poco feo, pero normalmente será solamente una pequeña parte de su programa, especialmente si usa Win32Lib, EuWinGUI, o la librería X Windows de Irv Mullin. La mayor parte de su programa se escribirá en Euphoria puro, que le dará una gran ventaja sobre aquellos forzados a codificar en C.


5.4 Call-backs hacia sus rutinas Euphoria

Cuando crea una ventana, el sistema operativo Windows necesitará llamar a su rutina Euphoria. Esto es un concepto extraño para los programadores DOS, quienes han usado llamadas a rutinas del sistema operativo, pero no han tenido llamadas del sistema operativo a sus rutinas. Para lograrlo, tiene que obtener una dirección de "call-back" de 32 bits para su rutina y dársela a Windows. Por ejemplo (en demo\win32\window.exw):

        integer id
        atom WndProcAddress
        
        id = routine_id("WndProc") 

        WndProcAddress = call_back(id)
routine_id() identifica unívocamente a un procedimiento o función Euphoria, devolviendo un valor entero pequeño. Este valor se puede usar más tarde para llamar a la rutina. También puede usarlo como un argumento de la función call_back().

En el ejemplo de más arriba, la dirección de call-back de 32 bits, WndProcAddress, se puede almacenar en una estructura de C y pasarla a Windows mediante la función C de API RegisterClass(). Esto le da a Windows la capacidad de llamar rutinas Euphoria, WndProc(), toda vez que el usuario realiza una acción en una cierta clase de ventana. Las acciones incluyen hacer click en el ratón, presionar una tecla, redimensionar la ventana, etc. Lea el programa de ejemplo window.exw, para ver la historia completa.

Nota:
Se puede obtener una dirección de call-back para cualquier rutina Euphoria que cumpla las siguientes condiciones:
  • la rutina tiene que ser una función, no un procedimiento.
  • tiene que tener de 0 a 9 parámetros.
  • los parámetros deberían ser todos declarados de tipo átomo (o entero), no como secuencia.
  • el valor de retorno debería ser un valor entero de 32 bits.
Puede crear tantas direcciones de call-back como desee, pero no debería llamar a call_back() varias veces a la misma rutina Euphoria - cada dirección de each call-back que cree necesita un pequeño bloque de memoria.

Los valores que se pasan a su rutina Euphoria pueden ser cualquier átomo de 32 bits sin signo, es decir, no negativo. Su rutina podría elegir interpretar números positivos grandes como negativos, si fuera necesario. Por ejemplo, una rutina de C intenta pasarle -1, aparecería como el número hexadecimal FFFFFFFF. Si se pasa un valor que no se ajusta al tipo elegido para un parámetro, ocurrirá un error de verificación de tipos de Euphoria (dependiendo de with/without type_check). No ocurrirá ningún error si declara al parámetro como átomo.

Normalmente, como en el caso de más arriba de WndProc(), Windows inicia esas call-backs a sus rutinas. También es posible que una rutina C en cualquier .dll llame a una de sus rutinas Euphoria. Solamente tiene que declarar adecuadamente la rutina C y pasarle la dirección de call-back.

Hay un ejemplo de una rutina de WATCOM C que toma su dirección de call-back address como único parámetro y entonces llama a su rutina Euphoria de 3 parámetros:

        /* rutina C de 1 parámetro que llama desde Euphoria */
        unsigned EXPORT APIENTRY test1(
                 LRESULT CALLBACK (*eu_callback)(unsigned a,
                                                 unsigned b,
                                                 unsigned c))
        {
            /* Su rutina Euphoria de 3 parámetros se llama aquí 
               via el puntero eu_callback */
            return (*eu_callback)(111, 222, 333); 
        }
La sentencia C de más arriba, declara a test1 como una rutina que se puede llamar externamente y que tiene un solo parámetro. Ese parámetro es un puntero a una rutina que tiene 3 parámetros sin signo, es decir, su rutina Euphoria.

En WATCOM C, "CALLBACK" es lo mismo que "__stdcall". Esta es la convención de llamadas que se usa para llamar a las rutinas WIN32 API, y el puntero C a su rutina Euphoria se deberá declarar de esta forma también, u obtendrá un error cuando su rutina Euphoria intente regresar de su .DLL.

Si necesita que su rutina Euphoria se la llame usando la convención __cdecl, tendrá que escribir la llamada a call_back() como sigue:

        myroutineaddr = call_back({'+', id})

El signo más y las llaves indican la convención __cdecl. El caso simple, sin llaves, es __stdcall.

En el ejemplo de más arriba, su rutina pasará los valores 111, 222 y 333 como argumentos. Su rutina devolverá un valor a test1. Luego, ese valor se devolverá inmediatamente al llamador de test1 (que puede estar en algún otro sitio de su programa Euphoria).

Se puede pasar una dirección de call-back a la función signal() de Linux o FreeBSD para especificar una rutina Euphoria, para manejar varias señales (por ejemplo, SIGTERM). También se le pueden pasar a C rutinas como qsort(), para especificar una función de comparación de Euphoria.