Особенности трех платформ Euphoria


1. Введение

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

Вторая платформа называется WIN32, чтобы подчеркнуть связь с операционной системой Microsoft Windows, точнее, с 32-битной версией Windows, которая относится к Windows 95, NT и более новым системам.

Третьей платформой является операционная система Linux. ОС Linux принадлежит к UNIX-подобным операционным системам. В последние несколько лет она становится очень популярной на PC. Linux для PC также является 32-битной системой.

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

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

Многие из программ Euphoria могут прогоняться на двух или всех трех платформах без всяких изменений. В этом случае тип файла обозначает предпочтительную платформу. Любой интерпретатор Euphoria будет пытаться исполнить любой файл Euphoria. Но вы должны задать полное имя файла, включая расширение.

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


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

Если вы начинающий программист, вы должны начать свои занятия, программируя для ex.exe на платформе DOS32, или, возможно, для exu на платформе Linux. Программирование для Windows всегда более сложное дело, не имеет значения, какой язык при этом вы будете использовать.

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

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

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

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

        SET CAUSEWAY=SWAP:путь
где   путь   включает в себя полный дисковый адрес заданного каталога, например, C:\ABC\EU\SWAP\. Вы можете запретить создание под DOS своп-файла командой DOS:
        SET CAUSEWAY=NOVM

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

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


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

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

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

        if getc(0) then
        end if
и она будет ждать, пока пользователь не нажмет на клавиатуре одну из клавиш.

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


3.1 Программирование высокого уровня для WIN32

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


3.2 Программирование низкого уровня для WIN32

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

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

Programming Windows
by Charles Petzold
Microsoft Press

Файл помощи WIN32 API Windows (8 Мб) может быть получен на Web-узле Borland :
        ftp://ftp.inprise.com/pub/delphi/techpubs/delphi2/win32.zip

Просмотрите также архивы Euphoria -- Архив файлов раздел - "Документация" .


4. Платформа Linux

Euphoria для Linux имеет некоторые общие возможности с Euphoria для DOS32, другие же некоторые возможности объединяют ее с Euphoria для WIN32.

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

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

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

Программирование GUI для X Windows в настоящее время возможно с использованием разработанного Ирвом Маллинсом интерфейса с пакетом graphapp.

Используя код DOS или Windows для Linux, вы должны учитывать следующие отличия:

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

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

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

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

  • Такие высокоспециализированные вещи как dos_interrupt(), разумеется, не будут работать под Linux.

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


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

Под WIN32 и Linux имеется возможность взаимодействия кода Euphoria и кода, написанного на C. Ваша программа Euphoria может вызывать подпрограммы C, а также читать и переписывать значения переменных C. Подпрограммы C даже могут вызывать ваши подпрограммы Euphoria. Этот код C должен быть размещен в библиотеках динамического связывания WIN32 (.dll-файлы), или в общих библиотеках Linux (.so-файлы). Такое взаимодействие с файлами .dll и общими библиотеками дает вам доступ к интерфейсу программирования обеих этих систем.


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

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

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

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

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

Пример:
include dll.e

atom user32
integer LoadIcon, icon

user32 = open_dll("user32.dll")

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

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

Просмотрите libraryr.doc в части описаний подпрограмм c_func(), c_proc(), define_c_func(), define_c_proc(), open_dll() и т.д. Просмотрите demo\win32 или demo\linux с примерами программ.

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

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


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

Под Windows и Linux вы можете получить адрес переменной C, используя функцию define_c_var(). Затем по этому адресу вы можете выполнить poke() и peek(), чтобы получить доступ уже к величине переменной.


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

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

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


        // Внимание, впереди код C!
        struct example {
            int a;           // смещение  0
            char *b;         // смещение  4
            char c;          // смещение  8
            long d;          // смещение 12
        };

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

        atom p

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

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

Вы можете установить эти самые поля, набрав что-либо наподобие:

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

Пример:
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, VEL, или библиотекой Ирва Маллинса X Windows. Основные разделы вашей программы будут написаны на чистой Euphoria, которая имеет и дает вам большое преимущество над C.


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

Когда вы создаете окно, операционной системе Windows будет нужно вызвать вашу подпрограмму Euphoria. Это довольно непривычная ситуация для программистов DOS, которые используют вызовы функций операционной системы, но уж никак не ожидают, что операционная система будет пытаться вызвать их собственные функции. Чтобы сделать то, что требует Windows, вы должны получить 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 через API-функцию C RegisterClass(). Этот прием дает Windows способность вызвать подпрограмму Euphoria, WndProc(), на исполнение, когда пользователь выполняет действия в окне некоторого определенного класса. Эти действия включают щелчки кнопками мыши, нажатия на клавиши клавиатуры, изменение размеров окна и т.д. Просмотрите файл window.exw с демо-программой, чтобы прочитать продолжение всей этой истории.

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

Величины, которые подаются в вашу подпрограмму Euphoria, могут быть любыми 32-битными атомами без знака, т.е. не-отрицательными. Ваша процедура может трактовать большие положительные числа как отрицательные, если это необходимо. Например, если функция C пытается подать вам -1, это может быть представлено как шестнадцатиричное FFFFFFFF. Если подана величина, которая не помещается в тип, выбранный вами для данного параметра, может произойти ошибка проверки типов (в зависимости от действующего режима 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 подпрограмма с тремя параметрами вызвана
               здесь через указатель eu_callback */
            return (*eu_callback)(111, 222, 333); 
        }
Объявления C, которые вы видите выше, касаются функции test1 как вызываемой извне функции C, требующей подачи единственного пераметра. Этот единственный параметр является указателем на подпрограмму, которая в свою очередь требует уже трех параметров без знака, то есть, это ваша подпрограмма Euphoria.

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

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