エンドユーザ向けアプリケーションを書くときに必要になる、フォーム入力、メニ ュ、テキストといったユーザ・インタフェースを作って、多くのタスクを組み立て るのは、なかなか手のかかる作業ですが、「Unix」を生んだ「AT&T Bell Laboratories」で開発され「AT&T」内部で長年に渡って数多くのプロジェクトに使 われてきた「Easel」(End-User Application System Encoding Language) と呼ば れるエンド・ユーザ向けアプリケーション開発言語が、一般の書籍
Ed. Balachander Krishnammurthy,- Practical Reusable UNIX Software
(John Wiley & Sons, Inc.) ISBN 0-471-05807-6)
にも紹介され、そのソースコードも
http://www.research.att.com/sw/tools/reuse/で公開されました。
一般に、対話型エンド・ユーザ・システムは、ユーザ・インタフェース(フォーム、 メニュ、テキスト)とシステム構造(タスクとサブ・タスク)からなる「デザイン・ プログラミング」(Design Programming) の部分と、計算機能とデータ構造からな るアプリケーション固有の「計算プログラミング」(Computation Programming)の 二つから構成されますが、問題の本質とは関係ない割に手のかかる前者がアプリケ ーションとは独立であることに着眼して、専用の言語(Easel Language)とそのコン パイラ、インタプリータ、開発ツールを実現したもので、従来のやりかたと比べて、 ざっと 1/10 の手間で済むことが実証されたそうです。
この言語の感覚は、前記の書籍が例にあげている電子メイルのシステム
1) メニュからメイルの相手先を選択し、 2) フォーム入力によりメイルを作成し、 3) mail コマンドで発送するの Easel による記述例を見ると良くわかると思います。
{frame email
~call users > ~users
~call select ~users > ~to
~call mform ~to > ~to ~subj ~mesg
(~to!=~null && ~mesg!=~null): ~call msend ~to ~subj ~mesg
}f
「{frame .. }f」はハイレベルのタスクで、Easel では「フレイム」(frame) と呼
んでいます。先頭が「~」で始まる名前は Easel のコマンドや変数で、このフレイ
ムでは、「users」というフレイムを呼び出して、その出力を「~users」という変
数に格納します。後でわかりますが、これがメイルの宛先のリストになっています。
「}f」等の「}」の後ろの文字はコンパイラが無視しますが、対応が明確になるよう
に、習慣として付けられています。
次に、「select」というフレイムにその結果を渡して、その処理結果を「~to」に 受け取りますが、これがユーザがメニュによって選択したメイルの宛先になります。
その後、「mform」というフレイムにメイルの宛先を渡して、メイルの宛先、表題、 本文をフォーム入力し、最後に宛先と本文の両方が記入されているかどうかをチェ ックしてから、「msend」フレイムに宛先、表題、本文を渡して、メイルを発送しま す。
最後の「~call」の前の「:」式は、全体あるいは部分として省略可能な
[実行条件 : 終了条件]というもので、Easel のほとんどのコマンドはループ構造になっていて、
if (実行条件)
while (終了条件)
コマンドを実行
という方式で実行されますから、この条件式を省略すると、「真」の条件を指定
したと見なされますから、二つ共省略すると、そのコマンドは一度だけ実行され
ることになります。上記のフレイムの最初の3行はこの両方が省略された場合で
す。
{frame users
{process "/bin/sh" > ~logins
~!"ShIsDone\n","echo ShIsDone\n"
~$
cat /etc/passwd | cut -d: -f1 | sort -u | xargs
}p
~return ~logins
}f
「users」フレイムでは /etc/passwd ファイルの最初のフィールドを切り出して、
そのホストを利用するユーザのリストを作っています。「process」ブロックは
入力と出力の2つのパイプを作って、指定されたコマンド(ここでは /bin/sh)の
標準入力と標準出力を Easel に接続し、「cat /etc/passwd」以下のコマンドを
実行させ、最後に「~!」で指定した「echo ShIsDone\n」コマンドを実行させ、
「~!」で指定した「ShIsDone\n」というレスポンスを待ちます。つまり、「~!」
は指定されたコマンドが持ち返る文字列の最後の識別に使われ、その直前までの
文字列が「~login」変数に代入されて、それを「email」フレイムに返します。
「~$ [変数]」はこの間ディスプレイに何を表示するかの指定で、この場合は表示 変数がありませんので、画面はそれまでのままになります。
{frame select ~list
{menu :(~pers == ~null) ~pers
.window( x=5, xlen=50, y=0, ylen=10 )
Mail To: ~to
{option ~list " \t\n"
~to = ~to * ~pers * " "
}o
}m
~return ~to
}f
「select」フレイムは宛先のリストを受け取って選択メニュを作ります。
「{option .. }o」がメニュ項目とユーザが何か選択したときのアクションになり
ます。ここでは、ユーザが選択した宛先をリストにまとめていますが、これは同一
のメイルを複数のユーザに送ることを考慮した結果です。ユーザは選択の終了を
「Ctrl-E」というキー入力で指示します。ここで何も選択せずに終了しても、次の
フォーム入力で任意の宛先を入力することができます。
{frame mform ~To
{context
.form( c=2, a=p,
To: <_____________________ $ ~To
Subj: <___________________________ $ ~Subj
Mesg: <___________________________ $ ~Mesg
)
Mail Form
{descript
Some HELP for the form
}d
{question ~To
To:
}q
{question ~Subj
Subj:
}q
{question ~Mesg
.field( r=10 )
Mesg:
}q
}c
~return ~To ~Subj ~Mesg
}f
「mform」フレイムでは宛先(To:)、表題(Subj:)、本文(Mesg) を記入するための
フォームを作って、ユーザが自由に記入できるようにしています。ユーザが
{frame msend ~To ~Subj ~Mesg
~getenv ~LOGNAME
{process "/bin/sh"
~!"ShIsDone\n","echo ShIsDone\n"
~$
mail ~To <
「msend」フレイムは mail コマンドにフォーム入力された、宛先、表題、本文
を渡してメイルの発送を行いますが、最後に「Thanks! 発信者の名前」という行
を自動的に追加するために、「LOGNAME」環境変数を使っています。
easel の使いかた
Easel のソース・ファイルは普通「.f」のサフィクスを付けておきます。全てを
一つのファイルにまとめても、フレイム毎に別のファイルにしてもかまいません。
例えば、上記のファイルを「email.f」にした場合は、「efc」というコンパイラ
で、
efc email.f
を実行すると、email.p, users.p, select.p, mform.p, msend.p というオブジェ
クト・ファイルができますので、エラーがなければ、「efm」というインタプリー
タを使って、
efm -semail
等で実際に実行することになります。
Easel が扱うデータは文字列だけですが、それが数値として解釈できる場合は、
数学関数を含めた数値計算も可能ですし、文字列や正規表現の処理もできるように
なっています。メニュやフォーム等の画面の細かな制御もできますが、ほとんどの
場合、デフォルトの動作で間に合うように、うまく設計されています。詳細は、ソ
ースに付属する詳細なドキュメント「EASEL Programmer's Manual」を見てくださ
い。140 ページほどですが、groff でフォーマットする場合は、mm マクロを最新
のもの(ftp://ftp.efd.lth.se/pub/mm*.tar.gz)で置き換える必要があります。古
いバージョンでは「.FG」「.TB」のバグがあって、表の一部がうまく印刷できませ
ん。
「Figure.1」だけは、ベル研の新しい roff のプリプロセサがないと処理できませ
んが、これは前記の書籍の「Figure 4.5」(pp 151)と同じもので、私が pic で書
いたものを、下記に付けておきます。
.PS
R: ellipse "Requirements" width 1.5 height 0.3 at 0,2.1
U: ellipse "User Interface" "Frames" width 1.5 height 0.5 at -1.2,1.4
C: ellipse "Computations" "Data" width 1.5 height 0.5 at 1.2,1.4
P: ellipse "Prototype" width 1.2 height 0.3 at 0,0.6
UT: ellipse "User Test" width 1.2 height 0.3 at -1.1,0
Rl: ellipse "Releases" width 1.2 height 0.3 at 1.1,0
arrow from 1/2 to U.ne
arrow from 1/2 to C.nw
arrow from U.se to P.nw
arrow from C.sw to P.ne
arrow from P.sw to UT.ne
arrow from P.se to Rl.nw
spline -> from UT.nw to (-2.3,1.8) then to R.sw
spline -> from Rl.ne to (2.3,1.8) then to R.se
.PE
Easel には「efb」(EASEL Frame Builder)と呼ばれる Easel のプログラムを対話
的に作成するツールがありますが、これは Easel で書かれています。
コンパイル
上記のサイトから「easel.src.unix.README」と「easel.src.unix.cpio.Z」を取
ってきてから、次の操作を行うとコンパイルできます。
1) /usr/local/easel 等のデュレクトリでソースを展開
zcat easel.src.unix.cpio.Z | cpio -icdmv」でソースを展開
2) インストール・スクリプトの実行
./Install
いくつかの質問がでますが、gcc を使う場合は cc のオプションで
「-traditional」か「-fwriteable-strings」を指定してください。
ソースの中に文字列定数を書き換えるところがあります。また、
「Multi-byte」文字を指定します。その他はデフォルトで だ
け押してください。
コンパイルは「Install」スクリプトで「Mk-efs」スクリプトを作成し、
「Mk-efs」をバックグラウンドで起動して、経過の記録「mk.out」に取る仕組にな
っています。ライブラリの一部のオブジェクトを消し忘れていますので、後から消
すか、Makefile を書き換えてください。移植やデバッグを行うときは、やりかた
を替えないとたいへんです。
多くのシステムでは簡単にコンパイルできますが、最近の BSD 系ではマクロ名の
衝突等があって、かなりの書き換えが必要でした。また、Sun の SparcServer1000
(マルチ・プロセッサ)では efm が起動されたとたんに core を吐いて死んでしま
うものですから、それに対応した変更が必要というのが私の経験です。
Easel のソースには次のライブラリが含まれていて、標準の「stdio」ライブラリ
や「curses」ライブラリは使われていません。バグが多くて使いものにならず、
新しいライブラリから作るしかなかったのだそうです。メニュやエディタ等の機能
も新しい「screen」(curses) ライブラリ内部で実現されています。
screen library - Easel の足場になっている高機能「curses」ライブラリ
sfio - 高速で安全でモダンな stdio ライブラリ
dict - 辞書操作を行うためのライブラリ
これらはすべて src/lib ディレクトリに入っていて、ドキュメントは doc/lib
にありますが、screen ライブラリのドキュメントは wmenu() 関数等で一部実物と
一致しないところがあります。screen ライブラリの名前は「curses」が商標権
問題で使用できなかったためということですが、非常に高機能なもので、
SystemV に含まれるものから、さらに拡張されていて、Termcap と Terminfo の
いずれでも使えるようになっています。sfio は従来の stdio に比べて、かなり
モダンな設計です。
日本語化
Easel そのものは、「Multi-byte Asian characters」に対応した「screen」
(curses)ライブラリを使っていますので、もともと EUC の半角カナに対応してい
ますし、メッセージをそれぞれの国の言語に簡単に書き換えられるように、一つの
ファイルにまとめてあるといった配慮が行われていますが、2バイトの漢字には対
応していませんので、かなりの書き換えが必要です。
以前、このソースを入手して実際に試してみて、ぜひ日本語化したいと思ったので
すが、なにしろライブラリを含めて、10 万行を越える大きさですから、なかなか
時間がとれなくて、2年後の1998年の正月休みにやっと読み始め、1998年
の1月から社内でテストを始めました。
とりあえずは、X11 の kterm+kinput2 や、Solaris のシステム・レベルの日本語
入力機能で使えるようにした段階ですが、テスト版のパッチを公開しておきます。
バグや改善提案は下記に御連絡ください。
日本語化パッチ
平林 浩一