Перевод утилиты DBU (от Clipper версии 5.2e) под Xbase++
Одно из приложений, чей исходный код знают все разработчики Clipper – это утилита баз данных Clipper DBU.EXE. Давайте попробуем перевести эту программу под Xbase++ и выявить все проблемы, которые мы испытаем. Вы встретитесь с подобными проблемами и с вашим кодом Clipper. Одно замечание, прежде чем мы начнем: мы используем код DBU от Clipper версии 5.2e.
Создайте новую директорию \XPPDBU и скопируйте оригинальные файлы PRG Clipper из директории Clipper \SOURCE\DBU в новую директорию.
Создайте файл проекта для DBU.EXE, набрав в сеансе DOS команду:
[C:\XPPDBU]dir *.prg /b > dbu.lst
Таким образом, в файле DBU.LST будут перечислены все файлы PRG для проекта DBU. Теперь позвольте ProjectBuilder создать файл PROJECT.XPJ. Это процесс из двух шагов:
[C:\XPPDBU]pbuild @dbu.lst
[C:\XPPDBU]pbuild -g
Просмотрите PROJECT.XPJ (вам не нужно менять его), и наберите PBUILD в сеансе DOS. ProjectBuilder, затем попытается создать DBU.EXE, но не сможет этого, и рано или поздно прервется сообщением об ошибке.
Невозможно точно сказать, когда ProjectBuilder выдаст ошибку на вашем компьютере, так как неизвестно какая у вас версия DBU.EXE (исходный код DBU менялся с каждой версией от Summer 87 до 5.2e). Поэтому мы перечислим ниже только изменения, которые были сделаны для версии 5.2e. Некоторые из них верны для всех версий DBU, или же, соответственно, программ Clipper.
DBU.PRG
ПереименуйтеPROCEDURE Dbu вPROCEDURE Main. Начальный цикл для всех программ Xbase++ должен называться Main.
DBUEDIT.PRG
Исправьте ошибку, которая не учитывается Clipper, но не Xbase++:
if ( "->" $ cEditField )
cAlias := Substr(cEditField, 1, At("->", cEditField) + 1)
Этот плюс должен быть минусом ^
Внимание: Некоторые из наших клиентов обнаружили ошибки в их коде Clipper после того, как они откомпилировали его с помощью Xbase++. Программы отлично работали все эти годы. Эта ошибка, наконец, нашлась, так как компилятор Xbase++ более строгий, чем компилятор Clipper.
Измените один вызов Inkey() на Inkey(0.1):
Было: WHILE (( keystroke := INKEY()) == 0 )
Стало: WHILE (( keystroke := INKEY(0.1)) == 0 )
Цикл DO WHILE постоянно запускается в коде Clipper до тех пор, пока не будет нажата клавиша. Это приводит к нежелательному результату в Xbase++, как результат мультипоточной архитектуры программ Xbase++: каждая программа Xbase++ запускается в нескольких потоках, которые вы не замечаете, и о которых вы не должны заботиться. Например, сборщик мусора запускается в одном потоке, или экран обновляется в другом потоке. Как уже было сказано ранее, вы не должны об этом беспокоиться. Но если поток, который запускает вашу программу, постоянно спрашивает, не было ли ввода с клавиатуры, операционная система придает ему приоритет в доступе к процессору, и остальным потокам достается меньше доступа. Это опять приводит к тому, что экран обновляется медленнее, чем возможно, и у вас создается впечатление, что сама программа медлительна. Поэтому, вам следует внимательно поискать циклы DO WHILE, которые проверяют на Inkey()==0. В таком случае, вам следует дать операционной системе 1/10 секунды времени для обслуживания других потоков.
DBUVIEW.PRG
Объявление LOCAL переменных должно произойти в Xbase++ перед тем, как строка PARAMETERS появляется в коде. Поищите объявление local saveColor и поместите их перед строкой PARAMETERS.
Измените код в FUNCTION bar_menu таким образом, чтобы он отражал немного другое действие функции Xbase++ Achoice(). Achoice() Clipper, в отличие от Xbase++, не показывает элементы массива, которые содержат нулевые строки:
FUNCTION bar_menu
——————————
Было: local saveColor
Должно быть: local saveColor, nElem
————————————————
Было:
IF M->num_d < LEN(M->array)
num_d = M->num_d + 1
array[M->num_d] = " "
ENDIF
Должно быть:
nElem := LEN(M->array)
IF M->num_d < nElem
num_d = M->num_d + 1
array[M->num_d] = " "
ASize( m->array, M->num_d )
ENDIF
———————————————
Было:
IF array[M->num_d] == " "
array[M->num_d] = ""
ENDIF
Должно быть:
IF array[M->num_d] == " "
ASize( M->array, nElem )
AFill( M->array, "", M->num_d )
ENDIF
DBUUTIL.PRG
В этом файле LOCAL переменные опять объявляются после строки PARAMETERS. Это невозможно в Xbase++. Объявление LOCAL должно находиться перед PARAMETERS. Измените строчку, в которой определены отношения между базами данных:
Было: SETRELATIONADDITIVETO&kINTO&t
Должно быть: DbSetRelation( t, &( "{||"+ k+"}" ), k)
Это изменение необходимо, так как Xbase++ создает блоки кода в соответствие с принципом late binding. Не существует early binding, как это иногда делал Clipper. Единственный способ создать early binding в Xbase++ - это скомпилировать строчное выражение, с помощью оператора макроса, в блок кода.
Перед строкой ~ 1411
menu_sel = achoice(3, M->ml, M->mb, M->mr, &a._m, &a._b, "mu_func",;
menu_deflt[M->menu_func], menu_deflt[M->menu_func] - 1)
добавим строку: CLEAR TYPEAHEAD.
DBUCOPY.PRG
В этом файле объявления LOCAL появляются после строки PARAMETERS. Из-за этого компилятор Xbase++ создает сообщения об ошибках. Перенесите объявления LOCAL перед объявлением PARAMETERS.
Когда это сделано, вы можете снова запустить ProjectBuilder для создания DBU.EXE. Запустите программу, она выглядит как исходное приложение Clipper, но это настоящая 32-разрядная программа, и она использует очень мало ресурсов процессора.
Резюме
Нам пришлось применить изменения в исходном коде программы DBU.EXE для того, чтобы позволить программе запускаться и под Clipper и под Xbase++ одновременно. Вы столкнетесь с подобными проблемами, когда будете переносить ваш код Clipper под Xbase++. Мы знаем об этих проблемах, и наша техническая поддержка будет доступна, когда вы столкнетесь с ними.
Различия между Xbase++ и Clipper оправданы. Это, в основном, результат различий между 16-разрядными и 32-разрядными операционными системами. Когда разработчики Xbase++ должны были решать, должен ли Xbase++ вести себя как Clipper’87 или 5.01, 5.2a или 5.2e, они выбрали наиболее совместимое поведение. Когда они представили новые 32-разрядные концепции в язык Clipper, они отказались от 16-разрядных концепций, которые бы противоречили новому подходу. Они верят в будущее языка Clipper, и убеждены, что этот язык будет существовать в 64-разрядном мире (по крайней мере, они создали свой компилятор таким образом, что он может создавать 64-разрядный код). Разработчики Xbase++ подготовились к будущему, и приглашают вас в путь к 64-разрядному миру, так как разговор идет на одном языке: на языке Clipper.
-