WhiteUnicorn |
| |
#WhiteUnicorn/ StartPage/ Programming/ Clipper+Asm > | |
|
Данный пример создавался как решение совершенно конкретной задачи, но может служить чем-то вроде шаблона для написания приложений на Clipper, в которых некоторые функции удобнее пишутся на Assembler.
Возможность подключить к Клиппер-программе Асм-модули (на уровне объектников) описана почти в любом руководстве Клиппер. Но _очень_ в общих чертах. И практически без живых примеров, которые можно было бы использовать в качестве шаблона. Попытки разобраться с этим всем налету осложняются тем, что большинство ошибочных действий подвешивают компьютер и приходится каждые пять минут перегружаться. (Если есть как минимум два компа, объединенных в сеть, то все становиться несколько проще ;)
Итак. Проблема возникла следующая. Есть БД на Клиппере. При регистрации клиентов они пишут свои фамилию/имя/отчество кто как - то маленькими буквами, то большими, то вообще со сменой регистра по-хакерски :) Это приводит к возникновению следующих проблем:
Короче, регулярно приходилось просто ручками все ФИО исправлять как положено.
Наконец руки дошли написать функцию, конвертирующую строку в правильный вид прямо при вводе. Чтобы в БД она добавлялась в человеческом виде.
И вот тут выяснилось несколько веселых вещей:
Когда размер кода для конвертилки начал не помещаться на один экран, а конца процесса было еще не видно, мне это надоело. На Ассемблере такие штуки пишуться на раз, причем это и выглядит совершенно естественно с точки зрения любой логики.
Собственно процесс поиска решения методом научного и не очень научного тыка к теме солюшена отношения особо не имеет, поэтому я его опускаю :)
(Комп остался жив :)
После решения основной задачи заодно уж были на Асме же переписаны все Клипперовские функции, чувствительные к языку (русский/английский 866CP)
Итак, в результате получился следующий набор:
Набор функций, конвертирующий переданную строку одним из трех способов:
char FirstUp (char szLine) // Конвертит строку в нижний регистр, первая буква заглавная char All2Upper (char szLine) // Конвертит строку в верхний регистр (аналог Upper(szLine)) char All2Lower (char szLine) // Конвертит строку в нижний регистр (аналог Lower(szLine))
Поскольку все функции пользуются одним и тем же типом и количеством :) входного параметра, то и используют они все фактически общий код (FirstUp), предварительно установив флаг признака вызванной функции
Собственно рабочие функции U2Lower и L2Upper живут в StrWFunc.asm
В этом модуле используются свои ds и es. После проверки исходных данных (количества и качества переданных параметров) строка затаскивается в наш сегмент данных, преобразуется нужным образом, после чего возвращается указатель на буфер с результирующей строкой.
Т.е. исходная строка не меняется. Если надо это сделать, то можно воспользоваться обычным присвоением:
szLine := FirsUp(szLine)
В функциях All2Upper и All2Lower происходит просто установка флажка, какая из трех функций модуля вызвана, а потОм мы уходим навсегда :) в FirsUp и там все делаем в зависимости от значения этого флажка.
Чтобы не плодить лишний код, All2Upper и All2Lower описываются, как void. (Возврат все равно идет через FirsUp)
И заодно в All2Upper сделана метка ErrorExit, позволяющая выйти из любой функции без возврата значения и без каких-либо лишних движений.
Ограничение: предельная длина обрабатываемой строки - 0ffh символов. Все лишние символы остануться в исходном состоянии (ну не умею я пока делать динамические буферы на Асме :)
Набор функций, конвертирующий переданную строку одним из трех способов:
void FirstUpR (char szLine) // Конвертит строку в нижний регистр, первая буква заглавная void All2UpperR (char szLine) // Конвертит строку в верхний регистр (аналог Upper(szLine)) void All2LowerR (char szLine) // Конвертит строку в нижний регистр (аналог Lower(szLine))
Отличие от предыдущих функций в том, что меняется исходная строка.
Соответственно принцип работы существенно отличается.
Все три функции точно так же пользуются телом FirstUpR для работы, а в своих рамках просто устанавливают флажок вызванной функции.
И точно также рабочие функции U2Lower и L2Upper живут в StrWFunc.asm
Но. Поскольку свои данные тут не нужны, то не нужны и свои ds,es.
Работа ведется напрямую со строкой-источником. Она же становиться строкой-приемником.
В конце функции там лежит измененное значение, поэтому возвращать ничего не нужно и мы просто выходим в Клипперную программу.
Т.е. использовать это можно прямо вот так:
FirstUp(szLine) // szLine теперь изменился
ErrorExit совпадает с обычным, но не восстанавливает ds и es (они должны сохраняться после того, как мы проверили исходные данные, и собираемся менять эти регистры)
Две рабочие функции для предыдущих модулей:
L2Upper // Конвертит строку в верхний регистр U2Lower // Конвертит строку в нижний регистр
Ессно, объявляем их здесь, как public, а в вызывющих файлах - как extrn
Чистый Асм, никаких извратов - просто проверяем соответствующие диапазоны символов и меняем нужные нужным образом.
Параметры передаются через регистры:
ds:[si] - Строка-источник es:[di] - Строка-приемник cx - Счетчик
Функция, проверяющая тип любого символа в строке.
int WhatIs (char szLine, int iNum)
Возвращаемые значения:
0 - error (чего-то не так вызывали)
1 - ни один из следующих
2 - цифра
3 - заглавная буква
4 - строчная буква
При отсутствии второго параметра (номер символа, начинаются с 1) проверяется первый символ.
Если заданный номер символа вылезает за пределы длины строки, то вернется код 0.
Заменяет собой четыре Клипперовские функции:
boolean IsDigit(char szLine) // первый символ цифра ? boolean IsAlpha(char szLine) // первый символ буква ? boolean IsLower(char szLine) // первый символ строчная буква ? boolean IsUpper(char szLine) // первый символ заглавная буква ?
Соответственно, вызовы будут соотноситься так:
if IsDigit(szLine) = .T. if WhatIs (szLine) = 2 if IsAlpha(szLine) = .T. if WhatIs (szLine) > 2 if IsLower(szLine) = .T. if WhatIs (szLine) = 4 if IsUpper(szLine) = .T. if WhatIs (szLine) = 3 Или можно еще вот так: if IsAlpha(szLine) = .F. .and. IsDigit(szLine) = .F. if WhatIs (szLine) = 1 if IsAlpha(szLine) = .T. .or. IsDigit(szLine) = .T. if WhatIs (szLine) > 1
Все. На этом Ассемблер заканчивается. :)
В Клипперной проге все эти функции вызываются самым обычным образом.
Для того, чтобы все это можно было проверить, сделан небольшой полигончик:
Main.prg - собственно проект,
и еще есть функция печати в файл Print.prg
Чтобы собрать вместе Асм и Клиппер файлы, просто компилим те и другие родными компайлерами в объектники, а потОм Клипперовским RTLink-ом собираем вместе, как обычную Клипперскую прогу.
Причем можно прямо в rmk-сценарии прописать masm для asm файлов и вообще забыть, что пишем мы на двух языках одновременно.
Файлы сценариев:
StrConv.lnk,
StrConv.rmk,
Make.bat
И два файла определений системы расширения Clipper+Asm:
Теоретически они должны быть в комплекте MAsm, но на всякий случай кладу здесь, мало ли.. У меня, например, они битые оказались, пришлось искать отдельно.
Они должны жить там, где компайлер ищет инклуд-файлы.
Sources:
StrCheck.asm - Character checker StrConv.asm - String converter StrConvR.asm - String converter (replacer) StrWFunc.asm - Working functions for StrConv & StrConvR Extasm.inc - Extend System definitions for assembly language Extenda.inc StrConv.lnk - Linker file StrConv.rmk - RTLink file Make.bat - Make file StrConv.zip - All (все вместе, включая это описание)
| |
#WhiteUnicorn/ StartPage/ Programming/ Clipper+Asm > | |
|
| ||
Anastasija aka WhiteUnicorn |
LiveJournal PhotoFile |
|
|