6AV6-6AR5直結アンプ --設計編--2023年09月18日 16:29

電力増幅管6AR5のプレート供給電圧は、電源器の制限から240Vです。 前回はこの制約から、下記のように電圧の配分をしました。

まず、6AR5のカソードの電位は90Vになり、カソード抵抗には、プレート電流と第二グリッド電流が流れますから、5.4KΩになります。 6AV6のプレートは、6AR5のカソード電位より第一グリッドバイアス分低い電位になりますので、79.2Vになります。このとき6AV6のプレートには、 約0.1mA流れますので、6AV6のプレート抵抗を470kΩとすると、供給電圧は126.2Vになります。 プレート供給電圧を作るためのプリーダーに5mA流すとして求めた、回路定数は下記のようになりました。

制作にあたって、手持ちの部品とにらめっこしながら、回路定数を調整したのが、次の回路図です。

6AR5のカソード抵抗が小さくなってしまい、カソードの電圧がが低くなってしまいました。 それに合わせて、6AV6のプレート電圧も低くなっています。コンデンサで化粧を施した回路は、このようになりました。

では、早速制作します。

6AV6-6AR5直結アンプ --構想編--2023年08月29日 21:36

手持ちの真空管 電圧増幅管 6AV6 と電力増幅管 6AR5 で、直結アンプを作ってみます。直結アンプの製作実験です。 6AV6と6AR5は、ともにラジオによく使われた真空管です。

真空管アンプの電圧増幅管のプレートと電力増幅管のグリッドは、コンデンサを介して接続するのが普通です。

これに対して、直結アンプは、電圧増幅管のプレートと電力増幅管のグリッドを直接接続します。

電力増幅管のグリッドは、カソードからみてマイナスの電位になっていなければなりません。電圧増幅管のプレートはプラスの電位です。 ちょっと矛盾するようですが、

電圧増幅管のプレート電圧=電力増幅管のグリッド電圧<電力増幅管のカソード電圧

と電圧を配分することで、実現できます。

6AR5の動作例を調べてみます。誠文堂新光社から出ている「実用真空管ハンドブック」に掲載されている動作例を見てみますと、 プレート電圧 250Vで、約3Wの出力が得られます。この場合のグリッド電圧は、-18Vです。

6AV6の動作例をについては、「実用真空管ハンドブック」の動作例を見てみますと、プレート供給電圧が 100Vのとき57倍の増幅率があります。

実験用の電源の出力は、240Vしかありません。これを考慮して電圧配分を図示すると、このようになります。

次回は、これをもとにして設計します。

TRN-8にEEPROMを搭載する2023年08月11日 15:36

私のCP/M機 TRN-8のROM-BIOSは、UVEPROMの27C256互換品を使っています。実験などで ROM を 書き換えることもあります。コードを書いては、アセンブリし、UVEPROMに書き込んでテストするという、手順を 繰り返します。書き込む前に、紫外線でUVEPROMをイレーズする必要があります。これには、10分から15分かかります。 テストの繰り返しの中で、結構な待ち時間になります。というわけで、EEPROMを使用してみることを計画していました。

最近、27C256の互換品のEEPROM 28C256を入手できましたので、早速、27C256の内容をダンプして、28C256に 書き込み、置き換えてみました。結果、動きません。ROMライターを変えてもだめでした。当然、書き込みエラーは起きません。 こなったら、初心に戻り、データシートを比較してみました。アクセス速度は200nsecで問題なしです。ピン接続を確認すると、 おぉっと、1番ピンと27番ピンに違いがありました。違いは以下のごとくです。

PIN#27C25628C257
1VppA14
27A14/WE

このままでは、EEPROM 28C256を使ってテストをして、本番にはUV-EPROM 27C256を使ってという、 当初の目論見が実現できません。苦肉の策として、このような下駄を作りました。

本来のPROMソケットにこの下駄を差し、テスト中は下駄にEEPROMを刺します。テストが完了したら、下駄を取り外し UVEPROMを直接、PROMソケットに刺すわけです。こんな感じです。

これで、効率よくテストする環境が揃いました。

5球スーパーラジオの整備2023年05月31日 10:20

ヤフオク!をみていたら、昭和時代の真空管5球スーパーラジオが沢山出品されてました。 ラジオを作ってはバラしていた遠い昔、5球スーパーに挑戦し組み立てたけれど、きちんと調整できなくて 完成に至らなかったことを思い出しました。調整に必要なテストオシレーターを持っていなくて、 調整をうまくできなかったのです。現在は必要な機器を所有しています。1台入手して、昔を懐かしむことにしました。

ヤフオク!で比較的状態が良さそうな物を探して入手しました。松下電器のトランスレスの球スーパーで、中波と短波の 2バンドが聞けて、中央のダイアルゲージがあり、左右にスピーカーが付いてます。 運が良いことに、届いたラジオは汚れや痛みはあるものの、私の手で修復・整備ができそうなものでした。

状態は、ケース全体に汚れがあります。電源コードが傷んでます。全面中央のダイアルゲージは、細かい傷が付いており曇っています。

内部は、熱で変形しているところは無く、パーツにも損傷はみられません。オイルコンデンサーや電解コンデンサーは、 無条件に交換します。真空管はゲッター膜が十分あり元気なようです。

不具合がないことがわかったので、電源を入れてみました。パイロットランプが切れてます。 ボリュームのガリとスイッチの切り替え時に大きなクリック音があります。

まずは、キャビネットの手入れです。取り外せる部品を取り外して、水洗いしました。 全面中央のダイヤルゲージ窓をピカールで磨いたところ、透明感が戻りました。

内部は、まずオイルコンデンサーを ほぼ同容量のセラミックコンデンサーと交換、電解コンデンサーは立形の物に交換。 ついでに、ダイアル糸も変えました。ダイアル指針の位置を所定の位置にセット。

ここまでで、シャシーの内部は、このようになりました。

ケース背面のアンテナ線とアース線の端子は、特殊なプラグだったのでジョンソンターミナルに、フォノ入力は3.5Φのジャックに交換。 ジャックは、ステレオ入力用とモノラル入力用を用意しました。これらのパーツを取り付けるため、新たにアクリル板で パネルを作り直し。電源コードも交換。背面はこのように。

調整です。まずは、IFTを調整。結構ブロードでした。

トラッキング調整には、悩みました。この5球スーパーは中波と短波の2バンドです。局発コイルは、中波用のコイルと 短波用のコイルが同一ボビンに巻かれており、なおかつ、コアが入っています。

まずは、中波から調整。600kHzで局発コイルのコアを 1400kHzで局発側のトリマを調整。2,3度繰り返した後、 アンテナ側のトリマを1400kHzで調整し、中波の調整を完了。

短波帯は、4MHzと11MHzで、アンテナ側トリマと局発トリマを交互に調整し完了。

アンテナ端子に3mぐらいのビニール線をつけて受信状態を確認。

再組み立てをして、作業完了。


インテリアとしても使えるぐらいに修復できたでしょうか。

6L6GCシングル・パワーアンプの修理2023年04月29日 15:41

オーディオ用の自作パワーアンプを2台持っています。6R-A8シングルと6L6-GC シングルです。この2年間程は6R-A8シングルを使っていました。 久しぶりに6L6-GCシングルを使おうとセットしてみました。

で、トラブル発生です。 電源を入れたところ、右のスピーカーから変なハム音が聞こえだし、 どうしたんだろうとしていたら、ボン!と爆発音がして、アンプの底から白煙が 出てきました。どうやら、電解コンデンサがパンクしたようです。

ひっくり返してシャシー内部を見ると、右チャネル6L6-GCのカソードに入れてある バイパス・コンデンサがこの通りパンクしていました。

カソード抵抗の両端に高い電圧が発生したのでしょう。 抵抗の両端に電圧計をつないで計ってみました。真空管があたたまるに連れ、 電圧がドンドン上がっていくのが確認できました。6L6-GCをつまんでグラグラと 動かしてみると正常な電圧を示すことがあります。どうも第一グリッドがオープン、 つまり、ゼロバイアスになり、カソードに過大な電流が流れたのでしょう。 案の定、様子見をしている最中にカソード抵抗が焦げてきました。 ソケットが古くなって、端子のバネ性が弱くなり接触不良を起こしたようです。

てことは、このアンプは、5年ほど前に今回のような症状を見せたことがあり、 その時は、6L6-GCを交換しました。 このときも、ソケットの接触不良が原因だったの可能性があります。 真空管を交換することで、たまたま、接触不良が解消したのでしょう。 根本治療になっていなかったようです。

今回は、コンデンサと抵抗だけでなく、ソケットも交換しました。

音出しをして、修理の確認をしました。

実は、以前のトラブルのときの6L6-GCを保管していたので、 差し替えてみました。なんと、トラブルなく音が出ました。前回のトラブルも ソケットの接触不良が原因だったことが確認できました。なんとお粗末なこと。 この2ヶ月程、毎日のように使っていますが、トラブルは再現しませんでした。

これで修理を完了としました。

DC-DCコンバーターの制作2023年04月13日 13:51

5Vの電源から、他の電圧の電源を作成するには、DC-DCコンバーター用のICを使うのが手っ取り早いです。 以前、自作CP/MマシンTRN-8にAMD9511を組み込むときに+21Vが必要となり、中華製のDC-DCコンバーターを使用しました。

コイルを作成できれば自作できそうなので、挑戦しました。使用したコンバーター用のICは、モトローラのMC34063Aです。

今回作成したDC-DCコンバーターは、RS-232-Cのドライバ/レシーバの電源を想定した、+12V出力と-12V出力のものです。

回路図中の部品定数は、モトローラのデータシートを参照し決定しました。 コイルはジャンクで入手したトロイダルコアを使用し、自作しました。 作成には、デリカのインピーダンスブリッジ D1Sが活躍してくれました。

約70mmX約50mmの大きさにまとまりました。大げさな抵抗器が付いていますが、これは手持ちの部品を使用したためです。

目標通り、+5Vから+12V/-12Vを得ることができました。

Windowsやめたい -- その後2023年03月30日 16:43

Windowsがとても重くなってしまい、身動きが取れなくなってきたので代替えを模索していました。 おせっかいで邪魔なプロセスが沢山動いていているのが原因なのはわかっているのですが、殺す手立てがわからないので 改善することができずにいました。

Windowsの代替としてLinuxを検討し、テスト運用をしてきました。Windowsで使っているツールうち必須のものについて、 動作確認ができましたので、本格的にLinuxに移行しました。

Linuxは、Debianです。これをベースに、wineをいれて必須のWindowsのツールを動かしています。

移行したツールは、以下のとおりです。

  1. Google Chrome
  2. Mozilla ThunderBird
  3. 画像編集ソフトの JTrim (Windows版)
  4. 水魚堂さんの回路図エディタ (Windows版)

この移行を期に、Warp ServerでNFSサーバーを立ち上げ、Debianマシンからマウントできるようにしました。 安定してファイルの共有ができてます。

これから便利ツールを追加する計画です。

久しぶりに、Modula-2でプログラミング --その4-- CmdArgsの修正2023年01月30日 15:50

先に公開した"CmdArgs"モジュールに危ないところがありました。エクスポートしている変数"Argc"は、 インポートしたモジュールで変更できます。変えられてしまうと、"CmdArgs"モジュールが誤作動します。これを さけるために、引数の数を手続き"Argc()"で返すようにしました。 これで、不用意に"CmdArgs"モジュールにダメージを 与えることがなくなりました。

修正版の定義モジュール"CmdArgs.def"は、以下の通り。

DEFINITION MODULE CmdArgs;

EXPORT QUALIFIED Argv,Argc;

PROCEDURE Argc(): CARDINAL;
PROCEDURE Argv(n: CARDINAL;VAR ArgString: ARRAY OF CHAR);

END CmdArgs.

修正版の実装モジュール"CmdArgs.mod"は、以下の通り。

IMPLEMENTATION MODULE CmdArgs;
FROM ASCII IMPORT nul,ht,lf,cr;
FROM SYSTEM IMPORT ADR,WORD;
FROM OpSys IMPORT BdosFunctions,Bdos,CPMStringBuffer;

CONST
        SPACE = ' ';
        TAB = ht;
        COMMA = ',';
        SQUORT = "'";
        DQUORT = '"';
        EOS = nul;
        MAXARGS = 20;
        EMPTY = -1;

VAR
        ArgList: ARRAY [0..MAXARGS-1] OF INTEGER;
        CommandLine: CPMStringBuffer;
        QChar: CHAR;
        c,s: CARDINAL;
        CommaFlag: BOOLEAN;
        nArgc: CARDINAL;
        Msg: ARRAY [0..80] OF CHAR;

PROCEDURE Argc(): CARDINAL;
BEGIN
        RETURN nArgc;
END Argc;

PROCEDURE Argv(n: CARDINAL;VAR ArgString: ARRAY OF CHAR);
VAR
        s,d: CARDINAL;
BEGIN
        IF nArgc < n THEN
                ArgString[0] := EOS;
        ELSIF ArgList[n] = EMPTY THEN
                ArgString[0] := EOS;
        ELSE
                s := ArgList[n];
                d := 0;
                WHILE CommandLine.text[s] # EOS DO
                        ArgString[d] := CommandLine.text[s];
                        INC(s);INC(d);
                END;
                ArgString[d] := EOS;
        END;
END Argv;

PROCEDURE skipBlanks();
BEGIN
        WHILE isBlankChar(CommandLine.text[c]) DO
                INC(c);
        END;
END skipBlanks;

PROCEDURE skipSeparator();
BEGIN
        WHILE isSeparator(CommandLine.text[c]) DO
                INC(c);
        END;
END skipSeparator;

PROCEDURE isBlankChar(ch: CHAR): BOOLEAN;
BEGIN
        IF (ch = SPACE) OR (ch = TAB) THEN
                RETURN TRUE;
        END;
        RETURN FALSE;
END isBlankChar;

PROCEDURE nextQuort();
BEGIN
        WHILE (CommandLine.text[c] # EOS)
                AND (CommandLine.text[c] # QChar) DO
                INC(c);
        END;
END nextQuort;

PROCEDURE nextSeparator();
BEGIN
        WHILE (CommandLine.text[c] # EOS)
                AND (NOT isSeparator(CommandLine.text[c])) DO
                INC(c);
        END;
END nextSeparator;

PROCEDURE getOneArg(): CARDINAL;
VAR
        s: CARDINAL;
BEGIN
        IF CommandLine.text[c] # EOS THEN
                IF isQuort(CommandLine.text[c]) THEN
                        QChar := CommandLine.text[c];
                        INC(c);
                        s := c;
                        nextQuort();
                ELSE
                        s := c;
                        nextSeparator();
                END;
                CommaFlag := FALSE;
                IF CommandLine.text[c] # EOS THEN
                        IF CommandLine.text[c] # COMMA THEN
                                CommandLine.text[c] := EOS;
                                INC(c);
                                skipBlanks();
                        END;
                        IF CommandLine.text[c] = COMMA THEN
                                CommaFlag := TRUE;
                                CommandLine.text[c] := EOS;
                                INC(c);
                        END;
                END;
        ELSE
                s := 0;
        END;
        RETURN s;
END getOneArg;

PROCEDURE isQuort(ch: CHAR): BOOLEAN;
BEGIN
        IF (ch = SQUORT) OR (ch = DQUORT) THEN
                RETURN TRUE;
        END;
        RETURN FALSE;
END isQuort;

PROCEDURE isSeparator(ch: CHAR): BOOLEAN;
BEGIN
        CASE ch OF
        SPACE: RETURN TRUE;
        | TAB: RETURN TRUE;
        | COMMA: RETURN TRUE;
        ELSE
                RETURN FALSE;
        END;
END isSeparator;

PROCEDURE getCmdLine();
VAR
        BDOSCmd: RECORD
                CASE BOOLEAN OF
                TRUE: Func: BdosFunctions;
                | FALSE: Cmd: WORD;
                END;
        END;
        junk: WORD;
BEGIN
        BDOSCmd.Func := prtStr;
        Msg := 'arguments>$';
        Bdos(BDOSCmd.Cmd,ADR(Msg),junk);

        CommandLine.maxLen := CHR(255);
        CommandLine.curLen := CHR(0);
        BDOSCmd.Func := rdCBuf;
        Bdos(BDOSCmd.Cmd,ADR(CommandLine),junk);
        CommandLine.text[ORD(CommandLine.curLen)] := EOS;

        BDOSCmd.Func := prtStr;
        Msg[0] := cr; Msg[1] := lf; Msg[2] := '$';
        Bdos(BDOSCmd.Cmd,ADR(Msg),junk);

        FOR nArgc := 0 TO MAXARGS-1 DO
                ArgList[nArgc] := EMPTY;
        END;

        nArgc := 0;
        c := 0;
        CommaFlag := FALSE;
        skipBlanks();
        WHILE (CommandLine.text[c] # EOS) AND (nArgc < MAXARGS) DO
                ArgList[nArgc] := getOneArg();
                skipBlanks();
        INC(nArgc);
        END;
        IF (CommandLine.text[c] = EOS) AND CommaFlag THEN
                ArgList[nArgc] := c;
                INC(nArgc);
        END;
END getCmdLine;

BEGIN
        getCmdLine();
END CmdArgs.

この修正にあわせて、"Find"モジュールの変更をしました。

久しぶりに、Modula-2でプログラミング -- その3 -- "CmdLine.mod"モジュールの応用"Find.mod"の紹介2023年01月26日 11:18

先に公開しました"CmdLine.mod"モジュールを使った応用を紹介します。

応用モジュール"Find.mod"は、指定された文字列をファイル中から探し表示します。このような感じです。

文字列"WriteLn"をファイル"find.mod"、"cmdargs.def"、"tstargs.mod"から探して表示します。

C0#find
arguments>WriteLn find.mod cmdargs.def tstargs.mod
find.mod[3]FROM InOut IMPORT Write,WriteCard,WriteString,WriteLn;
find.mod[35]    WriteLn;
find.mod[87]    WriteString('find');WriteLn;
find.mod[88]    WriteString('      TargetString File1 File2 FIle3,,,,');WriteLn; 
tstargs.mod[2]FROM InOut IMPORT Write,WriteInt,WriteLn,WriteString;
tstargs.mod[13] WriteString('Argc:=');WriteInt(Argc,3);WriteLn;
tstargs.mod[20]         Write(']');WriteLn;

このように、ファイル名、出現した行番号、出現した行を表示します。"CmdArgs.def"には、該当する文字列がありませんでした。

では、"Find.mod"モジュールの内容です。文字列の検索は"FindTarget()"手続きでします。 ストレートに書き下しましたので、ロジックを追えることと思います。

Find.mod

MODULE Find;
FROM CmdArgs IMPORT Argc,Argv;
FROM InOut IMPORT Write,WriteCard,WriteString,WriteLn;
FROM ASCII IMPORT nul,lf;
FROM Files IMPORT FILE,FileState,Open,Close,Read;
FROM OpSys IMPORT Bdos,BdosFunctions;
FROM SYSTEM IMPORT WORD;

CONST
        EOS = nul;
        MAXLINE = 128;
        FILENAMESIZE = 15;
        EOFMARK = 32C;

VAR
        FileName: ARRAY [0..FILENAMESIZE] OF CHAR;
        Target: ARRAY [0..MAXLINE] OF CHAR;
        LineBuffer: ARRAY [0..MAXLINE] OF CHAR;
        FileNumber,LineNumber: CARDINAL;
        inFile: FILE;
        EndOfFile: BOOLEAN;
        fs: FileState;
        BdosCmd: RECORD
                CASE BOOLEAN OF
                        TRUE: Func: BdosFunctions;
                        | FALSE: Cmd: WORD;
                END;
        END;

PROCEDURE putLine(Name:ARRAY OF CHAR;Line:CARDINAL;Buffer:ARRAY OF CHAR);
BEGIN
        WriteString(Name);
        Write('[');WriteCard(Line,1);Write(']');
        WriteString(Buffer);
        WriteLn;
END putLine;

PROCEDURE ReBoot();
VAR
        junk: WORD;
BEGIN
        BdosCmd.Func := boot;
        Bdos(BdosCmd.Cmd,junk,junk);
END ReBoot;

PROCEDURE findTarget(Target,Line:ARRAY OF CHAR): BOOLEAN;
VAR
        t,l: CARDINAL;
        found: BOOLEAN;
BEGIN
        found := FALSE;
        t := 0; l := 0;
        WHILE (Line[l] # EOS) AND (NOT found) DO
                IF Line[l] = Target[0] THEN
                        t := 1;
                        WHILE Line[l+t] = Target[t] DO
                                INC(t);
                        END;
                        IF Target[t] = EOS THEN
                                found := TRUE;
                        END;
                END;
                INC(l);
        END;
        RETURN found;
END findTarget;

PROCEDURE ReadLine(f:FILE;VAR Line:ARRAY OF CHAR);
VAR
        c: CARDINAL;
BEGIN
        c := 0;
        Read(f,Line[c]);
        WHILE (Line[c] # lf) AND (NOT EndOfFile) DO
                IF Line[c] = EOFMARK THEN
                        EndOfFile := TRUE;
                ELSE
                        INC(c);
                        Read(f,Line[c]);
                END;
        END;
        Line[c] := EOS;
END ReadLine;

PROCEDURE Usage();
BEGIN
        WriteString('find');WriteLn;
        WriteString('      TargetString File1 File2 FIle3,,,,');WriteLn; 
END Usage;

BEGIN
        IF Argc < 1 THEN
                Usage();
                ReBoot();
        END;
        Argv(0,Target);
        FileNumber := 1;
        WHILE FileNumber < Argc DO
                Argv(FileNumber,FileName);
                fs := Open(inFile,FileName);
                IF fs = FileOK THEN
                        EndOfFile := FALSE;
                        LineNumber := 1;
                        WHILE NOT EndOfFile DO
                                ReadLine(inFile,LineBuffer);
                                IF findTarget(Target,LineBuffer) THEN
                                        putLine(FileName,LineNumber,
                                                LineBuffer);
                                END;
                                INC(LineNumber);
                        END;
                        fs := Close(inFile);
                END;
                INC(FileNumber);
        END;
END Find.

久しぶりに、Modula-2でプログラミング--その2 CmdLineモジュールの紹介--2023年01月23日 20:58

コマンドライン・パラメーターを読みとり、分解する仕組みを実現したモジュールを公開します。 Modula-2で作成しました。Modula-2では、コンパイル単位を「モジュール」と呼びます。モジュールは3種類あり、 「定義モジュール(DEFINITION MODULE)」、「実現モジュール(IMPLEMENTATION MODULE)」、 「モジュール(MODULE") です。

「定義モジュール」は、モジュールのインターフェイスを記述したもので、他のモジュールに公開する定数や手続きを記述します。

「実現モジュール」は、名前の通り、モジュールの機能を書き下したプログラムです。

「モジュール」は、いわゆるメインプログラムです。

まずは、定義モジュール"CmdArgs.def"です。

DEFINITION MODULE CmdArgs;

EXPORT QUALIFIED Argv,Argc;

VAR
        Argc: CARDINAL;

PROCEDURE Argv(n: CARDINAL;VAR ArgString: ARRAY OF CHAR);

END CmdArgs.

モジュール"CmdArgs"が提供(EXPORT)する手続き"Argv"と変数"Argc"を定義しています。 これを事前コンパイルしておき、このモジュールを利用するモジュールをコンパイルする際に読み込まれ、 妥当性のチェックに使われます。

おつぎは、実現モジュール"CmdArgs.mod"です。

CmdArgs.mod

IMPLEMENTATION MODULE CmdArgs;
FROM ASCII IMPORT nul,ht,lf,cr;
FROM SYSTEM IMPORT ADR,WORD;
FROM OpSys IMPORT BdosFunctions,Bdos,CPMStringBuffer;

CONST
        SPACE = ' ';
        TAB = ht;
        COMMA = ',';
        SQUORT = "'";
        DQUORT = '"';
        EOS = nul;
        MAXARGS = 20;
        EMPTY = -1;

VAR
        ArgList: ARRAY [0..MAXARGS-1] OF INTEGER;
        CommandLine: CPMStringBuffer;
        QChar: CHAR;
        c,s: CARDINAL;
        CommaFlag: BOOLEAN;
(*      Argc: CARDINAL; defined in CmdArgs.Def  *)
        Msg: ARRAY [0..80] OF CHAR;

PROCEDURE skipBlanks();
BEGIN
        WHILE isBlankChar(CommandLine.text[c]) DO
                INC(c);
        END;
END skipBlanks;

PROCEDURE skipSeparator();
BEGIN
        WHILE isSeparator(CommandLine.text[c]) DO
                INC(c);
        END;
END skipSeparator;

PROCEDURE isBlankChar(ch: CHAR): BOOLEAN;
BEGIN
        IF (ch = SPACE) OR (ch = TAB) THEN
                RETURN TRUE;
        END;
        RETURN FALSE;
END isBlankChar;

PROCEDURE Argv(n: CARDINAL;VAR ArgString: ARRAY OF CHAR);
VAR
        s,d: CARDINAL;
BEGIN
        IF Argc < n THEN
                ArgString[0] := EOS;
        ELSIF ArgList[n] = EMPTY THEN
                ArgString[0] := EOS;
        ELSE
                s := ArgList[n];
                d := 0;
                WHILE CommandLine.text[s] # EOS DO
                        ArgString[d] := CommandLine.text[s];
                        INC(s);INC(d);
                END;
                ArgString[d] := EOS;
        END;
END Argv;

PROCEDURE nextQuort();
BEGIN
        WHILE (CommandLine.text[c] # EOS)
                AND (CommandLine.text[c] # QChar) DO
                INC(c);
        END;
END nextQuort;

PROCEDURE nextSeparator();
BEGIN
        WHILE (CommandLine.text[c] # EOS)
                AND (NOT isSeparator(CommandLine.text[c])) DO
                INC(c);
        END;
END nextSeparator;

PROCEDURE getOneArg(): CARDINAL;
VAR
        s: CARDINAL;
BEGIN
        IF CommandLine.text[c] # EOS THEN
                IF isQuort(CommandLine.text[c]) THEN
                        QChar := CommandLine.text[c];
                        INC(c);
                        s := c;
                        nextQuort();
                ELSE
                        s := c;
                        nextSeparator();
                END;
                CommaFlag := FALSE;
                IF CommandLine.text[c] # EOS THEN
                        IF CommandLine.text[c] # COMMA THEN
                                CommandLine.text[c] := EOS;
                                INC(c);
                                skipBlanks();
                        END;
                        IF CommandLine.text[c] = COMMA THEN
                                CommaFlag := TRUE;
                                CommandLine.text[c] := EOS;
                                INC(c);
                        END;
                END;
        ELSE
                s := 0;
        END;
        RETURN s;
END getOneArg;

PROCEDURE isQuort(ch: CHAR): BOOLEAN;
BEGIN
        IF (ch = SQUORT) OR (ch = DQUORT) THEN
                RETURN TRUE;
        END;
        RETURN FALSE;
END isQuort;

PROCEDURE isSeparator(ch: CHAR): BOOLEAN;
BEGIN
        CASE ch OF
        SPACE: RETURN TRUE;
        | TAB: RETURN TRUE;
        | COMMA: RETURN TRUE;
        ELSE
                RETURN FALSE;
        END;
END isSeparator;

PROCEDURE getCmdLine();
VAR
        BDOSCmd: RECORD
                CASE BOOLEAN OF
                TRUE: Func: BdosFunctions;
                | FALSE: Cmd: WORD;
                END;
        END;
        junk: WORD;
BEGIN
        BDOSCmd.Func := prtStr;
        Msg := 'arguments>$';
        Bdos(BDOSCmd.Cmd,ADR(Msg),junk);

        CommandLine.maxLen := CHR(255);
        CommandLine.curLen := CHR(0);
        BDOSCmd.Func := rdCBuf;
        Bdos(BDOSCmd.Cmd,ADR(CommandLine),junk);
        CommandLine.text[ORD(CommandLine.curLen)] := EOS;

        BDOSCmd.Func := prtStr;
        Msg[0] := cr; Msg[1] := lf; Msg[2] := '$';
        Bdos(BDOSCmd.Cmd,ADR(Msg),junk);

        FOR Argc := 0 TO MAXARGS-1 DO
                ArgList[Argc] := EMPTY;
        END;

        Argc := 0;
        c := 0;
        CommaFlag := FALSE;
        skipBlanks();
        WHILE (CommandLine.text[c] # EOS) AND (Argc < MAXARGS) DO
                ArgList[Argc] := getOneArg();
                skipBlanks();
        INC(Argc);
        END;
        IF (CommandLine.text[c] = EOS) AND CommaFlag THEN
                ArgList[Argc] := c;
                INC(Argc);
        END;
END getCmdLine;

BEGIN
        getCmdLine();
END CmdArgs.

手続き"getCmdLine()"は、このモジュールが初期化されるときに動きます。"getCmdLine()"は、プロンプト "arguments>"を表示し、引数を読みとります。その後、前回示したルールに従って引数を分解します。

変数"Argc"は、分解後の引数の数です。

手続き"Argv(n,Param)"は、"n"番目の引数(nilで終わる文字列)を "Param"にコピーして返します。 存在しない引数の時は、"Param"は、長さ0の文字列になります。第一引数は引数は、"n=0"です。

何の変哲のない下請け手続きで書き下しましたので、ロジックを簡単に追えると思います。

次回は、"CmdArgs"モジュールを使用した例を紹介します。