|
Система расширения
Практически 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 преобразованное к типу intlong _clip_parnl(ClipMachine * mp, int num)Возвращает значение параметра с номером num преобразованное к типу longdouble _clip_parnd(ClipMachine * mp, int num)Возвращает значение параметра с номером num преобразованное к типу doubleint _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/1ClipVar *_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 или аналогичным, в зависимости от компилятора. |