Преобразование между значениями 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_textract_integer(emacs_env *env, emacs_value arg) Эта функция возвращает значение целого числа Lisp, заданного параметром arg. Тип данных C возвращаемого значения,
intmax_t, — это самый широкий целочисленный тип данных, поддерживаемый компилятором C, обычноlong long. Если значение arg не помещается вintmax_t, функция сигнализирует об ошибке, используя символ ошибкиoverflow-error.
-
Функция:
boolextract_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 должен указывать на массив как минимум из*countэлементовunsigned long. Если массив magnitude достаточно велик, чтобы вместить модуль arg, эта функция записывает модуль в массив magnitude в порядке от младшего элемента к старшему, сохраняет число записанных элементов массива в*countи возвращаетtrue. Если массив magnitude недостаточно велик, функция сохраняет требуемый размер массива в*count, сигнализирует об ошибке и возвращаетfalse. Если count не равенNULL, а magnitude равенNULL, функция сохраняет требуемый размер массива в*countи возвращаетtrue.Emacs гарантирует, что максимальное требуемое значение
*countникогда не превышаетmin (PTRDIFF_MAX, SIZE_MAX) / sizeof (emacs_limb_t), поэтому для выделения массиваmagnitudeможно использоватьmalloc (*count * sizeof *magnitude), не беспокоясь о переполнении целого числа при вычислении размера.
- Псевдоним типа: emacs_limb_t
Это беззнаковый целочисленный тип, используемый в качестве типа элементов массивов модулей для функций преобразования больших целых чисел. Гарантируется, что представления объектов этого типа уникальны, то есть не содержат битов заполнения.
- Макрос: EMACS_LIMB_MAX
Этот макрос раскрывается в константное выражение, задающее максимально возможное значение объекта
emacs_limb_t. Это выражение подходит для использования в#if.
-
Функция:
doubleextract_float(emacs_env *env, emacs_value arg) Эта функция возвращает значение числа с плавающей точкой Lisp, заданного параметром arg, в виде значения C типа
double.
-
Функция:
struct timespecextract_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и используйте её возвращаемое значение. См. Преобразование времени.
-
Функция:
boolcopy_string_contents(emacs_env *env, emacs_value arg, char *buf, ptrdiff_t *len) -
Эта функция сохраняет текст строки Lisp, закодированный в UTF-8 и заданный параметром arg, в массиве
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, и вызовите функцию ещё раз с ненулевым buf (неNULL), чтобы выполнить копирование текста.
-
Функция:
emacs_valuevec_get(emacs_env *env, emacs_value vector, ptrdiff_t index) Эта функция возвращает элемент vector с индексом index. Индекс первого элемента вектора равен нулю. Функция вызывает ошибку
args-out-of-range, если значение index недопустимо. Чтобы извлечь данные C из возвращаемого функцией значения, используйте другие описанные здесь функции извлечения, соответствующие типу данных Lisp, хранящихся в этом элементе вектора.
-
Функция:
ptrdiff_tvec_size(emacs_env *env, emacs_value vector) Эта функция возвращает число элементов в vector.
-
Функция:
voidvec_set(emacs_env *env, emacs_value vector, ptrdiff_t index, emacs_value value) Эта функция сохраняет value в элементе vector с индексом index. Если значение index недопустимо, функция вызывает ошибку
args-out-of-range.
Следующие функции API создают объекты emacs_value из базовых типов данных C. Все они возвращают созданный объект emacs_value.
-
Функция:
emacs_valuemake_integer(emacs_env *env, intmax_t n) Эта функция принимает целочисленный аргумент n и возвращает соответствующий объект
emacs_value. В зависимости от того, находится ли значение n в пределах, заданныхmost-negative-fixnumиmost-positive-fixnum, функция возвращает fixnum или bignum (см. Основы целых чисел).
-
Функция:
emacs_valuemake_big_integer(emacs_env *env, int sign, ptrdiff_t count, const emacs_limb_t *magnitude) Эта функция, доступная начиная с Emacs 27, принимает целочисленный аргумент произвольного размера и возвращает соответствующий объект
emacs_value. Аргумент sign задаёт знак возвращаемого значения. Если sign не равен нулю, magnitude должен указывать на массив как минимум из count элементов, задающих модуль возвращаемого значения в порядке от младшего элемента к старшему.
В следующем примере библиотека GNU Multiprecision Library (GMP) используется для вычисления следующего вероятного простого числа после заданного целого числа. Общий обзор GMP см. в разделе (gmp)Введение, а сведения о преобразовании массива magnitude в значения GMP типа mpz_t и обратно — в разделе (gmp)Импорт и экспорт целых чисел.
#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);
/* Assume Emacs is linked to the full GMP library,
not to its mini-gmp subset that lacks mpz_nextprime. */
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_valuemake_float(emacs_env *env, double d) Эта функция принимает аргумент d типа
doubleи возвращает соответствующее значение Emacs с плавающей точкой.
-
Функция:
emacs_valuemake_time(emacs_env *env, struct timespec time) Эта функция, доступная начиная с Emacs 27, принимает аргумент time типа
struct timespecи возвращает соответствующую временную метку Emacs в виде пары(ticks . hz). См. Время суток. Возвращаемое значение представляет ту же временную метку, что и time: все входные значения представимы, потери точности не происходит.time.tv_secиtime.tv_nsecмогут иметь произвольные значения. В частности, time не обязательно должно быть нормализовано. Это означает, чтоtime.tv_nsecможет быть отрицательным или превышать 999 999 999.
-
Функция:
emacs_valuemake_string(emacs_env *env, const char *str, ptrdiff_t len) Эта функция создаёт строку Emacs из текстовой строки C, на которую указывает str и длина которой в байтах, не считая завершающего нулевого байта, равна len. Исходная строка в str может быть строкой ASCII или строкой с символами вне ASCII, закодированной в UTF-8; она может содержать встроенные нулевые байты и не обязана завершаться нулевым байтом в
str[len]. Если len отрицательно или превышает максимальную длину строки Emacs, функция вызывает ошибкуoverflow-error. Если len равно нулю, str может бытьNULL; в противном случае оно должно указывать на допустимую область памяти. При ненулевом значении len функцияmake_stringвозвращает уникальные изменяемые строковые объекты.
-
Функция:
emacs_valuemake_unibyte_string(emacs_env *env, const char *str, ptrdiff_t len) Эта функция, доступная начиная с Emacs 28, аналогична
make_string, но не накладывает ограничений на значения байтов в строке C и может использоваться для передачи двоичных данных в Emacs в виде однобайтовой строки.
API не предоставляет функций для работы со структурами данных Lisp, например для создания списков с помощью cons и list (см. Создание конс-ячеек и списков), извлечения элементов списка с помощью car и cdr (см. Доступ к элементам списков), создания векторов с помощью vector (см. Функции для векторов) и т. д. Для этого используйте intern и funcall, описанные в следующем подразделе, чтобы вызывать соответствующие функции Lisp.
Обычно срок жизни объектов emacs_value довольно короток: он заканчивается, когда указатель emacs_env, использованный для их создания, выходит из области видимости. Иногда может потребоваться создавать глобальные ссылки — объекты emacs_value, которые существуют столько, сколько нужно. Для управления такими объектами используйте следующие две функции.
-
Функция:
emacs_valuemake_global_ref(emacs_env *env, emacs_value value) Эта функция возвращает глобальную ссылку на value.
-
Функция:
voidfree_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_valuemake_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.
-
Функция:
voidset_user_ptr(emacs_env *env, emacs_value arg, void *ptr) Эта функция устанавливает указатель C, встроенный в объект
user-ptr, представленный параметром arg, в значение ptr.
-
Функция:
emacs_finalizerget_user_finalizer(emacs_env *env, emacs_value arg) Эта функция возвращает финализатор объекта
user-ptr, представленного параметром arg, либоNULL, если финализатора нет.
-
Функция:
voidset_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-2026 Free Software Foundation, Inc.
Licensed under the GNU GPL license.
https://www.gnu.org/software/emacs/manual/html_node/elisp/Module-Values.html