perlapio - perl の抽象入出力インターフェース
#define PERLIO_NOT_STDIO 0 /* For co-existence with stdio only */
#include <perlio.h> /* Usually via #include <perl.h> */
PerlIO *PerlIO_stdin(void);
PerlIO *PerlIO_stdout(void);
PerlIO *PerlIO_stderr(void);
PerlIO *PerlIO_open(const char *path,const char *mode);
PerlIO *PerlIO_fdopen(int fd, const char *mode);
PerlIO *PerlIO_reopen(const char *path, const char *mode, PerlIO *old); /* deprecated */
int PerlIO_close(PerlIO *f);
int PerlIO_stdoutf(const char *fmt,...)
int PerlIO_puts(PerlIO *f,const char *string);
int PerlIO_putc(PerlIO *f,int ch);
int PerlIO_write(PerlIO *f,const void *buf,size_t numbytes);
int PerlIO_printf(PerlIO *f, const char *fmt,...);
int PerlIO_vprintf(PerlIO *f, const char *fmt, va_list args);
int PerlIO_flush(PerlIO *f);
int PerlIO_eof(PerlIO *f);
int PerlIO_error(PerlIO *f);
void PerlIO_clearerr(PerlIO *f);
int PerlIO_getc(PerlIO *d);
int PerlIO_ungetc(PerlIO *f,int ch);
int PerlIO_read(PerlIO *f, void *buf, size_t numbytes);
int PerlIO_fileno(PerlIO *f);
void PerlIO_setlinebuf(PerlIO *f);
Off_t PerlIO_tell(PerlIO *f);
int PerlIO_seek(PerlIO *f, Off_t offset, int whence);
void PerlIO_rewind(PerlIO *f);
int PerlIO_getpos(PerlIO *f, SV *save); /* prototype changed */
int PerlIO_setpos(PerlIO *f, SV *saved); /* prototype changed */
int PerlIO_fast_gets(PerlIO *f);
int PerlIO_has_cntptr(PerlIO *f);
int PerlIO_get_cnt(PerlIO *f);
char *PerlIO_get_ptr(PerlIO *f);
void PerlIO_set_ptrcnt(PerlIO *f, char *ptr, int count);
int PerlIO_canset_cnt(PerlIO *f); /* deprecated */
void PerlIO_set_cnt(PerlIO *f, int count); /* deprecated */
int PerlIO_has_base(PerlIO *f);
char *PerlIO_get_base(PerlIO *f);
int PerlIO_get_bufsiz(PerlIO *f);
PerlIO *PerlIO_importFILE(FILE *stdio, const char *mode);
FILE *PerlIO_exportFILE(PerlIO *f, int flags);
FILE *PerlIO_findFILE(PerlIO *f);
void PerlIO_releaseFILE(PerlIO *f,FILE *stdio);
int PerlIO_apply_layers(PerlIO *f, const char *mode, const char *layers);
int PerlIO_binmode(PerlIO *f, int ptype, int imode, const char *layers);
void PerlIO_debug(const char *fmt,...)
Perl のソースコードと、最大の移植性を求めるエクステンションでは、 ANSI C の stdio.h にある関数ではなく上記の関数を使うべきです。 perl のヘッダ (特に "perlio.h") が Configure の実行時に選択した I/O 機構へ #define
します。
これらの関数は stdio.h にあるものがモデルになっていますが、 それに渡すパラメーターは「ちょっとばかし整頓」されています。
PerlIO *
は FILE * のようなものです。 FILE * と同様に、これは不透明なものとして扱われます(これを何かへの ポインタとして仮定することはおそらく安全です)。
現在のところ 3 つの実装があります:
上記の全ては stdio 関数への #define か、stdio を呼び出すためのありふれた ラッパ関数です。 この場合 のみ、PerlIO * は FILE * です。 抽象化が導入された perl5.003_02 以来、これがデフォルトの実装でした。
"sfio" ライブラリに関して、「レガシーな」実装です。 Unix マシンでの特殊なアプリケーションで使われています ("sfio" Unix 以外にはあまり移植されていません)。 上記のほとんどは sfio 関数への #define です。 この場合、PerlIO * は Sfio_t * です。
これはperl5.7.0 の直後に導入され、上述の抽象化の再実装です; これによって IO を OS と C ライブラリが物事を行うための選択と切り離すために、 IO がどのように行われるかを perl がより制御できるようになります。 USE_PERLIO では、PerlIO * は間接化の追加の層を持ちます - これは点対点です。 これにより、PerlIO * は既知の値のまま、基礎となる実装を 実行時に 交換することができます。 この場合上述の全ては基礎となる実装を呼び出す本当の(しかしとても単純な) 関数です。
これは PerlIO_apply_layers()
が何か「興味ある」ことを行う唯一の 実装です。
USE_PERLIO 実装については perliol に記述されています。
"perlio.h" は(効率のために)薄い層になっているので、これらの関数の意味は 基礎となる実装に若干依存しています。 変化があると分かっているところは以下に言及しています。
特に注意がなければ、関数は成功時に 0 を返し、エラー時には負数(普通は -1 の値を持つ EOF
)を返して errno
をセットします。
stdin
, stdout
, stderr
の代わりに使ってください。 これらは変数でなく“関数呼び出し”のように記述されていますが、 これは使用するプラットフォームにおいてロードモジュールに対するデータの エクスポートができなかったり、あるいは異なる“スレッド”が異なる値を 持つ可能性があるといったときに、これらを 関数呼び出しにする のが 簡単になるからです。
fopen()/fdopen() に対応し、同じ引数を取ります。 エラーの場合は NULL
を返し、errno
をセットします。 オープンするハンドルの数には実装の制限があるかもしれず、これはオープンする ファイルの数の制限より低いかもしれません - この制限を越えて NULL
を返されると、errno
はセットされません。
これは現在のところ 3 つ全ての実装に存在していますが、perl 自身はこれを 使っていません。 perl が使っていないので、十分にテストされていません。
Perl は存在する PerlIO によって使われている記述子よりも、新しい低レベル 記述子を dup
することを好みます。 これは将来この関数の振る舞いになるかもしれません。
fprintf()/vfprintf() と等価です。
これは printf() と等価です。 printf はこの関数に対する #define となっていますから、 (現時点では) Perl のソースコード中で printf(fmt,...)
とすることは 合法です。
fread() および fwrite() に対応する機能を持ちますが、引数と 返り値は異なります。 PerlIO_read() と PerlIO_write() のシグネチャは、代わりによりまともな 低レベルの read() と write() の関数をモデルにしています: "file" 引数は最初に渡され、count" は 1 つだけで、返り値はエラーと EOF
とで区別できます。
成功時にはバイトカウント(ゼロか正の数です)を返し、エラー時には負の数を 返して errno
をセットします。 実装に依存して、もし操作がシグナルで中断した場合は errno
は EINTR
に なるかもしれません。
実装によっては、操作がシグナルで中断した場合 errno
は EINTR
に なることがあります。
fputs() および fputc() に対応します。 最初の引数に“file”が来るということに 注意してください。
ungetc() に対応します。 最初の引数に "file" が来るということに注意してください。 次の読み込み操作でバイト c を返すように準備します。 名前の "character" が暗示しているものに関わらず、0..0xFF の範囲の値のみが 定義されています。 成功にはバイト c が、エラー時には -1 (EOF
) が返されます。 「押し返す」ことができるバイト数は異なります; 1 文字だけというのは確実で、 従ってハンドルから読み込んだ最後の文字だけということです。
getc() に対応します。 名前に c がありますが、バイトの範囲 0..0xFF にのみ対応しています。 読み込んだ文字か、エラーの場合は -1 (EOF
) を返します。
feof() に対応します。 ハンドルがファイルの最後かどうかを示す真か偽を返します。 端末デバイスでは、実装に依存して、これは "sticky" かもしれませんし、 そうではないかもしれません。 フラグは PerlIO_seek() か PerlIO_rewind() で解除されます。
ferror()に対応します。 ハンドルに IO エラーがあるかどうかを真偽値で返します。
fileno() に対応します。 一部のプラットフォームにおいては、“fileno”の 意味するところがUNIXとは違うということに注意してください。 Returns -1 if the handle has no open descriptor associated with it.
clearerr() に対応し、「ストリーム」の 'error' や (普通は) 'eof' といった フラグをクリアします。 値を返しません。
fflush() に対応します。 バッファリングされた書き込みデータをファイルに送ります。 引数 NULL
で呼び出すと、オープンしている全てのストリームを フラッシュします(USE_STDIO 実装にはコアダンプするものもあります)。 読み込み専用でオープンしているか、最後の操作がなんらかの読み込みである ハンドルで呼び出すと、USE_STDIO 実装には未定義の振る舞いとなるものが あります。 USE_PERLIO (層) 実装はよりよく振る舞おうとします: NULL
が渡されると オープンしている全てのストリームをフラッシュし、バッファの中か、現在の 論理位置にハンドルをシークすることで、読み込みストリームのデータを 維持しようとします。
fseek() に対応します。 バッファリングされた書き込みデータを対応するファイルに送るか、 バッファリングした読み込みデータを捨ててから、ファイル記述子の位置を <offset> と whence で指定された場所にします(シークします)。 これは同じハンドルの読み込みと書き込みを切り替えるときにするべき 正しいことです(上述の PerlIO_flush() の問題を参照してください)。 offset は perl の Configure 値である Off_t
型で、stdio の off_t
とは 異なるかもしれません。
ftell() に対応します。 現在のファイル位置か、エラーの場合は (Off_t) -1 が返されます。 システムコールや、基礎となるファイル記述子のチェックなしに、システムが 「知っている」値を返すかもしれません。 (従って、共有ファイル記述子での使用は、PerlIO_seek() なしでは 安全ではありません)。 返り値は perl の Configure 値である Off_t
型で、stdio の off_t
とは 異なるかもしれません。
それぞれ (大まかに) ftgetpos() と fsetpos() に対応します。 stdio のFpos_t と違って、これらは「Perl スカラ値」が渡されることを 想定しています。 ここで保存されるものは内部が見えないものとみなれさます。 データのレイアウトはハンドルによってさまざまです。 stdio を使わない場合や、プラットフォームが stdio 呼び出しを持っていない 場合にはこれらの関数は PerlIO_tell()、PerlIO_seek() によって実装されます。
rewind() に対応します。 これは普通以下のように定義されています:
PerlIO_seek(f,(Off_t)0L, SEEK_SET);
PerlIO_clearerr(f);
tmpfile() に対応し、無名 PerlIO (エラー時は NULL) を返します。 システムはファイルがクローズされると自動的にファイルを削除しようとします。 Unix では、ファイルは普通作成された直後に unlink
されるので、どうやって クローズされるかは気にされません。 その他のシステムでは、ファイルは PerlIO_close() で閉じられるか、プログラムが exit
で終了されたときにのみ削除されます。 実装に依存して、他のプロセスがこのファイルにアクセスできるという 「競合条件」が起こりえますが、一般的にはその場限りの仕組みよりこれの方が より安全でしょう。
これは setlinebuf() に対応します。 値を返しません。 何が「行」を構成するかは実装依存ですが、普通は "\n" を書くとバッファを フラッシュします。 "this\nthat" のようなものに対して何が起こるかは不明確です。 (Perl core は "dumping" が $| の自動フラッシュに 関係していない ときにのみ これを使います)。
PerlIO と stdio との共存をサポートするためのアウトラインがあります。 PerlIO が stdio を使って実装されているのであれば、明らかに問題はありません。 しかし、その他の場合では stdio 呼び出しを使おうとするライブラリコードに 渡すことができる FILE * を作成する機構がなければなりません。
最初のステップは以下の行を追加することです:
#define PERLIO_NOT_STDIO 0
あらゆる perl ヘッダファイルをインクルードする 前 に行います。 (これはおそらくある時点でデフォルトになります。) これにより "perlio.h" が stdio を PerlIO 関数に #define しようとするのを 妨げます。
XS コードは、もし FILE * 引数を想定しているなら、おそらく"typemap" を 使ったほうがよいでしょう。 標準の typemap は、この分野でのあらゆる変更を把握するために調整されます。
FILE * から PerlIO * を得るのに使います。
mode 引数は fopen/PerlIO_open に渡される文字列であるべきです。 もしこれが NULL なら - レガシーサポートのために - コードは (プラットフォームと実装に依存して) f がオープンされるモードを経験的に 決定しようとするか、読み書きストリームを示すために "r+" が使われます。
一度呼び出されると、この FILE * は返された PerlIO * で PerlIO_close()
を 呼び出すことによって のみ クローズされるべきです。
PerlIO はテキストモードにセットされます。 これが希望しているモードでない場合は、PerlIO_binmode を使います。
これは PerlIO_exportFILE() の逆 ではありません 。
PerlIO * を取り、ANSI C の stdio.h と共にコンパイルされ、リンクされる ことが想定されるコードに渡すのに適した‘ネイティブ’な FILE * 構造体を 作成します。 mode 引数は fopen/PerlIO_open に渡される文字列です。 これが NULL の場合は - レガシー対応のために - FILE * は PerlIO * と同じ モードでオープンします。
‘export’された FILE * は(通常は新しい :stdio 「層」を PerlIO * に プッシュすることで)記録され、それ以後のオリジナルの PerlIO * に対する PerlIO 操作に影響を及ぼす可能性があります。 PerlIO * との関連付けを解除するために PerlIO_releaseFILE()
を 呼び出さずに fclose()
を呼び出すべきではありません。 (関連付けの解除のために PerlIO_importFILE() を使ってはいけません。)
この関数を複数回呼び出すと、呼び出し毎に FILE * を作成します(そして 毎回 :stdio 層にプッシュします)。
PerlIO_releaseFILE は、PerlIO にすべてのFILE * の使用が完了したことを 知らせます。 完了したものは‘export’された FILE * のリストから削除されます。 そして、それに結び付けられている PerlIO * は元々の振る舞いに戻ります。
PerlIO_exportFILE() を使って PerlIO * に結び付けられたファイルを 分離するためにこれを使います。
stdio 層で使われるネイティブな FILE * を返します。 もしそれがなければ、PerlIO_exportFILE を使って作成されます。 どちらの場合でも、FILE * は PerlIO サブシステムに従うと考えられ、 PerlIO_close()
を呼び出すことによってのみクローズされるべきです。
上述した標準風の API に加えて、perl が PerlIO の内部で扱うことが できるようにする「実装」インターフェースがあります。 以下に挙げる呼び出しは、それぞれ Configure (あるいはその他の実装では これと等価なもの) で定義される FILE_xxx マクロに対応しています。 このセクションでは、perl-core の振る舞いの詳細、PerlIO のマッピングの実装、 また perl がする同じ方法で IO システムによって行われている 「先行読み込み」を使えるようなコードを書くことについてのみ注目します。 これらのインターフェースを使うコードは、もしハンドルがこれらに 対応していないなら、伝統的な方法で準備しておく必要があることに 注意してください。
もし実装が通常の IO 機構を「回避」するために perl の sv_gets
が 使えるために要求される全てのインターフェースを持っているなら真を返します。 これはハンドルによって異なる可能性があります。
PerlIO_fast_gets(f) = PerlIO_has_cntptr(f) && \
PerlIO_canset_cnt(f) && \
`Can set pointer into buffer'
“バッファ”中のカレントポジションへのポインターとバッファにある バイト数を返すことのできる実装です。 これを使わないでください - PerlIO_fast_gets を使ってください。
バッファ中の読み出すことのできるバイト数を返します。 0 や負数が返ると、もう読み出せないことを意味します。
バッファ中にある次の読み出し可能バイトへのポインターを返します; ポインタ経由のアクセス(デリファレンス)は、PerlIO_get_cnt() が 正の数を返した場合にのみ安全です。 PerlIO_get_cnt() で返される値以下の正の数のオフセットのみが使えます。
ポインターをバッファにセットし、バッファにあるバイト数はそのままです。 以前の PerlIO_get_ptr
と PerlIO_get_cnt
の呼び出しから 推測される範囲内のポインターをセットすることのみに使うべきでしょう。 2 つの値は互いに 一貫していなければなりません (実装はどちらか片方だけを使うかもしれませんし、両方が必要かもしれません)。
バッファにあるバイト数を調整することのできる実装です。 これは使わないでください - PerlIO_fast_gets を使ってください。
不明瞭 - バッファにあるバイト数をセットします。 非推奨です。 PerlIO_canset_cnt() は真を返す場合にのみ利用できます。 現在これは、doio.c でのみ -1 未満の count を 強制的に -1 にするために 使われています。 おそらく PerlIO_set_empty やそれに類するものがあるべきでしょう。 この呼び出しは、“count”がポインターと“limit”から導き出される場合には 実際にはなにもしません。 これは使わないでください - PerlIO_set_ptrcnt() を使ってください。
実装がバッファを持っていて、バッファ全体へのポインターやその大きさを 返すことができるなら真を返します。 -T/-B テストのために perl によって使われます。 そのほかのものは非常にはっきりしない形で使われます…
バッファの 開始位置 を返します。 バッファの中で、PerlIO_get_bufsiz() で返される値以下の正数のオフセットで のみアクセスできます。
バッファの 合計バイト数 を返します; これは読み込み可能な数や、バッファに割り当てられたメモリ量ではありません。 むしろ、最後に I/O が要求されたときに OS や 実装が read()
(あるいは そのようなもの) を行ったものです。
USE_PERLIO 実装への新しいインターフェースです。 ":crlf" と ":raw" の層はその他の実装では一つだけが許可され、これらは暗黙に 無視されます。 (perl5.8 から、":raw" は非推奨です。) 移植性が問題になる場合は後述する PerlIO_binmode() を使ってください。
perl の binmode
演算子で使われるフックです。 ptype は入出力の種類を示す perl の文字です:
imode は O_BINARY
か O_TEXT
です。
layers は適用される層の文字列で、USE_PERLIO 以外の場合では ":crlf" のみが 意味を持ちます。 (perl5.8 以降、":raw" は非推奨で、NULL を渡すことが好まれます。)
移植性のある場合は:
PerlIO_binmode(f,ptype,O_BINARY,NULL);
and
PerlIO_binmode(f,ptype,O_TEXT,":crlf");
Unix ではこれらの呼び出しはおそらく何の効果もありません。 それ以外では "\n" を CR,LF に変換し、特別なテキスト「ファイル終端」指示子を 読み書き時に使います。 ハンドルに対して I/O を行った後に呼び出した場合の効果は実装に依存します。 (無視されるかもしれませんし、既にバッファに入っているデータにも 適用されるかもしれませんし、以後のデータにだけ適用されるかもしれません。)
PerlIO_debug は、デバッグに使える printf() 風の関数です。 返り値はありません。 主な用途は、実 printf, warn() などが使っている PerlIO の内部で、PerlIO の 再帰呼び出しが問題になるようなところです。
PerlIO_debug は $ENV{'PERLIO_DEBUG'} で指定されたファイルに書き込みます。 典型的な使い方は:
Bourne shells (sh, ksh, bash, zsh, ash, ...):
PERLIO_DEBUG=/dev/tty ./perl somescript some args
Csh/Tcsh:
setenv PERLIO_DEBUG /dev/tty
./perl somescript some args
If you have the "env" utility:
env PERLIO_DEBUG=/dev/tty ./perl somescript some args
Win32:
set PERLIO_DEBUG=CON
perl somescript some args
$ENV{'PERLIO_DEBUG'} がセットされていない場合は PerlIO_debug() は 何もしません。