Преобразование между значениями Lisp и модуля
Практически все модули должны обмениваться данными с программами Lisp, которые их вызывают: принимать аргументы функций модуля и возвращать значения из функций модуля. Для этой цели модуль API предоставляет тип emacs_value, который представляет объекты Emacs Lisp, передаваемые через API; он функционально эквивалентен типу Lisp_Object , используемому в Emacs C-примитивах (см. Написание Emacs-примитивов). В этом разделе описываются части модуля API, которые позволяют создавать объекты emacs_value , соответствующие основным типам данных Lisp, и как получить данные C из объектов emacs_value , соответствующих объектам Lisp.
Все описанные ниже функции на самом деле являются указателями на функции, предоставляемые через указатель на среду, который принимает каждая функция модуля. Поэтому код модуля должен вызывать эти функции через указатель на среду, как показано ниже:
emacs_env *env; /* the environment pointer */ env->some_function (arguments…);
Указатель emacs_env обычно поступает из первого аргумента функции модуля или из вызова get_environment , если вам нужна среда в функции инициализации модуля.
Большинство функций, описанных ниже, стали доступны в Emacs 25, первой версии Emacs, поддерживающей динамические модули. Для нескольких функций, ставших доступными в более поздних версиях Emacs, мы указываем первую версию Emacs, в которой они появились.
Следующие функции API извлекают значения различных типов данных C из объектов emacs_value . Все они поднимают условие ошибки wrong-type-argument (см. Предикаты типов), если аргумент emacs_value объект не имеет ожидаемого типом функции. Подробности о работе с ошибками в модулях Emacs и о том, как перехватывать условия ошибок внутри модуля, прежде чем они будут сообщены Emacs, см. в разделе Нелокальные модули. Функция API type_of (см. type_of) может использоваться для получения типа объекта emacs_value .
- Функция: intmax_t extract_integer (emacs_env *env, emacs_value arg)
Эта функция возвращает значение целого числа Lisp, указанного arg. Тип данных C возвращаемого значения,
intmax_t, является самым широким типом целочисленных данных, поддерживаемым компилятором C, обычноlong long. Если значение arg не помещается вintmax_t, функция сигнализирует об ошибке, используя символ ошибкиoverflow-error.
- Функция: bool extract_big_integer (emacs_env *env, emacs_value arg, int *sign, ptrdiff_t *count, emacs_limb_t *magnitude)
-
Эта функция, доступная начиная с Emacs 27, извлекает целое значение arg. Значение arg должно быть целым числом (fixnum или bignum). Если sign не
NULL, он сохраняет знак arg (-1, 0 или +1) в*sign. Величина сохраняется в magnitude следующим образом. Если count и magnitude оба неNULL, то magnitude должен указывать на массив длиной не менее*countunsigned longэлементов. Если magnitude достаточно велик для хранения величины arg, то функция записывает величину в массив magnitude в формате little-endian, сохраняет количество записанных элементов в*count, и возвращаетtrue. Если magnitude недостаточно велик, он сохраняет необходимый размер массива в*count, сигнализирует об ошибке и возвращаетfalse. Если count неNULLи magnitudeNULL, то функция сохраняет необходимый размер массива в*countи возвращаетtrue.Emacs гарантирует, что максимальное необходимое значение
*countникогда не превышаетmin (PTRDIFF_MAX, SIZE_MAX) / sizeof (emacs_limb_t), поэтому вы можете использоватьmalloc (*count * sizeof *magnitude)для выделения массиваmagnitudeбез опасений целочисленного переполнения при расчёте размера.
- Тип алиаса: emacs_limb_t
Это тип беззнакового целого числа, используемый в качестве типа элементов для массивов величин в функциях преобразования больших целых чисел. Тип гарантирует уникальные представления объектов, т.е. без битов заполнения.
- Макрос: EMACS_LIMB_MAX
Этот макрос расширяется до константного выражения, определяющего максимальное возможное значение для объекта
emacs_limb_t. Выражение подходит для использования в#if.
- Функция: double extract_float (emacs_env *env, emacs_value arg)
Эта функция возвращает значение Lisp-числа с плавающей запятой, указанное arg, как значение C
double.
- Функция: struct timespec extract_time (emacs_env *env, emacs_value arg)
-
Эта функция, доступная начиная с Emacs 27, интерпретирует arg как значение времени Emacs Lisp и возвращает соответствующее значение
struct timespec. См. Время суток.struct timespecпредставляет собой временную метку с наносекундной точностью. Она имеет следующие члены:time_t tv_secЦелочисленное значение секунд.
long tv_nsecДробная часть секунд как число наносекунд. Для временных меток, возвращаемых
extract_time, это всегда неотрицательное значение, меньшее одного миллиарда. (Хотя POSIX требует, чтобы типtv_nsecбылlong, типlong longна некоторых нестандартных платформах).
Если time имеет более высокую точность, чем наносекунды, функция усекает ее до наносекундной точности в сторону отрицательной бесконечности. Функция сигнализирует об ошибке, если time (усеченное до наносекунд) не может быть представлено
struct timespec. Например, еслиtime_tявляется 32-битным целочисленным типом, то значение time в десять миллиардов секунд вызовет ошибку, но значение time в 600 пикосекунд будет усечено до нуля.Если вам необходимо работать со значениями времени, не представимыми типом
struct timespec, или если вам нужна более высокая точность, вызовите функцию Lispencode-timeи работайте со значением, которое она возвращает. См. Преобразование времени.
- Функция: bool copy_string_contents (emacs_env *env, emacs_value arg, char *buf, ptrdiff_t *len)
-
Эта функция сохраняет текст Lisp-строки, заданной arg в кодировке UTF-8, в массив
char, указанный buf, который должен быть достаточно большим, чтобы содержать не менее*lenбайтов, включая завершающий нулевой байт. Аргумент len не должен быть указателемNULL, и, при вызове функции, он должен указывать на значение, определяющее размер buf в байтах.Если размер буфера, указанный
*len, достаточно велик для хранения текста строки, функция сохраняет в*lenфактическое количество скопированных байтов в buf, включая завершающий нулевой байт, и возвращаетtrue. Если буфер слишком мал, функция поднимает условие ошибкиargs-out-of-range, сохраняет необходимое количество байтов в*len, и возвращаетfalse. См. Нелокальные модули для обработки ожидаемых условий ошибки.Аргумент buf может быть указателем
NULL, в этом случае функция сохраняет в*lenколичество байтов, необходимых для хранения содержимого arg, и возвращаетtrue. Таким образом вы можете определить размер buf, необходимый для хранения конкретной строки: сначала вызовитеcopy_string_contentsсNULLкак buf, затем выделите достаточно памяти, чтобы сохранить количество байтов, сохранённых функцией в*len, и вызовите функцию снова с не-NULLbuf для фактического копирования текста.
- Функция: emacs_value vec_get (emacs_env *env, emacs_value vector, ptrdiff_t index)
Эта функция возвращает элемент массива vector по индексу index. Индекс первого элемента массива равен нулю. Функция поднимает условие ошибки
args-out-of-rangeесли значение index некорректно. Для извлечения данных C из возвращаемого значения используйте другие функции извлечения, подходящие для типа данных Lisp, хранящихся в этом элементе массива.
- Функция: ptrdiff_t vec_size (emacs_env *env, emacs_value vector)
Эта функция возвращает количество элементов в vector.
- Функция: void vec_set (emacs_env *env, emacs_value vector, ptrdiff_t index, emacs_value value)
Эта функция сохраняет value в элементе массива vector с индексом index. Она поднимает условие ошибки
args-out-of-rangeесли значение index некорректно.
Следующие функции API создают объекты emacs_value из основных типов данных C. Все они возвращают созданный объект emacs_value .
- Функция: emacs_value make_integer (emacs_env *env, intmax_t n)
Эта функция принимает целочисленный аргумент n и возвращает соответствующий объект
emacs_value. Она возвращает либо fixnum, либо bignum, в зависимости от того, находится ли значение n в пределах, установленныхmost-negative-fixnumиmost-positive-fixnum(см. Основы целых чисел).
- Функция: emacs_value make_big_integer (emacs_env *env, int sign, ptrdiff_t count, const emacs_limb_t *magnitude)
Эта функция, доступная начиная с Emacs 27, принимает целое число произвольной длины и возвращает соответствующий объект
emacs_value. Аргумент sign определяет знак возвращаемого значения. Если sign отличен от нуля, то magnitude должен указывать на массив, содержащий не менее count элементов, определяющих представление возвращаемого значения в формате little-endian.
В следующем примере используется библиотека GNU для работы с большими числами (GMP) для вычисления следующего вероятного простого числа после заданного целого числа. См. (gmp)Top для общего обзора GMP и (gmp)Integer Import and Export для преобразования массива magnitude в значения GMP mpz_t и обратно.
#include <emacs-module.h>
int plugin_is_GPL_compatible;
#include <assert.h>
#include <limits.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <gmp.h>
static void
memory_full (emacs_env *env)
{
static const char message[] = "Memory exhausted";
emacs_value data = env->make_string (env, message,
strlen (message));
env->non_local_exit_signal
(env, env->intern (env, "error"),
env->funcall (env, env->intern (env, "list"), 1, &data));
}
enum
{
order = -1, endian = 0, nails = 0,
limb_size = sizeof (emacs_limb_t),
max_nlimbs = ((SIZE_MAX < PTRDIFF_MAX ? SIZE_MAX : PTRDIFF_MAX)
/ limb_size)
};
static bool
extract_big_integer (emacs_env *env, emacs_value arg, mpz_t result)
{
ptrdiff_t nlimbs;
bool ok = env->extract_big_integer (env, arg, NULL, &nlimbs, NULL);
if (!ok)
return false;
assert (0 < nlimbs && nlimbs <= max_nlimbs);
emacs_limb_t *magnitude = malloc (nlimbs * limb_size);
if (magnitude == NULL)
{
memory_full (env);
return false;
}
int sign;
ok = env->extract_big_integer (env, arg, &sign, &nlimbs, magnitude);
assert (ok);
mpz_import (result, nlimbs, order, limb_size, endian, nails, magnitude);
free (magnitude);
if (sign < 0)
mpz_neg (result, result);
return true;
}
static emacs_value
make_big_integer (emacs_env *env, const mpz_t value)
{
size_t nbits = mpz_sizeinbase (value, 2);
int bitsperlimb = CHAR_BIT * limb_size - nails;
size_t nlimbs = nbits / bitsperlimb + (nbits % bitsperlimb != 0);
emacs_limb_t *magnitude
= nlimbs <= max_nlimbs ? malloc (nlimbs * limb_size) : NULL;
if (magnitude == NULL)
{
memory_full (env);
return NULL;
}
size_t written;
mpz_export (magnitude, &written, order, limb_size, endian, nails, value);
assert (written == nlimbs);
assert (nlimbs <= PTRDIFF_MAX);
emacs_value result = env->make_big_integer (env, mpz_sgn (value),
nlimbs, magnitude);
free (magnitude);
return result;
}
static emacs_value
next_prime (emacs_env *env, ptrdiff_t nargs, emacs_value *args,
void *data)
{
assert (nargs == 1);
mpz_t p;
mpz_init (p);
extract_big_integer (env, args[0], p);
mpz_nextprime (p, p);
emacs_value result = make_big_integer (env, p);
mpz_clear (p);
return result;
}
int
emacs_module_init (struct emacs_runtime *runtime)
{
emacs_env *env = runtime->get_environment (runtime);
emacs_value symbol = env->intern (env, "next-prime");
emacs_value func
= env->make_function (env, 1, 1, next_prime, NULL, NULL);
emacs_value args[] = {symbol, func};
env->funcall (env, env->intern (env, "defalias"), 2, args);
return 0;
}
- Функция: emacs_value make_float (emacs_env *env, double d)
Эта функция принимает аргумент
doubled и возвращает соответствующее значение с плавающей точкой Emacs.
- Функция: emacs_value make_time (emacs_env *env, struct timespec time)
Эта функция, доступная начиная с Emacs 27, принимает аргумент
struct timespectime и возвращает соответствующую временную метку Emacs в виде пары(ticks . hz). См. Время суток. Возвращаемое значение представляет точно такую же временную метку, что и time: все входные значения могут быть представлены, и точность никогда не теряется.time.tv_secиtime.tv_nsecмогут быть произвольными значениями. В частности, нет требования, чтобы time была нормализована. Это означает, чтоtime.tv_nsecможет быть отрицательным или больше 999 999 999.
- Функция: emacs_value make_string (emacs_env *env, const char *str, ptrdiff_t len)
Эта функция создаёт строку Emacs из C-строки, указанной str, длина которой в байтах, не включая завершающий нулевой байт, равна len. Исходная строка в str может быть как строкой ASCII, так и строкой UTF-8 с не-ASCII символами; она может содержать вложенные нулевые байты и не должна заканчиваться завершающим нулевым байтом в
str[len]. Функция вызывает ошибкуoverflow-errorесли len отрицательное или превышает максимальную длину строки Emacs. Если len равно нулю, то str может бытьNULL, в противном случае он должен указывать на допустимую область памяти. Для ненулевого len,make_stringвозвращает уникальные изменяемые строковые объекты.
- Функция: emacs_value make_unibyte_string (emacs_env *env, const char *str, ptrdiff_t len)
Эта функция аналогична
make_string, но не имеет ограничений на значения байтов в C-строке и может использоваться для передачи двоичных данных в Emacs в виде строки unibyte.
API не предоставляет функций для манипулирования списками Lisp, например, создания списков с cons и list (см. Создание списков), извлечения элементов списка с car и cdr (см. Элементы списка), создания векторов с vector (см. Функции векторов) и т. д. Для этого используйте intern и funcall, описанные в следующем подразделе, чтобы вызвать соответствующие функции Lisp.
Обычно объекты emacs_value имеют довольно короткий срок жизни: он заканчивается, когда указатель emacs_env , используемый для их создания, выходит из области видимости. Иногда вам может потребоваться создать глобальные ссылки: объекты emacs_value , которые живут так долго, как вам нужно. Используйте следующие две функции для управления такими объектами.
- Функция: emacs_value make_global_ref (emacs_env *env, emacs_value value)
Эта функция возвращает глобальную ссылку для value.
- Функция: void free_global_ref (emacs_env *env, emacs_value global_value)
Эта функция освобождает global_value, ранее созданный функцией
make_global_ref. global_value больше недействителен после вызова. Ваш модульный код должен сопоставить каждый вызовmake_global_refс соответствующимfree_global_ref.
Альтернативой сохранению C-структур данных, которые необходимо передать функциям модуля позже, является создание объектов пользовательского указателя. Объект пользовательского указателя, или user-ptr, представляет собой объект Lisp, который инкапсулирует указатель C и может иметь связанную функцию-финализатор, которая вызывается при сборе мусора объекта (см. Сбор мусора). Модульный API предоставляет функции для создания и доступа к объектам user-ptr . Эти функции вызывают ошибку wrong-type-argument , если они вызываются для объектов emacs_value, которые не представляют собой объект user-ptr.
- Функция: emacs_value make_user_ptr (emacs_env *env, emacs_finalizer fin, void *ptr)
-
Эта функция создаёт и возвращает объект
user-ptr, который оборачивает указатель C ptr. Функция-финализатор fin может быть указателемNULL(что означает отсутствие финализатора) или функцией со следующим сигнатуром:typedef void (*emacs_finalizer) (void *ptr);
Если fin не является указателем
NULL, она будет вызвана с ptr в качестве аргумента, когда объектuser-ptrбудет собран мусором. Не выполняйте никакие дорогостоящие вычисления в финализаторе, так как сборка мусора должна выполняться быстро, чтобы Emacs оставался отзывчивым.
- Функция: void * get_user_ptr (emacs_env *env, emacs_value arg)
Эта функция извлекает указатель C из объекта Lisp, представленного arg.
- Функция: void set_user_ptr (emacs_env *env, emacs_value arg, void *ptr)
Эта функция устанавливает указатель C, встроенный в объект
user-ptr, представленный arg, в ptr.
- Функция: emacs_finalizer get_user_finalizer (emacs_env *env, emacs_value arg)
Эта функция возвращает финализатор объекта
user-ptr, представленного arg, илиNULL, если у него нет финализатора.
- Функция: void set_user_finalizer (emacs_env *env, emacs_value arg, emacs_finalizer fin)
Эта функция изменяет финализатор объекта
user-ptr, представленного arg, на fin. Если fin является указателемNULL, объектuser-ptrне будет иметь финализатора.
Обратите внимание, что тип emacs_finalizer работает как для финализаторов пользовательских указателей, так и для финализаторов функций модулей. См. Финализаторы функций модулей.
Copyright © 1990-1996, 1998-2022 Free Software Foundation, Inc.
Licensed under the GNU GPL license.
https://www.gnu.org/software/emacs/manual/html_node/elisp/Module-Values.html