みなさん、こんにちは。

前回で fl マクロの長い講義が一段落しました。疲れました?今回はここまで、取りこぼした小ネタを拾ってみたいと思います。

第5回で、#push/#pop built-in function を説明しました。variable の宣言と解放でしたね。ではここで次のコマンドを打ってみてください。

TACL> variables

これはあなたの TACL 環境に宣言されている variable の一覧です。だから結果は人によってまちまちです。サンプルを挙げてみましょう。

Directory :

FI FL FS
LS *UTILS *UTILS_GLOBALS
V _COMPLETION _COMPLETION^PROCDEATH
_FROM_TACLBASE _PROMPTER _TACLBASE_FILE

こんな感じで表示されます。ここで試しに1つ追加で variable を宣言してみましょう。

TACL> #push test^var^1

おお、忘れてた。variable 名で使える文字種ですが、alphanumeric に加えて "^""_" がOKです。

TACL> #push test_var_1

は大丈夫ですが、

TACL> #push test-var-1
TACL> #push test+var+1
TACL> #push test#var#1

などはだめなんです。で、話を戻して

TACL> varables

と打つとどうでしょうか。test^var^1 が追加されましたね。varinfo してみると、

TACL> varinfo test^var^1
Variable L/D Frm Mode Type File
Process        
TEST^VAR^1 1/1 TEXT 0  

などと今まで通り表示されます。

ここでもう一度 test^var^1#push してみましょう。

TACL> #push test^var^1

特にエラーは発生しません。同じ variable を二重に宣言しただけです。

と思ったら大間違い。varinfo を打ってください。

TACL> varinfo test^var^1
Variable L/D Frm Mode Type File
Process        
TEST^VAR^1 2/2 TEXT 0  

判りますか? L/D のところが 2/2 に代わりましたね。#push の機能は、文字通り stackpush するものです。2回 #push を実行したということは2個の test^var^1 variablestack に積んだということになります。積まれた2つの variable を区別するには、variable 名にレベル番号を付与してやります。test^var^1.1 とか test^var^1.2 とかです。具体的に見てみましょう。

TACL> #set test^var^1.1 bottom of the stack
TACL> #set test^var^1.2 new variable
TACL> outvar test^var^1.1
TACL> outvar test^var^1.2
TACL> varinfo test^var^1.1
TACL> varinfo test^var^1.2

いかがですか。それぞれ別の variable として区別されていますね。L/D のところは、LlevelDdepth です。レベル番号をつけないとトップレベルを指しますので、test^var^1test^var^1.2 と同じ意味です。

もちろん stackvariable が積み上がるとそれだけメモリーを消費しますので、必要のないものは #pop で解放するようにしてください。stack が積み上がっている場合、#pop は最後に #push したものから順番に解放していきます。

さらに安全策として #frame/#unframe built-in function を紹介しておきます。#frame#unframe はセットで使います。#frame を実行後に #push したすべての variable#unframe 実行時に自動的に #pop されます。マクロの最後に #unframe と書いておけば、マクロ内で #push した variable をすべて解放することができます。

なお、#frame はネストできますので、複数の階層で variable を管理することができます。そんな例は見たことはありませんが。ここで、#frame の階層と variableL/D は全く別物ということに注意してください。varinfo の出力で、Frm Mode として表示されているのが #frame の階層番号です。L/D とは別の値になってます。ま、この機能を使う人はいないよね。

もうひとつ思い出したので書いておきましょう。fl マクロの作成で load コマンドを多用しましたね。こんな感じです。

TACL> load/keep 1/ $vol.subvol.macsrc

この /keep 1/ とはなんでしょうか。 "/" は実行オプションを指定する記法なので特に意味はなし。意味があるのは keep 1 の部分です。

これを指定しないと、読み込むマクロは #push されます。つまり2回 loadすると最初のマクロは消えずに下位の level として残り、新しく読み込まれたマクロが上位の level として追加されます。keeplevel を指定するとその level までマクロが #pop されて、新しいマクロがその level に配置されます。keep 1 なら、新しいマクロが macro.1 に相当する(つまり全部消して新しいのだけ残す)ということです。これも keep 1 以外はまず使いませんね。

なお、#push/#popbuilt-in variable#push/#pop できます。一時的に built-in variable の値を変えてまた戻したい場合、

TACL> #set save_var [#informat]
TACL> #set #informat ....
TACL> #set #informat [save_var]

などとやるよりも

TACL> #push #informat
TACL> #set #informat ....
TACL> #pop #informat

とやる方がすっきりします。お勧めの小技です。

あ、そうそう #unframevariable の掃除をしてくれます。マクロもまた variable です。ということで、#frameload#unframe とやると load したマクロがきれいさっぱり消えてしまいます。愉快ですね。

うーむ、長くなってきたので、ここらで一服。お茶かたばこでもどうぞ……

休憩は済みましたか?それではもう一度 variables コマンドの出力結果に戻りましょう。最初の行にある Directory : ですが、":" は単なる飾りじゃなくて、ちゃんと意味があるんですよ。variabledirectory 構造を持つことができ、その区切り文字が ":" なんです。つまり Directory :root directory であることを示しているのです。出力結果の中に *UTILS とか *UTILS_GLOBALS がありましたね。* はその variabledirectory であることを示しています。試しに UTILS directory の下を覗いてみましょう。

TACL> variables utils

Directory :UTILS.1

*DP *EMF *EMSDINFO *FIXERRS *LMAP PATHMAKER
PMPROJECT            
*RUNV *TACL *VIEWPT *VPTLIB *ZBAT *ZPATHMKR

今度はタイトル部分が Directory :UTILS.1 になりました。.1 というのは level 番号ですね。directoryvariable なので #push/#pop の対象になり得ます。utils の中にも * が付いたものがいっぱいです。その中から tacl directoryを覗いてみます。

TACL> variables utils:tacl

見たことのある variable がずらずら現れました。いわゆる TACL コマンドの実態は、ここに格納された variable なのです。fileinfo variable を例に取ってみましょう。昔やったコマンドで

TACL> varinfo fileinfo

Variable L/D Frm Mode Type File
Process        
:UTILS.1:TACL.1        
FILEINFO 1/1 ALIAS 0  

というのがありましたね。よく見ると、fileinfo の上に :UTILS.1:TACL.1 と書いてあります。つまり fileinfo variable:UTILS.1:TACL.1 directory の下にあるよ、と言っていたのです。ここでやっと話がつながりましたね。つまりこの fileinfo variablefully qualified name で表示すると

:utils:tacl:fileinfo

となるわけです。

普段は :utils:tacl: をさっくり省略して使っているわけですが、ではなんで :utils:tacl: を省略できるのでしょうか。それは #uselist built-in variable に理由があります。

TACL> #uselist

#uselist expanded to:

: :UTILS.1 :UTILS.1:TACL.1 :UTILS.1:DP.1

:UTILS:TACLpath が通っている、というわけですね。level 番号が付いてますから、UTILS を変に #push してしまうとすべての TACL コマンドが使えなくなってしまうこともあり得ます。もちろん UTILS.1#pop してもアウトです。コマンドが使えなくなります。

それと、ここまで utils:utils を同じものとして説明してきましたが、root: を省略できたのも #uselist: が入っているおかげでした。

さらに directory にはもうひとつ秘密があります。seginfo コマンドというものを実行してみましょう。

TACL> seginfo

    Pgs Pgs Bytes Bytes        
Segment File Access Now Max Now Max % UC Directory
$WORK01.#0012480 PR 14 1036 15584 2121728 0 5 :
$SYSTEM.SYS17.TACLSEGF SH 252 1036 510852 2121728 24 4 :UTILS.1

Segment File なるものが登場しました。2行ありますね。$WORK01.#0012480が1行目です。特殊な名称のこのファイルは temporary file というものです。この行の Directory 欄に : と記載されています。この temporary fileroot である : directory に割り当てられています。root を仮想メモリに逃がすことで物理メモリの必要量を削減しています。

このファイルは Accesspr (private) になっているので書き込み可能領域です。特に指定しなければ、自作のマクロはここに格納されます。書き込み可能なので特に問題はありません。

2行目の $SYSTEM.SYS17.TACLSEGFUTILS に割り当てられています。このファイルはマクロを格納したバイナリファイルです。こちらは AccessSH (shared) になっていますので、書き込み不可です。このファイルが割り当てられた directory である utils には variable#push したりマクロを load したりすることはできません。UTILS にマクロを追加しようとしてもエラーになってしまうということです。

このセグメントファイルは HPE から直接提供されたものではなく sysgen 時に作成されたファイルです。さきほど UTILS 配下に TACL コマンドが格納されていると説明しました。その UTILS directory の実態が TACLSEGF ファイルで、このファイルの中に TACL マクロが格納されています。TACL プロセス起動時に TACLSEGF ファイルが(自動的に) attachseg されるので、ログオンしたユーザは TACL マクロを使用することができるのです。

整理します。マクロの配布方法はテキスト(ソース)ファイルから load するやり方と、バイナリファイルを attachseg する方法があります。ここまでの講座では load しか説明していませんし、現場でも恐らく load しか使っていないと思います。しかし自作のマクロでもバイナリのセグメントファイルを作成・配布することはできます。

attachsegload の違いはなんでしょうか。本質的な差はないのですが

これは本当はあまり美しくないやり方です。PCにファイルを作るとき、全てのファイル root ¥ 配下に置いたりしますか? directory を使って整理するでしょ?全部デスクトップに置いているって?美しくないですねぇ。セグメントファイルならどこかの directory に割り当てて使いますので、用途や環境毎に美しく整理整頓できます。

というくらいですかね~

セグメントファイルの詳しい扱い方までは説明しませんので、興味があれば直接問い合わせてください。

directory は必ずセグメントファイルと紐付くわけではありません。セグメントファイルを使わない directory もあり得ます。セグメントファイルを使うには directory と紐付けないといけないというだけです。

ちなみに、TACLSEGF のように TACL に関連するファイルは、他にどのようなものがあるかご存じですか?

$SYSTEM.SYSnn
  CODE EOF LAST MODIFIED OWNER RWEP PExt
SExt            
TACL O 100 4351080 10DEC2008 6:42 255,255 NUNU 112
112            
TACLBASE 101 172528 10DEC2008 11:37 255,255 NUNU 14
28            
TACLINIT 101 8338 19APR1995 22:30 255,255 NUNU 14
28            
TACLSEGF O 440 512000 30SEP2009 15:21 255,255 NUNU 14
14            
$SYSTEM.SYSTEM
  CODE EOF LAST MODIFIED OWNER RWEP PExt
SExt            
TACLLOCL 101 2344 05MAR2010 19:47 255,255 NUNU 112
112            
$vol.subvol
  CODE EOF LAST MODIFIED OWNER RWEP PExt
SExt            
TACLCSTM 101 2150 15MAR2006 10:24 255,255 AAAA 14
42            

こんな感じですね。簡単に説明しときましょ。

ついでなので、root directory 以外に load する手順を紹介しておきます。まず、コマンド用に directory を作成します。こんな感じ。

TACL> #def :mycmd directory

そして、current directory を移動して

TACL> #set #home :mycmd

そこに load します。

TACL> load/keep 1/macsrc
TACL> #set #home :

#homecurrent directory を示す built-in variable です。この時点で macsrc に定義したマクロは使用できますが、こんな使い方になります。

TACL> :mycmd:fl *

以前は root に置いていて、なおかつ root#uselist に含まれているので、

TACL> fl *

でも使えましたが、今回は mycmd directory に掃き出したので directory 名を修飾しないと使えません。これでは不便ですので、root にあるのと同じように使用するために #uselist built-in variable に追加します。

TACL> #set #uselist :mycmd [#uselist]

以上の処理を TACLCSTM に書いておけば、directory を整理しつつ、特に意識することなく自前の TACL マクロを使うことができるようになります。

今日はここら辺で終わりにします。お疲れ様でした。次回からは外部プログラムとの連携でもやってみますか。それでは次回をお楽しみに!Au revoir!