1995年9月1日 #a はじめに troff は、写植機で高品質印刷を行なうための UNIX や GCOS 上で動く文書清書プログラムで、 オサンナ (J.F.Ossana) によって書かれたものである。 この文書自身が troff の出力例である。 troff を使う上でただひとつの最も重要な規則は、それを直接使うのではなく、 なんらかの媒介を通して使うためのものであるということである。 troff は、非常に強力でかつ柔軟性に富んだものではあるけれども、 多くの点でアセンブラ言語に似ていて、 大部分の操作を詳細に記述しなければず、 多くの人々が効果的に利用するのは困難である。 大多数のユーザのための特別なアプリケーションとして、 troff とのインタフェースをとるプログラムが2つある。 eqn は、数学の写植のための簡単に習得できる言語である。 eqn のユーザは数学の組版を行なうために troff について何も知る必要がない。 tbl は、適度に複雑な表を作成することを容易にしてくれる。 きちんとした文書(それは数式や表を含んでいるかもしれないものであるが) を作成するために多くの「マクロ パッケージ」が容易されていて、 清書の規則や特定の文書のスタイルに関する操作を定義しているが、これらによって troff に直接触れる部分を少なくできるわけである。 特に、ベル研究所内部でメモおよび外に発表する論文用の「-ms」、 およびPWB/MM は、 広範囲にわたる文書の作成に必要な機能を ほとんど備えている(このメモは「-ms」を使って作成した)。 他にも、ビューグラフを作成するためのもの、昔 UNIX や GCOS にあった roff のシミュレーションを行なうもの、 特別なアプリケーションのためのもの等がある。 極く普通の操作を行なおうとすれば、 troff を使うよりはこれらのパッケージを使う方が容易であるということが 理解できるであろう。この事実を念頭におくべきである。 既存のパッケージではやりたい仕事がこなせないような場合の解決策は、 troff の命令を一から全部新しく書き直すので なく、 既にあるものを少しだけ変更して使えるようにすることである。 他のもの(プログラム)に仕事をさせるという哲学に従うと、 これから記述するものは troff 全体からみると極く一部分になってしまうけれども、 最も便利な部分をここに集約することを試みることにした。 いずれにせよ、完壁なものを示そうとするつもりはない。 むしろ、ここで強調したいのはいかにして単純に作業を行なうか、 いかにして既存のものに変更を加えていくかといったことを示すことである。 以下のセクションの内容は、次のとおりである。 2. ポイント サイズと行間 3. フォントと特殊文字 4. 字下げと行の長さ 5. タブ 6. 部分的移動: 線を引く、文字を描く 7. ストリング 8. マクロについて 9. 表題、頁分け、頁番号付け 10. 数値レジスタとその演算 11. 引数のあるマクロ 12. 条件式 13. 環境 14. ダイバージョン 付録: 写植機の文字セット ここで説明している troff は、参考文献にある、ベル研の UNIX 上で動いているものでC言語で書かれている。 troff を使うためには、実際に印刷したいテキストだけでなく、それを どのように 印刷したいのかという情報を用意しなければならない(このような方法は roff のユーザにはおなじみであろう)。 troff では、テキストと清書情報とは密接に絡み合わされている。 troff のコマンドのほとんどは、テキストそのものとは別の、 ピリオドで始まる行に置かれる(一行に一コマンドである)。 たとえば、 Some text. .ps 14 Some more text. のようなコマンドは、「ポイント サイズ」すなわち印刷される文字の大きさを、 14ポイント(1ポイントは、72分の1インチ)に変更するというもので、 結果は次のようになる。 Some text. Some more text. 特別なコマンドで行の途中に入るものもあり、 Area = \(*pr 2 という行を作りたいときは、 Area = \(\(**p\fIr\fR\ | \s8\u2\d\s0 とタイプすればよい。(簡単に説明すると、)テキスト内の行の途中に、 troff コマンドと特殊文字を入れるために逆スラッシュ \ \ が使われている。 #a ポイント サイズと行間 先に述べたように、 .ps .ps コマンドはポイント サイズを設定するためのものである。 1ポイントは72分の1インチなので、 6ポイントの文字はおよそ12分の1インチ高になり、 36ポイントの文字は2分の1インチになる。 次に示すような15種のポイント サイズがある。 6 point: Pack my box with five dozen liquor jugs. 7 point: Pack my box with five dozen liquor jugs. 8 point: Pack my box with five dozen liquor jugs. 9 point: Pack my box with five dozen liquor jugs. 10 point: Pack my box with five dozen liquor 11 point: Pack my box with five dozen 12 point: Pack my box with five dozen 14 point: Pack my box with five 16 point 18 point 20 point 22 24 28 36 .ps .ps の後ろに与えられた数がここに示した大きさのいずれでもない場合、 一番近い正しい値に切り上げられるが、それも36ポイントが限度である。 数の指定がなかった場合、直前のサイズに戻る。 troff のポイント サイズの初期値は10ポイントであるが、 一般にこれがよく好まれる。ちなみに、この文書は9ポイントである。 ポイント サイズはインライン コマンド \s \s を用いて、行の途中でも単語の途中でも変えることができる。 UNIX runs on a PDP-11/45 という行を作りたいときは、 \s8UNIX\s10 runs on a \s8PDP-\s1011/45 とタイプすればよい。 上のように、 \s \s の後ろには正しいポイント サイズを付けなければならない。 ただし、 \s0 \s0 は例外でサイズを直前の値に戻すためのものである。 \s1011 \s1011 は、「サイズ10の11」として正しく認識されるということに注意してほしい。 もし、(1011という)サイズが正しいものであれば、この限りではない。 似たようなことが他にもあるので気をつけてほしい。 相対的にサイズを変えることもできて、便利である。 \s\-2UNIX\s+2 は一時的に2ポイント、サイズを小さくした後またもとに戻す。 相対的にサイズを変化させることは、 サイズの違いがその文書の初期サイズに拘束されないという利点を持つ。 相対的変化に用いることのできる数は、数字1桁に制限されている。 タイプされるものがどのように見えるかを決定する他のパラメタとして、 行間の余白がある。これは、ポイント サイズとは独立して設定される。 行間はある行の底辺から次の行の底辺までで測る。行間を制御するコマンドは .vs .vs である。テキストを作る際、文字の大きさより20%程大きく行間をとることが、 一般に最もよいとされている。たとえば、この文書ではこれまで 『11に9』を使っていて、 これは次のように指定する。 .ps 9 .vs 11p もしこれを、 .ps 9 .vs 9p のように変更すると、テキストは次のようになる。 After a few lines, you will agree it looks a little cramped. The right vertical spacing is partly a matter of taste, depending on how much text you want to squeeze into a given space, and partly a matter of traditional printing style. By default, troff uses 10 on 12. 2、3行読めばこれでは少々きゅうくつだと思うようになるであろう。 正しい行間値は、与えられた空間にどれくらいテキストを詰め込みたいか といった問題であることもあるし、伝統的印刷スタイルの問題であることもある。 troff の標準では『12に10』を使っている。 Point size and vertical spacing make a substantial difference in the amount of text per square inch. This is 12 on 14. ポイント サイズや行間値は1平方インチ当りのテキストの量に実質的な差を もたらす。ちなみに、いまは『14に12』である。 Point size and vertical spacing make a substantial difference in the amount of text per square inch. For example, 10 on 12 uses about twice as much space as 7 on 8. This is 6 on 7, which is even smaller. It packs a lot more words per line, but you can go blind trying to read it. ポイント サイズや行間値は、1平方インチ当りのテキストの量に実質的な差を もたらす。たとえば、『12に10』は『8に7』の約2倍の面積を必要とする。 上は『7に6』であるが、少し小さすぎる。これであると、一行にたくさん詰め 込めるが、読むのはかなりつらいであろう。 引数なしで使ったとき、 .ps .ps と .vs .vs はそれぞれサイズと行間値を直前の値に戻す。 .sp .sp コマンドは、行間をさらにあけるために用いられる。 なにも指定しなければ、空行が一行得られる( .vs .vs ひとつ分である)。 それでは多すぎることもあるであろうし、少なすぎることもあるかもしれないので、 どれくらい空間がほしいのかという情報を与えることができるようになっている。 .sp 2i は「行間を2インチあける」ことを示し、 .sp 2p は「行間を2ポイントあける」ことを示し、 .sp 2 は「行間を2つあける」ことを示す。行間2つとは、 .vs .vs コマンドで設定されている値2つ分である(これは、はっきりと .sp 2v .sp 2v としてもよい)。 troff ではこのような指定をする場合、小数を用いることもできる。 .sp 1.5i は1.5インチの行間を示す。行間を決める .vs .vs コマンドにも同じようなスケール ファクタがある。実際、このような スケール ファクタは、物理的大きさを扱うほとんどのコマンドで 用いることができる。 大きさを表わす数はすべて、内部で 432分の1 インチ( 6分の1 ポイント)という 機械内部単位に変換されているという事に注意してほしい。 ほとんどの場合これでも充分な解像度が得られるので、 表現の正確さについて気にすることはない。ただし、 144分の1 インチ( 2分の1 ポイント)の解像度のところでは、 垂直方向の状態はそれほどよいとはいえない。 #a フォントと特殊文字 troff および写植機では、同時に4つの異なるフォントを用いることができる。 通常は、3つのフォント(タイムス ローマン、イタリック、ボルド)と、 特殊文字を集めたものがひとつ常時マウントされている。 abcdefghijklmnopqrstuvwxyz 0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz 0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz 0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ ギリシャ文字、数学記号、およびその他の特殊なフォントは付録Aに列挙してある。 troff は特に指定がない限り、ローマンを使う。 ボルドに切り替えるには、 .ft .ft コマンドを用いる。 .ft B イタリックにするには次のように指示する。 .ft I ローマンに戻すには、 .ft R .ft R を用いる。直前のフォントに戻すには、 .ft P .ft P または単に .ft .ft を用いる。「下線」付けコマンド .ul は、次の入力行をイタリックで印刷させる。 1行以上をイタリックで印刷するため、 .ul .ul コマンドに行数を指定することができる。 インライン コマンド \f \f を用いて行の途中、単語の途中でフォントを切り替えることができる。 boldface text は、次のようなテキストから作り出される。 \fBbold\fIface\fR text 一連の切替え前のフォントに戻したい場合は、次のようにさらに \fP \fP を挿入すればよい。 \fBbold\fP\fIface\fP\fR text\fP 変更される直前のフォントだけが常に記憶されているので、 変更の度に直前のフォントに戻すという手順を踏まないと、 わからなくなってしまうわけである。同様なことが .ps .ps および .vs .vs を引数なしで使うときにも起こる。 標準セットの他にも仕様可能なフォントがあるが、 いずれを使うにしても同時には4つしか使えない。 .fp .fp コマンドは、どのフォントが写植機にマウントされているかを troff に指示する。 .fp 3 H はヘルベティカがポジション3にマウントされていることを示す (フォント、およびどのようなものがあるかを示す完全なリストは troff のマニュアルを参照されたい)。 標準のフォントを使わない場合は、文書の先頭に適切な .fp .fp コマンドがなければならない。 フォント名のかわりにフォント番号を用いることにより、 実際に印刷するときのフォントとは比較的独立して文書を作成することもできる。 たとえば、 \f3 \f3 と .ft~3 .ft~3 は「ポジション3にマウントされているフォント」を表わし、 そこになにが設定されていても機能する。 通常のセッティングでは、ローマンが1、 イタリックが2、 ボルドが3、 特殊文字が4になっている。 ボルドを、文字をわずかにずらして二重打ちすることにより「合成」する 方法もある。参考文献 の .bd .bd コマンドの説明をみてもらいたい。 特殊文字は最初の2文字が \( \( である4文字の名前を持っていて、どこにでも挿入することができる。たとえば、 \(14 + \(12 = \(34 は次のような行から作られる。 \(14 + \(12 = \(34 特にギリシャ文字は、 \(\(**\- \(\(**\- の形をしていて、 \- \- はギリシャ文字を連想させる英大文字か英小文字である。 【英字と一対一に対応させている】 \(*S(\(*a\(mu\(*b) \(-> \(if を、はだかの troff で作るためには次のようにタイプしなければならない。 \(\(**S(\(\(**a\(mu\(\(**b) \(\(mi> \(if この行を解読すると、次のようになる。 \(\(**S \(*S ( ( \(\(**a \(*a \(mu \(mu \(\(**b \(*b ) ) \(\(mi> \(-> \(if \(if このような特殊なものの名前のリストは付録Aにある。 次のような入力を与えることにより、 eqn でも同じ効果を得ることができる。 SIGMA ( alpha times beta ) \-> inf これは簡潔ではないが、原理を知らない者にもわかりやすい。 上に述べたような4文字の名前は、 troff から見るとひとつの文字であるということに注意してほしい。 次のような「変換」コマンド .tr \(mi\(em の内容は明快で、 .tr \(mi\(em を表わし、これにより\(mi(マイナス)は\(em(全角のハイフン)に変換される。 いくつかの文字は自動的に変換されるようになっている。 グラーブアクセント\(gaやアキュートアクセント\(aaは 開きクォート、閉じクォート `~' に置き換えられる。これらの組み合わせ ``...'' の方がダブルクォートを用いた "..." のような表現よりも一般に好まれる。 同様に、ただのマイナス符号\-はハイフン-になる。 マイナス符号の方を印刷したい場合は \- \- を用いなければならず、逆スラシュを印刷したい場合は \e \e を用いる。 #a #vtyson 字下げと行の長さ troff では、一行の長さは初期状態で6.5インチであるが、 この値は8\(12 \(mu 11インチの用紙では長すぎる。 行の長さを変えるには ll ll コマンドを用いて、たとえば次のようにする。 .ll 6i .sp .sp と同様、長さもいく通りかの方法で指定することができる。 インチを用いるのはもっとも直感的であろう。 写植機の制約から決まる最大行長は、7.5インチである。 この長さいっぱいに使うつもりであれば、標準の物理的左マージン (『ページオフセット』のこと)も変更しなければならない。 左マージンは、通常用紙の左端から約1インチ弱になっている。 これの変更は .po .po コマンドを使って行なう。 .po 0 この例は、オフセットを可能な限り左に設定することを示す。 字下げコマンド .in .in では、ページオフセットから指定された量だけ左マージンの字下げを行なう。 .in .in コマンドを用いて左マージンを右側に寄せ、 .ll .ll コマンドを用いて右マージンを左側に寄せると、 テキストのオフセットブロックを作ることができる。たとえば、 .in 0.3i .ll \(mi0.3i text to be set into a block .ll +0.3i .in \(mi0.3i によって、次のようなブロックができあがる。 Pater noster qui est in caelis sanctificetur nomen tuum; adveniat regnum tuum; fiat voluntas tua, sicut in caelo, et in terra. ... Amen. 変化量を指定する時に+、\-を用いていることに注意してほしい。 このような方法による変更は直前の値を書き換えてしまうのではなく、 指定した量だけ値を変化させるというものである。 この違いは重要で、 .ll +1i .ll +1i は行長を1インチ長くすることであるのに対し、 .ll 1i .ll 1i は行長を ちょうど1インチに するというものである。 .in .in、 .ll .ll そして .po .po コマンドでは引数がない場合、直前の値をそのまま用いる。 1行だけ字下げを行なうために、「一時的字下げ」コマンド .ti .ti がある。 実際、このメモのパラグラフはすべて次のようなコマンドで始まっている。 .ti 3 ここで、3とは何のことであろうか? .ti .ti の標準の単位は、他の水平方向に係わるコマンド (.ll .ll、 .in .in、 .po .po) のほとんどと同様、エムである。 エムとは、だいたい現在のポイント サイズにおける文字「m」の巾のことである (正確にいうと、サイズ p のエムは p ポイントである)。 日常タイプをしていない人々にとっては、 エムよりもインチの方がわかりやすいのではあるけれども、 エムが標準になっている。 つまり、現在のポイント サイズに比例したサイズが物差しになっているのである。 ポイント サイズを考慮しないで釣り合いのとれたテキストを作りたい場合は、 大きさを表わす必要があるところではすべてエムを用いるべきである。 エムは、 .ti 2.5m .ti 2.5m のようにスケール ファクタとして直接指定することができる。 字下げの値が正になっている時は、負の字下げを施すことができる。 たとえば、 .ti \(mi0.3i とすると、次の行の先頭が10分の3インチ左に寄る。 したがって、パラグラフの最初の大文字を装飾的に大きくするためには、 パラグラフ全体を字下げして、 .ti .ti コマンドで「P」を引き戻せばよい。 P ater noster qui est in caelis sanctificetur nomen tuum; adveniat regnum tuum; fiat voluntas tua, sicut in caelo, et in terra. ... Amen. もちろん、「P」を大きくし(たとえば、「\s36P\s0」とする)、 それを本来の場所から動かす(部分的移動の節を参照) トリッキィな方法もいくつかある。 #a タブ タブ(ASCIIの「水平タブ」コード)はコラム分けに用いたり、 水平方向の位置を設定するために使われる。 これは通常、詰込みをしないテキストに対してのみ使われる。 タブ ストップは、標準で現在の字下げ位置から半インチ毎に設定されているが .ta .ta コマンドで変更することができる。 たとえば、1インチ毎に設定するには、次のようにする。 .ta 1i 2i 3i 4i 5i 6i あいにく、このタブ ストップでは(普通のタイプライタと同様) 左端揃えしかできない。 右端を揃えた数字のコラムを並べるために用いるのは困難である。 数字がたくさんあったり、複雑な作表を行なう場合は、 troff を直接 使わずに tbl を使うべきである。 tbl についてはで説明している。 作ろうとするコラムに数字が少ない場合は次のようにすればよい。 まずタイプするときに、数字の前にそれらを揃えるための充分な空白を入れておく。 .nf .ta 1i 2i 3i 1 tab 2 tab 3 40 tab 50 tab 60 700 tab 800 tab 900 .fi 次にそれらのスペースを文字列 \0 \0 で置き換える。 これは、印刷はされないが数字と同じ巾を持つ「文字」である。 上の例は印刷されると次のようになる。 1 2 3 40 50 60 700 800 900 .tc .tc コマンドで「タブ置換え文字」を設定すれば、 タブで広げられた空間を空白以外の文字で埋めることもできる。 .ta 1.5i 2.5i .tc \(ru (\(ru is "\(ru") Name tab Age tab は次のようになる。 Name \(ru\(ru\(ru\(ru\(ru\(ru\(ru\(ru\(ru\(ru\(ru\(ru\(ru\(ru\(ru\(ru Age \(ru\(ru\(ru\(ru\(ru\(ru\(ru\(ru\(ru\(ru タブ置換え文字をもとに戻したいときは .tc .tc を引数なしで用いればよい。(線は \l \l コマンドでも引くことができるが、これについては次節で説明する。) troff では、複雑なコラムの設定ができるように「フィールド」と呼ばれるメカニズムを 備えている( tbl で使う)が、ここでは触れない。 #a 部分的移動: 線を引く、文字を描く 「\(*pr 2 」や、 ラテン語の文章で使っていた大きい 「P」 を思い出してほしい。 あれらはどのようにして表現されていたであろうか? troff には、 様々な大きさの文字をどこにでも配置できるような 多くのコマンドが備わっている。 これらを使えば特殊文字を描いたり、 独特な形の出力をチューンしたりすることもできる。 これらのコマンドは簡単であるが、 読み辛く、正確にタイプするのも骨が折れる。 サブスクプリトやスーパースクリプトは、 eqn を使わなくても半改行 \u \u と逆半改行 \d \d によって簡単に処理することができる。 希望する箇所に \u \u を挿入することにより、 ページ位置をポイント サイズの半分だけ戻すことができる。 半分だけ下げる(進める)には \d \d を用いる。 (後で述べるように、 \u \u と \d \d は必ず組にして使うようにしないとまずいことが起こる。) Area = \(\(**pr\u2\d から Area = \(*pr 2 ができる。 「2」を小さくするためには、 \s\-2...\s0 \s\-2...\s0 でくくればよい。 \u \u と \d \d はそのときのポイント サイズを参照するので、 それらはサイズを変化させるところの外側または内側で 適格に位置付けなければならない。 さもないと、縦方向の移動がアンバランスになってしまう。 \u \u と \d \d で得られる空間が適切でないこともあるかもあり得る。 \v \v コマンドでは、任意の量だけ縦方向に移動することができる。 インライン コマンド \v\(aa(移動量)\(aa で、「(移動量)」で示された量だけペ-ジ内で上下に動くことができる。 たとえば、「P」を下げるために次のようにする。 .in +0.6i (move paragraph in) .ll \-0.3i (shorten lines) .ti \-0.3i (move P back) \v\(aa2\(aa\s36P\s0\v\(aa\-2\(aaater noster qui est in caelis ... マイナス符号で上向きの移動、符号がないかプラス符号で下向きの移動が起こる。 したがって、 \v\(fm\-2\(fm \v\(fm\-2\(fm で2行分上に移動する。 移動量を指定する方法は、他にもいろいろある。 \v\(aa0.1i\(aa \v\(aa3p\(aa \v\(aa\-0.5m\(aa i i、 p p、 m m 等のスケール指示子がクォートの内側にあることに注意してほしい。 クォートの代わりに他の文字を使うこともできる。 これは、この節で扱っている他の troff コマンドでも同様である。 troff はページ内の位置決めの時に、 行中の縦方向の移動を考慮していないので、 行の左右端の縦方向の位置が合っていない場合、 出力行に予想外の移動を起こすかもしれない。 したがって、 \v \v も \u \u、 \d \d と同様、ひとつの行の中での上方向と下方向の移動量を バランスさせなければならない。 \h \h は、 \v \v に似ていて、任意に水平方向の移動ができる。 ただし、標準のスケール ファクタは、 行間値ではなくエムを用いている。 たとえば、 \h\(aa\-0.1i\(aa は、10分の1インチ前に戻るということである。 実際の例として、数学記号「>>」を印刷することを考えてみよう。標準 の字間値では広すぎるので、 eqn ではこのような入力を >\h\(aa\-0.3m\(aa> に置き換えている。これにより、 > > が得られるわけである。 \h \h は、与えられた文字列の巾と同じだけの移動を作り出すという、 「巾に関する関数」 \w \w と同時に使われることが多い。 \w\(aaなにか\(aa で、「なにか」という文字列の持つ巾を機械内部単位( 432分の1 インチ)で 表わした値になる。 troff 内部で行なわれる計算はすべて、最終的にこの単位に換算して行なわれる。 「x」の巾だけ水平方向に移動するには、 \h\(aa\w\(aax\(aau\(aa とする。既に述べたように、 水平方向の大きさを表わすスケール ファクタの標準は m m すなわちエムである。 今の例では、 \w \w によって得られる値が機械内部単位であるので、 そのことを示すために u u を付けなければならない。 これを忘れると、かなり大きな移動になってしまうだろう。 troff は、クォートの入れ子構造を許しているが、 ひとつでも書き落とすとどうなるかわからない。 このように機能を組み合わせて使うことの実際の例は、 このテキスト自体にも表われている 等のコマンド名で、 これらはわずかにずらして二重打ちすることによってできている。 の場合のコマンドは、 .sp\h\(aa\-\w\(aa.sp\(aau\(aa\h\(aa1u\(aa.sp としている。 これはまず、「.sp」を打ち出し、「.sp」の巾だけ左に移動し、 1機械内部単位だけ右に移動してから再び「.sp」を打ち出している (コマンド名を入れるときにいちいちこれを全部タイプしなくても済む手段も もちろんあるが、それについては11節で述べることにする)。 部分的移動に関する特殊用途の troff troff コマンドもいくつかある。 既に、数字と同じ巾を持つパッドできない空白 \0 \0 について述べた。 「パッドできない」とは、行揃えや詰込みによって、 行をまたがったり巾を広げられたりすることができないという意味である。 パッドできない文字は他に、空白と同じ巾を持つ \(空白) \(空白)、 その半分の \| \|、 そのまた半分の \. \.、 巾のない \& \& がある( \& \& は、 たとえば行の先頭が「.」であるようなテキストを作りたいとき等に有効である)。 \o\(aa文字の集合\(aa のようにして使われる \o \o は、(9文字までの) 文字を巾の最も広いものの中心に合わせて二重打ちするために使う。 これはアクセント記号を入れるときに便利で、 syst\o"e\(ga"me t\o"e\(aa"l\o"e\(aa"phonique とすれば、 syste \(ga me te \(aa le \(aa phonique とできる。 アクセント記号は、 \(ga \(ga と \(aa \(aa、 または \\(ga \\(ga と \\(aa \\(aa である。これらは、 troff において、すべて一文字であることに注意してほしい。 別の特別な慣用法を用いて、独自の二重打ちを作り出すことができる。 これは、無移動コマンド \z \z である。 \zx \zx とすると、 x x を印刷した後の通常の水平方向の移動が抑制されるので、 次の文字は x x の上に印刷される。 \o \o でも移動サイズを変えることはできるが、 最も巾の広い文字の中心に合わされてしまうのに対し、 垂直にも水平にも移動しないので、 \z \z がこのようなことを行なう唯一の方法である。 \(sq\(sq\(sq\(sq は、次のコマンドで作ることができる。 .sp 2 \s8\z\(sq\s14\z\(sq\s22\z\(sq\s36\(sq 1行目の .sp .sp は、空間を確保するために必要である。 別の例として、次のようなぐっと大きいセミコロンは , . instead of ; or ; 大きなコンマと大きなピリオドを使って、次のように構成することができる。 \s+6\z,\v\(aa\(mi0.25m\(aa.\v\(aa0.25m\(aa\s0 「0.25m」というのは経験的に得られた値である。 もっと凝った二重打ちは、 かっこでくくる(ブラケッティング)機能 \b \b を使って作り出すことができる。 これは、現在のベースラインを中心に文字を縦に積み上げる。 このように、小さな要素を組み立てて大きなブラケットを得ることができる。 \(lt \(lk \(lb \(lc \(lf x \(rc \(rf \(rt \(rk \(rb は、次のようにタイプするだけで作り出すことができる。 .sp \b\(fm\(lt\(lk\(lb\(fm \b\(fm\(lc\(lf\(fm x \b\(fm\(rc\(rf\(fm \b\(fm\(rt\(rk\(rb\(fm troff は、任意の文字を用いて、 任意の長さの横線、縦線を引くという便利な機能を持っている。 \l\(fm1i\(fm \l\(fm1i\(fm とすると、このように \(ru \(ru\(ru\(ru\(ru\(ru\(ru\(ru\(ru\(ru\(ru\(ru\(ru\(ru\(ru 1インチの線が引ける。 線を引く文字として \(ru が適当でないのならば、 使用する文字を後ろに続けて指定することができる。 たとえば、 \l\(fm0.5i.\(fm \l\(fm0.5i.\(fm とすると、半インチの点線 .............. になる。 \L \L は、横線のかわりに縦線を 引くということ以外はまったく同じである。 #a ストリング ひとつの原稿の中にアキュート アクセントの付いた 「e」 がたくさん出てくる場合、 e \(aa それぞれに、いちいち \o"e\\(aa" \o"e\\(aa" とタイプするのは非常にめんどうである。 troff には、任意のテキストを「文字列」として覚えさせておき、 ストリング名を速記のようにして使うという方法がある。 ストリングをうまく使うことにより、 わずかな労力で文書をタイプすることができ、 広範囲にわたるフォーマットの変更も編集による変更をほとんどせずにできる、 troff のメカニズムのひとつである。 ストリングが参照されると、 それがどのようなものであれ、 定義されたテキストに置き換えられる。 ストリングは、 .ds .ds コマンドで定義する。 たとえば、 .ds e \o"e\\(aa" は、ストリング e e に \o"e\\(aa" \o"e\\(aa" という値を持たせるということを定義する。 ストリング名は一文字または二文字で、 一文字のものは \\(**x \\(**x という形で、二文字のものは \\(**(xy \\(**(xy という形で参照する。 上のようにストリング e e が定義されている場合、 te \(aa le \(aa phone を得るためには、 t\\(**el\\(**ephone. とすればよい。 もし定義したい文字列が空白で始まる場合は、 .ds xx " text のように定義する。 ダブルクォートが定義される文字列の先頭を表わす。 文字列の末尾を示すダブルクォートはなく、 行末がそれを示す。 ひとつのストリングが数行にわたることもある。 troff では、行末に \ \ があった場合、 それを無視して次の行を現在行に結合する。 したがって、途中の行を \ \ で終わらせることによって長い文字列を作ることができる。 .ds xx this \ is a very \ long string ストリングは他のストリングを用いて、 もしくは他のストリング自身によって定義することもできるが、 このことについては後で触れることにする。 #a マクロについて troff についてさらに説明する前に、 マクロ機能について少し述べる必要がある。 マクロは、形を簡単にするといった点で、 ストリングによく似た速記的表記法である。 いま、パラグラフはすべてまったく同じ形式で始めたいとする。 たとえば、パラグラフの先頭で一行あけて、 最初の行を2エムだけ字下げをしたい場合、 .sp .ti +2m とする。タイピングの手間を省くため、これらを一行に入れてもっと短く .PP のような「コマンド」で、 .sp .ti +2m として扱ってほしいわけである。 .PP .PP はマクロと呼ばれている。 コマンドによる 定義 によって の意味が何であるかを troff に指示する。 .de PP .sp .ti +2m .. 最初の行でマクロの名前を指定する (パラグラフなので 「.PP .PP」 という名前を用いる。 大文字の名前であるので、既にある他の troff コマンドと名前がぶつかることはないと思う)。 最後の .. .. は、定義の終わりを示している。 これらの間にあるものはテキストとみなされ、 troff が .PP のような「コマンド」すなわちマクロ呼出しに出会った時は、 これらが単に挿入される。 マクロでは、テキストと清書用コマンドをどのように取り混ぜてもよい。 このようなマクロは、 最初に使われる前に定義されていなければならない。 未定義なマクロは単に無視されるだけである。 マクロの名前は2文字までに制限されている。 共通して現われるコマンドの列にマクロを使うことは重要なことである。 それはタイピングの手間を省くばかりでなく、 後で変更するときたいへん容易に行なえる。 たとえば、パラグラフの字下げが少なすぎるし、 行間も広くあきすぎるのでそれぞれ修正し、 さらにフォントは必ずローマンを使うことにしたいとする。 この場合、文書全体を書き換えるのではなく、 .PP .PP の定義だけを次のように変更すればよい。 .de PP \" パラグラフ マクロ .sp 2p .ti +3m .ft R .. こうすれば、この変更が .PP .PP を用いている箇所すべてに変化を及ぼす。 \" \" も troff のコマンドで、行の残りの部分を無視するというものである。 ここでは、マクロの定義中にコメントを入れるために用いている (マクロ定義が複雑なときに便利であろう)。 別の例として、この論文にたくさん現われる、 詰込みをしないオフセット ブロックを作り出す2つのマクロをみてみよう。 .de BS \" 字下げブロック開始 .sp .nf .in +0.3i .. .de BE \" 字下げブロック終了 .sp .fi .in \(mi0.3i .. これにより、次のようなテキストを .BS .BS と .BE .BE で取り囲めば、ちょうどこのようなブロックを作ることができる。 Copy to John Doe Richard Roberts Stanley Smith ここで、字下げをするのに .in .in0.3i ではなく、 .in .in+0.3i を使ったことに注意してほしい。これにより、 .BS .BS と .BE .BE を使ったブロックの入れ子を作ることができる。 もし後でパラグラフの字下げを0.5iにしたくなれば、文書全体ではなく、 .BS .BS と .BE .BE の定義だけを書き換えればよいわけである。 #a 表題、頁分け、頁番号付け ここに述べる分野は、扱いが困難な領域である。 なぜなら、自動的に行なえることがなにもないからである。 この節のある部分は料理の本のようなものである。 すなわち、 ある程度経験してみるまでは文字どおり模倣してみることが必要になるからである。 いま、各ページの先頭に次のような表題を付けたいとしよう。 ~~~~左上 中央 右上~~~~ roff では、 各ページに自動的にヘッダとフッタをつけたいときは次のようにすればよかった。 .he\(aa左上\(aa中央上\(aa右上\(aa .fo\(aa左下\(aa中央下\(aa右下\(aa しかし、なんと、 troff にはこの機能がなく、 初心者にとってはたいへんやっかいなものになっている。 つまり、もっとたくさんのことを指示しなければならないのである。 まず、表題を何であるかを指定し(これは簡単)、 それをいつ印刷するかを指定し(これも簡単)、 表題行とその周辺でなにをするかを 指定しなければならない(これが極めて困難)。 逆順に説明するとまず、 表題の処理等、 各ページの終わりと次のページの始めで同じことをさせるために、 マクロ .NP .NP を定義する。 .de NP \(fmbp \(fmsp 0.5i .tl \(aa左上\(aa中央上\(aa右上\(aa \(fmsp 0.3i .. まず、ページの始まりにいることを明らかにするために、 「ページ開始」コマンド \(fmbp \(fmbp を発行する。( \(fm \(fm を簡単に説明すると) これによりページの先頭までのスキップを起こさせるわけである。 次に半インチほど間隔をおいて表題を印刷する。( .tl .tl コマンドの使い方は自明なので説明しない。 後で表題付けをパラメタ化することについて説明する。) 各ページの終わりでいつも .NP .NP を使うためには、 「テキストがページの終わりから1インチ以内に達していたら、 新しいページの処理を開始せよ」というような指示ができないと困るだろう。 これは、「when」コマンド .wh .wh で扱うことができる。 .wh \-1i NP (NPの前に「.」はない。 このNPは、マクロの名前を指定しているのであり、 マクロ呼出しではないのである。) マイナス符号は「ページの底から測って」という意味であって、 「\-1i」で「ページの底から1インチ」を意味する。 .wh .wh コマンドは、 .NP .NP の定義の外に現われる。たとえば、 .de NP ... .. .wh \-1i NP のようにである。 さて、どのようになるのであろうか? troff はテキストを実際に出力しているときにそのページ内の縦位置を監視していて、 印刷した行が底辺から1インチ以内に達すると .NP .NP マクロを起動する(専門的に説明すると、 .wh .wh コマンドは指定された場所にトラップを設定していて、 その位置を通ると(トラップが)「引き起こされ」る)。 .NP .NP は次のページの先頭までスキップし(これは \(fmbp \(fmbp が起こす)、その後適当なマージンをとって表題を印刷する。 .bp .bp や .sp .sp としないで、 \(fmbp \(fmbp と \(fmsp \(fmsp になっていることに気付いたであろうか。 これは、 .bp .bp や .sp .sp が他のいくつかのコマンドと同様、 ブレイク を引き起こすことによる。 ブレイクとは、 既に取り込まれているがまだ印刷されていないテキストを強制的にはき出し、 次の入力行が新しい出力行の先頭になるようにするものである。 .NP .NP マクロで .bp .bp や .sp .sp を使うと、 新しいページを開始したときにその時点の出力行の途中でブレイクが生じてしまう。 その結果、ページの先頭の行に残りの部分が印刷され、 次の入力行が新たな出力行になってしまう。 これは我々が望んだ結果では ない。 コマンドで、 . . の代わりに \(fm \(fm を用いることにより troff にブレイクを起こさないよう指示することができる。 つまりこのようにすると、 現在詰め込んでいる出力行が 空白や新しいページになるまで強引に出力されてしまうというようなことはない。 ブレイクを起こすコマンドを次に列挙するが、 これは数も少なく自然なものである。 .bp .br .ce .fi .nf .sp .in .ti 他のコマンドはすべて、 . . と \(fm \(fm のどちらを使ってもブレイクを起こすことは ない。 もし、ブレイクが必要な場合は、 適当な場所に .br .br コマンドを入れればよい。 注意しなければならないことがもうひとつある。 それは、フォントやポイント サイズを頻繁に変える場合、 それらの関係で予期せずそのページの範囲を越えてしまったときに、 意図していたものではなく、 そのときのフォントやサイズで表題が印刷されてしまうことがあるということである。 また、表題行の長さはその時々の行の長さとは無関係であり、 変更しない限り標準の6.5インチが用いられる。 表題行の長さの変更は、 .lt .lt コマンドで行なう。 このような表題行のポイント サイズやフォントの問題を 解決する方法はいくつかある。 最も簡単なのは、 .NP .NP の定義を変更して表題の部分だけ適切なサイズやフォントを設定し、 後で元に戻すことであろう。 たとえば、 .de NP \(fmbp \(fmsp 0.5i .ft R \" フォントをローマンにする .ps 10 \" サイズは10ポイント .lt 6i \" 行長は6インチ .tl \(aa左\(aa中\(aa右\(aa .ps \" 元のサイズに戻す .ft P \" 元のフォントに戻す \(fmsp 0.3i .. この .NP .NP は、 .tl .tl コマンドがサイズやフォントの変更を含む場合はうまく動かない。 うまく処理するには troff の「環境」メカニズムを用いなければならないが、 これについては13節で述べることにする。 ページの終わりにフッタを作るためには、 .NP .NP を修正して \(fmbp \(fmbp コマンドの前でなんらかの処理を行なうようにするか、 .NP .NP でやっていることをページの終わりで呼び出されるフッタ マクロと、 始めで呼び出されるヘッダ マクロに分ける等の方法がある。 どのようにするかは、課題として残しておく。 出力ページ数は、 ページが作り出される毎に自動的に計算される(1から始まる)。 しかし、これははっきりと指定しない限り印刷されることはない。 ページ番号を印刷したい場合は、 .tl .tl の行の中で希望する場所に文字 % % を置けばよい。 .tl \(aa\(aa- % -\(aa\(aa とすると、(このページにあるように) ページ番号をハイフンではさんで中央に印刷する。 次のようなコマンドにより、ページ番号を任意に設定することができる。 ひとつは .bp n .bp n で、ページ番号 n n の新しいページを直ちに作り出す。 もうひとつ .pn n .pn n は、次のページのページ番号をnにする。 こちらはページを作り出すことはない。 .bp +n .bp +n はページ番号が現在の値より n n 大きいページを作り出す。 .bp .bp は .bp +1 .bp +1 と同じことである。 #a 数値レジスタと演算 troff では、数値を値とし、演算を行なうことができる、 数値レジスタ と呼ばれる変数を定義して使うことができる。 数値レジスタは、ストリングやマクロと同様、文書作成に役立ち、 またそれを用いたものを後で修正することも容易になる。 もちろん種々の算術演算を行なうことができる。 ストリングと同様、数値レジスタも一文字ないし二文字の名前を持つ。 その値は、 .nr .nr コマンドで設定され、 \nx \nx (一文字の場合)または \n(xy \n(xy (二文字の場合)のようにして参照できる。 troff が管理している『あらかじめ定義された』数値レジスタがいくつかある。 それらは、現在のページ番号に関する % %、 ページ内の現在の縦の位置に関する nl nl、 現在の年月日に関する yr yr、 mo mo、 dy dy、 現在のポイント サイズとフォントに関する .s .s と .f .f である( .f .f の値は1から4までの数である)。 これらは、他の数値レジスタと同様、計算に用いることはできるが、 .s .s と .f .f は .nr .nr コマンドで値を変更することはできない。 数値レジスタの使用例に \-ms \-ms マクロ パッケージ があるが、 重要なパラメタのほとんどが、 極く少数の数値レジスタの値によって定義されている。 たとえばテキストのポイント サイズ、行間、 ふつうの行長および表題の行長等である。 パラグラフのポイント サイズと行間を設定するのは次のようにすればよい。 .nr PS 9 .nr VS 11 パラグラフ マクロ .PP .PP は(おおよそ)次のように定義される。 .de PP .ps \\n(PS \" サイズを再設定する .vs \\n(VSp \" 行間を再設定する .ft R \" フォントはローマンに .sp 0.5v \" 半行空ける .ti +3m .. これは、フォントをローマンに、 ポイント サイズと行間値を数値レジスタ PS PS と VS VS に設定されている値にするものである。 なぜ逆スラシュが2つずつあるのであろうか。 これは、クォートをどのようにクォートする(引用する)かという よく知られた問題の一種である。 troff マクロ定義を最初に読み取るむときに、 逆スラシュを(ひとつ)とってしまうので、 マクロ展開されたときにひとつが残っているようにするため2つあるのである。 逆スラシュがひとつしかなかった場合、 ポイント サイズと行間値は、マクロ定義のところで固定されてしまって、 マクロが使われるときには変化しないであろう。 逆スラシュを余分に置いて[その存在を]保護しなければならないのは、 \n \n、 \\(** \\(**、 \$ \$ (これらについてまだ触れていないが)と、 \ \ 自身である。 \s \s、 \f \f、 \h \h、 \v \v 等はその必要がない。 なぜならばこれらは、 troff が検出するとすぐに内部コードに変換されてしまうからである。 計算式は、数値が現われてもよいところならばどこに現われてもよい。 極く簡単な例として、次のものは数値レジスタ PS PS の値を2減ずるというものである。 .nr PS \\n(PS\-2 式のなかには、算術演算子+、\- 、\(** 、/ 、%(剰余)や 関係演算子>、>=、<、<=、=、!=(not equal) および、かっこを使うことができる。 これまで行なってきた計算はすなおなものであったが、 もっと複雑なものはいくぶんトリッキィになる。 数値レジスタが値として保持できるのは整数だけであり、 割り算はFORTRAN同様、切捨てを行なう。 また、かっこがない場合の評価は演算子の優先順位をまったく考慮せず、 左から右におこなわれる(関係演算子も同様)。たとえば、 7\(**\-4+3/13 は、「\-1」になる。 数値レジスタは式のどこに現われてもよい。 p p、 i i、 m m 等のスケール指示子も同様である(スペースは除く)。 割り算は切捨てを起こすが、 数値やスケール指示子は 計算を始める前に機械内部単位(432分の1インチ)に変換されるので、 1i/2u の値は正しく 0.5i になる。 スケール指示子 u u は、 なぜこのようなところに必要なのかと思える場所になければならないことがよくある。 特に、縦横の大きさに関する計算がおこなわれる文脈によくある。 たとえば、 .ll 7/2i は、 3\(12 インチと読める。 が残念なことに、 .ll .ll コマンドなどにおける水平方向のパラメタの標準単位は エムであるということを思い出してもらいたい。 上の例は、「7エム/2インチ」であり、 機械内部単位に置き換えてから計算すると結果はゼロになる。 .ll 7i/2 はどうだろうか。 これでもまだまずくて、2は2エムであるから7i/2はゼロではないが、 かなり小さな値である。 3\(12 インチを得るためには、 .ll 7i/2u と しなければならないのである。 前にも似たようなことを述べたが、 安全策は定数の場合を含めすべての数値にスケール指示子をつけるということである。 .nr .nr コマンドで行なわれる計算には、 縦横の大きさは何の係わりもなく、 標準単位が「機械内部単位」であるので、 7i/2 と 7i/2u は同じ意味であり、 .nr ll 7i/2 .ll \\n(llu は、 .ll .ll コマンドの u u を忘れない限り、上と同じものになる。 #a 引数のあるマクロ 次の段階として、 一度使ったものを引数として与えられたパラメタにしたがって変更し、 次にまた使えるような、マクロを定義することを考えよう。 このためにはふたつのことが必要になる。 ひとつは、マクロを定義する際、 どの部分をマクロ呼出し時に引数として使うのかを 指示しなければならないということである。 そしてもうひとつは、マクロを呼び出す際、 定義と結合させる実引数を与えなければならないということである。 ここで、テキストを引数とし、 それをまわりのテキストより2ポイント小さくするというマクロ .SM .SM の定義を示そう。 このマクロは、 .SM TROFF のように呼び出されると、 TROFF を生成するものである。 .SM .SM の定義は次のようにする。 .de SM \s\-2\\$1\s+2 .. 定義中に現われる \\$n \\$n という記号は、マクロが呼び出されたときのn番目の引数を参照している。 つまり、この場合の \\$1 \\$1 は .SM .SM が呼び出されたときに2ポイント小さく印刷される文字列のことである。 もう少し複雑な例として、次のように .SM .SM を定義すると、 通常のサイズで印刷される2番目、 3番目の引数をオプショナルに持たせることができる。 .de SM \\$3\s\-2\\$1\s+2\\$2 .. マクロが呼び出されたときに与えられなかった引数は、空として扱われる。 したがって、 .SM TROFF ), とすると、 TROFF), を生成し、 .SM TROFF ). ( とすると (TROFF). を生成する。 引数が実際に印刷される順番と引っ繰り返っているが、 (ピリオドやコンマ等の) 句読点は前につくよりも後につくことの方が普通であるから、 この方が便利である。 マクロが呼び出されたときの引数の個数は、数値レジスタ .$ .$ で知ることができる。 次のマクロ .BD .BD は、この文書自身の中で troff のコマンド名を表わすために用いている、 「ボルド ロ-マン」を作り出すものの一例である。 これは縦方向の移動、巾の計算、引数の再配置を組み合わせている。 .de BD \&\\$3\f1\\$1\h\(aa\-\w\(aa\\$1\(aau+1u\(aa\\$1\fP\\$2 .. 先に触れたように、 \h \h および \w \w コマンドは余分な逆スラシュを必要としない。 先頭の \& \& は、引数がピリオドで始まっている場合の対策としてある。 \\$n \\$n コマンドでは、2つの逆スラシュが必要であるが、 それはマクロ定義のときに、それらのうちの1つを保護するためであった。 次の例がたぶんこのことをよく示しているであろう。 この論文にあるように、節の見出しを、番号を自動的につけ、 表題を少し小さくボルドで印刷するようにする .SH .SH と呼ばれるマクロを考えてみてみよう。使うときは次のようにする。 .SH "節の表題 ..." (マクロの引数のなかに空白を入れたいときは、 引数をダブルクォートで くくらなければならない。 これは先頭のクォートだけでよい、ストリングとは異なる。) .SH .SH の定義は次のようにする。 .nr SH 0 \" 節番号の初期化 .de SH .sp 0.3i .ft B .nr SH \\n(SH+1 \" 数え上げ .ps \\n(PS\-1 \" PSを1減らす \\n(SH. \\$1 \" 番号. 表題 .ps \\n(PS \" PSを元に戻す .sp 0.3i .ft R .. 節の番号は数値レジスタ SH SH で管理していて、その値は使われる直前に毎回増やされる。 (数値レジスタはマクロと同じ名前を持つことができて衝突はおこらないが、 ストリングはこの限りではない。) ここでは、 \n(SH \n(SH のかわりに \\n(SH \\n(SH を、 \n(PS \n(PS のかわりに \\n(PS \\n(PS を使っている。もし、 \n(SH \n(SH を使ったとすると、 得られるレジスタの値はそれを 使ったときの値 ではなく、 定義されたときの値 である。 もしそのようにしたかったのであればそれでもよいのであるが、 ここではそのような使い方をしているのではない。 同様に、 \\n(PS \\n(PS を使う ことにより、マクロが呼び出されたときのポイント サイズを得ることができる。 数を含まない例として、 .NP .NP マクロのことを思い出してみよう。それは次のようなコマンドを含んでいた。 .tl \(aa左\(aa中\(aa右\(aa 代わりに次のようなものを用いることにより、 コマンドの引数をパラメタ化することができる。 .tl \(aa\\\(**(LT\(aa\\\(**(CT\(aa\\\(**(RT\(aa これにより、表題は、 LT LT、 CT CT、 RT RT という3つのストリングで作られる。 それらが空であれば、表題行は空行になる。 通常、 CT CT は次のようなものに設定されている。 .ds CT - % - これは、(原文のように)ハイフンでくくったページ番号になるが、 もちろんユーザが任意の文字列を使って自分専用の定義をすることができる。 #a 条件式 .SH .SH マクロを改良して、 この論文のように第1節の前だけ2インチの余白をあけ、 その他の節ではあけないようにしたいとしよう。 最もわかりやすい方法は、 .SH .SH マクロの中で節の番号が1であるかどうかを調べ、 もしそうであれば何行か空行をあけるようにすることである。 このように見出し行を印刷する前に条件判定ができるようにしてくれるのが、 .if .if コマンドである。 .if \\n(SH=1 .sp 2i \" 最初の節だけ .if .if の後に現われる条件式は、算術式か論理式であればなんでもよい。 論理式の値が真または算術式の値が0より大のとき、 その行の残りの部分はテキストとして扱われる。 上の例の場合はコマンドである。 論理式の値が偽または算術式の値が0以下のとき、残りは無視される。 条件が真のときには、1つ以上のコマンドを実行することもできる。 第1節の前にいくつかの操作を行ないたいとしよう。 ひとつの方法は、次のような形でマクロ .S1 .S1 を定義し、第1節のとき if if( で判断する)にそれを呼び出せばよい。 .de S1 --- 第1節の処理 --- .. .de SH ... .if \\n(SH=1 .S1 ... .. もうひとつの方法は、次に示すように拡張された形式の .if .if を用いることである。 .if \\n(SH=1 \{--- 第1節の 処理 ----\} 大かっこ \{ \{ と \} \} は上のような位置になければならない。 さもないと、予定外に余分な空行が印刷されてしまうはずである。 troff には「if-else」のような構文もあるが、ここでは扱わないことにする。 条件式は、前に ! ! をつけることにより 『否定』 をとることができる。 たとえば次のようにすることにより、前の .if .if と同じことができる(が、わかりずらくなる)。 .if !\\n(SH>1 .S1 .if .if を用いてテストできる条件が他にもいくつかある。 たとえば、現在のペ-ジ番号は偶数か奇数か、といったようなことである。 .if e .tl \(aa\(aa偶数ページの表題\(aa\(aa .if o .tl \(aa\(aa奇数ページの表題\(aa\(aa このようなコマンドを適当なページ マクロで用いれば、 向かい合ったページに異なる表題をつけることができる。 似たような条件に t t と n n があって、いま現在使っているフォーマッタが troff であるか nroff nroff であるかを教えてくれる。 .if t troffのスタッフ ... .if n nroffのスタッフ ... 文字列の比較も .if .if で行なうことができる。 .if \(aa文字列1\(aa文字列2\(aa スタッフ では、 文字列1と 文字列2 が等しいときにスタッフが処理される。 ふたつの文字列を区切っている文字は、 どちらの文字列にも含まれないものであればなんでもよい。 文字列は、 \\(** \\(** を使ったストリングや \$ \$ 等を参照していてもよい。 #a 環境 前にも述べたが、ページの境界を越えてしまったときのおこる潜在的問題がある。 すなわちそれは、ページ見出しのサイズやフォントのようなパラメタが、 ページ境界が起こったときに 実際に設定されている値と異なってしまうという問題である。 troff では、これやこれと似たような状況に対処するために、 極く普通の方法を提供している。 それは、処理に応じて独立してパラメタを設定できる「環境」を 3つ持っているということである。 ここでいうパラメタとは、サイズ、フォント、行長、表題の行長、 フィル モードかノー フィル モードか、タブ ストップ、 部分的に集められた行等である。 これにより、表題の問題は主テキストをひとつの環境で処理し、 表題をそれとは別の適切な環境で処理が実現でき、容易く解決する。 コマンド .ev n .ev n で、環境 n n に移行する。 ここで n n は0、1、2のいずれかでなければならない。 .ev .ev を引数なしで使うと、直前の環境に戻る。 環境の名前はスタックで管理されるので、 異なる環境の呼出しは入れ子構造になっていて、 なくなってしまうことはない。 いま、主テキストを環境0で処理しているとしよう。 troff は標準で環境0を用いている。 このとき、表題を環境1で処理するページ マクロ .NP .NP は次のように定義される。 .de NP .ev 1 \" 新しい環境にシフト .tl 6i \"以下で、パラメタを設定 .ft R .ps 10 ... 他の処理 ... .ev \" 元の環境に戻す .. 環境パラメタを .NP .NP マクロの外で初期化することも可能であるが、 この例ではすべての処理を一箇所で行なっている。 この方が理解しやすいし、変更も容易である。 #a ダイバージョン ページ レイアウト上、 テキストをすぐに印刷しないで一定期間記憶しておく必要が非常によくある。 フットノート(脚注)が最もよい例で、 そのテキストはそれが印刷されるべき場所よりずっと前に 現われてしまうのが普通である。 実際それが出力される場所は、 それがどれ位の大きさであるかということに依存する。 したがって、少なくとも空間の大きさが十分であるかどうかを、 印刷せずに判断できるような脚注を処理するための方法が必要になる。 troff には、これを可能にする「ダイバージョン」というメカニズムが取り入れられている。 出力はどの部分でも、 印刷する代わりにひとつのマクロの中にダイバートすることができ、 適当なところでそのマクロを入力として呼び戻すことができる。 .di xy .di xy というコマンドでダイバージョンが開始される。 すなわち、引き続く出力がすべて引数のない .di .di コマンドが現われるまで、マクロ xy xy に集められる。 これで、ダイバージョンが終了する。 処理されたテキストはそれ以降であればどこでも、 次のようにするだけで使うことができる。 .xy 最も新しく終了したダイバージョンの縦方向の大きさは、 組込み数値レジスタ dn dn に記憶されている。 簡単な例として、「キープ-リリース」オペレーションを実現したいとしよう。 これは、後に示すようなコマンド .KS .KS と .KE .KE の間にあるテキストが、 ページの境界をまたぐことがないようにするものである(図や表のとき便利である)。 もう明らかであるが、次のような処理をする。まず .KS .KS があったら、どれ位の大きさであるのかを決定するために、 出力のダイバートを始める。そして .KE .KE があったら、ダイバートしたテキストが現在のページに収まるかどうかを判断し、 もし入るのであればそのまま印刷し、入らなければ次のペ-ジの先頭に印刷する。 .de KS \" キープ開始 .br \" 新しい行を始める .ev 1 \" 新しい環境で .fi \" 詰込みをおこなう .di XX \" XXにコレクトする .. .de KE \" キープ終了 .br \" 最後に残っていた行を得る .di \" ダイバージョンの終わり .if \\n(dn>=\\n(.t .bp \" 入り切らなければ.bpを .nf \" ノーフィル モードに戻す .XX \" テキスト .ev \" 元の環境に戻る .. 数値レジスタ nl nl が、現出力ページの現在位置を保持していることを思い出してほしい。 これは、ダイバージョンが始まったときの値のままになっている。 dn dn はダイバージョンの対象となったテキストの量を示している。 (もうひとつ別の組込みレジスタ) .t .t が次のトラップまでの距離を示していて、 今はこれがページのボトムマージンになっていることを仮定している。 ダイバージョンの結果がトラップを起こすのに十分なほど大きければ、 .if .if の条件が真になり、 .bp .bp が起動される。この後、 .if .if の条件判定の結果にかかわらず、 ダイバートされた出力テキストが .XX .XX によって呼び戻される。 troff が余計な処理をしないように、 ノーフィル モードで呼び戻すことが大切である。 これは一般的に使えるようなキープ-リリースではないし、 あらゆる入力に対してうまく動くものでもない。 が、これをもっと一般的に書くには紙面が足りない。 この節では、ダイバージョンのすべてを教えようというのではなく、 むしろ既存のマクロ パッケージを詳細に読むことができるようになるために 必要なことをスケッチしている。 謝辞 謝辞 私は、 troff の著者である J.F. Ossana 氏に深く感謝する。 彼は細かい点について根気強く説明してくれ、 troff をより多くのユーザが容易に使えるように改良してくれた。 私はまた、この論文に対して助言をしてくれた Jim Blinn、 Ted Dolotta、 Doug McIlroy、 Mike Lesk、 Joel Sturman に感謝する。