[ << ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
オペレーティングシステムの用語では、 プロセス(process)とは、プログラムを実行する空間のことです。 Emacsはプロセスとして動いています。 Emacs Lispのプログラムでは、 独自のプロセスとして他のプログラムを起動できます。 それらは、Emacsプロセスのサブプロセス(subprocess)とか 子プロセス(child process)と呼ばれ、 Emacsプロセスはそれらの親プロセス(parent process)です。
Emacsのサブプロセスは、それを作成する方法に依存して、 同期(synchronous)であるか非同期(asynchronous)です。 同期サブプロセスを作成すると、 Lispプログラムは実行を継続するまえにそのサブプロセスの終了を待ちます。 非同期サブプロセスを作成すると、それはLispプログラムと並行して動作します。 この種のサブプロセスは、Emacs内部ではやはり『プロセス』と呼ばれる Lispオブジェクトで表現されます。 Lispプログラムはこのオブジェクトを用いて サブプロセスと通信したりそれを制御できます。 たとえば、シグナルを送ったり、状態情報を取得したり、 プロセスからの出力を受け取ったり、プロセスへ入力を送れます。
t
を返し、
さもなければnil
を返す。
36.1 サブプロセス作成関数 | Functions that start subprocesses. | |
36.2 シェル引数 | Quoting an argument to pass it to a shell. | |
36.3 同期プロセスの作成 | Details of using synchronous subprocesses. | |
36.4 非同期プロセスの作成 | Starting up an asynchronous subprocess. | |
36.5 プロセスの削除 | Eliminating an asynchronous subprocess. | |
36.6 プロセス情報 | Accessing run-status and other attributes. | |
36.7 プロセスへ入力を送る | Sending input to an asynchronous subprocess. | |
36.8 プロセスにシグナルを送る | Stopping, continuing or interrupting an asynchronous subprocess. | |
36.9 プロセスからの出力を受け取る | Collecting output from an asynchronous subprocess. | |
36.10 番兵:プロセスの状態変化の検出 | Sentinels run when process run-status changes. | |
36.11 トランザクションキュー | Transaction-based communication with subprocesses. | |
36.12 ネットワーク接続 | Opening network connections. |
プログラムを実行するために新たなサブプロセスを作る関数が3つあります。
その1つstart-process
は、非同期プロセスを作成して
プロセスオブジェクトを返します(see section 36.4 非同期プロセスの作成)。
残りの2つ、call-process
とcall-process-region
は
同期プロセスを作成しますが、プロセスオブジェクトは返しません
(see section 36.3 同期プロセスの作成)。
同期/非同期プロセスについては以下の節に述べます。 3つの関数の呼び出し方は類似しているので、 ここではそれらに共通な引数について述べます。
いずれの場合でも、関数の引数programは、
実行すべきプログラムを指定します。
そのファイルがみつからなかったり実行できないと、
エラーを通知します。
ファイル名が相対名であると、
変数exec-path
は探索すべきディレクトリのリストを保持しています。
Emacsは起動時に環境変数PATH
の値に基づいてexec-path
を
初期化します。
`~'、`.'、`..'のファイル名の標準的な書き方は、
exec-path
でも普通どおりに解釈されますが、
(`$HOME'などの)環境変数の置換は認識しません。
それにはsubstitute-in-file-name
を使います
(see section 24.8.4 ファイル名を展開する関数)。
サブプロセスを作成する各関数には、
プログラムの標準出力の受け取り場所を指定する
引数buffer-or-nameがあります。
これはバッファかバッファ名である必要があります。
バッファ名であると、そのバッファが既存でなければ新たに作成します。
nil
でもかまいませんが、その場合、
フィルタ関数で処理しない限り出力を破棄します。
(36.9.2 プロセスフィルタ関数とsee section 18. Lispオブジェクトの読み取りと表示)。
通常、複数のプロセスの出力を同じバッファへは送らないようにします。
それらの出力がでたらめに混ざってしまうからです。
サブプロセスを作成する3つの関数すべてに、
&rest
引数であるargsがあります。
argsはすべてが文字列である必要があり、
それぞれを区切ってコマンド行引数としてprogramに与えられます。
引数全体を指定されたプログラムへ直接渡すため、
これらの引数ではワイルドカード文字や他のシェル構文の特別な意味はありません。
注意:
引数programにはプログラムの名前だけを指定し、
コマンド行引数はいっさい指定しない。
コマンド行引数はargsで与えること。
サブプロセスのカレントディレクトリは
default-directory
の値で決まります(see section 24.8.4 ファイル名を展開する関数)。
サブプロセスはEmacsから環境変数を継承しますが、
優先するものをprocess-environment
で指定できます。
See section 37.3 オペレーティングシステム環境。
movemail
はそのようなプログラムの例であり、
inboxから新たなメイルを取り出すためにrmailが利用する。
default-directory
の値)
を意味するnil
である。
引数programが絶対ファイル名でないと、
call-process
とstart-process
は
exec-path
の値を使う。
Lispプログラムから、
ユーザーが指定したファイル名を含んだコマンドを指定して
シェルを実行する必要がときどきあります。
これらのプログラムでは、任意の正しいファイル名を扱える必要があります。
しかし、シェルは、特定の文字がファイル名として現れると特別に扱うので、
そのような文字がシェルに混乱をもたらします。
そのような文字を扱うには、関数shell-quote-argument
を使います。
この関数が行うことの詳細は読者のオペレーティングシステムに依存する。 この関数は通常のシェル構文に合うように設計してある。 非標準のシェルを使う場合には、この関数を再定義する必要があろう。 MS-DOSでは、この関数はargumentを無変更で返す。 MS-DOSのシェルにはクォートの機能がないため、 これは本当は正しいことではないが最良のことである。
;; つぎの例はGNUとUNIXシステムのふるまいである (shell-quote-argument "foo > bar") => "foo\\ \\>\\ bar" |
シェルコマンドを作るshell-quote-argument
の使用例をつぎに示す。
(concat "diff -c " (shell-quote-argument oldfile) " " (shell-quote-argument newfile)) |
同期プロセス(synchronous process)を作成すると、
Emacsは実行を続行するまえにそのプロセスが終了するのを待ちます。
diredはその例です。
ls
を同期プロセスで実行し、その出力を少々修正します。
プロセスは同期なので、Emacsがなにかを行おうとするまえに
ディレクトリ一覧全部がバッファに届きます。
Emacsは同期サブプロセスの終了を待ちますが、
ユーザーはC-gと打って中断できます。
C-gはまずシグナルSIGINT
でサブプロセスをキルしようとしますが、
中断を完了するまえにサブプロセスが終了するのを待ちます。
その期間にユーザーがさらにC-gを打つと、
SIGKILL
でサブプロセスを即座にキルし、ただちに中断を完了します。
See section 20.9 中断。
同期サブプロセス作成関数は、 そのプロセスがどのように終了したかを表すものを返します。
同期サブプロセスからの出力は、ファイルから読むテキストと同様に、
コーディングシステムを用いて一般には復号化します。
call-process-region
がサブプロセスへ送る入力は、
ファイルへ書くテキストと同様に、
コーディングシステムを用いて符号化します。
See section 32.10 コーディングシステム。
infileがnil
でなければ
プロセスへの標準入力はinfileであるが、
さもなければ`/dev/null'である。
引数destinationでプロセスの出力先をつぎのように指定する。
t
nil
この場合、このプロセスはEmacsと並行して動作するので真のサブプロセスではない。 しかし、この関数から戻るとEmacsはサブプロセスの処理を本質的には終えたと いう意味で同期プロセスと考えることができる。
(real-destination error-destination)
nil
であるとエラー出力を破棄し、
t
であると通常の出力に混ぜ、
文字列であるとその名前のファイルにエラー出力を振り向ける。
エラー出力を入れるバッファを直接に指定することはできない。 それを実装するのは難しすぎる。 しかし、エラー出力を一時ファイルへ送ってから そのファイルをバッファに挿入すれば、同じ効果を得られる。
displayがnil
以外であると、call-process
は、
出力が挿入されるとバッファを再表示する。
(しかし、コーディングシステムとして実際のデータから
コーディングシステムを推定するundecided
を指定していると、
非ASCII文字に出会うと再表示を継続できない場合もある。
これを修正するのが困難である根本的な理由がある。)
さもなければ、関数call-process
は再表示しないので、
Emacsが通常の過程でそのバッファを再表示するまでは、
スクリーン上で結果は見えない。
残りの引数argsは、プログラムに対する コマンド行引数を指定する文字列である。
(待たないように指示しない限り)call-process
が返す値は、
プロセスの終了理由を表す。
数でサブプロセスの終了状態を表し、
0は成功、それ以外の値は失敗を意味する。
プロセスがシグナルで終了すると、
call-process
はシグナルを記述する文字列を返す。
つぎの例では、バッファ`foo'がカレントである。
(call-process "pwd" nil t) => nil ---------- Buffer: foo ---------- /usr/user/lewis/manual ---------- Buffer: foo ---------- (call-process "grep" nil "bar" nil "lewis" "/etc/passwd") => nil ---------- Buffer: bar ---------- lewis:5LTsHm66CSWKg:398:21:Bil Lewis:/user/lewis:/bin/csh ---------- Buffer: bar ---------- |
insert-directory
の定義にあるcall-process
の
よい使用例をつぎに示す。
(call-process insert-directory-program nil t nil switches (if full-directory-p (concat (file-name-as-directory file) ".") file)) |
nil
以外であると、送ったテキストを削除する。
これは、カレントバッファに送った入力のかわりに出力を挿入することを
意味するdestinationがt
であるときに有用である。
引数destinationとdisplayは、
サブプロセスからの出力をどのように扱い、
出力か到着するたびに表示を更新するかどうかを制御する。
詳しくは、上記のcall-process
の記述を参照。
destinationが整数0であると、
call-process-region
は、サブプロセスの終了を待たずに
出力を破棄してただちにnil
を返す。
残りの引数argsは、プログラムに対する コマンド行引数を指定する文字列である。
call-process-region
の戻り値はcall-process
と同様であり、
待たずに戻るように指示するとnil
であり、
さもなければサブプロセスの終了状態を表す数か文字列である。
つぎの例では、
バッファ`foo'の始めの5文字(単語`input')を標準入力として
ユーティリティcat
を実行するためにcall-process-region
を使う。
cat
は、標準入力を標準出力へコピーする。
引数destinationがt
であるので、
出力はカレントバッファに挿入される。
---------- Buffer: foo ---------- input-!- ---------- Buffer: foo ---------- (call-process-region 1 6 "cat" nil t) => nil ---------- Buffer: foo ---------- inputinput-!- ---------- Buffer: foo ---------- |
コマンドshell-command-on-region
は、
つぎのようにcall-process-region
を使う。
(call-process-region
start end
shell-file-name ; プログラムの名前
nil ; リージョンを削除しない
buffer ; 出力は |
非同期プロセスを作成すると、Emacsとサブプロセスの両者は ただちに動作を継続します。 そしてプロセスはEmacsと並行に動作し、 両者は以下の節に述べる関数を用いて互いに通信できます。 しかし、通信は部分的に非同期です。 特定の関数を呼び出したときにだけEmacsはプロセスへデータを送り、 Emacsが入力待ちか時間待ちをしているときにだけ プロセスからの出力を受け取れます。
ここでは、非同期プロセスの作成方法について述べます。
残りの引数argsは、プログラムに対する コマンド行引数を指定する文字列である。
つぎの例では、最初のプロセスは動き始めると 100秒間(休止ではなく)動作する。 そのあいだに2番目のプロセスを動かし始めると、 一意であるためにそれには名前`my-process<1>'が与えられる。 2番目のプロセスは、最初のプロセスが終了するまえに バッファ`foo'にディレクトリ一覧を挿入する。 2番目のプロセスが終了するとそれを表すメッセージがバッファに挿入される。 しばらくして最初のプロセスが終了すると、 別のメッセージがバッファに挿入される。
(start-process "my-process" "foo" "sleep" "100") => #<process my-process> (start-process "my-process" "foo" "ls" "-l" "/user/lewis/bin") => #<process my-process<1>> ---------- Buffer: foo ---------- total 2 lrwxrwxrwx 1 lewis 14 Jul 22 10:12 gnuemacs --> /emacs -rwxrwxrwx 1 lewis 19 Jul 30 21:02 lemon Process my-process<1> finished Process my-process finished ---------- Buffer: foo ---------- |
start-process
と同様であるが、
指定したコマンドを実行するためにシェルを用いる点が異なる。
引数commandはシェルコマンドの名前であり、
command-argsはそのシェルコマンドに対する引数である。
変数shell-file-name
は、使用するシェルを指定する。
start-process
で直接にではなく
シェルを介してプログラムを実行すると、
引数のワイルドカードなどのシェルの機能を利用できる。
つまり、ユーザー指定の任意のファイル名をコマンドに入れる場合には、
まえもってshell-quote-argument
でクォートし、
ファイル名内のシェルの特別な文字が
そのような特別な意味を持たないようにする。
see section 36.2 シェル引数。
nil
以外であると疑似端末PTYを利用できる場合にはそれを用る。
さもなければパイプを用いる。
シェル(shell)モードなどのユーザーに見えるプロセス向けには、 パイプでは不可能なプロセスとその子プロセスとのあいだで ジョブ制御(C-c、C-zなど)を許すので 疑似端末PTYが望ましい。 プログラムの内部目的向けに使われるサブプロセスでは、 効率的なパイプを用いるほうがよい。 また、多くのシステムでは疑似端末PTYの総数には制約があり、 それらを浪費しないほうがよい。
process-connection-type
の値は
start-process
を呼び出したときに使われる。
したがって、start-process
の呼び出しの周りでこの変数を束縛することで、
1つのサブプロセスに対する通信方法を指定できる。
(let ((process-connection-type nil)) ; パイプを使う (start-process ...)) |
サブプロセスが実際にはパイプか疑似端末PTYのどちらを
使っているかを調べるには、関数process-tty-name
を使う
(see section 36.6 プロセス情報)。
プロセスを削除するとは、サブプロセスからEmacsをただちに切り離し、 サブプロセスを活性なプロセスリストから取り除くことです。 サブプロセスへシグナルを送ってサブプロセスを終了させますが、 ただちに終了するとは保証されません。 プロセスオブジェクトを指すLispオブジェクトがある限り、 プロセスオブジェクトは存在し続けます。 プロセスマークは以前と同様に同じ場所 (プロセスからの出力をバッファに挿入した箇所)を指し続けます。
プロセスはいつでも明示的に削除できます。 プロセスは終了後に自動的に削除されますが、 終了後ただちにではありません。 終了したプロセスが自動的に削除されるまえに明示的に削除しても無害です。
exit
を呼び出すかシグナルのために)終了した
プロセスの自動削除を制御する。
nil
であると、ユーザーがlist-processes
を
実行するまで存在し続ける。
さもなければ、終了後にただちに削除する。
SIGHUP
でキルし削除する。
引数は、プロセス、プロセス名、バッファ、バッファ名のいずれかである。
(delete-process "*shell*") => nil |
nil
であると、プロセスを黙って削除する。
さもなければ、Emacsはプロセスのキルに関して問い合わせる。
問い合わせるようにしてあったプロセスであると戻り値はt
であり、
さもなければ戻り値はnil
である。
新たに作成されたプロセスは、つねに問い合わせ用になっている。
(process-kill-without-query (get-process "shell")) => t |
プロセスに関する情報を返す関数がいくつかあります。
list-processes
は対話的利用のためにあります。
nil
を返す。
(process-list) => (#<process display-time> #<process shell>) |
nil
を返す。
nameが文字列でないとエラーを通知する。
(get-process "shell") => #<process shell> |
(process-command (get-process "shell")) => ("/bin/csh" "-i") |
t
を返し、
ネットワーク接続に対しては(hostname service)
を返す
(see section 36.12 ネットワーク接続)。
実際のサブプロセスに対して可能な値はつぎのとおり。
run
stop
exit
signal
open
closed
nil
(process-status "shell") => run (process-status (get-buffer "*shell*")) => run x => #<process xx<1>> (process-status x) => exit |
ネットワーク接続では、process-status
は
シンボルopen
かclosed
のいずれかを返す。
後者は、相手側が接続を閉じたか
Emacsがdelete-process
を行ったことを表す。
process-status
の結果を用いる。)
processが終了していないと値は0である。
nil
を返す
(36.4 非同期プロセスの作成のprocess-connection-type
を参照)。
(coding-system-for-decoding . coding-system-for-encoding) |
本節の関数を用いてEmacsが入力を送ると、 非同期プロセスは入力を受け取ります。 入力の送先であるプロセスと、送るべき入力データを指定する必要があります。 そのデータは、サブプロセスの『標準入力』に現れます。
疑似端末PTYのバッファ付き入力の容量に上限がある オペレーティングシステムもあります。 そのようなシステムでは、Emacsは他の文字に混ぜて定期的にEOFを送り、 文字が流れるように強制します。 ほとんどのプログラムでは、このようなEOFは無害なはずです。
ファイルに書き込むテキストと同様に、
サブプロセスの入力は、サブプロセスがそれを受け取るまえに
コーディングシステムを用いて普通は符号化されます。
set-process-coding-system
で
使用するコーディングシステムを指定できます
(see section 36.6 プロセス情報)。
さもなければ、coding-system-for-write
が
nil
以外であればこれを使います。
それ以外ではデフォルトの機構で決まるものを使います
(see section 32.10.5 デフォルトのコーディングシステム)。
nil
であると、カレントバッファのプロセスを用いる。
関数はnil
を返す。
(process-send-string "shell<1>" "ls\n") => nil ---------- Buffer: *shell* ---------- ... introduction.texi syntax-tables.texi~ introduction.texi~ text.texi introduction.txt text.texi~ ... ---------- Buffer: *shell* ---------- |
nil
であると、カレントバッファのプロセスを使う。)
startとendのどちらかが カレントバッファ内の位置を表す整数でもマーカでもないと、 エラーを通知する。 (どちらが大きな数であるかは重要ではない。)
process-nameを指定しなかったりnil
であると、
この関数はカレントバッファのプロセスにEOFを送る。
カレントバッファにプロセスがないとエラーを通知する。
関数はprocess-nameを返す。
(process-send-eof "shell") => "shell" |
サブプロセスにシグナルを送ることは、
サブプロセスの動作に割り込む一方法です。
それぞれ独自の意味を持つ異なるシグナルがいくつかあります。
一連のシグナルとそれらの名前は、オペレーティングシステムが定義します。
たとえば、シグナルSIGINT
は、ユーザーがC-cを打った、
あるいは、それと同様なことが起こったことを意味します。
各シグナルには、サブプロセスに対する標準的な効果があります。 ほとんどのシグナルはサブプロセスをキルしますが、 その実行を一時停止したり再開するものもあります。 プログラムがシグナルを処理している場合には、 シグナルの効果を一般的に述べることはできません。
本節の関数を呼び出してシグナルを明示的に送ることができます。
また、Emacsは特定の場面で自動的にシグナルを送ります。
バッファを削除すると、そのバッファに対応付けられているすべての
プロセスにシグナルSIGHUP
を送ります。
Emacsを終了するときには、動作しているすべてのサブプロセスに
シグナルSIGHUP
を送ります。
(SIGHUP
は、ユーザーが電話を切ったことを普通は表すシグナル。)
シグナルを送る各関数は、省略可能な2つの引数、 process-nameとcurrent-groupを受け付けます。
引数process-nameは、プロセス、プロセス名、nil
のいずれかです。
これがnil
であると、カレントバッファに対応付けられているプロセスが
デフォルトになります。
process-nameがプロセスを指定しないとエラーを通知します。
引数current-groupは、Emacsのサブプロセスとして
ジョブ制御可能なシェルを実行しているときに違いが現れるフラグです。
これがnil
以外であると、
Emacsがサブプロセスとの通信に用いている端末の現在のプロセスグループに
シグナルを送ります。
プロセスがジョブ制御可能なシェルであると、
これはシェルの現在のサブジョブ
(10)
であることを意味します。
nil
であると、Emacsのサブプロセスの直接のプロセスグループに
シグナルを送ります。
プロセスがジョブ制御可能なシェルであると、これはシェルそのものです。
オペレーティングシステムはパイプではプロセスグループを扱わないため、
サブプロセスとの通信にパイプを用いている場合には、
フラグcurrent-groupには効果はありません。
同じ理由で、パイプを用いている場合には
ジョブ制御可能なシェル(のジョブ制御機能)は働きません。
36.4 非同期プロセスの作成の
process-connection-type
を参照してください。
SIGINT
を送って割り込む。
Emacsの外側では、『割り込み文字』(普通、C-cであるシステムもあり、
その他のシステムではDEL
)を打つとこのシグナルを送る。
引数current-groupがnil
以外であると、
この関数は、Emacsがサブプロセスと通信している端末上で
『C-cを打つ』と考えることができる。
SIGKILL
を送ってキルする。
このシグナルはサブプロセスを即座にキルし、
サブプロセスはこれを処理できない。
SIGQUIT
を送る。
このシグナルは、『中断文字』
(Emacsの外側では普通はC-bやC-\)が
送るシグナルと同じものである。
SIGTSTP
を送って一時停止させる。
その実行を再開させるにはcontinue-process
を使う。
Emacsの外側でジョブ制御可能なシステムでは、
『一時停止文字』(普通はC-z)が普通はこのシグナルを送る。
current-groupがnil
以外であると、
この関数は、Emacsがサブプロセスと通信している端末上で
『C-zを打つ』と考えることができる。
SIGTCONT
を送って実行を再開させる。
以前に一時停止させられたprocessを再開する。
サブプロセスが標準出力に書く出力を受け取る方法は2つあります。 プロセスに対応付けられたバッファに出力を挿入するか、 あるいは、フィルタ関数(filter function)と呼ばれる関数を 出力に対して作用させます。 プロセスにバッファもフィルタ関数もなければ、その出力は破棄します。
サブプロセスからの出力は、Emacsが待っている、つまり、
端末入力を読んでいるとき、
sit-for
やsleep-for
を実行中のとき(see section 20.8 時間待ちと入力待ち)、
accept-process-output
(see section 36.9.3 プロセスからの出力を受け取る)を実行中のときに
だけ到着します。
これにより、並行プログラムを普通は悩ますような
タイミングエラーの問題を最小に抑えます。
たとえば、安全にプロセスを作成してから、
バッファかフィルタ関数を指定できます。
この処理の途中で待つような基本関数を呼び出さなければ、
出力は到着しません。
ファイルから読むテキストと同様に、
サブプロセスの出力は、バッファやフィルタ関数が受け取るまえに
コーディングシステムを用いて普通は復号化します。
set-process-coding-system
で
使用するコーディングシステムを指定できます
(see section 36.6 プロセス情報)。
さもなければ、coding-system-for-read
が
nil
以外であればこれを使います。
それ以外ではデフォルトの機構で決まるものを使います
(see section 32.10.5 デフォルトのコーディングシステム)。
警告:
データからコーディングシステムを決定するundecided
のような
コーディングシステムは、非同期サブプロセスの出力に対しては
完全に信頼性のある動作はできない。
これは、Emacsが非同期サブプロセスの出力が
到着するたびに一塊で処理するからである。
Emacsは1つの塊から正しい変換を検出しようと試みるが、
これがつねに動作するとは限らない。
したがって、可能な限り
文字コード変換と行末変換の両方を指定したコーディングシステムを使う。
つまり、undecided
やlatin-1
などではなく、
latin-1-unix
のようなものを使う。
36.9.1 プロセスバッファ | If no filter, output is put in a buffer. | |
36.9.2 プロセスフィルタ関数 | Filter functions accept output from the process. | |
36.9.3 プロセスからの出力を受け取る | Explicitly permitting subprocess output. Waiting for subprocess output. |
プロセスには対応付けられたバッファが(普通は)あります。 そのバッファはEmacsの普通のバッファであり、2つの目的に使われます。 プロセスからの出力を保存することと、 プロセスがキルされたことを判定するためです。 バッファを用いてそれを操作しているプロセスを識別することもできます。 普通は1つのバッファに1つのプロセスを対応付けるからです。 プロセスの多くの応用では、プロセスへ送る入力を編集するために バッファを使いますが、これはEmacs Lispに組み込まれたことではありません。
プロセスにフィルタ関数(see section 36.9.2 プロセスフィルタ関数)がなければ、
その出力は対応付けられたバッファに挿入されます。
出力の挿入位置はprocess-mark
で決定され、
process-mark
は挿入したばかりのテキストの末尾を
指すように更新されます。
process-mark
は普通はバッファの末尾にありますが、
つねにそうであるとは限りません。
(process-buffer (get-process "shell")) => #<buffer *shell*> |
processにバッファがなければ、
process-mark
はどこも指していないマーカである。
バッファにプロセス出力を挿入する際には、 挿入箇所を決定するためにこのマーカを使用し、 挿入したテキストの末尾を指すようにこのマーカを更新する。 これにより、出力の連続した塊を順に挿入できるのである。
バッファに出力を直接挿入する場合と同様に、
フィルタ関数はこのマーカを扱うべきである。
process-mark
を用いたフィルタ関数の好例は、以下の節にある。
プロセスへ送るためにユーザーがプロセスバッファに 入力することが予想されるときは、 プロセスマーカは新たな入力とそれ以前の出力を区切る。
nil
であると、
プロセスに対応付けられたバッファはない。
(get-buffer-process "*shell*") => #<process shell> |
プロセスのバッファを削除すると、
サブプロセスにシグナルSIGHUP
を送ってプロセスを削除する
(see section 36.8 プロセスにシグナルを送る)。
プロセスのフィルタ関数(filter function)は、 対応付けられたプロセスからの標準出力を受け取る関数です。 プロセスにフィルタがあると、そのプロセスからのすべての出力は フィルタに渡されます。 プロセスにフィルタがない場合に限って、 プロセスからの出力向けにプロセスバッファを直接使います。
フィルタ関数は、Emacsがなにかを待っているときにのみ呼ばれます。
そのような期間にのみプロセスの出力が到着するからです。
Emacsが待つのは、端末入力を読んでいるとき、
sit-for
やsleep-for
を実行中のとき(see section 20.8 時間待ちと入力待ち)、
accept-process-output
(see section 36.9.3 プロセスからの出力を受け取る)を実行中のときです。
フィルタ関数は2つの引数、 対応付けられたプロセスとそのプロセスから受け取ったばかりの出力である文字列を 受け取ります。 関数は出力に対してなにを行ってもかまいません。
フィルタ関数の内側では中断は普通は禁止されています。
さもないと、コマンドレベルで打ったC-gの効果や、
ユーザーコマンドを中断するために打ったC-gの効果は予測できません。
フィルタ関数の内側で中断を行いたい場合には、
inhibit-quit
にnil
を束縛します。
See section 20.9 中断。
フィルタ関数の実行中にエラーが発生するとそのエラーは自動的に捕捉され、
フィルタ関数を始動したときに動いていた
プログラムの実行を停止しないようにします。
しかし、debug-on-error
がnil
以外であると、
エラーを捕捉しません。
これにより、Lispデバッガでフィルタ関数をデバッグできます。
See section 17.1 Lispデバッガ。
多くのフィルタ関数は、ときどきあるいはつねに、
プロセスのバッファにテキストを挿入します。
これはフィルタ関数がないときのEmacsの動作を模倣するものです。
そのようなフィルタ関数では、対象のバッファに挿入するために
set-buffer
を使う必要があります。
カレントバッファをなかば恒久的に切り替えないように、
これらのフィルタ関数はカレントバッファを記録/復元する必要があります。
プロセスマーカを更新し、必要に応じてポイントの値も更新します。
これらはつぎのように行います。
(defun ordinary-insertion-filter (proc string) (with-current-buffer (process-buffer proc) (let ((moving (= (point) (process-mark proc)))) (save-excursion ;; テキストを挿入し、プロセスマーカを進める (goto-char (process-mark proc)) (insert string) (set-marker (process-mark proc) (point))) (if moving (goto-char (process-mark proc)))))) |
カレントバッファを記録/復元するためにsave-excursion
ではなく
with-current-buffer
を使うのは、
2番目のgoto-char
の呼び出しで行うポイントの移動効果を
有効にするためです。
新たにテキストが到着するたびにプロセスバッファが見えるように
フィルタ関数で強制するには、
つぎのような行をwith-current-buffer
の直前に入れます。
(display-buffer (process-buffer proc)) |
ポイント位置に関わらずに新たな出力の末尾にポイントを移動するには、
変数moving
を削除して、
無条件にgoto-char
を呼び出します。
Emacsの初期の版では、正規表現を探索したり一致処理するフィルタ関数では、 マッチデータを明示的に保存/復元する必要がありました。 今のEmacsは、フィルタ関数に対してはこれを自動的に行いますから、 フィルタ関数で明示的に行う必要はありません。 See section 33.6 マッチデータ。
プロセスのバッファに出力を書き込むフィルタ関数は、
そのバッファが有効であるかどうかを検査するべきです。
無効なバッファに挿入しようとするとエラーになります。
バッファが無効であれば、
式(buffer-name (process-buffer process))
を実行するとnil
を返します。
関数に渡される出力は任意のサイズの塊できます。 同じ出力を2回生成するプログラムは、 あるときには一度に200文字の塊を1つ送る場合もあれば、 40文字の塊を5つ送る場合もあります。 サブプロセスの出力から特定のテキスト文字列を探すフィルタでは、 そのような文字列が2つかそれ以上の出力の塊に分割される場合も 扱えるようにします。
nil
であると、プロセスにフィルタはない。
nil
を返す。
フィルタ関数の使用例をつぎに示します。
(defun keep-output (process output) (setq kept (cons output kept))) => keep-output (setq kept nil) => nil (set-process-filter (get-process "shell") 'keep-output) => keep-output (process-send-string "shell" "ls ~/other\n") => nil kept => ("lewis@slug[8] % " "FINAL-W87-SHORT.MSS backup.otl kolstad.mss~ address.txt backup.psf kolstad.psf backup.bib~ david.mss resume-Dec-86.mss~ backup.err david.psf resume-Dec.psf backup.mss dland syllabus.mss " "#backups.mss# backup.mss~ kolstad.mss ") |
非同期サブプロセスからの出力は、 Emacsが時間待ちや端末入力などの なんらかの外部事象を待っているときにのみ到着します。 Lispプログラムから特定の場面で出力の到着を明示的に許したり、 プロセスの出力が到着するのを待つことができると有用なことがあります。
nil
以外であると、
この関数は、processからなんらかの出力を得るまで戻らない。
引数secondsとmillisecは、時間切れを指定する。
前者は秒単位の時間、後者はミリ秒単位の時間を指定する。
指定された2つの時間は合計され、
任意のサブプロセスの出力を受け取ったどうかに関わらず、
その時間だけ経過するとaccept-process-output
は戻ってくる。
引数secondsは整数である必要はない。 浮動小数点数であると、この関数は秒未満の時間も待つ。 秒未満を扱えないシステムもある。 そのようなシステムでは、secondsを切り下げる。
すべてのオペレーティングシステムで秒未満を扱えるわけではない。 扱えないシステムでmillisecにゼロ以外を指定すると エラーになる。
関数accept-process-output
は、
出力を得るとnil
以外を返す。
あるいは、出力が到着するまえに時間切れするとnil
を返す。
プロセスの番兵(process sentinel)は、 プロセスを終了/一時停止/継続させる (Emacsが送ったかプロセス自身の動作によって生起した)シグナルを含めて 対応付けられたプロセスの状態が任意の理由で変化したときに 呼び出される関数です。 プロセスの番兵は、プロセスが終了しても呼び出されます。 番兵は2つの引数、事象が発生したプロセスと 事象の種類を記述する文字列を受け取ります。
事象を記述する文字列はつぎのとおりです。
"finished\n"
.
"exited abnormally with code exitcode\n"
.
"name-of-signal\n"
.
"name-of-signal (core dumped)\n"
.
番兵はEmacsが(たとえば、端末入力や時間経過、プロセスの出力を)
待っているときにのみ実行されます。
他のLispプログラムの実行途中で無秩序に番兵を実行した場合に起こる
タイミングエラーを回避するためです。
sit-for
やsleep-for
(see section 20.8 時間待ちと入力待ち)、あるいは、
accept-process-output
(see section 36.9.3 プロセスからの出力を受け取る)を
呼び出すとプログラムは待ちに入り、番兵が動けることになります。
Emacsは、コマンドループで入力を読むときにも番兵の実行を許します。
番兵の内側では中断は普通は禁止されています。
さもないと、コマンドレベルで打ったC-gの効果や、
ユーザーコマンドを中断するために打ったC-gの効果は予測できません。
番兵の内側で中断を行いたい場合には、
inhibit-quit
にnil
を束縛します。
See section 20.9 中断。
プロセスのバッファに出力を書き込む番兵は、
そのバッファが有効であるかどうかを検査するべきです。
無効なバッファに挿入しようとするとエラーになります。
バッファが無効であれば、
式(buffer-name (process-buffer process))
を実行するとnil
を返します。
番兵の実行中にエラーが発生するとそのエラーは自動的に捕捉され、
番兵を始動したときに動いていた
プログラムの実行を停止しないようにします。
しかし、debug-on-error
がnil
以外であると、
エラーを捕捉しません。
これにより、Lispデバッガで番兵をデバッグできます。
See section 17.1 Lispデバッガ。
Emacsの初期の版では、正規表現を探索したり一致処理する番兵では、 マッチデータを明示的に保存/復元する必要がありました。 今のEmacsは、番兵に対してはこれを自動的に行いますから、 番兵で明示的に行う必要はありません。 See section 33.6 マッチデータ。
nil
であると、プロセスに番兵はない。
番兵がない場合のデフォルトのふるまいは、
プロセス状態が変化するとプロセスのバッファにメッセージを挿入する。
(defun msg-me (process event) (princ (format "Process: %s had the event `%s'" process event))) (set-process-sentinel (get-process "shell") 'msg-me) => msg-me (kill-process (get-process "shell")) -| Process: #<process shell> had the event `killed' => #<process shell> |
nil
を返す。
nil
以外を返し、
それ以外ではnil
を返す。
トランザクションを用いたサブプロセスとの通信に
トランザクションキュー(transaction queue)を使えます。
まずtq-create
を用いて、
指定したプロセスとの通信用トランザクションキューを作成します。
そして、トランザクションを送るためにtq-enqueue
を呼び出します。
引数questionは、トランザクションを始める送出メッセージである。 引数fnは、対応する応答が戻ってきたときに呼び出す関数である。 その関数は2つの引数、closureと受け取った応答で呼び出される。
引数regexpは、1つの応答だけに一致する正規表現である。
tq-enqueue
が応答の末尾を判定するために使う。
tq-enqueue
の戻り値そのものに意味はない。
トランザクションキューはフィルタ関数を用いて実装してあります。 See section 36.9.2 プロセスフィルタ関数。
Emacs Lispプログラムは、同一マシンや別のマシン上の他のプロセスに対して
TCPネットワーク接続を開くことができます。
ネットワーク接続は、サブプロセスと同様にLispが扱い、
プロセスオブジェクトとして表現されます。
しかし、通信相手のプロセスはEmacsプロセスの子プロセスではありませんから、
キルしたりシグナルを送ることはできません。
データの送受信のみが可能です。
delete-process
は接続を閉じますが、
もう一方の端のプロセスをキルしません。
そのプロセスは、接続が閉じた場合の動作を判断する必要があります。
ネットワーク接続を表すプロセスオブジェクトと
サブプロセスを表すプロセスオブジェクトとは、
関数process-status
を使って区別できます。
この関数は、ネットワーク接続に対しては
open
かclosed
をつねに返し、
本当のサブプロセスに対してはこれらのいずれの値もけっして返しません。
See section 36.6 プロセス情報。
引数nameは、プロセスオブジェクトに付ける名前を指定する。 必要に応じて一意にするために修正される。
引数buffer-or-nameは、接続に対応付けるバッファである。
出力を扱うフィルタ関数を指定しない限り、
接続からの出力はそのバッファに挿入される。
buffer-or-nameがnil
であると、
接続にはバッファを対応付けないことを意味する。
引数hostとserviceは、接続先を指定する。 hostはホスト名(文字列)であり、 serviceは定義済みのネットワークサービス(文字列)か ポート番号(整数)である。
[ << ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |