みなさん、こんにちは。

これまでは既存のマクロを読み替える例ばかり紹介してきました。そろそろ自分でロジックを組む話に入りましょう。前回予告した variable の展開が出てきます。今回はエンジン全開で行きますよ。

まず、何か作ってみましょう。fileinfo マクロではファイルの最終更新日が表示されますが、最終オープン日時を知りたいこともあります。fup コマンドでも出せますが、表示結果が散漫です。fileinfo のような書式で出したいので、これを自作します。

最終更新日を取得するには #fileinfo を使います。# で始まっているので、これは built-in function ですね。#xfileinfo とよく似た名前ですがまったくの別のものです。試しにやってみましょう。LASTOPEN_GMT オプションを付けて、前々回作成したマクロソースファイル名を指定します。

どうですか。

などと表示されましたね。数値は人によってまちまちですが、18 桁の数字が表示されたと思います。

ここではポイントが2つあります。1点目は “expanded to:” です。これが「展開」です。built-in function の処理結果を取り出したり、 variable に保存された内容を取りだしたりすることを「展開」といいます。この例では#fileinfo built-in function の処理結果が212340079887808120だったということです。うん、あまり大した話じゃなかったですね。ただ、展開の重要な点は、「展開とは置き換えである」ということです。展開の本来的な動作からいうと

これは

と入力したのと同じ意味になります。つまり元のマクロが展開結果に置き換えられたということです。

そしてここにもう一つヤヤコシイ話が出てきます。コマンドラインで数字を入力してもエラーになるだけですよね。でも上記はエラーになっているようにはみえません。実は、built-in function の場合コマンドラインで直接展開すると “expanded to:” の注釈付きで展開結果を表示してくれる機能があります。これは built-in function の特徴で、variable とは扱いが違うところです。212340079887808120と展開される variable を用意して同じように展開させてみると、今度はエラーになります。後ほど variable の展開を紹介するときに実演してみることにします。私の宿題にしておきましょう。

2つ目のポイントは212340079887808120という数字です。TACL では日付・時刻精度を2種類持っています。

  • Julian timestamp, a four-word timestamp
  • Local timestamp, a three-word timestamp

Julian timestamp は紀元前4713年1月1日 12:00 からの経過時刻をマイクロ秒(マイクロ秒:100万分の1秒)の精度で保持しています。Local timestamp は 1974年12月31日 0:00 からの経過時刻を 0.01 秒(100分の1秒)の精度で保持しています。212340079887808120はJulian timestamp です。

このように書くと、「Julian timestamp の説明に four word と書いてあるけど、212340079887808120は 58 bit じゃないか。これなら two word で十分ではないの?」と、したり顔で指摘する人が出てきたりするものです。この手の質問には先生も手を焼くなぁ……えーと、TACL/TNS は 16 bit machine なのです。よって four word は 64 bit です。three word は 48 bit。だから 58 bit の Julian timestamp を管理するには four word 必要でしょ?

話を戻して、212340079887808120 という数字のままでは何日の何時かさっぱり分かりません。で、変換関数を使います。まず LASTOPEN_GMT というようにこれは GMT なので JST に変換します。#CONVERTTIMESTAMP という built-in functionに、GMT ⇒ LCT に相当するオプション0を付けます。

展開された結果の最初の0はエラーコードです。タイムスタンプとして不正な値なら1が返ります。JST に直すと212340112287808120ということがわかったので、これを人が読める形にしましょう。

先頭の2457640は通算日、ここでは使わないので無視するとして、その後ろに注目すると、

2016年9月8日 16時31分27.808120秒

が得られます。$vol.subvols.macsrc を最後にオープンしたのはこの時間ということが分かります。

前回までならこのくらいの分量で今日は終わり、となりますが、今回はまだまだ行きますよ。休憩は各自でどうぞ。

以上の流れで情報は得られましたが、1つ1つ手作業でちっともマクロではありません。ここまではあくまでもパーツの紹介。これを1つのマクロに組みあげます。ここからは実行結果は省略していきますので、ぜひ実習を交えて読んでください。

まず、第一ステップ。 #fileinfo の結果を表示するところまでをマクロにしましょう。マクロ名は fl にします。

以上の7行を macsrc に追加します。これで macsrc は ls マクロと fl マクロを定義するソースになりました。忘れずに load したら実行します。

前に #fileinfo を直接実行したときと同じような表示内容ですが、数字は違いますね。fl マクロを追加するときにオープンしたため、タイムスタンプが変わっています。

ではマクロの説明をしましょう。

#push fn1

は variable の宣言です。この形式では TEXT type の variable が宣言されます。次の

#set fn1 %1%

は、宣言した fn1 variable にパラメータを代入しています。%1% は macro のパラメータでしたね。次が例の built-in function ですが、パラメータが変わりました。

#fileinfo /LASTOPEN_GMT/ [fn1]

さきほどはファイル名を直書きしましたが、今度は variable を使っています。[ ] で fn1 を囲っています。これは fn1 variable を展開しろ、という意味です。[ ] で囲わずに

#fileinfo /LASTOPEN_GMT/ fn1

と書いてしまうと、fn1 という名前のファイルの最終更新日を取りだします。[fn1] とすることで fn1 に格納された名前(%1%、つまりマクロに与えたパラメータ)のファイルの最終更新日を取りだします。

さて、さきほど宿題にしていたところを実演してみますか。TACL のコマンドラインで次のように操作してみてください。

さあ、どうですか。

とエラー表示されましたね。つまり testmsg が展開されて

と入力したのと同じことになったわけです。今度は built-in function ではないので、エラーになってしまいました。なお、[ ] を付けないで

としても同じ結果になります。variable 名をコマンドラインで入力すると、マクロと解釈して自動的に展開されるからです。

おっと、ここで

とエラー表示された人はいませんか?そのときは

と入力してください。#informat については次回説明します。

宿題パートの最後に

と入力しておいてください。これは宣言した testmsg variable の削除です。ソースファイルに戻ってみると、こちらにも最後に

#pop fn1

とあります。これもfn1 variable を削除しています。#push と #pop はペアで使用するようにしましょう。(#pop を忘れるとどうなるか、とか防衛策は、とかはまた後日)

#fileinfo の結果は GMT だったので、これを JST に変換するステップを追加します。ソースファイルを修正しましょう。

どうでしょうか。#fileinfo も [ ] で囲われてしまいました。さきほどまでは #fileinfo の結果は画面に表示されていましたが、 [ ] で囲うことで展開結果を別の variable に代入することができるようになります。ここでは ts1という variable に一度代入して、さらにそれを #CONVERTTIMESTAMP に与えています。画面には #CONVERTTIMESTAMP の結果が表示されます。

しかしまだ時刻として読める形ではありません。今日の最後に JST を読める形に変換してみましょう。#interprettimestamp を使うよう、またまたソースファイルを修正します。

おや、#setmany って何でしょう。#CONVERTTIMESTAMP の実行時を思い出してください。結果が2項目ありましたね。

#set ts2 [#CONVERTTIMESTAMP [ts1] 0]

と書くと、1つ目と2つ目の項目が両方とも ts2 に代入されてしまいます。#interprettimestamp で使用するのは2つ目の項目だけなので、項目を分離しないといけません。そういうケースで使うのが #setmany で、複数の項目を複数の variable に分配してくれます。

#setmany err ts2,[#CONVERTTIMESTAMP [ts1] 0]

とすることで、エラーコードを err variable に、タイムスタンプを ts2 にそれぞれ代入してくれます。#set と異なり、 “,” が途中に入っていることに注意してください。

それでは実行してみましょう。

日付や時刻がバラバラッと表示されました。一応、役には立ちますが、見た目が、きれいではないですよね。次回はこれを成型することを考えます。

今回は長かった。お付き合いありがとう。お疲れ様でした。Au revoir!