Next: その他の便利なモジュール用関数, Previous: モジュール関数の記述, Up: 動的にロードされるモジュールの記述 [Contents][Index]
非常に少数の例外を除くほとんどのモジュールでは、モジュールを呼び出す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を参照)。
この関数はargで指定されたLisp整数の値をリターンする。リターン値のCデータ型intmax_tはCコンパイラーがサポートする最大の整数型であり、一般的にはlong long。argの値がintmax_tに収まらなければ、関数はエラーシンボルoverflow-errorを使用してエラーをシグナルする。
この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内での利用に適する。
この関数はargで指定されたLisp浮動小数の値をCのdouble値としてリターンする。
この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を呼び出してリターン値を処理すればよい。時刻の変換を参照のこと。
これは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で関数を再び呼び出す。
この関数はvectorのindexの要素をリターンする。ベクターの最初の要素のindexは0。indexの値が無効ならこの関数はエラーコンディションargs-out-of-rangeをraiseする。関数のリターン値からCデータを抽出するためには、ベクターの当該要素に格納されたLispデータタイプに応じて、ここで説明している他の抽出関数を使用すればよい。
この関数はvector内の要素数をリターンする。
この関数はvectorのインデックスindexの要素にvalueを格納する。indexの値が無効ならこの関数はエラーコンディションargs-out-of-rangeをraiseする。
以下はCの基本データ型からemacs_valueオブジェクトを作成するAPI関数です。これらはすべて作成したemacs_valueオブジェクトをリターンします。
この関数は引数n
(整数)を受け取り対応するemacs_valueオブジェクトをリターンする。nの値がmost-negative-fixnumとmost-positive-fixnumの内外いずれであるかに応じてfixnumかbignumのいずれかをリターンする(整数の基礎を参照)。nの値をEmacs整数で表現できない、すなわちmost-negative-fixnumとmost-positive-fixnumの範囲外(整数の基礎を参照)ならエラーコンディションoverflow-errorをraiseする。
この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;
}
この関数はdoubleの引数dを受け取り対応するEmacs浮動小数点値をリターンする。
このEmacs 27から利用可能になった関数はstruct
timespecの引数timeを受け取り、(ticks
.
hz)というペアーとしてそれに対応するEmacsタイムスタンプをリターンする。リターン値は正確にtimeと同一のタイムスタンプを表す。つまりすべての入力値は表現可能であり、精度を失うことは決してない。time.tv_secおよびtime.tv_nsecは任意の値をとり得る。特にtimeが正規化されている必要はない。これはtime.tv_nsecが負、あるいは999,999,999より大きくなり得ることを意味する。
この関数は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な文字列オブジェクトをリターンする。
この関数はmake_stringと似ているがC文字列のバイト値にたいする制限がなく、Emacsにユニバイト形式でバイナリーデータを渡すために使用できる。
このAPIはたとえばconsとlistによるリスト作成(コンスセルおよびリストの構築を参照)、carとcdrによるリストメンバーの抽出(リスト要素へのアクセスを参照)、vectorによるベクター作成(ベクターのための関数を参照)等のようなLispデータ構造を操作する関数は提供しません。これらにたいしてはたいおう
するLisp関数を呼び出すために、次のサブセクションで説明するinternとfuncallを使用します。
emacs_valueオブジェクトのライフタイムはかなり短いのが普通です。このライフタイムはオブジェクトの作成に使用されたemacs_envポインターがスコープ外になると終了します。emacs_valueが望む間は行き続けるようなグローバル参照(global
references)を作成を要する場合もあるかもしれません。そのようなオブジェクトの管理には以下の2つの関数を使用します。
この関数は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します。
この関数はCポインターptrをラップしたuser-ptrオブジェクトを作成してリターンする。ファイナライザー関数finはNULL
(ファイナライザーなし)、または以下のシグネチャをもつ関数のいずれか:
typedef void (*emacs_finalizer) (void *ptr);
finがNULLポインターでなければ、user-ptrオブジェクトがガーベージコレクトされる際にptrを引数として呼び出される。Emacsの応答性を維持するためにGCは短時間で終了しなければならないので、ファイナライザーでは高価なコードの実行は行ってはならない。
この関数はargで表されるLispオブジェクトからCポインターを抽出する。
この関数はargで表されるuser-ptrオブジェクトに埋め込まれたCポインターにptrをセットする。
この関数はargで表されるuser-ptrオブジェクトのファイナライザー、ファイナライザーがなければNULLをリターンする。
この関数はargで表されるuser-ptrオブジェクトのファイナライザーをfinに変更する。finがNULLならuser-ptrオブジェクトのファイナライザーはなくなる。
emacs_finalizerタイプはユーザーポインターと関数ファイナライザーの両方にたいして機能することに注意してください。Module Function Finalizersを参照してください。
Next: その他の便利なモジュール用関数, Previous: モジュール関数の記述, Up: 動的にロードされるモジュールの記述 [Contents][Index]