異なるまたはより複雑な媒体に対応する新しいストリーム・クラスは、Cプログラミング・インタフェースを使って直接に定義できます。新しいストリーム・クラス定義の仕方を理解するために、ここでは、既存のストリーム定義であるファイルを簡単にしたものを説明します。この例に関するソースファイルは$PROROOT/demos/stream/fileディレクトリの下にありますので参照して下さい。
例を単純化するため、ファイルの定義を簡単にしています。以下に示すプログラムはすべてファイルfile.cに書かれています。
ユーザー定義のストリーム・クラスは、C関数svInstall()を使ってインストールします:
Cboot() { svInstall(ioSERVER *server); }
ここで、serverとは新しいストリーム・クラスを記述する構造体へのポインターです。各ストリーム定義とIF/Prologとのインタフェースはインクルード・ファイルio.hで定義されているデータ構造ioSERVERを通してなされます。新しいストリーム定義では必ずgetとput及び制御に関する動作を定義しなければなりません。こうすることによって、PrologのI/O述語から操作できるようになります。
ストリーム・クラスで定義されている関数は、次のようにioCNTLとioSERVERという二つのデータ構造を通してIF/Prologの述語からアクセスできます。
static ioCNTL fileTable[] = { { "at_eof", 1, 1, fileError }, { (char*)0 } } ;
static ioSERVER fileServer = { "file_stream", fileTable, fileOpen, fileClose, fileStop, filePut, fileGet, fileEof, fileFlush } ;
ioSERVERの宣言はIF/Prologとの総称的なストリーム・インタフェースを提供するもので、すべてのストリーム定義に使用します。定義するべき操作はopen、close、stop、put、get、eof、flushです。
ioCNTLの宣言により、I/Oを含まない他の操作を可能にします。ここで扱う例では、ストリームがEOFにあるかどうかを検査する簡単なテストを提供します。
次に、file_streamを開いたり閉じたりするためのCのコードを示します。ここではストリームを入力または出力のどちらかで開けるようにしています:
static STREAM fileOpen(name, mode) char *name; int mode; { switch (mode) { case IO_INPUT: return (STREAM)fopen(name,"r"); break; case IO_OUTPUT: return (STREAM)fopen(name,"w"); break; default: return (STREAM)0; } }
static int fileClose(s) ioUNIT *s; { fclose((FILE*)s->stream); return 1; }
GetとputのためのCのコードではCのファイルI/O関数getcとputcを使います:
static int fileGet(s) ioUNIT *s; { return getc((FILE*)s->stream); }
static int filePut(s,c) ioUNIT *s; int c; { putc(c, (FILE*)s->stream); return 1; }
いつEOFになったかをチェックするためのCの手続きもCのファイルI/O関数を使用します:
static int fileEof(s) ioUNIT *s; { return feof((FILE*)s->stream); }
ストリームはデータをフラッシュすることもできますが、これも、CのファイルI/O関数を用いて直接に実現できます:
static int fileFlush(s) ioUNIT *s; { fflush((FILE*)s->stream); }
ファイルの場合は何もする必要がありませんが、ストリームを停止させる機能も提供されています:
static int fileStop() { return 1; }