Поддерживаемые платформы и интерфейсы с библиотеками C


1. Введение

Rapid Deployment Software в настоящее время поддерживает версии Euphoria для четырёх различных операционных платформ. Состав платформ планируется расширять.

Первая платформа называется DOS32, так как она связана и с операционной системой DOS, и обязательно с процессорами, работающими в 32-разрядном (защищённом) режиме. Это процессоры, как минимум, модели 386 SX и более мощные.

Вторая платформа называется WIN32, так как она связана с операционной системой (ОС) Microsoft Windows, конкретно, с 32-разрядными версиями Windows, к которым относятся Windows 95/98/ME, а также NT/2000/XP и более новые ОС.

Третьей платформой является Linux. Linux относится к серии операционных систем типа UNIX. Эта система стала очень популярной на персональных компьютерах. Имеется множество дистрибутивов Linux, включая Red Hat, Debian, Caldera и т.д. Системы серии Linux распространяются на CD по очень невысокой цене и в сети Интернет. Linux принадлежит к операционным системам с открытым исходным кодом.

Четвёртая платформа - FreeBSD. FreeBSD также относится к системам UNIX. Она очень популярна на серверах Интернет и также имеет открытый исходный код.

Пользователи, которые когда-то приобрели исходный код Euphoria, перенесли Euphoria и на другие платформы, такие как HP Unix и Sun Unix.

Установочный файл Euphoria для DOS32+WIN32 содержит два упакованных .exe-файла. Первый называется ex.exe. Это интерпретатор, исполняющий программы Euphoria на платформе DOS32. Второй интерпретатор называется exw.exe. Он исполняет программы Euphoria на платформе WIN32. Программы Euphoria, предназначенные для исполнения на платформе WIN32, имеют тип файла .exw, а тип файла .ex указывает, что программа предназначена для исполнения на платформе DOS32.

Пакет Euphoria для Linux, файл типа .tar, содержит только один интерпретатор, exu. Он исполняет программы Euphoria на платформе Linux. Программы Euphoria, предназначенные для Linux или FreeBSD, имеют тип файла .exu.

Версия Euphoria для FreeBSD устанавливается сначала как версия для Linux, а затем интерпретатор exu Linux заменяется версией exu для FreeBSD.

Многие программы Euphoria могут исполняться без изменений на двух, трёх или даже на всех четырёх платформах. В этих случаях тип файла программы указывает на предпочтительную платформу для исполнения программы. Любой интерпретатор Euphoria может попытаться исполнить любой файл Euphoria, но тогда нужно задать полное имя файла, включая тип, так как каждый интерпретатор автоматически ищет только предпочтительный тип файла, (.ex, .exw или .exu).

Иногда вы можете обнаружить, что ваш код, в основновном, будет одинаковым для всех платформ, но небольшие участки кода должны быть написаны индивидуально под каждую платформу. Используйте встроенную функцию platform(), чтобы выделить эти участки кода, как специфические для данной платформы. Имейте в виду, что функция platform() выдаёт одну и ту же величину (3) и для Linux, и для FreeBSD, так как эти системы весьма похожи.


2. Платформа DOS32

Если вы новичок в программировании, вам сначала может больше подойти работа с ex.exe на платформе DOS32. Вам нужно попытаться понять существо ядра Euphoria, прежде чем вы перейдёте к программированию графического интерфейса Windows (GUI). Все версии Windows (даже XP), дают вам возможность открыть окно текстовой консоли с командной строкой и запустить программы DOS. (Прим.перев. Интерпретатор ex.exe неплохо работает и с эмулятором DosBox, который можно запустить под более новыми версиями Windows, а также под Linux, FreeBSD, KolibriOS и т.д.)

Программы Euphoria исполняются в 32-разрядном (защищённом) режиме и имеют доступ ко всей оперативной памяти, установленной на вашей машине. Многие языки программирования для DOS ограничивают вас 16-разрядным реальным режимом. Это ограничение делает невозможным доступ к памяти сверх 640K. Ваша машина может иметь 256Mb памяти, но ваша программа не должна выходить за пределы всего лишь 640K. QBasic даже ещё более ограничен. Его предел - только 160K.

Программы DOS32 могут выводить информацию на экран в текстовом режиме или в пиксельно-графическом режиме, и Euphoria обеспечивает вас библиотечными подпрограммами для обоих режимов. Необходимость прямого вызова встроенных функций DOS возникает довольно редко, но вы можете делать и это, используя подпрограмму dos_interrupt(). Вы можете здесь также напрямую оперировать с выделенными участками памяти, применяя подпрограммы peek() и poke() для реализации высокоскоростной графики и получения доступа к деталям системы.

Под DOS32 на Windows 95 и более новых системах, файлы Euphoria могут иметь длинные имена, а программы могут открывать файлы с длинными именами для чтения и записи, но не для создания нового файла.

Под чистой DOS, вне Windows, системный файл подкачки отсутствует, однако расширитель DOS, встроенный в интерпретатор ex.exe платформы DOS32, создаёт этот файл для возможного использования вашей программой. Этот файл создаётся во время старта вашей программы Euphoria под DOS и удаляется, когда программа завершается. Он возникает как пустой файл с нулевой длиной и растёт, только когда подкачка становится необходимой. Он создаётся в каталоге, заданном переменной окружения TEMP или TMP. Если ни одна из этих переменных не установлена, файл подкачки (своп-файл) создаётся в каталоге, содержащем или интерпретатор ex.exe, или ваш связанный .exe-файл Euphoria. Вы можете назначить своп-файлу выделенный каталог, задав переменную CAUSEWAY следующим образом:

        SET CAUSEWAY=SWAP:path

где   path   означает полный путь к этому выделенному каталогу. Вы можете также предотвратить создание своп-файла командой:
        SET CAUSEWAY=NOVM

Когда оперативная память в системе исчерпана и начинается подкачка данных из неё на диск в своп-файл, ваша программа продолжает работать, как и работала, но скорость её исполнения очень заметно снижается. Некоторое облегчение ситуации может принести освобождение расширенной памяти за счёт остановки программ типа SMARTDRV, которые обычно резервируют для своих целей большие объёмы расширенной памяти.

Если свободное пространство на вашем диске меньше, чем объём установленной на вашей машине оперативной памяти, своп-файл не создаётся.


3. Платформа WIN32

Euphoria для WIN32 (exw.exe) имеет очень много общего с Euphoria для DOS32. C WIN32 вам так же доступна вся оперативная память на вашей машине. Большинство библиотечных подпрограмм работает идентично на каждой платформе. Многие из существующих программ DOS32 для текстового режима могут быть запущены с использованием exw без каких-либо изменений. С помощью exw вы можете запускать программы из командной строки. При этом текст будет отображаться в стандартном окне DOS (обычно 25 строк x 80 колонок). Окно DOS в терминологии Windows называется консоль. Euphoria делает тривиальным переход от программирования под DOS32 в текстовом режиме к консольному программированию под WIN32. Позже вы сможете добавить вызовы функций C API WIN32 и, если захотите, создать реальные графические окна Windows с GUI.

Консольное окно создаётся автоматически, когда программа WIN32 Euphoria в первый раз выводит что-то на экран или читает что-то с клавиатуры. Вы также увидите консольное окно, когда читаете со стандартного входа или записываете на стандартный выход, даже когда они перенаправлены в файлы. Консоль исчезает, когда ваша программа заканчивается или через вызов подпрограммы free_console(). Если на консоли есть что-то, необходимое для чтения пользователем вашей программы, вам следует пригласить его и ждать от него ввода, прежде чем прервать программу. Чтобы предотвратить быстрое исчезновение консоли, можно воспользоваться следующей командой:

        if getc(0) then

        end if

которая будет ждать от пользователя какого-либо ввода.

Если вам не нужны при прогоне программы Euphoria новые открывающиеся консольные окна, запустите эту программу с интерпретатором exwc.exe. Он использует текущее консольное окно таким же манером, как и программа DOS под управлением ex.exe.

Под WIN32 длинные имена файлов полностью поддержаны при чтении, записи и создании файлов.


3.1 Высокоуровневое программирование под WIN32

Благодаря Дэвиду Куни, Дереку Парнеллу, Джудит Эванс и многим другим, мы имеем пакет под названием Win32Lib, который вы можете использовать для разработки приложений Windows GUI в Euphoria. Он замечательно прост в изучении и применении, хорошо документирован и включает множество небольших примеров программ. Вы можете получить Win32Lib и IDE Джудит на сайте Euphoria. Недавно Андреа Кини разработал похожий пакет, но значительно более компактный, который называется EuWinGUI. Он также доступен на нашем сайте.


3.2 Низкоуровневое программирование под WIN32

Для доступа к WIN32 на низком уровне Euphoria предлагает механизм вызова любой функции C в любом библиотечном .dll-файле WIN32 API, или, на самом деле, в любом 32-разрядном Windows .dll-файле, который может быть создан вами или кем-то другим. Имеется также механизм обратных вызовов, позволяющий Windows вызывать ваши подпрограммы Euphoria. Обратные вызовы необходимы при программировании графического пользовательского интефейса (GUI).

Чтобы дать полный ход на платформе WIN32, вам потребуется документация по 32-разрядному программированию Windows, а конкретно, по WIN32 Application Program Interface (API), включая структуры C, определённые в API (API - это программный интерфейс приложений ОС). Имеется большой файл WIN32.HLP, выпущенный Microsoft(С), который доступен с множеством инструментальных средств для Windows. Широко известны многочисленные книги по теме WIN32-программирования на C/C++. Вы можете адаптировать большинство сведений из этих книг к нуждам Euphoria-программирования в среде WIN32. Вот хорошая книга:

Programming Windows
Charles Petzold
Microsoft Press

Файл справки по WIN32 API Windows (8 Mb) может быть получен на сайте Borland:
        ftp://ftp.borland.com/pub/delphi/techpubs/delphi2/win32.zip

Посетите также страницу документации" Архива Euphoria на сайте RDS.


4. Платформы Linux и FreeBSD

Euphoria для Linux и Euphoria для FreeBSD имеют ряд особенностей, общих с Euphoria для DOS32, и ряд особенностей, общих с Euphoria для WIN32.

Так же, как под WIN32 и DOS32, вы можете выводить текст на консоль или в окне xterm в многоцветном режиме и в любой позиции по строкам и колонкам.

Именно так, как под WIN32, вы можете вызывать функции C в общих библиотеках, а код C может совершать обратные вызовы ваших подпрограмм Euphoria.

Euphoria для Linux и FreeBSD не имеет встроенной поддержки пиксельной графики в отличие от DOS32, но Пит Эберлейн написал интерфейс Euphoria с библиотекой svgalib.

Простое программирование GUI в системе X Windows доступно с использованием или интерфейса EuGTK Ирва Маллинса, подключающего библиотеку GTK GUI, или пакета wxEuphoria, разработанного Мэттом Левисом. Пакет wxEuphoria работает также под Windows.

Перенося код из среды DOS или Windows на Linux или FreeBSD, вы заметите следующие отличия платформ:

  • Некоторые номера, присвоенные 16 главным цветам в библиотеке graphics.e, будут другими. Но если вы воспользуетесь константами, определёнными в graphics.e, проблема не возникнет. Если же вы будете указывать номера цветов непосредственно, вы увидите, что красный и синий поменялись местами и т.п.

  • Коды специальных клавиш, таких как Home, End, клавиш со стрелками будут другими, плюс некоторые дополнительные отличия имеются под XTERM.

  • Клавиша Enter имеет код 10 (перевод строки) на Linux, тогда как под DOS/Windows она имеет код 13 (возврат каретки).

  • Linux и FreeBSD используют символ '/' (косая черта) в записи путей к файлам. DOS/Windows используют символ '\\' (обратная косая черта).

  • Специализированные подпрограммы, такие как dos_interrupt(), не работают на Linux или FreeBSD, что вполне очевидно.

  • Вызовы подпрограмм system() и system_exec() вместо команд DOS должны иметь другие аргументы, соответствующие командам Linux или FreeBSD. То есть, "DEL" становится "rm", а "MOVE" становится "mv".


5. Интерфейс с кодом C (WIN32, Linux, FreeBSD)

На WIN32, Linux и FreeBSD имеется возможность взаимодействия кода Euphoria с кодом C. Ваша программа Euphoria может вызывать функции C а также обращаться к переменным C. Функции C могут даже вызвать ваши подпрограммы Euphoria ("обратный вызов"). Код C должен находиться в динамически подключаемой библиотеке WIN32 (в .dll-файле) или в общей библиотеке Linux (FreeBSD) (в .so-файле). Взаимодействуя с .dll- и .so-файлами, вы получаете полный доступ к программному интерфейсу на системах, имеющих такую организацию.

Используя транслятор с Euphoria на C, вы можете перевести подпрограммы Euphoria на C, а затем откомпилировать их в .dll- или .so-файл. Вы можете подавать атомы и ряды Euphoria в эти откомпилированные подпрограммы Euphoria и получать в качестве результата данные Euphoria. Оттранслированные/компилированные подпрограммы исполняются значительно быстрее, чем интерпретируемые подпрограммы. Детали вопроса вы найдёте в документе Транслятор.


5.1 Вызов функций C

Чтобы вызвать функцию в .dll- или .so-файле, вы должны выполнить следующие действия:

1. Открыть .dll- или .so-файл, который содержит данную функцию, вызвав подрограмму open_dll(), которая определена в библиотеке euphoria\include\dll.e.
2. Определить функцию C, вызвав define_c_func() или define_c_proc() в dll.e. Тем самым вы сообщите Euphoria число и тип аргументов функции, а также тип выдаваемой величины.

Euphoria в настоящее время поддерживает все целые типы C и указатели в качестве аргументов и выдаваемых величин. Поддержаны также аргументы и выдаваемые величины с плавающей точкой (тип C double). В настоящее время пока нет возможности подавать структуры C по величине или принимать структуры в качестве результата функции, хотя вы можете подать указатель на структуру и получить указатель на структуру в качестве результата. Подача структур C по величине редко требуется для системных вызовов.

Euphoria также поддерживает все формы данных Euphoria - атомы и произвольно-сложные ряды, как аргументы для переведённых/компилированных подпрограмм Euphoria.

3. Вызвать функцию C через вызов подпрограмм c_func() или c_proc().

Пример:
include dll.e

atom user32
integer LoadIcon, icon

user32 = open_dll("user32.dll")

-- Имя функции в user32.dll - "LoadIconA".
-- Функция требует указатель и целое в качестве аргументов,
-- и выдаёт целое.
LoadIcon = define_c_func(user32, "LoadIconA",
                         {C_POINTER, C_INT}, C_INT)

icon = c_func(LoadIcon, {NULL, IDI_APPLICATION})

В документе library.doc - Вызов функций C вы найдёте описание подпрограмм c_func(), c_proc(), define_c_func(), define_c_proc(), open_dll() и т.д. В каталогах demo\win32 или demo\linux имеются примеры программ.

На платформе Windows имеется несколько правил по вызову функций C. Все функции API Windows используют правило __stdcall. Однако большинство компиляторов C по умолчанию придерживается правила __cdecl. Правило __cdecl позволяет иметь переменное число аргументов, подаваемых в функцию. По умочанию Euphoria подразумевает правило __stdcall, но если вам необходимо вызвать функцию C, которая требует __cdecl, вы можете добавить знак '+' перед именем функции в подпрограммах define_c_proc() и define_c_func(). В примере выше это выглядело бы как "+LoadIconA" вместо "LoadIconA".

Вы можете проверить .dll-файл, щёлкнув на нём правой кнопкой мыши и запустив "QuickView" (если это есть в вашей системе). Там вы увидите список всех функций C, которые данная .dll экспортирует.

Чтобы найти, какой .dll-файл содержит конкретную функцию C WIN32, запустите программу euphoria\demo\win32\dsearch.exw.


5.2 Доступ к переменным C

Вы можете получить адрес переменной C, воспользовавшись подпрограммой define_c_var(). А затем с помощью poke() и peek() прочитать или переписать значение этой переменной.


5.3 Доступ к структурам C

Многие функции C требуют подачи в них указателей на структуры. Вы можете моделировать структуры C, используя выделенные блоки памяти. Адрес, выдаваемый подпрограммой allocate(), может быть подан в функцию C так, как будто это и есть указатель C.

Вы можете читать и записывать элементы моделируемой вами структуры C, используя подпрограммы peek() и poke(), или peek4u(), peek4s(), и poke4(). Выделять пространство в памяти под структуры следует с помощью подпрограммы allocate(). Вы должны рассчитать смещения элементов структуры C. Это не слишком сложно сделать, так как всё в C, что требует 4-х байт, будет присвоено 4-м байтам в структуре. Таким образом, все эти C int, char, unsigned int, pointer и т.д. будут все занимать по 4 байта. Объявление структуры в C выглядит как-то так:

        // Внимание, впереди код C!

        struct example {
            int a;           // смещение  0
            char *b;         // смещение  4
            char c;          // смещение  8
            long d;          // смещение 12
        };

Чтобы выделить память для "struct example" в Euphoria, вам нужно написать:

        atom p

        p = allocate(16) -- размер "struct example"

Адрес, который вы получаете от функции allocate(), всегда кратен, по крайней мере, 4-м байтам. Это обстоятельство является полезным, так как структуры WIN32 начинаются на этих 4-х байтовых границах. Поля (элементы) внутри структуры C, которые имеют размер 4 байта или более, должны начинаться в памяти на этих границах. Но 2-х байтовые поля должны бы начинаться на 2-х байтовой границе. Чтобы обойти этот вопрос, вам придётся оставлять внутри структуры небольшие незаполненные промежутки. На практике упорядочивание большинства структур не доставляет лишних затруднений, так как 90% полей представляют 4-х байтовые указатели (пойнтеры) или 4-х байтовые целые.

Вы можете заполнить поля, например, так:

        poke4(p + 0, a)
        poke4(p + 4, b)
        poke4(p + 8, c)
        poke4(p +12, d)
А прочитать поля можно так:
        d = peek4(p+12)
Совет:
Для более удобного чтения программы определите константы, соответствующие смещениям полей. Ниже приведен пример кода.

Пример:
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)

-- подаёт rect как указатель на структуру C
-- hWnd является "ручкой" для окна
if not c_func(InvalidateRect, {hWnd, rect, 1}) then

    puts(2, "InvalidateRect failed\n")

end if

Код Euphoria, предоставляющий доступ к функциям и структурам данных C, может показаться довольно уродливым, но обычно он занимает совсем небольшую долю вашей программы, особенно, если вы используете Win32Lib, EuWinGUI, или библиотеку X Windows Ирва Маллинса. Основной массив кода вашей программы будет написан на понятном языке чистой Euphoria, что даёт вам значительное преимущество по сравнению с программированием на C.


5.4 Обратные вызовы ваших подпрограмм Euphoria

Когда вы создаёте окно, операционной системе Windows будет необходим вызов подпрограммы Euphoria. Это довольно странная концепция в глазах программистов DOS, которые привыкли к вызовам функций операционной системы из своих программ, но никогда не сталкивались с ситуацией, чтобы операционная система вызывала их собственную подпрограмму. Чтобы привести эту концепцию в действие, вы должны получить 32-х разрядный "обратный" адрес вашей подпрограммы и передать его Windows. Например (взято из demo\win32\window.exw):

        integer id
        atom WndProcAddress

        id = routine_id("WndProc") 

        WndProcAddress = call_back(id)
Здесь функция routine_id() уникальным образом идентифицирует подпрограмму Euphoria, присваивая ей по её имени номер в виде небольшой целочисленной величины. Этот номер может быть использован позже для вызова данной подпрограммы. И вы можете также использовать его как аргумент функции call_back(), выдающей адрес обратного вызова.

В примере выше 32-х разрядный адрес обратного вызова, WndProcAddress, может быть помещён в структуру C и подан в Windows через функцию C API RegisterClass(). Это даёт Windows возможность вызова подпрограммы Euphoria, WndProc(), всякий раз, когда пользователь производит какое-то действие с определённым классом окна. Эти действия включают нажатия на кнопки мыши, печать на клавиатуре, изменение размеров окна и т.п. Просмотрите файл демо-программы window.exw, чтобы узнать всю эту историю до конца.

Примечание:
Вы можете получить адрес обратного вызова не для любой подпрограммы Euphoria, а только когда она отвечает следующим условиям:
  • подпрограмма должна быть функцией, но не процедурой;
  • она должна иметь от 0 до 9 параметров (аргументов);
  • все параметры должны быть типа atom (или integer и т.п.), но не типа ряд;
  • выдаваемая величина должна быть целочисленной, размером до 32-х разрядов.
Вы можете создать столько адресов обратного вызова, сколько вам необходимо, но не вызывайте функцию call_back() для одной и той же функции Euphoria много раз - каждый адрес обратного вызова, который вы создаёте, требует некоторого небольшого блока памяти.

Величины, которые подаются в эту вашу функцию Euphoria из операционной системы, могут быть любыми 32-х разрядными беззнаковыми атомами (неотрицательными). Ваша функция может трактовать большие положительные числа как отрицательные, если это желательно. Например, если функция C пытается подать вам -1, это может выглядеть как hex FFFFFFFF. Если подаваемая величина не соответствует типу, который вы назначили для данного параметра, может возникнуть ошибка проверки типов, которую выполняет Euphoria (в зависимости от опции with/without type_check и т.д.). Ошибка не случится, если вы объявите все параметры как atom.

Обычно, как в случае с WndProc() в примере, приведенном выше, обратные вызовы ваших функций инициируются Windows. Имеется также возможность вызова любой функцией C в любой библиотеке .dll одной из ваших функций Euphoria. Вам нужно лишь правильно объявить функцию C и послать ей адрес обратного вызова.

Вот пример функции WATCOM C, которая берёт ваш адрес обратного вызова как единственный свой параметр, а затем вызывает вашу функцию Euphoria, имеющую три параметра:

        /* Функция C с одним параметром, которую вы вызываете из Euphoria */
        unsigned EXPORT APIENTRY test1(
                 LRESULT CALLBACK (*eu_callback)(unsigned a,
                                                 unsigned b,
                                                 unsigned c))
        {
            /* Ваша функция Euphoria с тремя параметрами, она вызывается здесь
               через указатель (pointer) eu_callback */
            return (*eu_callback)(111, 222, 333); 
        }
Объявление C задаёт функцию test1 как внешне-доступную функцию C, которая принимает единственный параметр. Этот единственный параметр является указателем на функцию, которая принимает три беззнаковых параметра - то есть, вашу функцию Euphoria.

В WATCOM C, "CALLBACK" - это то же самое, что и "__stdcall". Это правило по вызовам, используемое для обращения к функциям WIN32 API, и указатель C на вашу функцию Euphoria тоже должен быть объявлен по этому правилу, иначе вы будете получать ошибку, когда ваша функция Euphoria пытается вернуться в вашу .DLL.

Если вам нужно, чтобы ваша функция Euphoria вызывалась по правилу __cdecl, вы должны кодировать вызов call_back() следующим образом:

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

Знак плюс и фигурные скобки указывают на правило __cdecl (подаётся ряд). Иначе, без скобок (подаётся атом), будет действовать правило __stdcall.

В примере, приведенном выше, функция Euphoria принимает три величины: 111, 222 и 333 как аргументы. Эта функция выдаёт некоторую величину в test1. Эта некоторая величина затем будет немедленно выдана в функцию, вызвавшую test1 (которая может быть в другом участке вашей программы Euphoria).

Адрес обратного вызова может быть подан в функцию signal() систем Linux или FreeBSD, чтобы специфицировать функцию Euphoria, обрабатывающую различные сигналы (например, SIGTERM). Он также может быть подан в функции C, подобные qsort(), чтобы определить специфическое правило сравнения Euphoria.