ごく少数の例外を除き、ほとんどのモジュールは、自身を呼び出すLispプログラムとデータをやり取りする必要があります。具体的には、モジュール関数への引数を受け取り、モジュール関数から値を返すことです。この目的のため、モジュールAPIは、API経由でやり取りされるEmacs
Lispオブジェクトを表すemacs_value型を提供しています。これは、Emacs
Cプリミティブで使用されるLisp_Object型の機能的な相当物です(Writing Emacs
Primitivesを参照)。本節では、基本的なLispデータ型に対応するemacs_valueオブジェクトを作成するためのモジュールAPIの構成要素と、Lispオブジェクトに対応するemacs_valueオブジェクト内のCデータにアクセスする方法について説明します。
以下に説明する関数はすべて、実際には各モジュール関数が受け取る環境ポインタを介して提供される関数ポインタです。したがって、モジュールコードでは、次のように環境ポインタを通じてこれらの関数を呼び出す必要があります。
emacs_env *env; /* the environment pointer */ env->some_function (arguments...);
emacs_env
ポインタは通常、モジュール関数の第1引数から取得されます。また、モジュールの初期化関数内で環境が必要な場合は、get_environment の呼び出しから取得されます。
以下に説明する機能の多くは、動的モジュールをサポートした最初のEmacsリリースであるEmacs 25で利用可能になりました。それ以降のEmacsリリースで利用可能になった少数の機能については、それらをサポートした最初のEmacsバージョンを記載しています。
以下のAPI関数は、emacs_valueオブジェクトから各種Cデータ型の値を抽出します。これらの関数はいずれも、引数のemacs_valueオブジェクトが関数の想定する型でない場合、wrong-type-argumentエラー条件(型述語を参照)を発生させます。Emacsモジュールにおけるエラーシグナリングの仕組みや、モジュール内でエラー条件がEmacsに報告される前にそれを捕捉する方法の詳細については、モジュールにおける非局所脱出を参照してください。API関数type_of(type_ofを参照)は、emacs_valueオブジェクトの型を取得するために使用できます。
intmax_t extract_integer (emacs_env *env,
emacs_value arg) ¶
この関数は、arg で指定された Lisp 整数の値を返します。戻り値の 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 は少なくとも *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)を超えることはないことが保証されているため、サイズ計算における整数オーバーフローを心配することなく、malloc (*count * sizeof *magnitude)を用いてmagnitude配列を割り当てることができます。
これは符号なし整数型であり、巨大整数変換関数の絶対値配列の要素型として使用されます。この型は、一意なオブジェクト表現を持つこと、すなわちパディングビットを持たないことが保証されています。
このマクロは、emacs_limb_tオブジェクトの取り得る最大値を指定する定数式に展開されます。この式は#ifでの使用に適しています。
double extract_float (emacs_env *env,
emacs_value arg) ¶この関数は、arg で指定された Lisp 浮動小数点数の値を、C の double 値として返します。
struct
timespec extract_time (emacs_env *env,
emacs_value arg) ¶Emacs 27 以降で利用可能なこの関数は、arg を Emacs Lisp
の時刻値として解釈し、対応する struct timespec を返します。Time of Day を参照してください。struct timespec はナノ秒精度のタイムスタンプを表します。これには以下のメンバがあります:
time_t tv_sec秒単位の整数。
long tv_nsecナノ秒単位の小数秒。extract_time
によって返されるタイムスタンプの場合、この値は常に非負であり、10億未満となります。(POSIX では tv_nsec の型を long
と規定していますが、一部の非標準プラットフォームでは型が long long となっています。)
(libc)経過時間を参照してください。
time の精度がナノ秒よりも高い場合、この関数はそれを負の無限大方向へナノ秒精度に切り詰めます。time(ナノ秒に切り詰められた値)が struct
timespec で表現できない場合、この関数はエラーを通知します。例えば、time_t が32ビット整数型である場合、time
の値が100億秒であればエラーとなりますが、time の値が600ピコ秒であれば0に切り詰められます。
struct timespec
で表現できない時間値を扱う必要がある場合や、より高い精度を求める場合は、Lisp 関数 encode-time を呼び出し、その戻り値を使用してください。時間変換 を参照してください。
bool copy_string_contents (emacs_env *env,
emacs_value arg, char *buf,
ptrdiff_t *len) ¶この関数は、arg で指定された Lisp 文字列の UTF-8 エンコード済みテキストを、buf が指す char
の配列に格納します。この配列には、終端のヌルバイトを含めて少なくとも *len バイトを格納できる十分な領域がある必要があります。引数 len は NULL
ポインタであってはならず、関数呼び出し時には、buf
のサイズをバイト単位で指定する値を指している必要があります。
*len
で指定されたバッファサイズが文字列のテキストを格納するのに十分な大きさである場合、関数は終端ヌルバイトを含む buf にコピーされた実際のバイト数を *len に格納し、true
を返します。バッファが小さすぎる場合、関数は args-out-of-range
エラー条件を発生させ、必要なバイト数を *len
に格納し、false を返します。保留中のエラー条件の処理方法については、モジュールにおける非ローカル終了 を参照してください。
引数 buf は NULL
ポインタであることができ、その場合、関数は arg の内容を保持するために必要なバイト数を *len に格納し、true を返します。特定の文字列を格納するために必要な buf
のサイズは、次のようにして求めることができます。まず NULL を buf として copy_string_contents
を呼び出し、次に関数が *len
に格納したバイト数を保持するのに十分なメモリを割り当て、最後に NULL 以外の buf を指定して再度関数を呼び出し、実際にテキストのコピーを行います。
emacs_value vec_get (emacs_env *env,
emacs_value vector, ptrdiff_t index) ¶この関数は、vector の index
番目の要素を返します。最初のベクトル要素の index は 0 です。index の値が無効な場合、この関数は args-out-of-range エラー条件を発生させます。関数が返す値から 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) ¶この関数は、インデックスが index である vector
の要素に value を格納します。index
の値が無効な場合は、args-out-of-range エラー条件を発生させます。
以下のAPI関数は、C言語の基本データ型からemacs_valueオブジェクトを生成します。いずれの関数も、生成したemacs_valueオブジェクトを返します。
emacs_value make_integer (emacs_env *env, intmax_t
n) ¶この関数は整数引数 n を受け取り、対応する emacs_value オブジェクトを返します。n の値が
most-negative-fixnum と most-positive-fixnum で設定された範囲内にあるかどうかに応じて、fixnum または
bignum のいずれかを返します(整数の基本
を参照)。
emacs_value make_big_integer (emacs_env *env, int sign,
ptrdiff_t count, const emacs_limb_t *magnitude)
¶Emacs 27 から利用可能なこの関数は、任意のサイズの整数引数を受け取り、それに対応する emacs_value オブジェクトを返します。sign
引数は戻り値の符号を指定します。sign が 0 でない場合、magnitude は戻り値のリトルエンディアン形式の絶対値を指定する、少なくとも count 個の要素を持つ配列を指している必要があります。
以下の例では、GNU Multiprecision Library (GMP)
を使用して、指定された整数の次の確率的素数を計算します。GMPの概要については (gmp)Top を、magnitude 配列を GMP の mpz_t
値に変換する方法およびその逆の手順については (gmp)Integer
Import and Export を参照してください。
#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_value make_float (emacs_env *env, double
d) ¶この関数は double 引数 d
を受け取り、対応する Emacs の浮動小数点値を返します。
emacs_value make_time (emacs_env *env, struct
timespec time) ¶Emacs 27 から利用可能なこの関数は、struct timespec 引数 time を受け取り、対応する Emacs タイムスタンプをペア (ticks . hz) として返します。Time of Day を参照してください。戻り値は 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) ¶この関数は、str が指す C 言語のテキスト文字列(終端のヌルバイトを除いたバイト長が len)から、Emacs 文字列を生成します。str
にある元の文字列は、ASCII 文字列、または UTF-8 エンコードされた非 ASCII 文字列のいずれかであり、ヌルバイトが埋め込まれている場合もあり、str[len]
で終端のヌルバイトで終わる必要はありません。len が負であるか、または Emacs
文字列の最大長を超える場合、この関数は overflow-error
エラー条件を発生させます。len が 0 の場合、str は
NULL となり得ますが、それ以外の場合は有効なメモリを指している必要があります。len が 0 以外の場合、make_string
は一意の可変文字列オブジェクトを返します。
emacs_value make_unibyte_string (emacs_env *env, const
char *str, ptrdiff_t len) ¶Emacs 28から利用可能なこの関数はmake_stringに似ていますが、C文字列内のバイト値に制限がなく、バイナリデータをユニバイト文字列の形式でEmacsに渡すことができます。
APIには、Lispのデータ構造を操作するための関数は用意されていません。例えば、consやlistでリストを作成したり(Consセルとリストの作成を参照)、carやcdrでリストの要素を抽出したり(リストの要素へのアクセスを参照)、vectorでベクトルを作成したり(ベクトル用関数を参照)することはできません。これらについては、次のサブセクションで説明するinternおよびfuncallを使用して、対応するLisp関数を呼び出してください。
通常、emacs_value オブジェクトの寿命はかなり短く、生成に使用された emacs_env ポインタがスコープ外になると消滅します。場合によっては、グローバル参照、つまり任意の期間生存する emacs_value
オブジェクトを作成する必要があることもあります。こうしたオブジェクトを管理するには、以下の2つの関数を使用してください。
emacs_value make_global_ref (emacs_env *env,
emacs_value value) ¶この関数は、value のグローバル参照を返します。
void free_global_ref (emacs_env *env,
emacs_value global_value)
¶この関数は、make_global_ref によって事前に作成された global_value を解放します。呼び出し後、global_value は無効になります。モジュールのコードでは、make_global_ref への各呼び出しに対して、対応する free_global_ref を紐付ける必要があります。
後でモジュール関数に渡す必要があるCのデータ構造を保持しておく代わりの方法として、ユーザーポインタオブジェクトを作成することが挙げられます。ユーザーポインタ(またはuser-ptr)オブジェクトとは、Cのポインタをカプセル化したLispオブジェクトであり、オブジェクトがガベージコレクションされる際に呼び出されるファイナライザ関数を関連付けることができます(ガベージコレクションを参照)。モジュールのAPIには、user-ptrオブジェクトを作成および参照するための関数が用意されています。これらの関数は、user-ptrオブジェクトを表さないemacs_valueに対して呼び出された場合、wrong-type-argumentエラー条件を発生させます。
emacs_value make_user_ptr (emacs_env *env,
emacs_finalizer fin, void *ptr) ¶この関数は、Cポインタ ptr をラップする user-ptr オブジェクトを生成して返します。ファイナライザ関数 fin は、NULL
ポインタ(つまりファイナライザなし)であるか、あるいは以下のシグネチャを持つ関数であることができます:
typedef void (*emacs_finalizer) (void *ptr);
fin が NULL ポインタでない場合、user-ptr オブジェクトがガベージコレクションされる際に、ptr を引数として呼び出されます。Emacs の応答性を維持するため、GC
は迅速に完了させる必要があり、ファイナライザ内で負荷の高いコードを実行しないでください。
void
*get_user_ptr (emacs_env *env, emacs_value arg) ¶この関数は、arg で表される Lisp オブジェクトから C のポインタを抽出します。
void set_user_ptr
(emacs_env *env,
emacs_value arg, void *ptr) ¶この関数は、arg で表される user-ptr
オブジェクトに埋め込まれた C ポインタを ptr に設定します。
emacs_finalizer get_user_finalizer (emacs_env *env,
emacs_value arg) ¶この関数は、arg で表される user-ptr
オブジェクトのファイナライザを返します。ファイナライザがない場合は NULL を返します。
void set_user_finalizer (emacs_env *env,
emacs_value arg, emacs_finalizer fin) ¶この関数は、arg が表す user-ptr
オブジェクトのファイナライザを fin に変更します。fin
が NULL ポインタである場合、user-ptr オブジェクトにファイナライザは設定されません。
なお、emacs_finalizer
型はユーザーポインタとモジュール関数ファイナライザの両方で使用可能です。モジュール関数ファイナライザを参照してください。