[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
6.19.1 ポート | ||
6.19.2 ポートとスレッド | ||
6.19.3 ポート共通の操作 | ||
6.19.4 ファイルポート | ||
6.19.5 文字列ポート | ||
6.19.6 コーディング認識ポート | ||
6.19.7 入力 | ||
6.19.8 出力 |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Portは、Schemeにおいて抽象化された入出力のインタフェースを提供します。 Gaucheはportにいくつかの拡張を行い、いろいろなアプリケーションに対応できるようにしました。
標準のSchemeでは、portはキャラクタを一文字づつ読み込む(一文字先読み可)、 もしくは書き出すだけのもので、他の入出力ルーチンはその上に構築されています。
Gaucheではさらに次のような操作がportに対して可能になっています。
キャラクタ毎でなく、オクテット毎のI/Oが可能です(Gaucheではマルチバイト文字を 扱うので、この2つが異なることに注意して下さい)。大抵のポートでは キャラクタI/OとバイナリI/Oを混ぜて使うことができます。
最も基本的なバイナリI/Oプリミティブはread-byte
とwrite-byte
です。
また、より高機能なpack
やunpack
といった手続きが
binary.pack
- バイナリデータのパック で提供されています。
ポートから指定した数のバイト列を読んだり、ポートへ書いたりできます。 ポートがブロックI/Oを行うデバイスに接続されている場合、ある程度大きなブロック毎に 読み書きすると効率の良いデータ転送ができます。
ポートはまた、データストリームを変換するのにも使えます。例えばgauche.charconv
モジュールでは、文字コード間の変換を行うポートを提供しています
(詳しくはgauche.charconv
- 文字コード変換を参照)。
また、特殊な機能を実現するポートもあります。
コーディング認識ポート(コーディング認識ポート参照)は
ファイル中の特殊なコメントを認識して、そのファイルがどの文字エンコーディング
で書かれているかを検出します。
仮想ポート(gauche.vport
- 仮想ポート参照)はSchemeでふるまいをプログラムできる
ポートを提供します。
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
GaucheがスレッドサポートをONにしてコンパイルされている場合、
組み込みのポート操作関数はポートをロックして、
複数のスレッドからの同一のポートへのアクセスがポートの内部状態を壊さないように
しています。
(SRFI-18によって要求されている動作です)。
ここで「組み込みのポート操作関数」はGaucheにより提供される、
ポートを引数に取り何らかのI/O動作や問い合わせを行う手続きで、
read
/write
、read-char
/write-char
、
port->string
等を含みます。
但し、call-with-*
やwith-*
系関数は、
与えられた手続きを呼ぶ際にはポートをロックしません。
その手続きが別のスレッドにポートを渡すかもしれず、Gaucheにはそれを知ることが
できないからです。
従って、マルチスレッド環境でポートへのアクセス競合により ポートの内部状態を壊してしまうんじゃないか、などとあまり神経質に なる必要はありません。但し、このロック機構はあくまで予想外の アクセス競合によってポートがおかしな状態になってしまうことを 防ぐための安全ネットであって、一般的な排他制御機構として使われる ことは想定していないのに注意して下さい。このロックの実装は、 ポートへのアクセス競合は例外的な場合のみであると仮定し、 通常のアクセスにおけるオーバヘッドを避けるために、スピンロックを 使用します。もし、意図的にポートアクセスが競合するようなコードを書く場合は、 明示的に排他制御をしてください。
portをロックし、thunkを実行します。 ロックはthunkのダイナミックエクステントの期間有効です。
portがロックされている期間での組み込みのポートアクセス関数の 呼び出しは排他制御をバイパスするため、性能向上が見込まれます。
ロックの有効期間はthunkのダイナミックエクステントなので、
thunk内からwith-port-locking
の外で捕捉された
継続を呼んだ場合、ロックは解放されます。その後、thunk内で
捕捉された継続が呼ばれた場合、再びロックが獲得されます。
with-port-locking
はネスト可能です。ロックは最も外側の
with-port-locking
の期間中有効となります。
この手続きはポート組込みのロック機構を利用します。つまり、ポートアクセスが 競合した場合はbusy waitになるということです。この手続きはあくまで 頻繁なロックによるオーバヘッドを回避するためのものです。 もし本当に競合が予測される場合は明示的に排他制御を行ってください。
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
[R5RS]
obj がそれぞれポート、入力ポート、出力ポートなら真を返します。
port?
はR5RSの"Standard Procedures"の項には
載っていませんが、"Disjointness of Types"の項に挙げられています。
objがポートであり、既に閉じられていた場合に真を返します。 一度閉じたポートは再び開くことはできません。
[R5RS] 現在の入力ポートと出力ポートをそれぞれ返します。
現在のエラーポートを返します。
プログラム開始時点の入力、出力、エラーポートをそれぞれ返します。
それぞれ入力、出力、エラーポートをportにセットした状態でthunkを呼び出します。
上の3つの動作を同時に行う手続きです。
入力、出力、エラーの各ポートをそれぞれiport, oport, eportに
セットしてthunkを呼び出します。変更する必要がないポートの引数には
#f
を渡すことができます。
[R5RS] それぞれ、入力ポートと出力ポートを閉じます。
portのタイプを、シンボルfile
、string
、proc
の
いずれかで返します。
portの名前を返します。ポートがファイルに関連付けられている場合は、ポートの名前は ファイル名です。そうでない場合、ポートを説明する文字列が返されます。
ファイルポート((port-type port)
がfile
を返すもの)
に対して、そのバッファリングモードを読みだし、もしくは変更します。
入力ポートではバッファリングモードは
:full
、 :modest
、:none
のいずれかです。
出力ポートでは
:full
、 :line
、:none
のいずれかです。
バッファリングモードの詳細な説明は、ファイルポート を参照してください。
port-buffering
がファイルポート以外のポートに対して呼ばれた場合は
#f
を返します。port-buffering
のsetterが
ファイルポート以外のポートに対して呼ばれた場合はエラーとなります。
portの現在の行番号を返します。行番号は、ファイルに関連付けられたポートで かつシーケンシャルなキャラクタI/Oを行っている場合のみ有効です。それ以外の場合は -1を返します。
portがファイルに関連付けられている場合、そのファイルディスクリプタ番号を
返します。それ以外の場合は#f
を返します。
portがランダムアクセス可能なポートの場合、
この手続きはportのread/writeポインタをoffsetとwhenceの値によって
設定し、新たなread/writeポインタの値(データの先頭からのバイトオフセット)を
返します。portがランダムアクセス可能でない場合は#f
が返されます。
現在のバージョンでは、ファイルポートおよび入力文字列ポートがランダムアクセス可能です。
出力文字列ポートは現在のポインタの値を問い合わせる動作だけが可能です。
ポートのポインタはバイト数で表現され、文字数とは異なることに注意して下さい。
portが出力ファイルポートの場合は、データの終端を超えた位置までseek することが可能です。その場合の動作はPOSIXのlseek(2)に準じます。 入力ファイルポートや入力文字列ポートではデータの終端以降にseekすることはできません。
whence引数は、offsetの基準を指定する小さな整数です。 以下の定数が定義されています。
SEEK_SET
offsetはデータ先頭からのバイト数を指定します。 whenceが省略された場合のデフォルトの動作です。
SEEK_CUR
offsetは現在のread/writeポインタからの相対バイト数を指定します。 offsetが0であれば、ポインタを動かさずに現在のポート位置を知ることができます。
SEEK_END
offsetはデータの終端からの相対バイト数を指定します。
portの現在のread/writeポインタの値をバイト数で返します。
portがランダムアクセス可能でない場合は#f
が返されます。
これは以下の呼び出しと等価です。
(port-seek port 0 SEEK_CUR) |
名前に関するメモ: port-seek
は他の処理系で
seek
、file-position
、input-port-position
/
output-port-position
等と呼ばれています。
port-tell
はtell
、ftell
、set-file-position!
等と
呼ばれています。いくつかの処理系はport-position
という手続きを
持っていますが、port-seek
とは別の機能を実現しています。
file-position
はCommonLisp由来の名前ですが、
fileポート以外のものも扱うため採用しませんでした。
また、seek
とtell
はPOSIXの名前由来であり、
Gaucheの名前付け規則を使ってsys-seek
とsys-tell
としても
よさそうですが、portの操作はシステムコールレベルよりも抽象度が高いため
これも採用しませんでした。結局、新しい名前を採用することにしました。
srcからEOFまでデータを読みだし、dstへ書き出します。
キーワード引数unitは0以上の整数か、シンボルbyte
もしくはchar
でなければなりません。これはデータをコピーする単位を指定します。
整数ならば、その大きさ(0の場合はシステム規定の大きさ)のバッファが確保され、
ブロックI/Oを使って転送が行われます。通常のファイルをコピーする場合などはこれが
速いでしょう。もしunitがシンボルbyte
であれば、バイト毎
に読みだし/書き込みが行われます。unitがシンボルchar
であれば、
キャラクタ毎に読みだし/書き込みが行われます。
キーワード引数sizeに非負の整数が与えられた場合、それはコピーされるデータの
最大量を指定します。unitがシンボルchar
の場合はsizeは
コピーされる文字数を、そうでない場合はバイト数を指定します。
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
[R5RS+] ファイルfilenameを入力または出力用にオープンし、 入力ポートまたは出力ポートを作成して返します。
キーワード引数により、動作を細かく指定できます。
:if-exists
このキーワード引数はopen-output-file
のみに指定でき、
filenameが既に存在した場合の動作を指定します。次の値のいずれかを与えることができます。
:supersede
既存のファイルが長さ0に縮められます。これが既定の動作です。
:append
既存のファイルにこれから書き出す内容が追加されます。
:overwrite
既存のファイルにこれから書き出す内容が上書きされます。 書き出されるデータが既存のファイルのデータよりも短い場合、 残りの部分はそのまま残されます。
:error
エラーが報告されます。
#f
何もせず、#f
を返します。
:if-does-not-exist
このキーワード引数はfilenameが存在しない場合の動作を指定します。
:error
エラーを報告します。これがopen-input-file
の既定の動作です。
:create
ファイルが作成されます。これがopen-output-file
の既定の動作です。
ファイルの存在のチェックと作成はアトミックに行われます。
このオプションに加え、if-existsオプションに:error
か#f
を
指定することで、排他的にファイルを作成することができます。
open-input-file
に対してはこの値を指定することはできません。
#f
何もせず、#f
を返します。
:buffering
この引数はバッファリングモードを指定します。以下の値が設定できます。
ポートのバッファリングモードは手続きport-buffering
(ポート共通の操作参照)によって
読みだし/変更可能です。
:full
出来る限りデータをバッファリングします。これがデフォルトのモードです。
:none
バッファリングを行いません。出力ポートにデータが書き出されるか、 入力ポートからデータが読み込まれる度に、下位にあるシステムコールが呼ばれます。 プロセスの標準エラーポートはこのモードでオープンされています。
:line
このモードは出力ポートにのみ有効です。書き出されたデータはバッファに 貯められますが、改行文字が書かれたらフラッシュされます。 このモードは対話的な出力ポートなどに便利です。 プロセスの標準出力ポートはこのモードでオープンされています。 (これは、Cのstdioライブラリの「ラインバッファリング」とちょっと違うことに 注意してください。stdioでは同じファイルディスクリプタから入力が行われる時も バッファはフラッシュされますが、Gaucheではそうはなりません)。
:modest
このモードは入力ポートにのみ有効です。ほとんど:full
バッファリングモードと
同じですが、read-block
はポートに要求されたデータより少ないデータしか
無かった場合、要求された量がたまるまで待つのではなく、今あるデータだけを
返します。このモードはポートがパイプやネットワークに接続されている場合に
便利です。
:element-type
この引数はファイルのタイプを指定します。
:character
ファイルはキャラクタモード(テキストモード)でオープンされます。
:binary
ファイルはバイナリモードでオープンされます。
現在のバージョンでは、この引数は無視され、全てのファイルはバイナリモードで オープンされます。いずれにせよUnixプラットフォームでは違いはありません。
:encoding
この引数はファイルの文字エンコーディングを指定します。引数は文字列かシンボルで、
文字エンコーディングスキーム(CES)の名前でなければなりません。
open-input-file
では、ここにワイルドカードCES (例: *jp
) を
渡して、入力ファイルのエンコーディングを推測させることもできます
(文字エンコーディングの自動判定参照)。
この引数が与えられた場合、Gaucheは自動的にgauche.charconv
モジュールを
ロードし、ポートの入出力時に文字コード変換を行います。
CESについて詳しくはサポートされる文字エンコーディングを参照してください。
:conversion-buffer-size
この引数は、文字エンコーディング変換に使うバッファサイズを指定するために encoding引数と共に使うことができます。渡された値はそのまま 文字コード変換ポートのコンストラクタのbuffer-size引数に渡されます (変換ポート参照)。
この引数を指定する必要は滅多にありませんが、入力ファイルの文字エンコーディングを 推測しなければならない場合、大きめのバッファサイズの方が精度が上がります。 推測ルーチンがより多くのデータを見て文字エンコーディングを決定できるからです。
if-existsとif-does-not-existフラグの組合せにより、 色々な動作を実現できます。
(open-output-file "foo" :if-exists :error) ⇒ ;"foo"を排他的にオープンするかエラーを報告する (open-output-file "foo" :if-exists #f) ⇒ ;"foo"を排他的にオープンするか#fを返す (open-output-file "foo" :if-exists :append :if-does-not-exist :error) ⇒ ;"foo"が既に存在する場合に限り、それを追加モードでオープン |
ファイルをオープンせずにその存在をチェックするには、
sys-access
かfile-exists?
を使って下さい (ファイルの状態参照)。
移植性に関する註:Schemeシステムによっては、filenameのところに
シェルコマンドを指定して、サブプロセスの標準入出力と通信できるようにするものが
あります。他のスクリプティング言語(例:Perl)にも同様の機能があります。
Gaucheでは、open-input-file
とopen-output-file
は
あくまでファイル (OSがファイルとして扱うもの) のみに対して使えます。
サブプロセスと通信するためには、「プロセスポート」という機能が提供されています。
Process portsを参照して下さい。
[R5RS] stringで示されるファイルを入力または出力用にオープンし、 作成されたポートを引数として手続きprocを呼び出します。 procが正常終了するか、proc内で捕捉されないエラーが起きた場合に ファイルはクローズされます。
キーワード引数は
open-input-file
及びopen-output-file
のものと同じ意味を持ちます。
if-existsやif-does-not-existに#f
を指定した場合、
ファイルがオープンされなかった場合はprocにポートではなく#f
が渡される
ことに注意して下さい。
procが返す値を返します。
[R5RS] stringで示されるファイルを入力または出力用にオープンし、オープンされた ポートを現在の入力または出力ポートに設定して、thunkを呼び出します。 thunkが戻るか、thunk内で捕捉されないエラーが生じた際にファイルは閉じられます。
thunkが返す値を返します。
キーワード引数は
open-input-file
及びopen-output-file
のものと同じ意味を持ちます。
但しif-existsやif-does-not-existに#f
が指定され、
ファイルがオープンできなかった場合は、thunkは呼ばれずに
直ちに#f
が返されます。
ポートを閉じるセマンティクスについて:
R5RSはcall-with-input-file
等の説明において、次のように述べています。
「procが戻って来なかった場合、今後ポートが読み書きに一切使われないことが
証明できない限りは、ポートは自動的には閉じられない」。
Gaucheの実装は若干この条件には反しています。捕捉されないエラーがprocから 発せられたというだけでは、そのポートが今後一切使われないかどうかはわかりません。 しかし実際には、そのようなエラーが発せられた後でポートに対して意味のある操作をするのは 非現実的です。ポートがどのような状態にあるかわからないわけですから。 現実的なプログラムでは、ポートに対して意味のある操作をしつづけたいのなら、 procの中で明示的にエラーをハンドルすべきでしょう。
call-with-input-file
の外で捕捉された継続をproc内で呼んだ場合には
ポートは閉じられないことに注意して下さい。後でprocへと制御が戻ってくるかも
しれないからです (コルーチン等)。また、
低レベルの例外メカニズム(例外の処理
参照)を利用した場合、エラー時にポートを閉じるのはプログラマの責任になります。
与えられたファイルディスクリプタにアクセスする入力または出力ポートを
作成して返します。buffering はopen-input-file
の項で
説明されたポートのバッファリングモードを指定します。デフォルトは:full
です。
nameはport-name
によって返されるポートの名前を指定します。
owner? は、このポートを閉じた時にfdもクローズすべきかどうかを
指定するブーリアン値です。
システムのdup2(2)
のインタフェースです。
アトミックにtoportのファイルディスクリプタをクローズし、fromportの
ファイルディスクリプタを複製したものをtoportに設定します。
toport、fromportはいずれもファイルポートでなければなりません。
ファイルディスクリプタが「複製」されると、ふたつのディスクリプタ番号が異なっていても
それらはシステムのオープンファイルテーブルの同じエントリを指します。
例えば、現在の(システムレベルでの)ファイル上の読み書き位置は共有されます。
port-fd-dup!
の後で、port-seek
をfromportに
対して呼び出せば、その変更はtoportの読み書き位置にも影響を与えるでしょうし、
その逆もまたあります。ただし、共有されるのはシステムレベルの情報のみで、
toportやfromportがバッファリングされている場合、バッファの内容は
共有されません。
この手続きは、主にファイルディスクリプタを明示的に制御する必要のあるプログラム
のために用意されています。例えばデーモンプロセスがその入出力を‘/dev/null’などの
無難なデバイスに切り替えたり、シェルプロセスが子プロセスをexec
する前に
そのファイルディスクリプタをセットアップしたりするような場合です。
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
文字列ポートは、メモリ上のデータと関連付けられたポートです。
[SRFI-6]
stringを内容とする入力文字列ポートを作って返します。
文字列に逐次的にアクセスする場合、インデックスをインクリメントしながら
string-ref
を呼び出すより効率の良い方法です。
(define p (open-input-string "文字 列")) (read p) ⇒ 文字 (read-char p) ⇒ #\space (read-char p) ⇒ #\列 (read-char p) ⇒ #<eof> (read-char p) ⇒ #<eof> |
portは入力文字列ポートでなければなりません。 入力ポートに残っている文字列を返します。 portの内部ポインタは動かされないので、portに対するreadは 影響を受けません。portが既にEOFに達していた場合は、空文字列が返されます。
(define p (open-input-string "abc\ndef")) (read-line p) ⇒ "abc" (get-remaining-input-string p) ⇒ "def" (read-char p) ⇒ #\d (read-line p) ⇒ "ef" (get-remaining-input-string p) ⇒ "" |
[SRFI-6]
出力文字列ポートを作成して返します。このポートに書き出された文字列は
内部のバッファにたくわえられ、get-output-string
で取り出すことが
できます。
これは、順番に文字列を構成する方法として、あらかじめ文字列をアロケートして
string-set!
で埋めて行くよりもずっと効率の良い方法です。
[SRFI-6]
出力文字列ポートport
を取り、それまでそのポートに蓄積された
文字列を返します。バイトデータがそのポートに書き出されていた場合、
この手続きはまず内部バッファをスキャンし、結果が完全な文字列で表現できるかどうかを
調べます。もし表現できなければ、不完全な文字列が返されます。
これはportの操作には影響をあたえません。get-ouptut-string
を
呼んだ後でも、portに内容を蓄積しつづけることができます。
これらのユーティリティ関数は次に定義されるような動作をします。 インタフェースはファイルポートを扱う類似の関数と揃えてあります。
(define (call-with-output-string proc) (let ((out (open-output-string))) (proc out) (get-output-string out))) (define (call-with-input-string str proc) (let ((in (open-input-string str))) (proc in))) (define (with-output-to-string thunk) (let ((out (open-output-string))) (with-output-to-port out thunk) (get-output-string out))) (define (with-input-from-string str thunk) (with-input-from-port (open-input-string str) thunk)) |
(define (call-with-string-io str proc) (let ((out (open-output-string)) (in (open-input-string str))) (proc in out) (get-output-string out))) (define (with-string-io str thunk) (with-output-to-string (lambda () (with-input-from-string str thunk)))) |
文字列ポートを使う定型句をユーティリティ関数にしました。
(write-to-string obj writer) ≡ (with-output-to-string (lambda () (writer obj))) (read-from-string string) ≡ (with-input-from-string string read) |
writerの既定値はwrite
です。start, endは
省略されればそれぞれ0と文字列の長さになります。
移植性への註:Common Lispに同名の関数があります。必須引数の動作は同じですが、
省略可能な引数は異なります。
STkにはread-from-string
がありますが、省略可能な引数は取りません。
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
コーディング認識ポートは特殊な手続的入力ポートで、load
が
プログラムソースコードを読む際に使われています。このポートは
;; -*- coding: utf-8 -*-
のような、プログラムソースの
文字エンコーディングを指定する特殊なコメントを認識し、適切な
文字エンコーディング変換を行います。
特殊なコメントでソースの文字エンコーディングを指定することについては、
マルチバイトスクリプトを参照して下さい。
入力ポートを引数としてとりコーディング認識入力ポートを返します。 基本的には iport からの入力データをリーダにわたしているだけです。 しかし、iport からの入力データの最初の2行以内に、特別な呪文コメント が現れた場合、コーディング認識ポートは、その後に読み込まれるデータについて 必要な文字エンコーディング変換を行います。
引数として渡されたポート、iport は生成されたコーディング認識 ポートによって所有されます。つまり、コーディング認識ポートがクローズ されると、iport もクローズされます。iport から読み込まれた 内容はコーディング認識ポート内でバッファリングさます、したがって、 別のコードで iport から読み出しを行うべきではありません。
デフォルトでは、Gauche の load
はプログラムソースを読むのに
コーディング認識ポートを使います。したがって、文字エンコーディングを
示す特別な呪文コメントは、Gauche のソースプログラムでは有効になります
(Schemeファイルのロード参照)。ただし、この機構自身は load
とは
独立しており、このポートを別の目的で利用できます。特にコーディングの
呪文コメントがある Scheme のソースプログラムを処理する関数を書くときに
便利です。
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
入力に関する手続きで、省略可能な引数iportは入力ポートでなければなりません。 省略された場合が現在の入力ポートが使われます。
6.19.7.1 データの読み込み | ||
6.19.7.2 読み込み時コンストラクタ | ||
6.19.7.3 入力ユーティリティ手続き |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
[R5RS] iportからS式をひとつ読み込んで返します。 GaucheはR5RSに定義されている構文要素に加え、字句構造に 定義されている拡張構文要素を認識します。
iportが既にEOFに達していた場合は、EOFオブジェクトが返されます。
この手続きはS式を構成する最後の文字までを読み、その後の文字はポートに
残します。これは、S式に続く空白文字も読み込むCommonLispのread
の
振る舞いとは異なります。
[SRFI-38]
これらの手続きは、SRFI-38 で定義されていて、共有構造を表す記法
(#n=
, #n#
)を認識できます。Gauche の組み込み read
は
この SRFI-38 の記法を認識します。それゆえ、これらの手続きは、read
と同じで、SRFI-38 との互換性のために用意されています。
[R5RS] iportから1文字読み込んで返します。 iportが既にEOFに達していた場合はeofオブジェクトを返します。 iportにあるバイトストリームが正しい文字を構成しない場合、 ふるまいは未定義です。(将来はポート側に、不正な文字に対する対応を決める オプションを設ける予定です)。
[R5RS] iportから1文字読み込んで返します。文字はそのままiportに留まります。 iportが既にEOFに達していた場合はeofオブジェクトを返します。 iportにあるバイトストリームが正しい文字を構成しない場合、 ふるまいは未定義です。(将来はポート側に、不正な文字に対する対応を決める オプションを設ける予定です)。
入力ポートiportから1バイト読み込み、0から255までの整数値として返します。 iportが既にEOFに達していた場合はeofオブジェクトを返します。
入力ポートiportの先頭の1バイトを見て、それを0から255までの整数値として返します。 iportが既にEOFに達していた場合はeofオブジェクトを返します。
入力ポートから、行末もしくはEOFまで読み込んで文字列として返します。 よく使われる行末 (LF only, CRLF, and CR only) を認識します。 戻り値にはこれらの行末文字は含まれません。 iportが既にEOFに達していた場合はeofオブジェクトを返します。
iportから、内部文字エンコーディングでは文字を構成し得ないバイトシーケンスが
読まれた場合、デフォルトではread-line
はエラーを通知します。
しかし、省略可能な引数allow-byte-string?に真の値が与えられた場合は、
read-line
はエラーを通知せず、かわりにバイト文字列 (不完全な文字列) を
返します。この動作は、特に文字エンコーディングが不明なソースから読み込む際に
便利です。例えばXMLドキュメントを読み込む際、最初の行のcharsetパラメータを
チェックしてから適切な文字エンコーディング変換ポートを使うといった用途などです。
nbytesバイトのデータをiportから読み込み、 不完全な文字列として返します。iportに十分なデータが無い場合、 返される文字列はnbytesより短いかもしれません。 nbytesが0の場合は、常に空文字列が返されます。
iportが既にEOFに達していた場合はEOFオブジェクトが返されます。
iportがファイルポートだった場合、read-block
は
ポートのバッファリングモードによってふるまいが異なります
(バッファリングモードの詳細についてはファイルポートを参照して下さい)。
:full
の場合、read-block
は
EOFを読まない限り、nbytesのデータが読まれるまで待ちます。
:modest
か:none
である場合、
read-block
はEOFが読まれなくても、すぐに読めるデータがnbytesよりも
少ない場合はそのデータだけを返します。
read-block
は呼ばれるたびに新たな文字列をアロケートします。
アロケーションを避け、あらかじめ用意された固定長のバッファにデータを読み込みたい
場合は、gauche.uvector
モジュールのread-block!
を使って下さい (ユニフォームベクタのブロック入出力参照)。
Read-block!
はuniform vectorをバッファとして用います。
データブロックをポートに書き出すには、データが文字列で表現されている
場合は単純にdisplay
が使えます。データがuniform vectorで表現されている
場合はgauche.uvector
モジュールのwrite-block
が
使えます (ユニフォームベクタのブロック入出力参照)。
[R6RS] EOFオブジェクトを返します。
[R5RS]
objがEOFオブジェクトなら#t
を返します。
[R5RS]
portから文字が読み出せる状態ならば#t
を返します。
今のところ、この手続きはportから少なくとも1バイト読み出せる状態なら#t
を返します。そのバイトがマルチバイト文字を構成する場合、char-ready?
を返した
ポートから文字全てを読み込もうとすると、ブロックする可能性があります。
(通常の使用状況ではそのようなことは起きないでしょうが、理論的には起こり得ます。
慎重を期したい場合はread-block
でバイトシーケンスとして読み込んだ後、
入力文字列ポート等を使って文字毎に読むようにして下さい。)
If one byte (octet) is ready to be read from port, returns
#t
.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
SRFI-10で定義されている読み込み時コンストラクタは、ユーザ定義の構造の 外部表現を作るための簡単な方法を提供します。
#,(tag arg …)
[SRFI-10] Gaucheはtag (シンボル)をコンストラクタ手続きに関連付ける グローバルなテーブルを管理しています。
リーダーがこの構文に出会ったとき、arg …を読み込み、 tagに関連付けられた読み込みコンストラクタを探し、 arg …を引数としてそのコンストラクタを呼び出し、 その構文を読み込んだ結果としてそのコンストラクタが返した値を挿入します。
この構文はリーダー内部で処理されることに注意して下さい。評価器は argを見ず、リーダーが返したオブジェクトしか見ません。
[SRFI-10] 読み込みコンストラクタprocedureをtagに関連付けます。
例:
(define-reader-ctor 'pi (lambda () (* (atan 1) 4))) #,(pi) ⇒ 3.141592653589793 '(#,(pi)) ⇒ (3.141592653589793) (define-reader-ctor 'hash (lambda (type . pairs) (let ((tab (make-hash-table type))) (for-each (lambda (pair) (hash-table-put! tab (car pair) (cdr pair))) pairs) tab))) (define table #,(hash eq? (foo . bar) (duh . dah) (bum . bom))) table ⇒ #<hash-table eq? 0x80f9398> (hash-table-get table 'duh) ⇒ dah |
write-object
メソッド(出力参照)と組み合わせて、
読み戻ることが可能なフォームで書かれたユーザ定義のクラスを
作ることが簡単になります。
(define-class <point> () ((x :init-value 0 :init-keyword :x) (y :init-value 0 :init-keyword :y))) (define-method write-object ((p <point>) out) (format out "#,(<point> ~s ~s)" (ref p 'x) (ref p 'y))) (define-reader-ctor '<point> (lambda (x y) (make <point> :x x :y y))) |
注意: define-reader-ctor
の効果の範囲はSRFI-10には
規定されておらず、SRFI-10をサポートする実装においても互換性の問題を
起こすことがあるかもしれません。
(実際に、define-reader-ctor
の存在そのものが実装の選択に
任されています。)
Gaucheでは、現時点においては、define-reader-ctor
はそのフォームが
コンパイルされ評価された時点で効力を持ちます。
Gaucheはトップレベルのフォームを順番にコンパイル・評価するので、
define-reader-ctor
で指定されたtagは、その指定の直後から
使えます。
しかし、define-reader-ctor
の呼び出しとtagの使用が
begin
フォームで囲まれている場合は、begin
フォーム全体は
評価される前に一度にコンパイルされるため、うまく動作しません。
他の実装では、define-reader-ctor
の呼び出しが効力を持つようにする
前にファイル全体を読み込むことを要求するかも知れません。
その場合は、define-reader-ctor
と定義されたtagの使用を
同じファイルに置く事は実質的に不可能です。
可能ならば、define-reader-ctor
の呼び出しと、tagの使用は
異なるファイルに分離されることが望まれます。
現在のdefine-reader-ctor
に関するもう1つの問題は、それが
Gaucheシステムのグローバルテーブルを変更してしまうことで、それゆえに
モジュール性が良くありません。
複数人によって書かれたコードは同じタグを使っているかも知れず、
期待されない結果を引き起こすかも知れません。
作者にはまだ明確なアイデアがありませんが、将来のバージョンでは、
Gaucheにはtagのスコープをカプセル化する方法が導入されるかも
しれません。
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
便利な入力手続きです。APIはScshとSTkから取りました。
port->string
はportをEOFまで読み込み、
読んだものを文字列として返します。
port->list
は手続きreaderをportに繰り返し適用し、
結果をリストに蓄積します。readerがEOFを返したら
蓄積されたリストを返します。
(port->string-list port)
≡
(port->list read-line port)
であり、
(port->sexp-list port)
≡
(port->list read port)
です。
readerによって読まれる入力に対する便利な繰り返し手続きです。 基本的に、readerが引数無しでEOFを返すまで繰り返し呼ばれ、 それが返した値に対してfnが呼ばれます。 readerはいずれEOFを返す手続きなら、入力ポートと関係している必要はありません。
readerが要素 {X0, X1, …, Xn} を返したとすると、
port-fold
は次の値を返します。
(fn Xn (fn Xn-1 … (fn X0 knil))) |
一方、port-fold-rightは次の値を返します。
(fn X0 (fn X1 … (fn Xn knil))) |
すなわち、(port-fold cons '() read)
は全ての入力の逆リストを
返し、(port-fold-right cons '() read)
は
(port->list read port)
と同じものを返します。
port-for-each
とport-map
はfnを読まれた要素に
次々と適用します。前者はfn
の結果を捨てますが、後者はfn
の
結果をリストにして返します。
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
以下の手続きで、省略可能な引数portは出力ポートでなければなりません。 省略された場合が現在の出力ポートが使われます。
[R5RS]
オブジェクトobjの表示可能な表現を生成し、出力ポートに書き出します。
write
は可能な限り、objの標準的な外部表現を使い、
生成された出力がread
で再び読み込めるようにします。
displayはより人間にとって可読性の高い出力を生成します。
write
やdisplay
が表示中にユーザ定義クラスのオブジェクトに
出会った場合は、ジェネリックファンクションwrite-object
を呼び出します。
objが循環する構造を持っていた場合、これらの手続きは停止しないかも
しれません。write/ss
を参照して下さい。
[SRFI-38]
write
と同じような出力を生成しますが、これらの手続きはさらに
共有される部分構造や循環構造を認識し、#n=
, #n#
構文を使って
それらを表現します。
(write/ss (let ((x (list 'a))) (list x x))) ⇒ ;; writes (#0=(a) #0#) (write/ss (let ((x (list 'a))) (set-cdr! x x) x)) ⇒ ;; writes #0=(a . #0#) |
read
手続きもこの構文を認識するので、読み込めば
もとの構造と同型の構造が得られます。
3つの手続きは等価です。
Gaucheは、STklosから取ったwrite*
という名前を長く使ってきましたが、
srfi-38によってwrite-with-shared-structure
とwrite/ss
が
定義されました。今後は後者の名前を使った方がポータブルでしょう。
註: ユーザ定義のwrite-object
メソッドはこれらの手続きに対して
透過的に動作します。
expr … をdisplay
を使って現在の出力ポートに表示し、
最後に改行を書き出します。
このメソッドをつかって、オブジェクトをどのように印字するかをカスタマイズ できます。
[R5RS] portに改行文字を書き出します。
それぞれ、port、および全てのポートにバッファされているデータを 全て書き出します。
手続き"flush"はScheme実装によって様々な名前で呼ばれています:
force-output
(Scsh, SCM)、
flush-output
(Gambit)、flush-output-port
(Bigloo) 等。
flush
の名前はSTkとSTklosから取りました。
[R5RS] 文字charをポートに出力します。
出力ポートに1バイトのデータbyteを書き出します。 byteは0から255の間の正確な整数でなければなりません。
[SRFI-28+]
string の指示に従い、arg …をフォーマットします。
この手続きはCommonLispのformat
のサブセットに、Gauche独自の拡張を
加えたものです。また、これはSRFI-28 "Basic format strings" のスーパーセットに
なっています (SRFI-28)。
portは出力先を指定します。それが出力ポートであれば、フォーマットされた
結果はそのポートに書き出されます。portが#t
であれば、結果は
現在の出力ポートに書き出されます。portが#f
であれば、結果は
文字列としてformat
から返されます。
portは省略することもできます。その場合は、port
に#f
を指定したのと同じ動作をします(SRFI-28のformat
)。
stringはフォーマット指示子を含んだ文字列です。
フォーマット指示子はチルダ`~
'から始まり、特定の文字で終了する文字の並びで、
それぞれのフォーマット指示子が対応するargを取りフォーマットします。
string内のフォーマット指示子以外の文字列はそのまま出力されます。
(format #f "the answer is ~s" 42) ⇒ "the answer is 42" |
フォーマット指示子は一つ以上のコンマで区切られたパラメータを取ることもできます。 パラメータは整数か文字です。文字の場合、クオート文字に続けてその文字を置きます。 パラメータが省略された場合は既定値が使われます。パラメータの意味はフォーマット指示子毎に 異なります。
さらに、フォーマット指示子は2種類のフラグ、`@
' と `:
' を
取ることができます。これらの組合せでフォーマットの動作が変わります。フラグは
(もしあれば)パラメータの後、指示子の文字の直前に置かれなければなりません。
パラメータの位置に文字 `v
' か `V
' を置くこともできます。
その場合、パラメータの値が引数リストから取られます。対応する引数は整数か
文字、または#f
でなければなりません。#f
の場合はそのパラメータが
省略されたのと同じになります。
いくつかの例です。
~10,2s
パラメータ10と2を伴う、フォーマット指示子~s
。
~12,,,'*A
第1パラメータに数値12、第4パラメータに文字`*
'を取るフォーマット指示子~a
。
第2と第3のパラメータは省略されています。
~10@d
フォーマット指示子~d
。パラメータ10と`@
'フラグがついています。
~v,vx
フォーマット指示子~x
。第1パラメータと第2パラメータは引数リストから取られます。
以下にサポートされているフォーマット指示子を示します。フォーマット指示子の文字自体は 大文字であっても小文字であっても構いません。特に断りのない限り両者は同じ動作をします。
ASCII出力。対応する引数がdisplay
を使ってフォーマットされます。
整数がmincolに与えられた場合、それは出力される最小の文字数を指定します。
引数のフォーマット結果がmincolより短ければ、空白が右に追加されます(つまり、
左詰めになります)。
colinc、minpad、そしてpadcharは更に細かいパディング方法を 指定します。padcharに文字が与えられた場合、それが空白文字の代わりにパディング文字と して使われます。minpadに0以上の整数が与えられた場合、少なくともその数だけの パディング文字が追加されます。colincが指定された場合、 追加されるパディング文字の数がcolincの倍数に調整されます。
アトマーク `@
' フラグが与えられた場合、結果は右詰めになります。
maxcolパラメータは与えられていれば書かれる文字数の上限を指定します。
フォーマット後の文字列の長さがmaxcolを超えた場合、maxcol文字だけが
書かれます。コロン `:
' フラグが同時に与えられていれば、
maxcol - 4 文字が書かれた後、文字列“ ...
”が書かれます。
(format #f "|~a|" "oops") ⇒ "|oops|" (format #f "|~10a|" "oops") ⇒ "|oops |" (format #f "|~10@a|" "oops") ⇒ "| oops|" (format #f "|~10,,,'*@a|" "oops") ⇒ "|******oops|" (format #f "|~10,,,'☆a|" "oops") ⇒ "|oops☆☆☆☆☆☆|" (format #f "|~,,,,10a|" '(abc def ghi jkl)) ⇒ "|(abc def gh|" (format #f "|~,,,,10:a|" '(abc def ghi jkl)) ⇒ "|(abc de ...|" |
S式出力。対応する引数がwrite
を使ってフォーマットされます。
パラメータの意味は~A
指示子と同じです。
(format #f "|~s|" "oops") ⇒ "|\"oops\"|" (format #f "|~10s|" "oops") ⇒ "|\"oops\" |" (format #f "|~10@s|" "oops") ⇒ "| \"oops\"|" (format #f "|~10,,,'*@s|" "oops") ⇒ "|****\"oops\"|" (format #f "|~10,,,'★s|" "oops") ⇒ "|\"oops\"★★★★|" |
10進出力。対応する引数が10進数表記でフォーマットされます。もし引数が数値でなければ、
全てのパラメータは(`v
'パラメータの処理後に)無視され、
引数は~A
でフォーマットされます。
もしmincolに整数が与えられたら、それが最小の文字数を指定します。 結果の文字数がそれより少なければ、文字padcharが左に追加されます(右詰めになります)。 padcharが省略された場合は空白文字が使われます。
(format #f "|~d|" 12345) ⇒ "|12345|" (format #f "|~10d|" 12345) ⇒ "| 12345|" (format #f "|~10,'0d|" 12345) ⇒ "|0000012345|" |
アトマーク `@
' フラグが与えられた場合、正の引数に対して `+
' が
先頭につけられます。
コロンフラグ `:
' が与えられた場合、結果の文字はinterval文字毎に
まとめられ、間に文字commacharが挿入されます。デフォルトでは3文字毎にコンマが
挿入されます。
(format #f "|~:d|" 12345) ⇒ "|12,345|" (format #f "|~,,'_,4:d|" -12345678) ⇒ "|-1234_5678|" |
2進出力。対応する引数が2進数の整数としてフォーマットされます。
パラメータの意味は~D
と同じです。
8進出力。対応する引数が8進数の整数としてフォーマットされます。
パラメータの意味は~D
と同じです。
16進出力。対応する引数が16進数の整数としてフォーマットされます。
フォーマット指示文字に `X
' が与えられた場合は `ABCDEF
' が桁文字として
使われ、 `x
' が与えられた場合は `abcdef
' が桁文字として使われます。
パラメータの意味は~D
と同じです。
(format #f "~8,'0x" 259847592) ⇒ "0f7cf5a8" (format #f "~8,'0X" 259847592) ⇒ "0F7CF5A8" |
引数のカウンタをcountだけ後方にずらします。つまり、count個の引数が
無視されることになります。countのデフォルト値は1です。
コロンフラグが与えられた場合は引数カウンタを前方に動かします。
例えば~:*
は次のディレクティブが直前に使った引数を再び使うようにします。
アトマークフラグが与えられた場合は、countが引数の絶対位置を示します。
0が最初の引数です。
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] |
This document was generated by Shiro Kawai on November, 22 2009 using texi2html 1.78.