Harbour — язык программирования и кроссплатформенный компилятор с препроцессором, полностью совместимый с Clipper. Он позволяет создавать 16-, 32- и 64-разрядные приложения для DOS, Windows, Unix/Linux, OS/2, Mac OS X, Windows CE, BSD, Pocket PC, Symbian, iOS, QNX, VxWorks, eComStation, Haiku/BeOS, AIX. Harbour является свободным программным обеспечением.

Кроме работы с локально расположенными данными, Harbour позволяет работать с данными как в режиме «файл-сервер», так и в режиме клиент-сервер (в том числе, в режиме запросов к удалённой системе управления базами данных, поддерживающей SQL).

Язык использует традиционные конструкции Clipper, объектную нотацию, принятую в языке C++, а также дает возможность писать на языке C. Harbour активно развивается и в язык включаются некоторые современные технологии программирования.

xHarbour () — ответвление проекта Harbour, существует как в коммерческом, так и в свободном вариантах.

Имеются GUI-библиотеки — как коммерческие, так и бесплатные (в частности, MiniGUI — для Windows; HwGUI — для Windows и GNU/Linux).

Harbour распространяется под свободной лицензией, схожей с GNU General Public License, за исключением того, что на Harbour возможно свободно разрабатывать и распространять коммерческие приложения (как пример тиражируемого коммерческого ПО − Система для учёта и управления предприятием БЭСТ-5 ). См. также в конце статьи Тиражируемое ПО, написанное на Harbour.

История создания Основателем проекта является испанский программист Антонио Линарес (). Первое сообщение о «мыслях, витающих в воздухе» относительно адаптации программного обеспечения, написанного для Clipper, к новым реалиям, инициировав тем самым дискуссию, приведшую к созданию Harbour, он опубликовал в Usenet-группе comp.lang.clipper 16 марта 1999 года . Название Harbour () было предложено проекту Линаресом по общности «морского контекста» с названием компилятора Clipper () (в смысле «безопасная гавань для клипера»). В том же 1999 году группой разработчиков, среди которых, помимо Линареса, особенно следует отметить Рышарда Глаба (), были выпущены первые версии компилятора.

В 2009 году Harbour был глубоко переработан международным сообществом разработчиков под руководством Виктора Сакаца () и Пшемыслава Черпака (), по состоянию ведётся активное развитие и разработка, имеются как международное, так и языково-ориентированные сообщества разработчиков и пользователей (русское, испанское, португальское, итальянское и на прочих языках).

В настоящее время с использованием Harbour создаются как бесплатные, так и коммерческие приложения.

Работа с базами данных Harbour расширяет возможности использовавшихся в Clipper драйверов баз данных (RDD, ). Он поддерживает традиционные для Clipper RDD — такие как DBF, DBFNTX, DBFCDX, DBFDBT и DBFFPT. В Harbour можно использовать разные драйверы в одном приложении (например, брать данные из традиционной для Clipper базы данных в формате DBFNTX и записывать их в формате FoxPro — DBFCDX), а также создавать новые («логические») RDD из комбинации нескольких имеющихся. Архитектура RDD разрешает наследование, то есть новый драйвер может использовать функциональные возможности уже имеющихся. Для Harbour переписаны наиболее популярные драйверы сторонних производителей: RDDSQL, RDDSIX, RMDBFCDX, ADS (), Mediator. Такие RDD, как NETIO и LetoDBLetoDB на SourceForge.Net дают возможность удаленного доступа к базам данных через TCP-протокол путём создания Web-приложений, функционирующих на стороне сервера локальной сети либо Web-сервера, с доступом пользователя к данным через сеть, используя любой Интернет-браузер и любую операционную систему.

В Harbour используется доступ к данным посредством технологий ODBC и ADO, созданы специальные библиотеки для доступа к некоторым популярным СУБД: MySQL, PostgreSQL, SQLite, Firebird, Oracle Database, используя программный интерфейс приложения на языке C.

Концепции В проекте Harbour стремятся к обеспечению кроссплатформенности на уровне исходных кодов при специфической компиляции под каждую платформу, согласно концепции (написано однажды — компилируется везде). Если для некоего набора операционных систем есть подходящие для использования компиляторы Harbour, то нет препятствий к тому чтобы создавать идентичные программы для всех этих платформ, написав исходный текст один раз, за исключением случаев, когда используются возможности, специфичные для разных операционных систем. Кросс-компиляция возможна благодаря MinGW32. Большое количество программ, исходный код которых ранее написан для работы с Xbase++, Flagship, FoxPro, xHarbour и другими диалектами xBase, могут быть также достаточно легко адаптированы для компиляции через Harbour.

Harbour может использовать многие компиляторы Си, в частности: GCC, MinGW, Clang, ICC, Microsoft Visual C++ (6.0+), Borland C++, Watcom C, Pelles C и Sun Studio.

В проекте Harbour используется эмуляция многих графических терминалов, включая драйверы консоли, а также гибридные консольно-графические — такие как GTWvt и GTWvg.

Harbour поддерживает внешние библиотеки графического пользовательского интерфейса, как свободно распространяемые (наиболее известные — HWGuiHwGUI на SourceForge.Net , MiniGUI и Qt), так и коммерческие (например, FiveWin или Xailer). Взаимодействие с Qt производится через библиотеку hbQt.

Разработчиками проекта утверждается, что язык Harbour на 100 % совместим с Clipper на уровне исходного кодаOfficial Harbour page .

Макро-оператор (компилятор времени выполнения) Одна из наиболее мощных возможностей xBase-языков — это Макро-оператор '&'. Реализация макро-оператора в Harbour позволяет создавать любое допустимое в Harbour выражение прямо во время выполнения программы (компиляция времени выполнения). Такое скомпилированное выражение может быть использовано как значение, то есть в правой части операции присваивания (rvalue), но также — что более интересно — и как левая часть операции присваивания (lvalue), то есть как PRIVATE или PUBLIC переменная, или как поле (FIELD) базы данных.

Кроме того, макро-оператор может компилировать «на лету» и выполнять вызовы функций, выполнять присваивания значений или даже создавать список аргументов — а результат выполнения макро-оператора может использоваться в любом из указанных контекстов в скомпилированной прикладной программе. Иными словами, любое Harbour-приложение может изменять логику своей работы во время выполнения, создавая и выполняя необходимый код «по запросу».

Последний макро-компилятор может компилировать любой допустимый в Harbour код, включая код для препроцессора, обрабатываемый до компиляции.

Синтаксис макро-оператора:

&( ...)

Текстовое значение выражения в скобках '…' будет скомпилировано во время выполнения программы, а результатом макроса будет значение, полученное в результате выполнения скомпилированного кода.

&SomeId

это более короткая форма макро-оператора &(SomeId).

&SomeId.postfix

это более короткая форма макро-оператора &(SomeId + «postfix»).

Возможности, предоставляемые макро-оператором, в сильной степени упрощают программирование.

Например, представим ситуацию, когда программа должна считывать в переменную «data1» некие данные из поля «FIELD1» одной из многочисленных имеющихся баз данных (например, различающихся только именами, но одинаковых по структуре, баз-справочников). Имя базы-источника данных вводится пользователем (или получается каким-либо иным путём) в переменную «bd».

Не используя макро-оператор, нам пришлось бы расписать в исходном коде программы все возможные значения, которые могла бы получать в ходе работы программы переменная «bd», и описывать, какую базу открыть в данном конкретном случае — нечто вроде:

if bd == "BAZA1" use BAZA1 alias BAZASP new endif if bd == "BAZA2" use BAZA2 alias BAZASP new endif .... (и так много-много раз, для всех возможных значений) .... data1 := BAZASP->FIELD1 ....

В случае же применения макро-оператора нам достаточно написать просто:

use &(bd) alias BAZASP new data1 := BAZASP->FIELD1

и этого достаточно!.. Ну, может быть, ещё предварительно, до попытки открытия, проверить существование базы с таким именем:

if .not. file( bd + ".DBF" ) ? "База данных с именем " + bd + ".DBF не найдена!" ... (и здесь обработка этой ситуации - ... что при этом должны делать программа или пользователь) endif

Объектно-ориентированное программирование В Harbour для использования классов не требуется подключать дополнительные библиотеки, объектно-ориентированное программирование является здесь частью языка и Harbour предоставляет большие возможности, чем Clipper со всеми сторонними библиотеками.

Синтаксис и семантика языка

Harbour — как любой xBase-язык — регистронезависим (то есть команды или имена переменных воспринимаются одинаково при написании заглавными или строчными буквами: например, «sStr», «sstr» и «SStr» — это одна и та же переменная; «DbCreate()» и «dbCREATE()» — одна и та же функция) и содержит опцию распознавания зарезервированных ключевых слов (например, команды) по первым четырём буквам (например, вместо команды «COPY STRUCTURE EXTENDED …» можно писать просто «COPY STRU EXTE …»).

Встроенные типы данных В Harbour есть 6 скалярных типов данных: ничто Nil, строка String, дата Date, логический тип Logical, число Number, указатель Pointer, и 4 составных типа: массив Array, объект Object, блок кода CodeBlock и хеш Hash. Скалярные данные содержат единичное значение — такое как строка, число или ссылка на переменную любого другого типа. Массивы — это упорядоченные списки скалярных или составных значений (то есть элементом массива может быть в том числе и другой массив, а его элементом — другой и т. п.), индексированный по номеру, начиная с 1 (а не с 0, как в некоторых других языках). Хеш-таблицы, или ассоциативные массивы — неупорядоченные собрания значений любых типов, индексируемые по ключу, связанному с каждым значением, который может быть любого скалярного или составного типа.

Литеральное (статическое) представление скалярных типов: Nil: NIL String: «hello», 'hello', [hello], E"hello\n" Date: 0d20100405 Logical: .T., .F. Number: 1, 1.1, −1, 0xFF

Составные типы тоже можно представить в виде значений-литералов: Array: { «Строка», 1, { «Вложенный массив» }, .T., FunctionCall(), @FunctionPointer() } CodeBlock: { |Arg1, ArgN| Arg1 := ArgN + OuterVar + FunctionCall() } Hash: { «Имя» => «Джон», 1 => «Числовой ключ», { «Вложенная» => «Хеш-таблица» } }

В хеш-таблицах в качестве ключа для любого элемента может использоваться значение любого типа, включая другую хеш-таблицу. Хеш-таблицы и массивы могут содержать в качестве значения любого элемента значение любого типа, в том числе вложенные массивы и хеш-таблицы.

Блоки кода могут содержать ссылки на переменные процедуры, функции или метода, в котором определён блок кода. Такие блоки кода могут возвращаться в виде значения или в аргументе, передаваемом по ссылке; в этом случае блок кода «переживёт» подпрограмму, в которой он определён, и все переменные, на которые он ссылается, будут «отсоединенными (detached)» переменными.

Отсоединенные переменные сохраняют своё значение, пока существует ссылающийся на них блок кода. Эти значения будут общими для всех блоков кода, у которых есть доступ к тем же самым переменным. Если блок кода не переживает содержащую его подпрограмму и вычисляется за время жизни подпрограммы, в которой он определён, изменения в его отсоединённых переменных, вызванные его вычислением, отражаются в этой подпрограмме.

Блок кода можно вычислять неограниченное количество раз с помощью функции Eval(Блок кода).

Разработка клиент-серверных и Web-приложений

Leto DB server