ということで、今回は、プログラム(リソース)の再利用、 つまりライブラリと呼ばれるものを使う方法を採用しようと考えた。いろいろ調べてみると、runというコマンドが使えることがわかった。これについては、後で詳述することにして、まずはrunを使うことになった経緯について述べておく。
Postscriptには「関数」という概念がない。その代わりに、procedure(「手続き」と訳している人もいる)という、コマンドのまとまりを再定義する方法を利用する。ただ、procedureへの変数の受け渡しは定義されてない。たとえば、円を2つ書くコマンドをdarc(=="double arc")というprocedureにまとめる方法は、
/darc {
x0 y0 r0 0 360 arc
x1 y1 r1 0 360 arc
} def
とする。こうすると、procedureである"double_circle"が定義される。
では、このprocedureの中で定義されている「変数」x0, y0, ...などはどうやって渡すのか、というと、スタックを利用するのだ。たとえば、procedureの定義において、
/darc {
/r1 exch def
/y1 exch def
/x1 exch def
/r0 exch def
/y0 exch def
/x0 exch def
x0 y0 r0 0 360 arc
x1 y1 r1 0 360 arc
} def
という具合に、スタックからデータを受け取るコマンドを書き込む。注意するのは、取り込む順番だ。このprocedureを使う段になって、
0 1 5 10 12 7 darc
とやると、(x0, y0, r0, x1, y1, r1)=(0, 1, 5, 10, 12, 7)という対応でprocedureに取り込まれる。procedureの中では、7, 12, 10, 5, 1, 0という順番でスタックの取り込みが行われるので、r1, y1, x1, y0, y0, x0の順番で「変数」を定義する。
このように、procedureをたくさん定義しておけば、次にプログラムを書くときに、それを再利用することができる。しかし、ファイルの中に長々とcut&pasteするのは、見栄えと読みやすさを犠牲にする。一般のプログラミング言語のようにライブラリにまとめて一括読み取りができると便利だ。例えば、C言語の#includeとか、LaTeXのusepackageみたいな機能だ。
Postscriptに関する古い解説文書を読むと、この機能に対応するのは"run"だと書いてある。たとえば、先ほどのdarcのprocedureを別のファイルdarc.psに書いておき、それを新しいファイルappli_darc.psで再利用するときは、appli_darc.psの中で、
(darc.ps) run
とすれば、darc.psの内容がappli_darc.psで再利用できるというわけだ。
ところが、この手法を用いてmacOSで、appli_darc.psをopenすると、エラーが発生して読み込むことができない。書式が悪いのか、読み込みの定義が間違っていたのか、といろいろと疑ってみたが、どうもどこもおかしくない。長いこと検索してみると、ついにこの問題の核心をついていると思われるdiscussionを見つけることができた。
この議論で引用されているMITの元記事はリンク切れしていて読めなかったが、こちらのページで内容は大体わかった。ghostscriptの脆弱性(vulnerability)が、2018年8月にgoogleのエンジニアによって発見されたという内容だ。
結局、runコマンドによって外部ファイルを読み込めるようにしてしまうと、悪意のあるコードや命令を埋め込まれてしまうという内容だ。これを受けて、macOSのpreviewや、Adobeシステムの製品では、runを含むpsファイルはエラーが出るように修正されている、ということらしい。
天体観測の画像処理などでもよく利用するImage Magickもgsのライブラリを利用しているので、同じ脆弱性をはらんでいるそうだ。パッチが公開されているらしい。
ただ、macOSにデフォルトで入っているgsコマンドを利用すれば、runを含むposgtscriptファイルを実行することがは可能である、とdiscussionに書いてあった。そこで、試してみるとちゃんとrunコマンドが動くことが確認できた。
また、ps2pdf -dNOSAFERでもrun付きpsファイルをpdfに変換することができる。ちょっと手間だが、ps2pdf -dNOSAFER ps_with_run.ps; open ps_with_run.pdfと打ち込むか、次にようなbashスクリプトを書いて(psviewと命名し、chmod 755 psviewとしておく)、利用すればよい。
[psview]
#!/bin/bash if [ $# -eq 1 ]; then fname=`head -1 $1.ps` if [ ${fname} == "%!PS-Adobe-3.0" -o ${fname} == "%!PS-adobe-3.0" ]; then ps2pdf -dNOSAFER $1.ps; open -a preview $1.pdf exit 1 else echo "Error. File must be of Postscript." exit 0 fi exit 1 fi cat << __EOF__ The argument must be the name of the postscript file to be processed with ghostview, and to be opened with preview. __EOF__ exit 0
runコマンドのvulnerabilityがあることを認識し、あくまでpsviewで開くのは自作のpostscriptファイルだけとわきまえておけば、これでrunを利用した自作のprocedureのライブラリを使ってプログラム群を構築することができる!