Compilador Harbour

Harbour es un moderno lenguaje de programación que nace como compilador del lenguaje de programación Clipper (una variante de xBase) desarrollado como software libre. Su objetivo inicial fue soportar todas las sentencias y extensiones de la versión más popular del compilador, Clipper 5.2. Harbour es además un compilador multiplataforma, capaz de compilar para y ejecutarse en DOS (MS-DOS, DR-DOS, etc), Microsoft Windows, OS/2, GNU/Linux, varias variantes de Unix, varios descendientes de BSD, Mac OS X, MINIX 3, Windows CE, Pocket PC, Symbian, iPhone OS, QNX, VxWorks, OS/2 BeOS/Haiku, AIX utilizando el mismo código fuente y ficheros de base de datos.

Harbour Project
Desarrollador(es)
Viktor Szakáts y la comunidad Harbour
https://harbour.github.io/
Información general
Extensiones comunes .prg, .ch, .hbs, .dbf
Paradigma multi-paradigma: imperativa, funcional, orientada a objetos, reflective
Apareció en 1999
Diseñado por Antonio Linares
Última versión estable 3.0.0 (17 de julio de 2011 (12 años y 2 meses))
Última versión en pruebas 3.1.x disponible en SVN (Aunque existe una versión llamada "nightly" que se genera diriamente con las últimas modificaciones a Harbour o alguno de sus componentes.
Sistema de tipos opcionalmente duck, dinámico, seguro, tipado fuerte parcial
Dialectos Clipper, Xbase++, Flagship, FoxPro, xHarbour
Influido por dBase, Clipper
Ha influido a xHarbour
Sistema operativo Multiplataforma
Licencia Open source GPL Compatible

A pesar de que es un poderoso lenguaje de programación de propósito general , se utiliza principalmente para crear programas de bases de datos y negocios. Harbour ha mantenido activamente la adición de características mientras mantiene compatibilidad retroactiva con el estilo de Clipper. Ha sufrido muchos cambios y revisiones y recuperado ampliamente popularidad entre los programadores de 1980 y 1990.

La licencia open source de Harbour[1] es similar a la GNU General Public License, con la excepción del soporte de aplicaciones propietarias, por lo que las aplicaciones propietarias pueden ser creadas y distribuidas con Harbour.

Historia

La idea de un compilador de software libre de Clipper había estado dando vueltas durante mucho tiempo y era a menudo tema de debate en comp.lang.clipper. El proyecto fue iniciado por Antonio Linares, creador de la biblioteca FiveWin, y fue rápidamente secundado por otras figuras del desarrollo en Clipper. Varias de las casas que desarrollan bibliotecas para Clipper respaldaron el proyecto, soportándolo en sus productos. El nombre Harbour es un juego de palabras con los barcos tipo Clipper que arribaban a un puerto, siendo Harbour el puerto de Clipper.

En 2009 Harbour fue rediseñado sustancialmente, sobre todo por Viktor Szakáts y Przemyslaw Czerpak.

Compatibilidad con base de datos

Harbour extiende la definición Clipper Replaceable Database Drivers (RDD). Ofrece múltiples DDR como DBF, DBFNTX, DBFCDX, DBFDBT y DBFFPT. En Harbour pueden usarse múltiples RDDs en la misma aplicación, y las nuevas lógicas de DDR se pueden definir por la combinación de otros DDRs. La arquitectura de los RDDs permite la herencia, por lo que un RDD dado puede ampliar la funcionalidad de otro RDD existente(s). Desarrollos de terceros, como RDDSQL, RDDSIX, RMDBFCDX, Advantage Database Server, y Mediator ejemplifican algunas de las características de la arquitectura del RDD. La implementación DBFNTX tiene casi las mismas funciones de DBFCDX y RDDSIX. NETIO y LetoDB[2] proporcionan acceso remoto a través del protocolo TCP protocol.

Harbour también ofrece soporte ODBC por medio de una sintaxis de programación orientada a objetos, y soporte ADO a través de OLE. MySQL, PostgreSQL, SQLite, Firebird, Oracle son ejemplos de bases de datos con las que se puede conectar Harbour.

Las tecnologías xBase a menudo se confunden con un RDBMS software. Aunque esto es cierto, xBase es más que un sistema de base de datos simple, pues las variantes xBase que utilizan exclusivamente DBF no pueden proporcionar el concepto completo de un verdadero RDBMS.

Filosofía de programación

A diferencia del lenguaje de programación Java, que está destinado a escribir una vez, ejecutar en cualquier lugar, Harbour aspira a ser escribir una vez, compilar en cualquier lugar. A medida que el mismo compilador está disponible para todos los sistemas operativos anteriores, no hay necesidad de recodificación para producir productos idénticos para diferentes plataformas, excepto cuando se utilizan las características dependientes del sistema operativo. Se soporta la compilación cruzada con MinGW32. En Microsoft Windows, Harbour es más estable pero no tan bien documentado como Clipper, pero tiene la capacidad multi-plataforma y es más transparente, personalizable y se puede ejecutar desde una Memoria USB.

En Linux y Windows Mobile, el código fuente Clipper puede ser compilado con Harbour, con muy poca adaptación. La mayoría del software escrito originalmente para funcionar con Xbase++, Flagship, FoxPro, xHarbour y otros dialectos pueden ser compilados con Harbour con algunas adaptaciones. En 2010 se han hecho muchos esfuerzos para hacer la transición de otros dialectos xBase más fácil.

Harbour puede utilizar los siguientes compiladores de C, entre otros: GCC, MinGW, Clang, ICC, Microsoft Visual C++ (6.0+), Borland C++, Watcom C, Pelles C y Sun Studio, tanto para ser generado el compilador Harbour y sus herramientas auxiliares, como también para incluir rutinas en lenguaje C, embebidas en el código de Harbour.

Interfaz Gráfica

Harbour puede hacer uso de múltiples emulaciones de terminal gráfico, incluidos los controladores de la consola, e híbridos consola/GUIs, como GTWvt, y GTWvg.

En el modo consola (ventana DOS), la ejecución de un programa en Harbour es de tipo top-down el programa avanza de arriba hacia abajo, según las directivas de programación que va encontrando.
En cambio en el modo Gráfico, se utiliza el paradigma por eventos y la ejecución no necesariamente sigue con la próxima directiva de programación.
Es muy importante tener en cuenta esto, porque el código fuente debe ser modificado según el tipo de interfaz que se elija.

Harbour soporta interfaces gráficas de usuario externas, por ejemplo:


  • Comerciales:
    • FiveWin
    • Xailer

HBQt es una biblioteca que proporciona enlaces a Qt. La aplicación HBIDE incluida en la distribución oficial y en el repositorio SVN es una muestra del potencial de HBQt.

Harbour es 100% compatible con Clipper[3] y soporta muchas extensiones de la sintaxis del lenguaje, incluyendo en gran medida extensiones en tiempo de ejecución, tales como bibliotecas OLE, Blat, OpenSSL, FreeImage, GD, TIP, Tpathy, PCRE, HbZip (zlib y bzip2), cURL, Cairo, su propia implementación de las librerías CA-Tools y NanFor y muchos otros. Harbour cuenta con una activa comunidad de desarrollo y con un amplio apoyo de terceros.

Cualquier lenguaje xBase proporciona una manera muy productiva para construir aplicaciones de negocios y de grandes volúmenes de datos. Harbour no es una excepción.

Operador de Macro (compilación en tiempo de ejecución)

Una de las características más potentes de los lenguajes xBase es el operador de macro '&'. La implementación en Harbour del operador de macro permite la compilación en tiempo de ejecución de cualquier expresión válida Harbour. Una expresión compilada se puede utilizar como un VALUE, es decir, el lado derecho de una asignación (rvalue), pero es más interesante, tal expresión compilada puede utilizarse para resolver el lado izquierdo (lvalue) de una asignación, es decir, variables PRIVATE o PUBLIC, o en un campo de base de datos.

Además, el operador de macro puede compilar y ejecutar llamadas a funciones, tareas completas, o incluso la lista de argumentos, y el resultado de la macro se puede utilizar para resolver cualquiera de los contextos anteriores en la aplicación compilada. En otras palabras, cualquier aplicación Harbour puede ser extendida y modificada en tiempo de ejecución para compilar y ejecutar código adicional bajo demanda.

El compilador de macro puede compilar cualquier código Harbour válido, incluyendo el código de pre-proceso antes de la compilación.

Sintaxis:

 &( ... )

El valor del texto de la expresión '...' será compilado, y el valor resultante de la ejecución del código compilado es el resultado.

 &SomeId

es la forma corta de &( SomeId ).

 &SomeId.postfix

es la forma corta de &( SomeId + "postfix" ).

Programación Orientada a Objetos

El estilo de programación orientada a objetos es un tema más amplio que el de una biblioteca específica o una interfaz específica, pero la programación orientada a objetos es algo que muchos programadores Clipper han llegado a esperar. CA-Clipper 5.2 y en especial 5.3 añadieron una serie de clases base, y una sintaxis de programación orientada a objetos correspondiente. Bibliotecas, como Class(y), FiveWin, Clip4Win y TopClass ofrecen funcionalidad de programación orientada a objetos adicionales.

Harbour tiene extensiones de programación orientada a objetos con soporte completo para las clases, incluyendo la herencia, basado en la sintaxis de Class(y). La sintaxis de programación orientada a objetos en Harbour es muy similar a la de anteriores bibliotecas de clases de Clipper por lo que debería ser posible mantener el código heredado Clipper con cambios mínimos.

Sintaxis y semántica

Código Harbour en HBIDE.

Harbour como cada lenguaje xBase es in-sensible a mayúsculas y, opcionalmente, puede aceptar palabras clave escritas con solo los cuatro primeros caracteres.

Tipos de datos incorporados

Harbour cuenta con 6 tipos escalares: Nil, Cadena, Fecha, Lógico, Numérico, y 4 tipos complejos: Matriz (Array), Objeto, CodeBlock, y Hash. Un escalar tiene un valor único, como una cadena, número o referencia a cualquier otro tipo. Las matrices son listas ordenadas de escalares o tipos complejos, con un índice por número, comenzando por el 1. Hashes, o matrices asociativas, son conjuntos no ordenados de los valores de tipo indexados por la clave de su asociado, que puede ser de cualquier tipo escalar o compleja.

Representación literal (estática) de tipos escalares:

  • NIL: Este valor especial es asignado a todas las variables no inicializadas, excepto las públicas, y es también pasado también como un sustituto cuando los argumentos son omitidos en el llamado a una función o procedimiento.
  • Cadena de caracteres: "hola", 'hola', [hola]
  • Fecha: 0d20100405
  • Lógico: .T., .F.
  • Numérico: 1, 1.1, −1, 0xFF

Los tipos complejos también pueden presentarse como valores literales:

  • Array: { "Cadena"", 1, { "Matriz Anidada" }, .T., FunctionCall(), @FunctionPointer() }
  • CodeBlock: { |Arg1, ArgN| Arg1 := ArgN + OuterVar + FunctionCall() }
  • Hash: { "Nombre" => "Juan", 1 => "Clave numérica", { "Anidado" => "Hash" } }

Los valores hash puede utilizar cualquier tipo incluyendo otros hashes como la Clave para cualquier elemento. Hashes y arrays pueden contener cualquier tipo como el valor de cualquier miembro, incluidas las matrices de anidación, y hashes.

Los Codeblocks pueden tener referencias a variables del Procedimiento/Función/Método en el que se ha definido. Estos Codeblocks pueden ser devueltos como un valor, o por medio de un argumento pasado por referencia, en tal caso el bloque de código va a "sobrevivir" a la rutina en la que se definió, y las variables de las que hace referencia, será una variable INDEPENDIENTE.

Las variables independientes mantendrán su valor durante el tiempo que un bloque de código (Codeblock) hace referencia a ellos aún exista. Estos valores serán compartidos con cualquier otro bloque de código que puede tener acceso a esas mismas variables. Si el bloque de código no sobrevive a la rutina que contiene, y será evaluado durante la vida de la rutina en la que se define, los cambios en sus variables independientes por medio de su evaluación, se reflejan de vuelta en la rutina de los padres.

Los Codeblocks se pueden evaluar cualquier número de veces, por medio de la función Eval( BlockExp ).

Variables

Todos los tipos se pueden asignar a las variables declaradas. El nombre de una variable tiene de 1 a 63 caracteres de largo, comienza por [A-Z|_] y además constará de caracteres [A-Z|0–9|_] hasta el máximo de 63 caracteres. Los nombres de las variables no distinguen entre mayúsculas y minúsculas.

Las variables tienen uno de los siguientes ámbitos:

  • LOCAL: Visible solo dentro de la rutina, que lo declaró. El valor se pierde al salir de la rutina.
  • STATIC: Visible solo dentro de la rutina, que lo declaró. El valor es preservado para las siguientes llamadas a la rutina. Si una variable STATIC (estática) se declara antes de que cualquier procedimiento/función/método se defina, tiene un alcance de MODULE (módulo), y es visible dentro de cualquier rutina definida dentro de ese mismo archivo de origen, que mantendrá su vida durante toda la duración de la aplicación.
  • PRIVATE: Visible dentro de la rutina que lo declaró, y todas las rutinas llamadas por esa rutina.
  • PUBLIC: Visible por todas las rutinas en la misma aplicación.

LOCAL y STATIC se resuelven en tiempo de compilación, y por lo tanto son mucho más rápidas que las variables PRIVATE y PUBLIC que son entidades dinámicas a las que se accede en tiempo de ejecución por medio de la tabla de símbolos. Por esta misma razón, las variables LOCAL y STATIC no están disponibles para el compilador de macros, y cualquier código de macro que intenta hacer referencia a ellos va a generar un error de ejecución.

Debido a la naturaleza dinámica de las variables PRIVATE y PUBLIC, que pueden ser creados y destruidos en tiempo de ejecución, se puede acceder y modificar por medio de macros en tiempo de ejecución, y pueden ser consultados y modificados por Codeblocks creados sobre la marcha.

Fields (Campos)

Las variables de los campos de las bases de datos están limitados a: Carácter, Numérico, Fecha, Lógico y un tipo especial llamado 'MEMO' que es tratado como una Cadena de caracteres (con algunos caracteres especiales de control).

Estructuras de control

Las estructuras de control básicas incluyen todas las estructuras de control estándar de dBase y Clipper, así como otras adicionales inspirados en las de los lenguajes de programación C o Java :

Bucles

[DO] WHILE ConditionExp
   ...
   [LOOP]
   [EXIT]
END[DO]


FOR Var := InitExp TO EndExp [STEP StepExp]
   ...
   [LOOP]
   [EXIT]
NEXT
FOR EACH Var IN CollectionExp
   ...
   [HB_EnumIndex()]
   [LOOP]
   [EXIT]
NEXT
  • ... es una secuencia de una o más expresiones Harbour statements, y los corchetes [] indican la sintaxis opcional.
  • HB_EnumIndex() puede ser utilizado opcionalmente para recuperar el índice de iteración actual (basado en 1).
  • La sentencia LOOP reinicia la iteración actual de la estructura de bucle a que pertenece, y si el circuito de cierre es un bucle FOR o FOR EACH, incrementa el contador, pasando a la siguiente iteración del bucle.
  • La sentencia EXIT termina inmediatamente la ejecución de la estructura de bucle a que pertenece.
  • La sentencia NEXT cierra la estructura de control y se traslada a la siguiente iteración de la estructura de bucle.

En la sentencia FOR, la expresión de asignación se evalúa antes de la repetición del bucle en primer lugar. La expresiónTO se evalúa y se compara con el valor de la variable de control, antes de cada iteración, y el bucle se termina si se evalúa como un valor numérico mayor que el valor numérico de la variable de control. La expresión opcional STEP se evalúa después de cada iteración, antes de decidir si se debe realizar la siguiente iteración.

En FOR EACH, la variable Var tendrá el valor (escalar, o complejo) del elemento respectivo en el valor de la colección. La expresión de la colección, puede ser una matriz (de cualquier tipo o una combinación de tipos), una tabla hash, o un Objeto.

Sentencias IF

IF CondExp
   ...
[ELSEIF] CondExp
   ...
[ELSE]
   ...
END[IF]

... representa 0 o más sentencias.

Las expresiones de condición tiene que evaluar a un valor LOGICAL (lógico).

Sentencias SWITCH

Harbour admite el constructor SWITCH inspirado en la implementación en C de switch().

SWITCH SwitchExp
   CASE LiteralExp
      ...
      [EXIT]
   [CASE LiteralExp]
      ...
      [EXIT]

   [DEFAULT]
      ...
END
  • La LiteralExp debe ser una expresión numérica que pueda resolverse en tiempo de compilación, y puede involucrar operadores, siempre y cuando los operadores en cuestión afectan a un valor en tiempo de compilación estática.
  • La sentencia opcional EXIT es el equivalente de la declaración break en C, y si está presente, la ejecución de la estructura SWITCH termina al alcanzar la sentencia EXIT, de lo contrario se continuará con la primera declaración CASE siguiente (fall through).

Sentencias BEGIN SEQUENCE

BEGIN SEQUENCE
   ...
   [BREAK]
   [Break([Exp])]
RECOVER [USING Var]
   ...
END[SEQUENCE]

o:

BEGIN SEQUENCE
   ...
   [BREAK]
   [Break()]
END[SEQUENCE]

La estructura BEGIN SEQUENCE permite un aborto ordenado de cualquier secuencia, incluso cuando se utilizan procedimientos y funciones anidadas. Esto significa que un procedimiento/función llamado, puede emitir una sentencia BREAK, o una expresión Break(), para forzar el retorno de cualquier procedimiento/función anidadas, todo el camino de regreso a la primera estructura externa BEGIN SEQUENCE, incluso después de su respectiva declaración END, o a una cláusula RECOVER si está presente. La sentencia Break puede pasar opcionalmente cualquier tipo de expresión, que puede ser aceptado por la sentencia RECOVER para permitir su entrega y posterior recuperación.

Además, el Error Object (objeto de error) de Harbour soporta las propiedades canDefault, canRetry y canSubstitute, que permiten a los controladores de errores llevar a cabo algunos preparativos, y luego solicitar una Retry Operation (operación de reintento), un Resume, o devolver un Valor para sustituir la expresión que dispara la condición de error.

Alternativamente las declaraciones TRY [CATCH] [FINALLY] están disponibles en la biblioteca xHB trabajando como el constructor SEQUENCE.

Procedimientos y funciones

[STATIC] PROCEDURE SomeProcedureName
[STATIC] PROCEDURE SomeProcedureName()
[STATIC] PROCEDURE SomeProcedureName( Param1' [, ParamsN] )
INIT PROCEDURE SomeProcedureName
EXIT PROCEDURE SomeProcedureName
[STATIC] FUNCTION SomeProcedureName
[STATIC] FUNCTION SomeProcedureName()
[STATIC] FUNCTION SomeProcedureName( Param1' [, ParamsN] )

Procedimientos y Funciones en Harbour puede ser especificadas con la palabra clave PROCEDURE, o FUNCTION. Las reglas de asignación de nombres son los mismos que para las variables (hasta 63 caracteres que mayúsculas y minúsculas). Procedimientos y funciones pueden ser calificados por el calificador de ámbito STATIC para restringir su uso al ámbito de aplicación del módulo donde se define.

Los calificadores opcionales INIT or EXIT, marcarán el procedimiento que se invoca automáticamente justo antes de llamar al procedimiento de inicio de la aplicación, o justo después de salir de la aplicación, respectivamente. Los parámetros que se pasan a una procedure/function aparecen en la subrutina como variables locales, y puede aceptar cualquier tipo, incluyendo las referencias.

Los cambios en las variables de parámetros no se reflejan en las variables respectivas pasadas en la llamada al procedimiento/función/método a menos que pasen explícitamente BY REFERENCE (por referencia) usando el prefijo @.

Un PROCEDURE no tienen valor de retorno, y si se utiliza en un contexto de expresión va a producir un valor Nulo.

Una FUNCTION puede devolver cualquier tipo por medio de la instrucción RETURN, en cualquier parte del cuerpo de su definición.

A continuación, una llamada a una FUNCTION y la definición de dicha FUNCTION :

 x := Cube( 2 )

 FUNCTION Cube( n )
 RETURN n ** 3

Ejemplos de código

El típico programa hola mundo puede implementarse como:

 
  ? "¡Hola, mundo!"

O:

  QOut( "¡Hola, mundo!" )

O:

  Alert( "¡Hola, mundo!" )

O, dentro de un procedimiento explícito:

 PROCEDURE Main()
 
    ? "¡Hola, mundo!"

 RETURN

Ejemplos de OOP

 #include "hbclass.ch"

 PROCEDURE Main()

    LOCAL oPerson := Person():New( "Dave" )

    oPerson:Eyes := "Invalid"

    oPerson:Eyes := "Blue"

    Alert( oPerson:Describe() )
 RETURN

 CLASS Person
    DATA Name INIT ""

    METHOD New( cName ) CONSTRUCTOR

    ACCESS Eyes INLINE ::pvtEyes
    ASSIGN Eyes( x ) INLINE IIF( ValType( x ) == 'C' .AND. x IN "Blue,Brown,Green", ::pvtEyes := x, Alert( "Invalid value" ) )

    // Ejemplo de definición de método IN-LINE
    INLINE METHOD Describe()
       LOCAL cDescription

       IF Empty( ::Name )
          cDescription := "I have no name yet."
       ELSE
          cDescription := "My name is: " + ::Name + ";"
       ENDIF

       IF ! Empty( ::Eyes )
          cDescription += "my eyes' color is: " + ::Eyes
       ENDIF
    ENDMETHOD

    PRIVATE:
       DATA pvtEyes
 ENDCLASS

 // Ejemplo de definición de un método normal.
 METHOD New( cName ) CLASS Person

   ::Name := cName

 RETURN Self

Herramientas

  • HBIDE – Entorno de desarrollo integrado para ayudar al desarrollo Harbour y varios dialectos xBase
  • HBMK2 – Potente herramienta de construcción como make
  • HBDoc2 e HBExtern – Crea la documentación para Harbour
  • HPPP – Preprocesador, una poderosa herramienta que evita los problemas típicos que se encuentran en el Preprocesador de C
  • HBFormat – Formatea código fuente escrito en Harbour u otro dialecto a otro según las reglas definidas
  • HBi18n – Herramientas para la localización de texto en las aplicaciones
  • HBRun – intérprete de Shell para Harbour. La macro compilación permite ejecutar cualquier código Harbour válido, ya que se está compilando

Todas las herramientas son multiplataforma.

Nota:
A pesar de no estar incluida la herramienta DBU para crear y manejar tablas en formato DBF (por cuestiones de copyright), aún sigue siendo posible compilar el código original DBU.PRG y generar el ejecutable en cualquiera de las plataformas soportadas.

Desarrollo

HBIDE look.

Hoy en día el desarrollo de Habour está liderado por Viktor Szakáts con gran colaboración de Przemysław Czerpak que lleva muchos componentes del núcleo y contribuciones. HBIDE y algunos componentes, especialmente HBQt, son desarrollados por Pritpal Bedi. Otros miembros aportan los cambios de menor importancia al repositorio SVN de Sourceforge.[4] En 2010 el desarrollo de Harbour mantiene una vibrante actividad.

Popularidad

Aunque no hay manera de medir la popularidad de Harbour o xBase, el TIOBE Programming Community Index[5] situaba a Microsoft Visual FoxPro, un dialecto de alto perfil de xBase, en la 12 posición en el ranking de popularidad de lenguajes de programación en junio de 2006, y a FoxPro/xBase en el puesto 25 en agosto de 2010. En septiembre de 2010, los newsgroups de Usenet sobre Clipper comp.lang.clipper todavía está activo. En agosto de 2010 Harbour figuraba en la posición 16 en descargas semanales en la categoría del compilador y en la posición 132 en la clasificación mundial.[6]

Comparación con xHarbour

xHarbour es un fork[7] del primitivo proyecto Harbour. xHarbour tiene un enfoque más agresivo para la aplicación de las nuevas características del lenguaje, mientras que Harbour es más conservador en su planteamiento, con el objetivo en primer lugar por una réplica exacta del comportamiento de Clipper dejando la aplicación de las nuevas características y extensiones como una consideración secundaria. También hay que señalar que Harbour es compatible con una amplia variedad de sistemas operativos , mientras que xHarbour solo está soportado por las versiones de 32 bits de Microsoft Windows y Linux.

Los desarrolladores de Harbour han tratado de documentar todo el comportamiento oculto en el lenguaje Clipper y testeado código compilado con Harbour con el mismo código compilado con Clipper para mantener la compatibilidad.

Los desarrolladores de Harbour rechazan explícitamente extensiones del lenguaje cuando las extensiones rompen la compatibilidad Clipper. Este rechazo se suaviza recientemente ya que la nueva arquitectura de Harbour permite extensiones fuera del núcleo del compilador.

Una comparación detallada entre las extensiones aplicadas en Harbour y xHarbour se puede encontrar en el repositorio SVN del proyecto en SourceForge.[8]

A partir de 2009-2010, Harbour ha visto un enorme aumento en su adopción, mientras que el declive de xHarbour puede verse en su lista de correo.[9][10][11]

Véase también

Referencias

  1. Harbour license
  2. LetoDB
  3. Official Harbour page Archivado el 5 de junio de 2012 en Wayback Machine.
  4. http://sourceforge.net/projects/harbour-project/
  5. «TIOBE Programming Community Index». Archivado desde el original el 29 de noviembre de 2007. Consultado el 4 de marzo de 2012.
  6. SourceForge
  7. About xHarbour
  8. xhb-diff.txt
  9. «Harbour developers' mailing list statistics». Archivado desde el original el 13 de marzo de 2012. Consultado el 4 de marzo de 2012.
  10. «xHarbour developers' mailing list statistics». Archivado desde el original el 13 de marzo de 2012. Consultado el 4 de marzo de 2012.
  11. ohloh.net Activity comparison

Enlaces externos

Este artículo ha sido escrito por Wikipedia. El texto está disponible bajo la licencia Creative Commons - Atribución - CompartirIgual. Pueden aplicarse cláusulas adicionales a los archivos multimedia.