非常に少数の例外を除くほとんどのモジュールでは、モジュールを呼び出すLispプログラムとの間でモジュール関数への引数やリターン値の受け渡しでデータのやり取りが必要になります。この目的にたいしてモジュールAPIはemacs_value
タイプを提供しています。これはAPIを通じたやり取りにおいてEmacsのLispオブジェクトを表現するタイプであり、EmacsのCプリミティブ(Emacsプリミティブの記述を参照)で使用されるLisp_Object
タイプと機能的には等価です。このセクションではLispの基本データ型に対応するemacs_value
オブジェクトの作成を可能とするモジュールAPIの部分と、Lispオブジェクトに対応するemacs_value
オブジェクト内のCデータへのアクセス方法について説明します。
以下で説明するすべての関数は、実際にはすべてのモジュール関数が受け取る環境へのポインターを介して提供される関数ポインター(function pointers)です。したがってモジュールのコードでは以下のように環境ポインターを通じてこれらの関数を呼び出す必要があります:
emacs_env *env; /* the environment pointer */ env->some_function (arguments...);
emacs_env
ポインターは通常はモジュール関数の1つ目の引数、モジュール初期化関数内で環境が必要な場合にはget_environment
の呼び出しから取得できます。
以下で説明するもののほとんどはEmacs 25で利用可能になった関数であり、Emacs 25はダイナミックモジュールを最初にサポートした最初のEmacsリリースです。それ以降のリリースで利用可能になったいくつかの関数につていは、それらをサポートする最初のEmacsバージョンを付記します。
以下のAPI関数はemacs_value
オブジェクトから種々のCデータ型を抽出します。これらすべては引数のemacs_value
オブジェクトがその関数の期待するタイプでなければ、エラーコンディションwrong-type-argument
をraiseします(型のための述語を参照)。Emacsモジュール内でエラーをシグナルする方法、およびEmacsにエラーが報告される前にモジュール内部でエラーコンディションをcatchする方法の詳細はモジュールでの非ローカル脱出を参照してください。emacs_value
のタイプ取得にはAPI関数type_of
を使用できます(type_ofを参照)。
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:
大きさ)は次のように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
にたいして可能な最大値を指定する定数式に展開されるマクロ。この式は#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のtime値として解釈して、それに対応するstruct
timespec
をリターンする。時刻を参照のこと。struct
timespec
はナノ秒の精度のタイムスタンプを表す。以下のメンバーをもつ:
time_t tv_sec
整数秒。
long tv_nsec
ナノ秒としての小数秒数。extract_time
がリターンするタイムスタンプでは常に非負かつ十億未満(tv_nsec
のタイプがlong
であることをPOSIXがが要求しているとしても、非標準的なプラットフォームではlong
long
である)。
(libc)Elapsed Timeを参照のこと。
timeがナノ秒より高い精度をもつ場合には、この関数はナノ秒の精度へ負の無限大方向に切り詰める。struct
timespec
が(ナノ秒に切り詰めた)timeを表現できなければ、この関数はエラーをシグナルする。たとえばtime_t
が32ビット整数タイプなら100億秒というtime値はエラーをシグナルするが、600ピコ秒のtime値は0に切り詰められるだろう。
struct
timespec
で表現できないtime値を処理する必要があったり、より高い精度が必要ならLisp関数encode-time
を呼び出してリターン値を処理すればよい。時刻の変換を参照のこと。
bool
copy_string_contents (emacs_env *env, emacs_value arg, char *buf, ptrdiff_t *len)
¶これはargで指定されたLisp文字列をUTF-8にエンコードしたテキストをbufが指すchar
配列に格納する。bufは少なくとも終端のnullバイトを含む*len
バイトを保持するために十分なスペースをもつこと。引数lenはNULL
ポインターであってはならない。この関数の呼び出し時にはbufのバイトサイズを指定する値を指していること。
*len
で指定されたバッファーサイズが文字列のテキストを保持するために十分大きければ、関数は終端のnullバイト含む実際にコピーされる*len
バイトをbufにコピーしてtrue
をリターンする。バッファーが小さすぎる場合には、関数はエラーコンディションargs-out-of-range
をraiseするとともに、必要なバイト数を*len
に格納してfalse
をリターンする。保留中のエラーコンディションのハンドル方法はモジュールでの非ローカル脱出を参照のこと。
引数bufはNULL
ポインターでもよく、この場合には関数はargのコンテンツの格納に必要なバイト数を*len
に格納してtrue
をリターンする。これは特定の文字列を格納するために必要なbufサイズを決定する手段となり得る。1回目はbufをNULL
で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
をraiseする。関数のリターン値から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)
¶この関数はvectorのインデックスindexの要素にvalueを格納する。indexの値が無効ならこの関数はエラーコンディションargs-out-of-range
をraiseする。
以下はCの基本データ型からemacs_value
オブジェクトを作成するAPI関数です。これらはすべて作成したemacs_value
オブジェクトをリターンします。
emacs_value
make_integer (emacs_env *env, intmax_t n)
¶この関数は引数n
(整数)を受け取り対応するemacs_value
オブジェクトをリターンする。nの値がmost-negative-fixnum
とmost-positive-fixnum
の内外いずれであるかに応じてfixnumかbignumのいずれかをリターンする(整数の基礎を参照)。nの値をEmacs整数で表現できない、すなわちmost-negative-fixnum
とmost-positive-fixnum
の範囲外(整数の基礎を参照)ならエラーコンディションoverflow-error
をraiseする。
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); 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を受け取り、(ticks
.
hz)
というペアーとしてそれに対応するEmacsタイムスタンプをリターンする。リターン値は正確に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が指す、終端のnullバイトを含まないバイト長がlenであるようなCテキスト文字列からEmacs文字列を作成する。strの元文字列はASCII文字列かUTF-8にエンコードされた非ASCII文字列が可能であり、文字列には埋め込みのnullバイトを含むことができ、str[len]
にあるnullバイトで終端される必要はない。lenが負、またはEmacs文字列の最大長を超過する場合には、この関数はエラーコンディションoverflow-error
をraiseする。lenが0ならstrはNULL
でもよいが、そうでなければ有効なメモリーを指していなければならない。非0のlenでは、make_string
は一意でmutableな文字列オブジェクトをリターンする。
emacs_value
make_unibyte_string (emacs_env *env, const char *str, ptrdiff_t len)
¶この関数はmake_string
と似ているがC文字列のバイト値にたいする制限がなく、Emacsにユニバイト形式でバイナリーデータを渡すために使用できる。
このAPIはたとえばcons
とlist
によるリスト作成(コンスセルおよびリストの構築を参照)、car
とcdr
によるリストメンバーの抽出(リスト要素へのアクセスを参照)、vector
によるベクター作成(ベクターのための関数を参照)等のようなLispデータ構造を操作する関数は提供しません。これらにたいしてはたいおう
するLisp関数を呼び出すために、次のサブセクションで説明するintern
とfuncall
を使用します。
emacs_value
オブジェクトのライフタイムはかなり短いのが普通です。このライフタイムはオブジェクトの作成に使用されたemacs_env
ポインターがスコープ外になると終了します。emacs_value
が望む間は行き続けるようなグローバル参照(global
references)を作成を要する場合もあるかもしれません。そのようなオブジェクトの管理には以下の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
pointer)オブジェクトの作成です。ユーザーポインター(またはuser-ptr
)はCポインターをカプセル化したLispオブジェクトであり、関連付けられたファイナライザー(オブジェクトがガーベージコレクトされる際に呼び出される。ガーベージコレクションを参照)をもつことができます。モジュールAPIはuser-ptr
オブジェクトの作成やアクセスを行う関数を提供します。これらの関数はuser-ptr
オブジェクトを表現しないemacs_value
で呼び出されるとエラーコンディションwrong-type-argument
をraiseします。
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
タイプはユーザーポインターと関数ファイナライザーの両方にたいして機能することに注意してください。Module Function Finalizersを参照してください。