Easel (End-User Application System Encoding Language)

概要

エンドユーザ向けアプリケーションを書くときに必要になる、フォーム入力、メニ ュ、テキストといったユーザ・インタフェースを作って、多くのタスクを組み立て るのは、なかなか手のかかる作業ですが、「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) を記入するための フォームを作って、ユーザが自由に記入できるようにしています。ユーザが をタイプして記入を完了すると、宛先(~To)、表題(~Subj)、 本文(~Mesg) を「email」フレイムに返します。「{question .. }q」はフォーム の入力フィールドです。
{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 のシステム・レベルの日本語 入力機能で使えるようにした段階ですが、テスト版のパッチを公開しておきます。 バグや改善提案は下記に御連絡ください。

日本語化パッチ

平林 浩一