Harbour — новое лицо xBase family

    Для справки: xBase — семейство систем программирования, СУБД, берущих начало с dBase (1980 г.). Их объединяет общий язык программирования ( естественно, с вариациями, присущими конкретной реализации ) и встроенные в этот язык средства доступа к реляционным базам данных формата DBF. Собственно, dBase начинался как СУБД с языком, предназначеннным для обслуживания баз данных. Это процедурный язык программирования, он относится к группе интерпретируемых языков и обладает многими, если не всеми, их родовыми чертами, такими, например, как динамическая типизация.

    Clipper, непосредственный предшественник Harbour, был создан в 1985 г. с целью повышения производительности dBase III. Для этого исходный код программы преобразовывался на стадии компиляции в байт-код, который встраивался в исполнямый файл вместе с виртуальной машиной, предназначенной для исполнения этого байт-кода. Таким образом, Clipper давал на выходе автономный exe файл, не требующий для своего запуска и выполнения внешнего интерпретатора, как в случае dBase или FoxBase ( другой популярный xBase продукт ).

    В конце 80-х и начале 90-х Clipper был очень популярен, он был одним из основных средств программирования для приложений, связанных с использованием баз данных, в первую очередь бухгалтерских, управленческих, банковских. Язык модернизировался от версии к версии, добавлялись новые подсистемы. Среди последних особенно следует отметить Extend System и RDD. Extend System (система расширения) предназначена для связи с модулями, написанными на С — вызов функций, передача параметров, получение возвращаемых значений. RDD — Replaceable Database Drivers (заменяемые драйверы баз данных) — технология, которая позволяла, прилинковав взамен стандартной другую, специальную библиотеку, работать с БД другого типа, не изменив ни строчки кода. Именно так Clipper-приложения работали, например, с Novell'овским Btrieve (если кто помнит, была такая клиент-серверная не SQL СУБД).

    XBase системы всегда воспринимались как предназначенные, в первую очередь, для работы с базами данных и, возможно поэтому, с ростом популярности SQL стали выходить из тренда. И если с Fox'ом все было более-менее благополучно — купившая его Microsoft сделала на его основе популярный продукт Visual Foxpro, который еще несколько лет назад (в 2006, согласно Википедии), был на почетном 12-м месте в списке TIOBE, то у Clipper дела были куда хуже. Computer Associates, которая владела им с начала 90-х, сделала ставку на другие продукты. Clipper же остался в стороне от магистрального пути, назревшие проблемы не решались, а в 1997 году Computer Associates объявила о закрытии дальнейшей его разработки, оставив пишущих на нем программистов наедине с 16-разрядной, рассчитанной на применение в среде MS-DOS системой программирования.

    Многие из тех, кто задумывался о своем будущем, мигрировали на другие платформы, но остались и те, кто считал, что достоинства Clipper, будучи реализованы в современной среде программирования, будут востребованы и дальше. Были созданы несколько таких реализаций (xBase++, Clip, Harbour), об одной из которых, наиболее успешной на этот день я и поведу речь — прошу простить меня за такое длинное, но, на мой взгляд, необходимое вступление.

    Итак, Harbour. Проект стартовал в 1999 году, официальный сайт — www.harbour-project.org. Текущая версия — 3.0 (stable), 3.2 (development).

    Как и Clipper, Harbour транслирует исходный текст программы в байт-код, но, в отличие от своего предшественника, компилятор Harbour создает не объектные, а с файлы, которые потом надо «скормить» С компилятору. Например, вот такую простейшую функцию, выводящую приветствие на консоль:

    Function Hello
       ? "Hello"
       Return Nil
    


    он транслирует в (комментарии — мои):

    // HB_FUNC определено как:
    // #define HB_FUNC( funcname )        HB_EXTERN_C_ HB_EXPORT HARBOUR HB_FUN_##funcname ( void )
    
    HB_FUNC( HELLO )
    {
       // байт-код
       static const HB_BYTE pcode[] =
       {
          36,2,0,176,2,0,106,6,72,101,108,108,111,0,
          20,1,36,3,0,100,110,7
       };
       // Вызов виртуальной машины (далее - ВМ) для выполнения байт-кода
       hb_vmExecute( pcode, symbols );
    }
    


    Рассмотрим байт-код подробнее:

       static const HB_BYTE pcode[] =
       {
          36,2,0,                          // 36 - код, за которым следует номер строки 
                                           // исходного текста, в данном случае - 2
          176,2,0,                         // 176 - помещает символ на стек ВМ, имеется 
                                           // ввиду символ, представляющий функцию вывода
          106,6,'H','e','l','l','o','\0',  // 106 - помещает строку на стек ВМ
          20,1,                            // 20 - ВМ должна выполнить функцию и отбросить 
                                           // ее результат, 1 - количество параметров
          36,3,0,                          // 36 - код, за которым следует номер строки 
                                           // исходного текста, в данном случае - 3
          100,                             // 100 - помещает Nil на стек ВМ
          110,                             // 110 - ВМ должна вернуть значение с вершины стека
          7                                // 7 - ВМ должна завершить работу
       };
    


    Ваш проект может включать исходники на Harbour (*.prg), на C, специальные объектные файлы и библиотеки. С код может быть встроен и в prg-файл, его надо заключить в #pragma BEGINDUMP#pragma ENDDUMP и, естественно, он должен соответствовать соглашениям EXTEND SYSTEM (я упоминал о ней, когда говорил о Clipper). Ниже — пример такого симбиоза:

    Function Main
       ? Sinus( 30 ), Sinus( 60 )
       ?
    
       Return Nil
    
    #pragma BEGINDUMP
    #include <math.h>
    #include "hbapi.h"
    #include "hbapiitm.h"
    
    #define PI 3.14159265
    // Вычисляем синус угла, заданного в градусах
    
    HB_FUNC( SINUS )
    {
       // hb_parnd( n ) - функция EXTEND SYSTEM, принимает n-й переданный параметр
       //    как double из Harbour функции
       // hb_retnd( d ) - функция EXTEND SYSTEM, возвращает double значение d
       //    обратно в Harbour функцию
    
       hb_retnd( sin( hb_parnd( 1 ) * PI / 180 ) );
    }
    #pragma ENDDUMP
    


    Я не случайно уделил столько внимания С в Harbour. Расширенная ( извините за невольную тавтологию ), по сравнению с Clipper, Extend System и Item API, предоставляющая доступ из С кода к внутренним структурам Harbour, его переменным, массивам, объектам позволяют говорить о симбиозе двух языков, я считаю это одной из важнейших особенностей Harbour. Благодаря этому Harbour уже «оброс» большим количеством модулей — оболочек к разнообразным продуктам, имеющим C API и список таких модулей, как open source, так и коммерческих, постоянно растет (в настоящее время подумываю об OpenCV). Конечно же, С используется в Harbour не только для создания оболочек к готовым продуктам, но и для самостоятельных разработок — новые RDD, GUI библиотеки и др. Иногда, в контексте некоторых приложений я рассматриваю Harbour как оболочку к С коду — для облегчения реализации пользовательского интерфейса, доступа к БД и пр.

    Встроенный доступ к БД, эта родовая черта xBase, — еще одна тема, которой хочется уделить особое внимание. Это, действительно, очень удобно — иметь возможность, не используя внешние СУБД, с помощью только встроенных языковых средств производить все необходимые манипуляции с базами данных — создание, модификация, пополнение, редактирование, поиск. В случае, когда количество информации, хранящейся в БД, сравнительно невелико, использовать внешнюю СУБД представляется совершенно излишним, для таких приложений и MySQL выглядит монстром (а ведь некоторые даже MS SQL ставят) — xBase подход здесь выглядит наиболее адекватным решением. Впрочем, и для больших БД Harbour может применяться (и применяется) вполне успешно.

    Приведу небольшой фрагмент кода, демонстрирующий типичные конструкции доступа к данным — для тех, кто не сталкивался с xBase языками раньше. Конечно же, арсенал средств для работы с БД в Harbour гораздо богаче, чем использованный в этих нескольких строчках.

    Function Test
       Local aStru := { {"FAMILY","C",16,0}, {"IMYA","C",16,0}, {"OTCHES","C",16,0}, ;
          {"TELEFON","C",10,0} }
    
       // Создаем таблицу БД mytable с ФИО и номерами телефона
       dbCreate( "mytable", aStru )
    
       // Открываем mytable
       USE mytable
    
       // Создаем индексы по фамилии и по телефону
       INDEX ON FAMILY TAG FAMILY
       INDEX ON TELEFON TAG TELEFON
    
       // Добавляем записи
       APPEND BLANK
       REPLACE FAMILY WITH "Иванов", IMYA WITH "Игорь", OTCHES WITH "Константинович", ;
          TELEFON WITH "9101682020"
       ...
    
       // Ищем запись по номеру телефона, используя индекс
       ordSetFocus( "TELEFON" )
       IF dbSeek( "9101682020" )
          // Если запись найдена, изменяем номер
          REPLACE TELEFON WITH "9102875555"
       ENDIF
       ...
    
       Return Nil
    


    Средства доступа к БД не ограничиваются стандартными. Есть RDD, написанные для клиент-серверных СУБД, как основанных на DBF ( коммерческая Advantage Database Server от Sybase и open source LetoDb ), та и SQL. Есть модули, обеспечивающие доступ посредством ODBC и ADO, есть модули для MySQL, PostgreSQL, SQLite, использующие C API этих СУБД.

    В Harbour получили дальнейшее развитие все особенности Clipper, сделавшие его языком высокого уровня, на котором удобно программировать — автоматическое выделение и освобождение памяти, сборщик мусора, так называемые raw arrays, возможность компилировать и исполнять в run-time, в динамике фрагменты кода. Добавлена полноценная реализация ООП. Препроцессор, сохранив всю мощь Clipper'овского, расширен за счет некоторых конструкций, взятых из С. Впрочем, не буду перечислять здесь все новшества, а просто сошлюсь на раздел моего сайта Harbour для начинающих.

    Да, я, кажется, забыл сказать, что Harbour — кроссплатформенная система с открытыми исходниками. Он существует на 32- и 64-разрядных платформах, на Windows, Linux, Unix, Mac OS X, QNX, OS/2, вроде бы и на Android, и еще на чем-то, чего я не видел.

    Буду рад, если эта статья вызовет интерес. В этом случае можно будет рассмотреть какие-то аспекты более подробно.
    Метки:
    Поделиться публикацией
    Комментарии 4
    • 0
      Спасибо за экскурс в историю. Clipper был первым языком за программы на котором я начал получать деньги. Писали, емнип, на Clipper 5.1 или на Summer 87.

      Одной из интересных особенностей Clipper был итерактивный интерфейс ввода GET. Можно было указать координаты полей ввода на экране (в текстовом режиме) и получить что-то похожее на современную форму в GUI-приложениях.
      • 0
        Да, GET-система — мощный механизм, позволяет сделать очень многое. Кстати, в GUI-оболочках Harbour он тоже реализован.
      • 0
        Вот эти товарищи харбор во всю используют www.bestnet.ru/

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

      Интересные публикации