
La Gua del Hacker de Allegro



Esta es una gua sobre ciertas partes internas de Allegro, para gente que
est interesada en modificarlas. Este documento est lejos de ser completo,
y puede no ser correcto al 100%. Recuerde que en caso de duda, el cdigo
fuente es siempre la referencia definitiva. Sern bien aceptadas sugerencias
sobre qu inclur en este documento: hay demasiado cdigo como para que
pueda describirlo con todo lujo de detalles, por lo que quiero concentrarme
en las cosas que ms confunden a la gente...




===========================================
============ Estilo de cdigo. ============
===========================================

No voy a ser un fascista sobre esto, pero hace la vida ms sencilla si todo
el cdigo usa un formato consistente. Si va a escribir y mantener ms de
un fichero de cdigo fuente completo, creo que es libre para hacer lo que
usted quiera, pero para pequeas contribuciones, posiblemente reformatear
su cdigo para que encaje con mi estilo actual. Obviamente me ahorrar
tiempo si usted escribe el cdigo con ste estilo, y aqu viene la
descripcin:

Estilo Allegro bsico: K&R, con 3 espacios de tabulado visual. Sin embargo,
en disco los tabuladores sern de 8 espacios, por lo que una lnea que
estuviese tabulada 12 espacios, sera salvada en un fichero como 12
carcteres de espacio o 1 tabulador y 4 espacios, no 4 tabuladores. Si su
editor de textos no puede entender la diferencia entre tabuladores internos
de 3 espacios y externos de 8 espacios, sera buena idea que consiguiese un
editor de textos mejor, o que usase el programa indent para conseguir este
efecto. El fichero indent.pro includo con la distribucin de Allegro casi
consigue formatear el texto con este estilo, pero no lo consigue siempre, y
algunas cosas tienen que ser retocadas a mano.

Los defines de preprocesador y los nombres de las estructuras estn
EN_MAYUSCULAS. Las funciones y las variables estn en_minsculas. Los
NombresConMaysculasMezcladas son malvados y no deberan ser usados.
Esa estpida notacin m_pHngara es _realmente_ malvada, y ni si quiera
debera pensar en ella.

Todos los smbolos deberan ser declarados como static, a no ser que sea
imposible hacerlo, en cuyo caso deberan ser prefijados con un subrayado.

Las funciones se veran as:

/* foobar:
 *  Descripcin de lo que hace.
 */
void foobar(int foo, int bar)
{
   /* hace algo til */
}

Tres lneas en blanco entre funciones.

Los condiciones se veran as:

   if (foo) {
      /* cosas */
   }
   else {
      /* cosas */
   }

La nica situacin en la que algo est en la misma lnea tras una llave de
cerrado es el caso de un bucle do/while, ejemplo:

   do {
      /* cosas */
   } while (foo);

Los case se veran as:

   switch (foo) {

      case bar:
    /* cosas */
    break;

      default:
    /* cosas */
    break;
   }

Ejemplo de dnde poner espacios:

   char *p;
   if (condicion) { }
   for (x=0; x<10; x++) { }
   funcion(foo, bar);
   (BITMAP *)data[id].dat;

Tdos los ficheros de cdigo fuente deben empezar con la cabecera estndar:

/*         ______   ___    ___
 *        /\  _  \ /\_ \  /\_ \
 *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___
 *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
 *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
 *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
 *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
 *                                           /\____/
 *                                           \_/__/
 *
 *      Breve descripcin de qu hace este fichero.
 *
 *      Por Autor.
 *
 *      Cosas chachis aadidas por Alguien Ms.
 *
 *      Fallo estpido corregido por Tercera Persona.
 *
 *      Lea en readme.txt la informacin de copyright.
 */

Los crditos de autor deben ser aadidos en orden cronolgico, y las
direcciones de email no deben ser incluidas: esa informacin se puede
encontrar en el fichero principal de crditos, y si slo existe en un lugar,
es ms fcil actualizarla cuando alguien cambie de email.

Las personas slo deben ser includas en la cabecera del cdigo fuente si han
hecho alguna contribucin significativa (las correcciones de una lnea no
cuentan), pero sin importar el tamao de la contribucin, deben ser aadidos
al fichero docs/thanks._tx. Este fichero es ordenado alfabticamente por
nombre. Si la persona ya est en el fichero, hay que actualizar el texto
para describir el nuevo cambio, en caso contrario habr que crear una nueva
entrada para el contribuyente. Adems, cualquier cosa mayor que una
modificacin minscula debe ser aadida al fichero docs/changes._tx, que
crece desde arriba en orden cronolgico inverso. Este fichero debe describir
brevemente tanto la naturaleza de la modificacin como la persona que hizo
esta modificacin.



=================================================
============ Proceso de Construccin ============
=================================================

Esto es muy diferente dependiendo de si est usando autoconf o un makefile
fijo. Sin embargo, para la mayora de las plataformas, el script de
correccin (ej. fixdjgpp.bat), crear un pequeo makefile, que define
MAKEFILE_INC  al make de otro fichero (ej. makefile.dj), y entonces incluye
makefile.all. Este contiene un montn de reglas genricas, e incluye el
fichero nombrado en MAKEFILE_INC para proveer informacin adicional
especfica de cada plataforma. Los ficheros fuente actuales estn listados en
el fichero makefile.lst.

Hay tres versiones de la biblioteca de funciones: alleg (versin final), alld
(depuracin), y allp (profiling). Los ficheros objeto van en
obj/compilador/version/, donde versin es alleg, alld, o allp. Los ficheros
.lib van en lib/compilador/. Algunas cosas generadas (asmdefs.inc, mmxtest.s,
etc), van en el directorio raz obj/compilador/. Las dependencias son
generadas con "make depend", y van en obj/compilador/version/makefile.dep,
que es includo por makefile.all.

Cuando ejecuta "make clean", esto solamente borra los ficheros generados por
el usuario, como los ficheros objeto. "make distclean" le deja con la
distribucin original, e incluye deshacerse de los ejecutables de test y la
propia biblioteca de funciones. Para obtener la mxima higiene personal,
ejecute "make veryclean", lo que eliminar absolutamente todos los ficheros
generados. Tras esta operacin, tendr que ejecutar "make depend" para poder
reconstruir la biblioteca de funciones, y tambin "fixdll.bat" si est
trabajando con la plataforma Windows.

Para pasar lneas de comando largas a los enlazadores de MSVC y Watcom, el
programa runner.exe es compilado usando gcc, para que les pueda pasar un
nmero decente de parmetros. Este programa salva los parmetros en un
fichero temporal, y entonces invoca al programa usando el fichero con los
argumentos como entrada.

Por ahora todos los makefiles usan gcc para generar las depependencias,
porque es m fcil que conseguir que MSVC o Watcom faciliten la informacin
correcta.

El smbolo LIBRARY_VERSION, definido al comienzo de makefile.ver, es usado
para inclur el nmero de versin en cosas como el nombre de fichero de la
DLL.



==============================================
============ Ficheros de Cabecera ============
==============================================

allegro.h vive en el directorio include/. Este incluye otros ficheros de
cabecera que existen en el rbol de subdirectorios include/allegro/. La razn
de este mtodo ligeramente extrao es que allegro.h puede incluir cosas como
"allegro/internal/alconfig.h", lo cual funcionar tanto si compilamos
Allegro, como si copiamos allegro.h al directorio include del sistema y los
otros ficheros de cabecera en include_sistema/allegro/. Esto evita inundar
los directorios de sistema con cientos de ficheros de cabecera, y a la vez
permite a un programa incluir solamente <allegro.h>, y hace posible el
acceso a las cabeceras internas mediante #include <allegro/include/aintern.h>.

allegro.h incluye alconfig.h, el cual detecta la plataforma actual e incluye
un fichero de cabecera adicional para este compilador (aldjgpp.h, almsvc.h,
alwatcom.h, etc).  Ese fichero de cabecera adicional define un grupo de
macros que describen el sistema, emula lo que sea necesario para hacer que el
cdigo compile adecuadamente, y opcionalmente define ALLEGRO_EXTRA_HEADER y
ALLEGRO_INTERNAL_HEADER si va a necesitar otros ficheros de cabecera
especficos de la plataforma.

Tras incluir el fichero de cabecera de plataforma, el resto de alconfig.h
define un montn de macros genricas de ayuda a sus valores por defecto,
pero slo si el fichero de cabecera de plataforma no las ha sustituido por
algo especfico.

allegro.h contiene definiciones de estructuras y prototipos de funciones. Al
final del fichero, incluye alinline.h, el cual define todas las rutinas
inline y los wrappers vtable, junto con versiones en C de las rutinas
matemticas de punto fijo si no hay versin de stas en ensamblador en lnea.
Si el cdigo de ensamblador en lnea est soportado, incluye al386gcc.h,
al386vc.h, o al386wat.h.

Si ALLEGRO_EXTRA_HEADER est
definido, allegro.h lo incluye al final. Este define suele incluir aldos.h,
alwin.h, etc, que definen cosas especficas para cada plataforma, como
valores ID para los drivers hardware. A diferencia de los ficheros de
plataforma incluidos al principio de allegro.h, stos son especficos para
cada SO en vez de para cada compilador, por lo que el mismo fichero alwin.h
puede ser usado tanto con MSVC como con MinGW32. Describen funciones de la
biblioteca relacionadas con la plataforma, mientras los ficheros de cabecera
previos describan la sintaxis bsica del lenguaje.

aintern.h es como internal.h en versiones previas de Allegro, y define
rutinas compartidas entre mltiples ficheros de cdigo fuente, pero que
generalmente no queremos que sean usadas por programas de usuario. Para
definiciones internas especficas de cada plataforma tenemos aintdos.h,
aintwin.h, etc. Esto ficheros de cabecera no son incluidos directamente por
allegro.h, pero pueden ser incluidos por los programas de usuario valientes 
estpidos :-)

En plataformas que tienen rutinas API especficas y no portables, stas
deberan ir en un fichero de cabecera especial en la raz del directorio
include, ej: winalleg.h. Este puede ser incluido por programas de usuario que
quieran acceder a estas rutinas, a la vez que se les indica claramente que al
incluir este fichero de cabecera estn escribiendo cdigo no portable.



======================================
============ Definiciones ============
======================================

Todos los prototipos de funciones de cabecera deben usar la macro AL_FUNC().
Las rutinas en lnea usan la macro AL_INLINE(). Las variables globales usan
AL_VAR() o AL_ARRAY(). Los punteros globales a funciones usan AL_FUNCPTR().
Los punteros a funciones que se pasan como parmetros a otras rutinas o que
estn almacenados en una estructura usan AL_METHOD(). Esto puede parecer
innecesario, pero da mucha flexibilidad para aadir a una DLL especificadores
de importacin/exportacin, marcadores de convencin de llamada como __cdecl,
e incluso transformar los nombres de los smbolos en algunos compiladores. Si
olvida usar estas macros, su cdigo no funcionar en algunas plataformas.

Esto slo es aplicable a ficheros de cabecera: puede escribir cdigo C normal
en el cdigo fuente.

El smbolo ALLEGRO_SRC es definido al compilar cdigo fuente de la
biblioteca. Si quiere incluir una funcin en lnea en su cdigo fuente, use
la macro INLINE. Para declarar arrays de tamao cero en una estructura, use
int x[ZERO_SIZE]. Para usar enteros de 64 bits, declare la variable como
LONG_LONG (esto no est definido en todas las plataformas). Para realizar
operaciones con nombres de ficheros, compruebe las macros ALLEGRO_LFN,
OTHER_PATH_SEPARATOR, y DEVICE_SEPARATOR. Lea los ficheros de cabecera para
ver los detalles.



=========================================
============ Soporte Unicode ============
=========================================

No asuma que las cadenas de caracteres son ASCII. No lo son. Si asume que si
lo son, su cdigo puede funcionar mientras la gente que lo use est tratando
con datos UTF-8, pero fallar horriblemente en cuanto alguien intente usarlo
con cadenas Unicode de 16 bits, o cdigo GB Chino, o algn otro formato MIME
extrao, etc. En cuanto vea un char * en alguna parte, debe considerar que
esto realmente contendr el texto en el formato actualmente seleccionado, por
lo que debe ser extremadamente cuidadoso manipulando cadenas de texto. No lo
olvide y nunca use una rutina libc con ellas!

Use las funciones Unicode para manipular todo el texto: lea los detalles en
la documentacin. Cuando reserve memoria para su cadena, asuma que cada
carcter ocupa como mucho cuatro bytes: esto le dar espacio de sobra para
los formatos de codificacin actuales.

Si quiere especificar una cadena constante, use la funcin
uconvert_ascii("mi texto", buf) para obtener una copia de "mi texto" en el
formato de codificacin actual. Si buf es NULL, se usar un buffer interno
esttico, pero el texto convertido ser sobreescrito por la siguiente
llamada a cualquier rutina de conversin de formato, por lo que no debera
pasar el texto a otras funciones de la biblioteca. Normalmente debera
proveer usted el espacio de conversin, reservando buf como un objeto
temporal en la pila.

Para convertir en sentido contrario (ej. antes de pasar una cadena de texto
de Allegro a una rutina de SO que espera datos ASCII), llama a
uconvert_toascii(mitexto, buf).

Para cualquier mensaje que pueda ser visto por el usuario, puede llamar
get_config_text("mi cadena ascii") en vez de uconvert_ascii(). Esto retornar
un puntero a memoria persistente (por lo que puede contar con la cadena
indefinidamente), tras convertirla al formato de codificacin actual. Esta
funcin es genial porque le evita la molestia de reservar memoria para los
datos convertidos, y porque permite que la cadena sea reemplazada por las
traducciones de language.dat. Debe tener la seguridad de pasar siempre
cadenas constantes a get_config_text(), en vez de texto generado o datos de
otras cadenas variables de texto: esto es para que el script findtext.sh
pueda encontrar fcilmente las cadenas que necesiten ser traducidas.

Los drivers de hardware deben inicializar su nombre y los campos desc a la
cadena global empty_string, y almacenar un nombre de driver ASCII en el campo
ascii_name. El cdigo de soporte traducir y convertir automticamente este
valor, almacenando el resultado en los campos name y desc. Para la mayora de
los drivers esto ser suficiente, pero si desea proporcionar una descripcin
ms detallada, es problema de su driver ajustar ese dato desde la rutina de
inicializacin, y encargarse de todas las conversiones necesarias.



================================================
============ Rutinas de Ensamblador ============
================================================

Los desplazamientos de estructuras estn definidos en asmdef.inc, el cual es
generado por asmdef.c. Esto permite usar al cdigo en ensamblador nombres
legibles por un humano para los miembros de una estructura, y ajustarlos
automticamente cuando se modifique la estructura para aadir ms valores,
por lo que siempre siempre se ajustarn al formato interno de las
estructuras de C.

El cdigo en ensamblador debe usar la macro FUNC(nombre) para declarar el
comienzo de una rutina, y GLOBL(nombre) cuando se quiera acceder a un
smbolo externo (ejemplo: una variable o funcin de C). Esto es para
manejar las transformaciones de nombres de un modo portable (COFF requiere
un subrayado como prefijo, ELF no lo necesita).

Puede modificar %ds y %es en ensamblador, siempre y cuando recupere sus
valores. Si USE_FS y FSEG estn definidos, tambin puede modificar %fs, de
otro modo esto no es requerido, y puede usar sin problemas el acceso con
nearptr para todo.

No asuma que los cdigos de operacin MMX estn soportados: no todas las
versiones de ensamblador los conocen. Compruebe la macro ALLEGRO_MX, y
sustituya su cdigo MMX en caso de que estas instrucciones no estn
disponibles.



=====================================
============ Otras Cosas ============
=====================================

Cualquier rutina portable que se ejecute en un temporizador o una funcin
callback de entrada debe estar fijando (lock) todo el cdigo y datos que
toque. Esto se hace poniendo END_OF_FUNCTION(x) o END_OF_STATIC_FUNCTION(x)
tras toda definicin de funcin (no obstante, esto no es requerido si
declara la funcin como INLINE), y llamando a LOCK_FUNCTION() en alguna
parte del cdigo de inicializacin. Use LOCK_VARIABLE para fijar variables
globales, y LOCK_DATA para fijar memoria dinmica reservada.

Cualquier mdulo que necesite cdigo de desinicializacin debera registrar
una funcin de salida llamando _add_exit_func(). Esto se asegurar de que
todo se cierre grcilmente sin importar si el usuario llama allegro_exit(),
la funcin main() llega al final, o el programa muere repentinamente debido
a un error de ejecucin. Debe llamar _remove_exit_func() desde su rutina
de desinicializacin, o se encontrar atascado en un bucle infinito.

