TOPS-20 ディレクトリ構造の調査
2018年1月、歴史的に貴重なDEC社 TOPS-20を使用しています。
Panda TOPS-20 distributionには、どんなプログラムをインストールしているのでしょうか? ディレクトリ構造は、どのような構成になっているのでしょうか? ディレクトリの構造を調べてみたいと思います。
ディレクトリ構造ツリーを出力するようなコマンドが見当たりません。Unixのtreeコマンドなどがあれば良いのですけど。
DIRECTORYコマンドは、ディレクトリ名とそのファイル名の一覧を表示します。
@DIRECTORY (OF FILES) TOPS20:<PI> DIR.TXT.1 HELLOX.C.1 PROJ.DIRECTORY.1 Total of 3 pages in 4 files @
ディレクトリ名にワイルドカード(*)を指定するとすべてのディレクトリ一覧が得られそうです。
大量のディレクトリ一覧が出力されました。その中のディレクトリ名の出力部分を加工すると、ディレクトリの構造をツリー表示できそうです。
TOPS20:<BBOARD>
・
TOPS20:<CHIVES>
・
TOPS20:<CHIVES.V1>
・・・
Unixなら標準出力をリダイレクトしてファイルに保存するか、パイプを通してteeコマンドでファイルに保存します。
何か方法はないかと、カンマ(,)を入力してサブコマンドに入ります。クエスチョンマーク(?)を入力してヘルプ表示してみると、OUTPUTサブコマンドがありました。もう一度クエスチョンマーク(?)を入力して、OUTPUTサブコマンドのオプションを調べるとファイル名を指定することがわかりました。
本当に、TOPS-20のシェルはユーザーインターフェイスが優れていますね。
@DIRECTORY (OF FILES) , @@? confirm with carriage return or one of the following: ACCOUNT ALPHABETICALLY ARCHIVE BEFORE CHECKSUM CHRONOLOGICAL COMPLETE CRAM DATES DELETED DOUBLESPACE EVERYTHING FIND GENERATION-RETENTION-COUNT HEADING INVISIBLE LARGER LENGTH LPT NO OFFLINE ONLINE OUTPUT PROHIBIT-MIGRATION PROTECTION RESIST-MIGRATION REVERSE SEPARATE SINCE SIZE SMALLER TIMES USER @@OUTPUT (TO FILE) ? FILE NAME @@OUTPUT (TO FILE) ^C @
システムのディレクトリ一覧も取得するので、ENABLEコマンドで特権モードになります。
DIRECTORYコマンドで、PS:(プライマリーストレージ)のすべてのディレクトリ一覧を取得して、テキストファイルに出力します。
@ENABLE (CAPABILITIES) $ $DIRECTORY (OF FILES) PS:<*>, $$OUTPUT (TO FILE) DIR.TXT $$ $ $DISABLE (CAPABILITIES) @
ディレクトリ一覧をAWKスクリプトで加工してディレクトリ構造をツリー表示すれば、ディレクトリ構造を調べることができます。
TOPS-20 ディレクトリ構造
AWKスクリプトで、TOPS-20のディレクトリをツリーウォークするスクリプトを作成しました。
AWKスクリプトによるTOPS-20ディレクトリ構造を以下に示します。
@AWK -f DIR_TREE.AWK DIR.TXT TOPS20: |-- ROOT-DIRECTORY |-- ACCOUNTS |-- ALGOL |-- BBOARD |-- BLISS |-- BLISS-SOURCES |-- CHIVES | `-- V1 | |-- CONFIG | |-- DOCUMENTATION | `-- SOURCE |-- CLISP |-- DECNET-SOURCES |-- DECNET-TOOLS |-- DOCUMENTATION |-- DOMAIN |-- EMACS |-- EXEC-SOURCES |-- FAIL |-- FINGER |-- FORTRAN | |-- COMPILER | |-- DOCUMENTATION | |-- OTS-DEBUGGER | |-- SYSTEM | |-- TEST | `-- TOOLS |-- FTP | `-- OLD |-- GALAXY-SOURCES |-- GAMES |-- GIGI |-- HELP |-- KCC-6 | |-- BUILD | |-- INCLUDE | | |-- ARPA | | |-- NET | | |-- NETINET | | `-- SYS | |-- KCC | |-- LIB | | |-- GEN | | |-- INET | | |-- MATH | | |-- SOCKET | | |-- STDIO | | |-- TEST | | |-- USER | | `-- USYS | `-- T20 |-- KERMIT |-- LANGUAGE-SOURCES |-- LISP | `-- DCROSS |-- LISPUSERS |-- LOGO | |-- HELP | |-- LIBRARY | `-- SOURCES |-- MACLISP |-- MAIL |-- MAKE |-- MM | |-- BINARIES | |-- DOCUMENTATION | |-- LOCAL | |-- SPELL | `-- VAX | `-- CAFARD |-- MONITOR-SOURCES |-- NETSRV |-- NFS |-- OLD-SYSTEM |-- OPERATOR |-- PDP-8 | `-- MAINDEC |-- PHONE |-- PI | `-- PROJ |-- ROOT | |-- BIN | |-- ETC | `-- USR | |-- BIN | |-- DICT | |-- LIB | `-- LOCAL | |-- EMACS | | |-- ETC | | |-- INFO | | `-- LISP | | `-- TERM | `-- LIB |-- SAIL |-- SCRIBE |-- SOURCES |-- SPOOL |-- SUBSYS |-- SWSKIT |-- SYSTEM |-- SYSTEM-ERROR |-- TELNET |-- TOOLS | |-- ALU | |-- BLIS10 | |-- CHANS | |-- CISTS | |-- DCNSPY | |-- DOBOPR | |-- DOCUMENTATION | |-- ENQTST | |-- EXEC-MODS | |-- FORMAT | |-- KRYPTN | |-- MAIL | |-- MAILER | |-- MONRD | |-- QUETST | |-- RDMAIL | |-- REDIT | |-- REV | |-- RMTCON | |-- SCM | |-- SED | |-- SSU | |-- SYSDPY | |-- TSTATS | |-- TTYINI | |-- TYPVFU | |-- UNITS | |-- USAG20 | |-- USAH20 | `-- VNP36 |-- TSU |-- UNSUPPORTED |-- UTF9 |-- UTILITIES `-- WINDOW @
ALGOL、LOGO、FORTRAN、LISPというディレクトリ名がありますので、いろんな言語処理系がインストールされているようです。
AWKでディレクトリツリーウォーク
AWKスクリプト
ディレクトリをツリーウォークするAWKスクリプトを以下に示します。
@TYPE dir_tree.awk BEGIN { } $1 ~ /^([A-Z][A-Z0-9]*):<([A-Z0-9\-\.]+)>$/ { fDev = match($1,/([A-Z][A-Z0-9]*):/) if (fDev > 0) { sDev = substr($1, RSTART , RLENGTH) } fDir = match($1,/<(.+)>/) if (fDir > 0) { sDir = substr($1, RSTART+1 , RLENGTH-2) } # if (fDev > 0 && fDir > 0) { sDirF = sDev "." sDir num = split(sDirF ,aryDir , ".") ix = 1 sDirP = aryDir[ix] while (num-- >1) { sDirC = aryDir[++ix] if (!(sDirP in Dic)) { Dic[sDirP] = sDirC } else { if (","Dic[sDirP]"," !~ ","sDirC"," ) { Dic[sDirP] = Dic[sDirP] "," sDirC } } sDirP = sDirP "." sDirC } } } END { treeout("",sDev ) } # Tree Outout function treeout(Tab ,sDirP ,_sDirC ,_sDirN ,_num ,_ix ,_aryDir ) { if (Tab=="") { printf("%s\n", sDirP) } _num = split(Dic[sDirP] ,_aryDir ,",") _ix = 1 while (_num--> 0) { _sDirC = _aryDir[_ix++] printf("%s %s\n",Tab "" ((_num!=0)?" |--":" `--"), _sDirC) _sDirN = sDirP "." _sDirC if (_sDirN in Dic) { treeout(Tab "" ((_num!=0)?" | ":" "),_sDirN) } } } @
AWKスクリプト説明
ディレクトリ構造をツリー表示するAWKスクリプトのアルゴリズムは、思ったより簡単ではありませんでした。プログラミングする前に、PAD図でアルゴリズムを書きます。
PAD図はプログラム論理を記述する方法で、Problem Analysis Diagram(問題分析図)と呼ぶ二次元木構造の図面です。
TOPS-20のディレクトリは、「デバイス名:<ディレクトリ名.サブディレクトリ名・・・>」です。
パターンにマッチする正規表現「^([A-Z][A-Z0-9]*):<([A-Z0-9\-\.]+)>$」で、ディレクトリ一覧の行を抽出します。
メイン処理部のPAD図を下記に示します。
辞書 Dic[]は、親ディレクトリに対応する子ディレクトリをカンマで区切って格納します。
DirA
DirA,DirB
DirA,DirB,DirC・・・
入力フィールド $1からmatch()関数でデバイス名(sDev)とディレクトリ名(sDir)を取り出します。
変数 sdirFにデバイス名(sDev)とディレクトリ名(sDir)をドットで連結します。
sdirFをドットで分解して配列 aryDir[]に設定します。ドットの数がデバイス名から始まるディレクトリ階層の深さになります。
階層のインデックス(ix)←1とします。
aryDirの1番目を親ディレクトリ(sDirP)に設定します。
階層の深さだけ、以下を繰り返します。
- aryDirの(++ix)番目を子ディレクトリ(sDirC)に設定します。
- 親ディレクトリ(sDirP)が辞書 Dicに未登録の場合は、辞書 Dic[sDirP]に子ディレクトリ(sDirC)を格納します。
- 辞書に登録済みの場合は、辞書 Dic[sDirP]にカンマ(,)で子ディレクトリ(sDirC)を連結します。この場合、子ディレクトリが連結内にあれば二重登録にならないように子ディレクトリは捨てます。
- 親ディレクトリに子ディレクトリをドット連結したものを親ディレクトリにします。
子ディレクトリの二重登録防止のチェックは、前後にカンマを付加したパターンでマッチするか調べます。
「”,”Dic[sDirP]”,”」 と 「”,”sDirC”,”」 のパターンマッチ
このメイン処理は、下記入力から次のように辞書登録します。
【入力】
TOPS20:<BBOARD>
TOPS20:<CHIVES>
TOPS20:<CHIVES.V1>
TOPS20:<CHIVES.V1.CONFIG>
TOPS20:<CHIVES.V1.SOURCE>
親ディレクトリ | 子ディレクトリ |
---|---|
TOPS20: | BBOARD,CHIVES |
TOPS20:.CHIVES | V1 |
TOPS20:.CHIVES.V1 | CONFIG,SOURCE |
入力ファイルがEOFになるとENDパターンで関数 treeout(“” ,sDev)を呼出してツリー出力します。変数 sDevは、デバイス名で「TOPS20:」を格納しています。
次にツリー出力する関数treeout()のPAD図を下記に示します。
仮引数 | 内容 |
---|---|
Tab | 左部のTreeタブ |
sDirP | 親ディレクトリ |
Treeタブが空文字のときツリーのトップなので、親ディレクトリを出力します。
辞書 Dic[sDirP]は、親ディレクトリに対応する子ディレクトリをカンマで区切った情報を格納しています。カンマで分解して配列 _aryDir[]に設定します。子ディレクトリの数は _num です。
以下を_num回繰り返します。
- 子ディレクトリ(_sDirC)を取り出します。
- ツリーを書きます。Treeタブと”├─”と子ディレクトリ(_sDirC)を出力します。
- 子ディレクトリに孫がいるか調べるために、親と子ディレクトリをドットで連結したフルパス(_sDirN)を生成します。
- 辞書 Dic[]に_sDirNが存在した場合は、関数treeout()をリカーシブコールして孫以下のツリーを書きます。
まとめ
Panda TOPS-20 distributionのディレクトリ構造を調べるために、AWKでディレクトリをツリーウォークするスクリプトを作成しました。
ディレクトリ名を見ると、なかなか興味深いプログラムがインストールされているみたいです。そのうち、調べてみようと思います。
TOPS-20に関するブログ
歴史的に貴重なDEC社 TOPS-20を使うためにKLH10エミュレーターをLinuxにインストールして、TOPS-20を実行することができました。
TOPS-20に関するブログを以下に示します。