Система расширения
Практически 90% функциональных возможностей CLIP, сделаны на базе его
системы расширения.
Система расширения представляет собой набор функций для получения
параметров при вызове, возврат данных, генерация ошибок, некоторые
функции для обработки массивов, объектов и других типов в
представлении на языке С/С++.
Например простейшая функция будет представляться в С-сырце примерно так:
#include "clip.h"
#include "error.ch" // ну еще тут надо stdlib, stdio, .....
int
clip_SUBSTR(ClipMachine * mp)
// Название подключаемой функции должно начинаться с "clip_" и далее
// название CLIPPER-функции в верхнем регистре.
// такие имена clip-компилятор помещает в специальный список доступных
// в run-time функций.
// mp - это описание текущего состояния clip-машины, лучше смотрите ее структуру
// непосредственно в clip.h
// Если эта функция возвращает 0 - то ошибок не произошло, если
// не 0 - то это будет код ошибки.
{
int l;
char *ret;
char *str = _clip_parcl(mp, 1, &l);
// получаем первый параметр в виде строки с конкретной длиной.
int from = _clip_parni(mp, 2);
int kol = _clip_parni(mp, 3);
// получаем второй и третий параметр в виде числа с автоматическим преобразованием
// в int - тип.
// если передаваемые параметры были не того типа - в качестве С-значений
// будет получено NULL
if (str == NULL)
{
_clip_retc(mp, "");
return _clip_trap_err(mp, EG_ARG, 0, 0, __FILE__, __LINE__, "SUBSTR");
// проверка полученной строки и генерация ошибки в случае неправильно
// переданного параметра
}
// собственно алгоритм обработки
// на него можно не обращать внимания
if (kol <= 0)
kol = 0;
if (from <= 0)
{
from = l+from;
if (from<0) from=0;
}
else
from--;
if (_clip_parinfo(mp, 0) < 3)
kol = l - from;
if ((kol + from) > l)
kol = l - from;
if (kol < 0)
kol = 0;
ret = malloc(kol + 1);
memcpy(ret, str + from, kol);
ret[kol] = 0;
_clip_retcn_m(mp, ret, kol);
// возврат значения в clip-машину в виде строки (с выделенной областью памяти)
// с указанной длиной (потому что в clipper-строках могут быть нулевые
// байты!).
// если ничего не вернуть посредством _clip_.... , то в clip-машину вернется NIL
return 0;
// сообщение clip-машине что функция завершилась без ошибок
}
Ну а теперь собственно коротко о тех функциях расширения, которыми надо
пользоваться при написании новых возможностей для clip.
Для тех, кто легко читает и пишет на Си - лучше загляните в файл clip.h.
Функции получения передаваемых параметров
int _clip_parinfo(ClipMachine * mp, int num)
Если num==0 - выдает количество параметров, если не 0 - выдает
тип переданного параметра с номером num.
int _clip_parni(ClipMachine * mp, int num)
Возвращает значение параметра с номером num преобразованное к типу int
long _clip_parnl(ClipMachine * mp, int num)
Возвращает значение параметра с номером num преобразованное к типу long
double _clip_parnd(ClipMachine * mp, int num)
Возвращает значение параметра с номером num преобразованное к типу double
int _clip_parp(ClipMachine * mp, int num, int *len, int *dec)
Заполняет информацию о параметре с номером num - длину и точность представления
char *_clip_parc(ClipMachine * mp, int num)
Возвращает значение параметра с номером num как строку без длины
char *_clip_parcl(ClipMachine * mp, int num, int *len)
Возвращает значение параметра с номером num как строку с длиной (в clipper-строках
могут быть нулевые байты!)
int _clip_parl(ClipMachine * mp, int num)
Возвращает логическое значение параметра с номером num в виде 0/1
ClipVar *_clip_par(ClipMachine * mp, int num)
Думаю, это и так понятно, а кому не понятно лучше не трогать.
long _clip_pardj(ClipMachine * mp, int num)
Возвращает значение параметра с номером num, как дату преобразованную в julian - представление
long _clip_pardc(ClipMachine * mp, int num, int *yy, int *mm, int *dd, int *ww)
Возвращает значение параметра с номером num как дату представленную в виде year,month,day, millenium
Функции возврата данных в clip-машину
void _clip_retni(ClipMachine * mp, int n)
Вернуть число, преобразовав его из int.
void _clip_retnl(ClipMachine * mp, long n)
Вернуть число, преобразовав его из long.
void _clip_retnd(ClipMachine * mp, double n)
Вернуть число, преобразовав его из double.
void _clip_retndp(ClipMachine * mp, double n, int len, int dec)
Вернуть число, преобразовав его из double в формате с длиной len и точностью dec.
void _clip_retc(ClipMachine * mp, char *str)
Вернуть строку, предварительно скопировав данные из str.
Str должна быть освобождена без участия clip-машины!
void _clip_retcn(ClipMachine * mp, char *str, int len)
Вернуть строку c длиной len, предварительно скопировав данные из str.
Str должна быть освобождена без участия clip-машины!
void _clip_retcn_m(ClipMachine * mp, char *str, int len)
Вернуть строку c длиной len, без копирования данных из str.
Str будет освобождена clip-машиной когда эта строка не будет больше
использоваться (когда кол-во ссылок на эту строку станет равно 0).
void _clip_retl(ClipMachine * mp, int l)
Вернуть логическое значение.
void _clip_retdj(ClipMachine * mp, long julian)
Вернуть дату, преобразовав из формата julian.
void _clip_retdc(ClipMachine * mp, int yy, int mm, int dd)
Вернуть дату, преобразовав из формата year, month, day.
void _clip_retnr(ClipMachine * mp, struct rational *r, int len, int dec)
Вернуть рациональное число в формате с длиной len и точностью dec.
Функции вычисления hash-кодов
hash-коды используются в clip-машине на каждом углу, так что частенько
их приходиться вычислять.
Описывать особенно их собственно и нечего - и так понятно по параметрам.
long _clip_hashstr(const char *x)
long _clip_casehashstr(const char *x)
long _clip_hashbytes(long seed, const char *bytes, int len)
long _clip_casehashbytes(long seed, const char *bytes, int len)
long _clip_hash(ClipMachine * mp, ClipVar * vp)
long _clip_casehash(ClipMachine * mp, ClipVar * vp)
Функции генерации run-time ошибок
Для более полного понимания сущности "ошибка" читайте о классе error и тогда
все эти функции вам станут понятными.
void _clip_trap(ClipMachine * mp, const char *filename, int line)
void _clip_trap_str(ClipMachine * mp, const char *filename, int line, const char *str)
void _clip_trap_printf(ClipMachine * mp, const char *filename, int line, const char *fmt,...)
void _clip_trap_printv(ClipMachine * mp, const char *filename, int line, const char *fmt, void *vect)
void _clip_trap_var(ClipMachine * mp, const char *filename, int line, ClipVar * var)
void _clip_trap_pop(ClipMachine * mp)
void _clip_trap_invargv(ClipMachine * mp, const char *filename, int line)
int _clip_trap_err(ClipMachine * mp, int genCode, int canDefault, int canRetry,
const char *subSystem, int subCode,
const char *operation)
Функции управления статическими данными
Если появиться необходимость хранить какие-то статические данные
(например какой-нибудь свой set(_MY_SET_1,MY_DATA) ), то в clip-машине существует
небольшой набор функций для этого.
Внимание! Явно в языке Си объявлять конструкции типа "static my_type var_name"
категорически запрещено. Такие данные могут привести в конфликту между несколькими
clip-процессами!
void _clip_store_item(ClipMachine * mp, long hash, void *item)
Запомнить данные item под идентификатором hash (для его генерации лучше всего
использовать функции *_hash_*). Область памяти под item должна быть явно выделена!
void _clip_store_item_destroy(ClipMachine * mp, long hash, void *item, void (*destroy) (void *))
Установить функцию освобождения памяти для статических данных с идентификатором hash.
void _clip_free_item(ClipMachine * mp, long hash)
Освободить память для идентификатора hash.
void _clip_remove_item(ClipMachine * mp, long hash)
Вообще уничтожить всю информацию о hash.
void *_clip_fetch_item(ClipMachine * mp, long hash)
Возвращает указатель на область памяти с идентификатором hash.
Функции управления контейнерами
Контейнер - это еще одно средство для хранения статических данных.
Например, в clip-машину трудно вернуть какой-нибудь Си-указатель на структуру.
например:
FILE * fh
fh=open(filename,...)
Куда девать указатель "FILE * fh"?
А ведь в clipper-функции fopen() возвращаемое значение - простое число.
Или, например, структура открытого соединения с ORACLE,MYSQL и т.п.
Тоже ведь желательно внутри clip-программы лучше все-таки оперировать числом.
Вот именно для хранения таких структур и предназначен контейнер.
void *_clip_fetch_c_item( ClipMachine *cm, int key, int type )
int _clip_destroy_c_item( ClipMachine *cm, int key, int type )
int _clip_store_c_item( ClipMachine *cm, void *item, int type, void (*destroy)(void*) )
В данных функциях:
key - номер файла,соединения и т.п.
type - тип хранимой информации (это для того, чтобы случайно не подсунули
номер файла вместо номера соединения).
*destroy - функция уничтожения/закрытия хранимой структуры.
Другие возможности
Вышеперечисленными функциями C-API не ограничивается. Есть еще масса
функций по управлению массивами, объектами, вводом-выводом, вызовами
кодовых блоков и многое другое.
Но данная информация будет предоставляться только тем, кто имеет
соответствующую квалификацию, так как некорректное, бестактное и
неквалифицированное использование данных возможностей может привести к
грубым и непонятным "падениям" прикладных программ, утечке памяти,
и как результат - наезды на нас.
Кто захочет прикрутить что-то серьезное к clip - обращайтесь -
дадим и информацию и примеры, поможем в работе и освоению внутреннего
устройства clip-машины.
Создание динамически загружаемых модулей для clip.
В clip имеется функция load(), которая загружает динамические модули (*.so)
или байт-код (*.po) и библиотеки байт-кодов (*.pa).
Байт-код и so-модули легко получить из prg-файлов командами:
clip -p module.prg -> module.po
clip -s module.prg -> module.c -> module.so
А вот написать на Си такой же загружаемый модуль можно таким способом:
Создается module.prg и в нем описываются все необходимые пустые функции
function my_func1()
return
function my_func2()
return
затем этот модуль компилируется
clip -s module.prg
в результате получается Сишный текст в файле module.c.
Этот текст имеет заготовки для описанных функций my_func1,my_func2,....
Остается просто поменять тело функций по вышеописанным правилам для C-API
и получится so-модуль написанный на Си. Далее его останется только
скомпилировать Си-компилятором с ключиком -shared или аналогичным,
в зависимости от компилятора.
© Ю.Хныкин, uri@itk.ru, 2000