[ 前のページ ] [ 次のページ ] [ 目次 ] [ 索引 ]
日本語DIGITAL TCP/IP Services for OpenVMSは,FTP,TELNET,SMTP,リモート・プリントにおいて, 漢字フィルタの機能が提供されています。シフトJIS漢字,7ビットJIS漢字(2 種類),およびUJIS漢字とDEC漢字コードとの変換フィルタが標準で提供されています。 上記以外の漢字コードとDEC漢字コードとの変換フィルタも, ユーザが必要に応じて作成して利用することができます。
また,このフィルタは漢字コードの変換にとどまらず,より一般的なフィルタと考えることができます。 本章の最後に示すUPCASEフィルタは,すべての小文字を大文字に変換するフィルタを作成して, 利用する場合のプログラム例です。
作成した漢字フィルタ・ルーチンは,以下に示すセットアップを行うことにより, 上記アプリケーションで使用することが可能になります。
作成したフィルタを使用するには次の作業を行ってください。
以下に詳細を示します。
作成したフィルタ・ルーチンをTCPIP$ フィルタ名_FSHR.EXEというファイル名でSYS$SHARE: ディレクトリに置きます。ただし,論理名TCPIP$フィルタ名_FSHR を定義すれば,必ずしもSYS$SHARE:ディレクトリに置く必要はありません。 サーバのフィルタ指定に論理名を使用する場合は,システム(/SYSTEM) 論理名の定義が必要です。システム(/SYSTEM)論理名を定義する場合は,/EXEC も同時に指定してください。
漢字フィルタ共用イメージは,INSTALLユーティリティで/OPENを指定してインストールします。SYS$SHARE: ディレクトリに標準で提供されているフィルタ共用イメージTCPIP$ フィルタ名_FSHR.EXEは,日本語DIGITAL TCP/IP Services for OpenVMS起動コマンド・ プロシージャ(SYS$STARTUP:TCPIP$FILTER_STARTUP.COM)が自動的にインストールします。SYS$SHARE: ディレクトリ以外にフィルタ共用イメージを置く場合には, 論理名の定義を行いINSTALLユーティリティで/OPENを指定してインストールしてください。 漢字フィルタ共用イメージのファイル保護を W:RE にすれば,あるユーザが作成したフィルタをすべてのユーザが使用できるようになります。
日本語DIGITAL TCP/IP Services for OpenVMS漢字フィルタ機能は,ANET+に提供されていた漢字フィルタ機能に基づいて実装されています。 以下のようなコマンドにより, ANET+用に作成されたフィルタを, 日本語DIGITAL TCP/IP Services for OpenVMSにおいても,使用することができます。 以下の例において,フィルタ名はANET+用に使用する場合のフィルタの名称を指定します。
ANETP用に作成されたフィルタを使用するには次の作業を行ってください。
前述のTCPIP漢字フィルタのセットアップの説明中において, TCPIP$フィルタ名_FSHR.EXEは,ANETP_フィルタ名_FSHR.EXEと, TCPIP$フィルタ名_FSHRは,ANETP_フィルタ名_FSHRと置き換わります。
TELNETクライアントの場合
$ TELNET/ANETP/FILTER=フィルタ名
FTPクライアントの場合
UNIX形式のコマンドを用いる場合
$ FTP/ANETP/FILTER=フィルタ名
または
FTP> filter [フィルタ名_ANETP]
OpenVMS形式のコマンドを用いる場合
$ FTP/ANETP/FILTER=フィルタ名
または
FTP> set filterフィルタ名_ANETP
FTPサーバの場合
ftp> quote "site filterフィルタ名_ANETP"
SMTPの場合
$ DEFINE [/SYSTEM] TCPIP$SMTP_KANJI_FILTERフィルタ名_ANETP
リモート・プリントの場合
TCPIP$PRINTCAP.DAT中のエントリでのフィルタ指定。
:kf=フィルタ名_ANETP
PRINTコマンドでのフィルタ指定
$ PRINT /PARAMETER=(FILTER=フィルタ名_ANETP)
漢字フィルタは2つの要素から構成されています。コード変換を行うためのサブルーチン群と, それを呼び出すFTP,TELNETなどの通信ユーティリティです。 コード変換を行うサブルーチン群は共用イメージです。 SYS$SHARE:TCPIP$SJIS_FSHR.EXEは,DEC漢字コードとSJIS漢字コードの変換フィルタです。 フィルタ共用イメージは,次に説明するフィルタ設定ルーチンと, 以下の5つのフィルタ・ルーチン群を用意する必要があります。
| ルーチン名 | 内容 | 
|---|---|
| BEGIN_FILTER | フィルタ・ストリーム初期化ルーチン | 
| NTOH_FILTER | 入力フィルタ・ルーチン | 
| HTON_FILTER | 出力フィルタ・ルーチン | 
| RELEASE_FILTER | バッファ資源解放ルーチン | 
| END_FILTER | フィルタ・ストリーム解放ルーチン | 
FTP,TELNETなどの通信ユーティリティは,各ユーティリティのコマンド行, または修飾子/FILTERによりフィルタ名が指定されると, フィルタ名からフィルタ共用イメージのファイル名を作成します。 たとえばFTP/FILTER=SJISコマンドでFTPを起動すると,FTPはTCPIP$ フィルタ名_FSHR.EXE という規則にしたがい,TCPIP$SJIS_FSHR.EXEを得ます。
次に通信ユーティリティはLIB$FIND_IMAGE_SYMBOLを呼び出し,共用イメージを起動し,tcpip_filter というユニバーサル・シンボルの値を得ます。 すべてのフィルタ共用イメージはtcpip_filterというユニバーサル・ シンボルを持たなければなりません。そしてこのユニバーサル・シンボルは, フィルタ設定ルーチンのエントリ・ポイントのアドレスとして使われます。
FTPに対して/FILTER=SJISが指定されていると,FTPはtcpip_filterというユニバーサル・ シンボルの値を解決し,サブルーチンとして呼び出します。 このサブルーチンをフィルタ設定ルーチンと呼びます。フィルタ設定ルーチンを呼び出すことにより, 第3.3節で説明する5つのフィルタ・ルーチン群のエントリ・ポイントが明らかになります。
フィルタ・ルーチン群はフィルタ・ストリームを管理しなければなりません。FTP ,TELNETなどの通信ユーティリティは,フィルタ・ストリーム初期化ルーチンBEGIN_FILTER を呼び出して必要な数のフィルタ・ストリームを得ます。BEGIN_FILTER ルーチンはフィルタ・ストリームの管理に必要なデータ構造の割り当て, 初期化などを行った後,その識別子を呼び出し者に与えます。 以後,入力/出力フィルタ・ルーチン,バッファ資源解放ルーチン, フィルタ・ストリーム解放ルーチンの呼び出しは,この識別子でフィルタ・ ストリームを指定します。
フィルタ・ストリームは,変換されるデータの流れに対応するものです。 フィルタ・ルーチンに変換のために渡されるデータ,それ自体で変換可能な完結したレコードではなく, 変換されるべきデータの流れの一部が連続して渡されると考えなければなりません。
7ビットJIS漢字コードをDEC漢字コードに変換する場合を考えてみます。7 ビットJIS漢字コード自体はASCIIコードと見分けがつかず,(いわゆる漢字IN ,漢字OUTと呼ばれる)エスケープ・シーケンスにより文字集合を指示しています。 もし,第N回目のJIS漢字からDEC漢字への変換ルーチンの呼び出しで漢字文字集合が指示されたら, 第N+1回目の変換は,漢字文字集合が指示された状態から開始されなければなりません。 このように,現在JIS 漢字文字集合が指示されているのか,それともASCII文字集合が指示されているのか, という状態をフィルタ・ストリームに記憶する必要があります。 また,7ビットJIS漢字コードに限らず,変換されるべきデータが2 バイト漢字コードの1バイト目で終了しているという場合もありえます。 この場合は2バイト漢字コードの1バイト目をフィルタ・ストリームに記憶し, 次の呼び出しで与えられたデータの先頭の1バイトと合わせて2バイト漢字コードとして変換しなければなりません。
フィルタ・ストリームはデータの流れに対応しますから,1つのストリームで入力フィルタ・ ルーチンと出力フィルタ・ルーチンが混合して呼び出されることはありません。 入力フィルタ(ネットワークから読み込んだデータの変換)と出力フィルタ(ネットワークへ書き込むデータの変換)の両方を同時に必要とするときは2 つのストリームが取得されます。
FTP,TELNETなどの通信ユーティリティは,BEGIN_FILTERルーチンの呼び出し時に, あらかじめ確保すべきバッファ資源の数を指示します。バッファ資源とは, 入力/出力フィルタ・ルーチンが変換結果を格納して呼び出し者に一時的に与えるバッファです。 入力/出力フィルタの呼び出しのたびにこのバッファ資源が消費されます。 通信ユーティリティは変換結果が必要でなくなると, バッファ資源解放ルーチンを呼び出し,フィルタ・ストリームにバッファ資源を返します。 通信ユーティリティはBEGIN_FILTER で指定したバッファ資源の数の回数分はRELEASE_FILTERを呼び出さずに, 連続して資源を消費する場合があります。
ただし,BEGIN_FILTERルーチンに対してあらかじめ確保するバッファ資源の数1 を指示した場合は,通信ユーティリティはバッファ資源解放ルーチンを呼び出しません。 バッファ資源の数が1の場合は,入力/出力フィルタ・ ルーチンの呼び出しで与えられたバッファ資源は,次の入力/出力フィルタ・ ルーチンの呼び出しで自動的に解放されるものとして扱われます。
各フィルタ・ルーチンについて説明します。
TCPIP_FILTER (control-block)
BEGIN_FILTER (stream, application, resource)
NTOH_FILTER (stream, src, srclen,dst, dstlen)
HTON_FILTER (stream, src, srclen, dst, dstlen)
RELEASE_FILTER (stream, buffer)
END_FILTER (stream)
フィルタ・ルーチン群のエントリ・ポイントを明らかにします。通信ユーティリティはフィルタ設定ルーチンを呼び出して5 つのフィルタ・ルーチンのエントリ・ ポイントのアドレスを得ます。
VMS用法: cond_value データ型: longword (unsigned) アクセス: write only 受け渡し方: by value
データ型: record アクセス: write only 受け渡し方: by reference
FLINK,BLINK,SIZE,TYPE,FILLは通信ユーティリティが使用します。フィルタ・ ルーチンはFLINK,BLINK,SIZE,TYPE,FILLの内容を変更できません。BEGIN_FILTER フィールドにはフィルタ・ストリーム初期化ルーチンの,HTON_FILTER フィールドには出力フィルタ・ルーチンの,また, NTOH_FILTERフィールドには入力フィルタ・ルーチンのエントリ・ポイントのアドレスを書き込みます。RELEASE_FILTER フィールドにはバッファ資源解放ルーチンの,END_FILTER フィールドにはフィルタ・ストリーム解放ルーチンのエントリ・ ポイントのアドレスを書き込みます。
戻り値がサクセスの場合,フィルタが設定され,以後必要に応じてフィルタ・ ストリーム初期化ルーチンが呼び出されます。戻り値がエラーの場合, フィルタは設定されません。
フィルタ・ストリームを生成,初期化し,識別子を呼び出し者に与えます。
VMS用法: cond_value データ型: longword (unsigned) アクセス: write only 受け渡し方: by value
データ型: longword (unsigned) アクセス: write only 受け渡し方: by reference
データ型: longword (unsigned) アクセス: read only 受け渡し方: by reference
| 通信ユーティリティ | 規定値 | 
|---|---|
| FTP | 1 | 
| TELNET | 2 | 
| SMTP | 3 | 
| LPR | 4 | 
FTP,TELNET,SMTP,LPRの各通信ユーティリティはフィルタ・ストリーム初期化ルーチンを呼び出すとき, それぞれに割り当てられた番号をapplication パラメータとしてセットします。この番号はフィルタ・ルーチンのストリームに記憶するべきです。 フィルタ・ルーチンはこの番号により上位通信ユーティリティが何であるか知ることができます。 これは1 つのフィルタ・ルーチンの中で,上位通信ユーティリティに依存する異なるフィルタ処理をしなければならない場合を予想しての準備です。
データ型: longword integer (signed) アクセス: read only 受け渡し方: by reference
バッファ資源の数は,フィルタ資源解放ルーチンを呼び出すことなく連続して入力/ 出力フィルタ・ルーチンを呼び出すことができる最大の回数を示します。 入力/出力フィルタを呼び出すたびにバッファ資源は消費されます。 入力/出力フィルタが変換結果を格納し,dstパラメータでサブルーチンの呼び出し者に与えるバッファは, その変換結果が不要となった時点でフィルタ・ ストリームに返されます。通信ユーティリティはあらかじめ確保した資源数の回数以内で, フィルタ資源解放ルーチンを呼び出すことなく, 入出力フィルタ・ルーチンを呼び出す場合があります。ただし,バッファ資源の数が1 の場合,通信ユーティリティはフィルタ資源解放ルーチンを呼び出しません。 資源の数が1の場合,つぎに入力/出力フィルタ・ ルーチンが呼び出された時点で,前回の入力/出力フィルタ・ルーチンが与えたバッファ資源は解放されているものとみなします。
戻り値がサクセスの場合,以後必要に応じて入力/出力フィルタ・ルーチン, フィルタ資源解放ルーチンが呼び出されます。フィルタ・ストリームが不要になった時点でフィルタ・ ストリーム解放ルーチンが呼び出されます。 戻り値がエラーの場合,入力/出力フィルタ・ルーチンは呼び出されません。 フィルタなしの状態になります。
ネットワーク(リモート・ホスト)から受信したデータ・ストリームを変換するフィルタ・ ルーチンです。漢字変換フィルタは他機種漢字コードからDEC 漢字コードへの変換を行います。
VMS用法: cond_value データ型: longword (unsigned) アクセス: write only 受け渡し方: by value
データ型: longword (unsigned) アクセス: read only 受け渡し方: by reference
データ型: character string アクセス: read only 受け渡し方: by reference
データ型: word (unsigned) アクセス: read only 受け渡し方: by reference
データ型: address of character string アクセス: write only 受け渡し方: by reference
データ型: word (unsigned) アクセス: write only 受け渡し方: by reference
漢字コードの変換においては,入力文字列と出力文字列の長さが異なる場合が予想されます。 入力フィルタ・ルーチンは変換結果の格納のために, あらかじめ確保されていたバッファ資源,あるいはバッファ資源解放ルーチンでストリームに返されたバッファ資源を使用します。 しかし,変換中に変換結果文字列を格納するための領域が不足することが判明したら, その時点でさらに大きな領域を取得する必要があります。
戻り値がサクセスの場合,変換結果の文字列が変換前の文字列の代わりに使われます。FTP の場合変換結果文字列がファイルに出力され,TELNETの場合変換結果文字列は端末に表示されます。 戻り値がエラーの場合,フィルタ処理は解除されフィルタなしの状態に戻ります。
ネットワーク(リモート・ホスト)へ送信するデータを変換するフィルタ・ ルーチンです。漢字変換フィルタはDEC漢字コードから他機種漢字コードへの変換を行います。
VMS用法: cond_value データ型: longword (unsigned) アクセス: write only 受け渡し方: by value
データ型: longword (unsigned) アクセス: read only 受け渡し方: by reference
データ型: character string アクセス: read only 受け渡し方: by reference
データ型: word (unsigned) アクセス: read only 受け渡し方: by reference
データ型: address of character string アクセス: write only 受け渡し方: by reference
データ型: word (unsigned) アクセス: write only 受け渡し方: by reference
漢字コードの変換においては,入力文字列と出力文字列の長さが異なる場合が予想されます。 出力フィルタ・ルーチンは変換結果の格納のために, あらかじめ確保されていたバッファ資源,あるいはバッファ資源解放ルーチンでストリームに返されたバッファ資源を使用します。 しかし,変換中に変換結果文字列を格納するための領域が不足することが判明したら, その時点でさらに大きな領域を取得する必要があります。
戻り値がサクセスの場合,変換結果の文字列が変換前の文字列の代わりに使われます。FTP の場合変換結果文字列がリモート・ホストに送信されます。 戻り値がエラーの場合,フィルタ処理は解除され,フィルタなしの状態に戻ります。
入力/出力フィルタ・ルーチンの呼び出しにより消費されたバッファ資源をフィルタ・ ストリームに解放するために呼び出されます。
VMS用法: cond_value データ型: longword (unsigned) アクセス: write only 受け渡し方: by value
データ型: longword (unsigned) アクセス: read only 受け渡し方: by reference
データ型: character string アクセス: read only 受け渡し方: by reference
ストリーム初期化ルーチンで指示した,あらかじめ確保する資源の数が1 だった場合,フィルタ資源解放ルーチンを呼び出すことなく入力/出力フィルタ・ ルーチンが繰り返し呼び出されます。
あらかじめ確保するバッファ資源が2以上だった場合,入力/出力フィルタ・ ルーチンの呼び出しでdstパラメータとして与えたバッファは,バッファ資源解放ルーチンが呼び出されてストリームに返されるまでは再び使用することはできません。
戻り値がエラーの場合,フィルタ処理は解除されフィルタなしの状態に戻ります。
不要となった変換ストリームを解放するために呼び出されます。
VMS用法: cond_value データ型: longword (unsigned) アクセス: write only 受け渡し方: by value
データ型: longword (unsigned) アクセス: read only 受け渡し方: by reference
戻り値がエラーの場合,フィルタ処理は解除されフィルタなしの状態に戻ります。
この例は,STR$UPCASEルーチンを使ってすべての小文字を大文字に変換するフィルタです。 使用言語はVAXC V3.1です。
次のようにコンパイル/リンクします。^ZはCtrl/Zを表します。
      $ CC UPCASE.C
      $ LINK/SHARE=TCPIP$UPCASE_FSHR.EXE UPCASE, TT/OPT
        UNIVERSAL = tcpip_filter
      ^Z
      $
このフィルタ共用イメージを使用するには,TCPIP$UPCASE_FSHR.EXE をSYS$SHARE:ディレクトリにコピーするか,あるいはTCPIP$UPCASE_ FSHR.EXEのあるディレクトリで次のように論理名を定義してください。
      $ DEFINE TCPIP$UPCASE_FSHR 'F$ENVIRON("DEFAULT")'TCPIP$UPCASE_FSHR.EXE
             #module UPCASE "V2.2-021"
             #include ssdef
             #pragma builtins
             #define KF_LENGTH sizeof(struct KnjFilter)
             struct KnjFilter {
                 struct KnjFilter *kf_next;          /* Forward link                     */
                 struct KnjFilter *kf_prev;          /* Backward link                    */
                 unsigned short int kf_size;         /* Length                           */
                 unsigned char kf_type;              /* Type                             */
                 unsigned char kf_fill;              /* Unused                           */
                 int (*kf_begin_filter)();           /* Allocate filter stream           */
                 int (*kf_hton_filter)();            /* Host to net filter               */
                 int (*kf_ntoh_filter)();            /* Net to host filter               */
                 int (*kf_release_filter)();         /* Resource deallocation            */
                 int (*kf_end_filter)();             /* Deallocate filter stream         */
                 } ;
             #define KB_LENGTH (sizeof(struct KnjBuf)-sizeof(char))
             struct KnjBuf {                         /*                                  */
                 struct KnjBuf *kb_next;             /* Forward link                     */
                 struct KnjBuf *kb_prev;             /* Backward link                    */
                 long int kb_size;                   /* Length                           */
                 char kb_data [1];                   /* Data                             */
                 } ;
             #define KC_LENGTH sizeof(struct KnjContext)
             struct KnjContext {                     /*                                  */
                 struct KnjContext *kc_next;         /* Forward link                     */
                 struct KnjContext *kc_prev;         /* Backward link                    */
                 unsigned short int kc_size;         /* Length                           */
                 unsigned char kc_type;              /* Type                             */
                 char kc_fill;                       /* Unused                           */
                 long int kc_application;            /* Name of caller                   */
                 struct KnjBuf *kc_kb [2];           /* Queue header of free KnjBuf      */
                 struct KnjBuf *kc_kbinuse [2];      /* Queue header of in-use KnjBuf    */
                 long int kc_flags;                  /* Flags, see KC_                   */
                 } ;
             #define KC_M_RELREQ 1
             #define KC_M_PRESERVE 2
             #define HLA_FTP 1                       /* File Transfer Protocol           */
             #define HLA_TELNET 2                    /* TELNET, virturl terminal         */
             #define HLA_SMTP 3                      /* Simple Mail Transfer Protocol    */
             #define HLA_LPR 4                       /* LPR                              */
             #define HLA_MAX 4
             typedef unsigned char u_char;
             typedef unsigned short u_short;
             typedef unsigned long u_long;
             /*
              * The macros used to check condition value
              */
             #define issuccess(r) (1&(r))
             #define iserror(r) (!issuccess(r))
             #define check(f) {long $$r=(f);if(iserror($$r))lib$stop($$r);}
             #define onerror(f,a) {long $$r=(f);if(iserror($$r)) a;}
             /*
              * When filter routines realize that KanjiBuf is too short to
              * store resultant string, ReplaceKB macro is executed.
              */
             #define ReplaceKB(kc,kb,d,dl){\
                     long l = (kb)->kb_size - (dl);\
                     if(((kb) = NewBuf((kc),(kb),l)) == 0) return(SS$_INSFMEM);\
                     (d) = (kb)->kb_data + l; (dl) = (kb)->kb_size - l;}
             #define Display(m){\
                     static char d$[]=m; long d[]={sizeof(d$)-1,d$}; lib$put_output(d);}
             static begin_filter();
             static end_filter();
             static hton_filter();
             static ntoh_filter();
             static release_filter();
             static struct KnjBuf *GetBuf();
             static struct KnjBuf *NewBuf();
             static handler();
             static long KnjContext[] = {KnjContext,KnjContext};
             /*
              * tcpip_filter
              *
              *      This routine fills Kanji Filter block with entry
              *      points of all filter routines. To make the address
              *      of this routine known to external, TCPIP$UPCASE_FSHR
              *      is an universal symbol.
              */
             tcpip_filter(kf)
             register struct KnjFilter *kf;
             {
                     /*
                      * Place known entry points of filter routine in KnjFilter block.
                      */
                     kf->kf_begin_filter = begin_filter;
                     kf->kf_hton_filter = hton_filter;
                     kf->kf_ntoh_filter = ntoh_filter;
                     kf->kf_end_filter = end_filter;
                     kf->kf_release_filter = release_filter;
                     return(SS$_NORMAL);
             }
             /*
              * BEGIN_FILTER
              *
              *      Begin_filter routine is called by TCPIP applications
              *      to get filter stream. Filter stream preserves several
              *      stream specific information.
              *      When a value of resource arguent is 1, TCPIP application
              *      do not call release_filter routine after a call of
              *      ntoh_filter or hton_filter. When a value of the argument
              *      is greater than 1, release_filter routine must be called
              *      after a call of ntoh_filter or hton_filter.
              */
             static begin_filter(stream,application,resource)
             u_long *stream;
             u_long *application;
             long *resource;
             {
                     register struct KnjContext *kc;
                     register struct KnjBuf *kb;
                     static char *t;
                     /*
                      * Establish a condition handler.
                      * R13 = FP.
                      */
                     ((long *)_READ_GPR(13))[0] = handler;
                     /*
                      * Allocate Kanji Filter Context block for the stream.
                      */
                     onerror(lib$get_vm(&sizeof(struct KnjContext),&t), return($$r));
                     kc = (struct KnjContext *)t;
                     kc->kc_size = sizeof(struct KnjContext);
                     kc->kc_type = 0;
                     kc->kc_fill = 0;
                     kc->kc_application = *application;
                     kc->kc_kb[1] = kc->kc_kb[0] = kc->kc_kb;
                     kc->kc_kbinuse[1] = kc->kc_kbinuse[0] = kc->kc_kbinuse;
                     kc->kc_flags = 0;
                     /*
                      * Queue it
                      */
                     _INSQUE((void *)kc,(void *)KnjContext);
                     /*
                      * Allocate 1 Kanji Buff. Length of buffer
                      * depends on high level application.
                      */
                     kb = GetBuf(kc,512);
                     if(kb == 0) {
                             end_filter(kc);
                             *stream = 0;
                             return(SS$_INSFMEM);
                     }
                     /*
                      * Queue the Kanji Buff into Kanji Context.
                      */
                     _INSQUE((void *)kb,(void *)kc->kc_kb);
                     if(*resource > 1)
                             kc->kc_flags |= KC_M_RELREQ;
                     *stream = (long)kc;
                     return(SS$_NORMAL);
             }
             /*
              * END_FILTER
              *
              *      This routine is called when TCPIP application no longer
              *      needs filter stream, that was previously allocated by
              *      begin_filter call. Note that this routine must be called
              *      after all resource has been released by release_filter
              *      calls.
              */
             static end_filter(stream)
             u_long *stream;
             {
                     register struct KnjContext *kc;
                     register struct KnjBuf *kb;
                     static char *t;
                     /*
                      * Establish a condition handler.
                      * R13 = FP.
                      */
                     ((long *)_READ_GPR(13))[0] = handler;
                     /*
                      * Remove all Kanji Buffers from queue.
                      * Deallocate memory.
                      */
                     kc = (struct KnjContext *)*stream;
                     while(_REMQUE((void *)kc->kc_kbinuse[0],(void **)&kb) != 2) {
                             kb->kb_size += KB_LENGTH;
                             lib$free_vm(&kb->kb_size,&kb);
                     }
                     while(_REMQUE((void *)kc->kc_kb[0],(void **)&kb) != 2) {
                             kb->kb_size += KB_LENGTH;
                             lib$free_vm(&kb->kb_size,&kb);
                     }
                     /*
                      * Release Kanji Context block.
                      */
                     _REMQUE((void *)kc,(void **)&t);
                     lib$free_vm(&kc->kc_size,&t);
                     return(SS$_NORMAL);
             }
             /*
              * HTON_FILTER
              *
              *      Translates from Host representation to Network representation.
              */
             static hton_filter(stream,src,slen,dst,dlen)
             u_long *stream;
             u_char *src,**dst;
             u_short *slen,*dlen;
             {
                     register struct KnjBuf *kb;
                     register struct KnjContext *kc;
                     register unsigned char *s,*d;
                     register long sl,dl;
                     long sdsc[2],ddsc[2];
                     /*
                      * Establish a condition handler.
                      * R13 = FP.
                      */
                     ((long *)_READ_GPR(13))[0] = handler;
                     kc = (struct KnjContext *)*stream;
                     kb = kc->kc_kb[0];
                     /*
                      * If multi-buffer was requested in begin_filter,
                      * we will remque Kanji buffer, then insque it
                      * to in-use queue later. The buffer can be
                      * replaced by larger one when we realize
                      * the size of buffer is insufficient.
                      */
                     if(kc->kc_flags) {
                             if(_REMQUE((void *)kb,(void **)&kb) == 2)
                                     if((kb = GetBuf(kc,*slen)) == 0) {
                                             *dlen = 0;
                                             *dst = (char *)0;
                                             return(SS$_INSFMEM);
                                     }
                     }
                     s = src;
                     d = kb->kb_data;
                     dl = kb->kb_size;
                     sl = *slen;
                     if(sl == 0)
                             goto end;
                     if(sl > dl) {
                             ReplaceKB(kc,kb,d,dl);
                     }
                     sdsc[0] = sl, sdsc[1] = s;
                     ddsc[0] = sl, ddsc[1] = d;
                     str$upcase(ddsc,sdsc);
             end:
                     /*
                      * Insert Kanji Buf to in-use queue,
                      * if release_filter should be called later.
                      */
                     if(kc->kc_flags)
                             _INSQUE((void *)kb,(void *)kc->kc_kbinuse);
                     /*
                      * Give resultant buffer to user.
                      */
                     *dlen = sl;
                     *dst = d;
                     return(SS$_NORMAL);
             }
             /*
              * NTOH_FILTER
              *
              *      Translates Network representation to Host representation.
              */
             static ntoh_filter(stream,src,slen,dst,dlen)
             u_long *stream;
             u_char *src,**dst;
             u_short *slen,*dlen;
             {
                     register struct KnjBuf *kb;
                     register struct KnjContext *kc;
                     register unsigned char *s,*d;
                     register long sl,dl;
                     long sdsc[2],ddsc[2];
                     /*
                      * Establish a condition handler.
                      * R13 = FP.
                      */
                     ((long *)_READ_GPR(13))[0] = handler;
                     kc = (struct KnjContext *)*stream;
                     kb = kc->kc_kb[0];
                     /*
                      * If multi-buffer was requested in begin_filter,
                      * we will remque Kanji buffer, then insque it
                      * to in-use queue later. The buffer can be
                      * replaced by larger one when we realize
                      * the size of buffer is insufficient.
                      */
                     if(kc->kc_flags) {
                             if(_REMQUE((void *)kb,(void **)&kb) == 2) {
                                     if((kb = GetBuf(kc,*slen)) == 0) {
                                             /*
                                              * Woops no buffer available...
                                              */
                                             *dlen = 0;
                                             *dst = (char *)0;
                                             return(SS$_INSFMEM);
                                     }
                             }
                     }
                     s = src;
                     d = kb->kb_data;
                     dl = kb->kb_size;
                     sl = *slen;
                     if(sl == 0)
                             goto end;
                     if(sl > dl) {
                             ReplaceKB(kc,kb,d,dl);
                     }
                     sdsc[0] = sl, sdsc[1] = s;
                     ddsc[0] = sl, ddsc[1] = d;
                     str$upcase(ddsc,sdsc);
             end:
                     /*
                      * Insert Kanji Buf to in-use queue,
                      * if release_filter should be called later.
                      */
                     if(kc->kc_flags)
                             _INSQUE((void *)kb,(void *)kc->kc_kbinuse);
                     /*
                      * Give resultant buffer to user.
                      */
                     *dlen = sl;
                     *dst = d;
                     return(SS$_NORMAL);
             }
             /*
              * RELEASE_FILTER
              *
              *      This routine is called to release resource. The buffers
              *      allocated by hton_filter or ntoh_filter routine must be
              *      deallocated, unless value of resource argument of begin_filter
              *      call was 1. When the value one for resource argument of
              *      begin_filter routine had been specified, release_filter
              *      must not be called.
              */
             static release_filter(stream,c)
             u_long *stream;
             u_char *c;
             {
                     register struct KnjBuf *kb;
                     register struct KnjContext *kc;
                     /*
                      * Establish a condition handler.
                      * R13 = FP.
                      */
                     ((long *)_READ_GPR(13))[0] = handler;
                     kc = *stream;
                     kb = c - KB_LENGTH;
                     {long z;_REMQUE((void *)kb,(void **)&z);}
                     _INSQUE((void *)kb,(void *)kc->kc_kb);
                     return(SS$_NORMAL);
             }
             /*
              * GETBUF
              *
              *      Allocates filter routine internal buffers. Ntoh_filter and
              *      hton_filter fills the buffer with resultant string, and
              *      give it to TCPIP application.
              */
             static long newlength = 0;
             static struct KnjBuf *
             GetBuf(kc,min)
             register struct KnjContext *kc;
             long min;
             {
                     register struct KnjBuf *kb;
                     long len;
                     if(newlength == 0)
                             switch(kc->kc_application) {
                                     case HLA_FTP:   newlength = 4096*2; break;
                                     case HLA_TELNET:
                                     case HLA_SMTP:
                                     case HLA_LPR:
                                     default:        newlength = 1024*2; break;
                             };
                     len = (min * 125 / 100 + 511) & ~511;
                     if(newlength < len)
                             newlength = len;
                     onerror(lib$get_vm(&newlength,&kb), return(0));
                     kb->kb_size = newlength - KB_LENGTH;
                     return(kb);
             }
             /*
              * NEWBUF
              *
              *      This routine replaces a short buffer by a large buffer,
              *      which is newly allocated. Contents of a short buffer is
              *      copied to a large buffer.
              *      See also ReplaceKB macro.
              */
             static struct KnjBuf *
             NewBuf(kc,kb,l)
             register struct KnjContext *kc;
             register struct KnjBuf *kb;
             long l;
             {
                     struct KnjBuf *kb0;
                     kb->kb_size += KB_LENGTH;
                     newlength = (kb->kb_size * 125 / 100 + 511) & ~511;
                     if(iserror(lib$get_vm(&newlength,&kb0))) {
                             if(!kc->kc_flags)
                                     _REMQUE(kb,&kb);
                             lib$free_vm(&kb->kb_size,&kb);
                             return(0);
                     }
                     kb0->kb_size = newlength - KB_LENGTH;
                     _MOVC3(l,kb->kb_data,kb0->kb_data);
                     if(!kc->kc_flags) {
                             _REMQUE(kb,&kb);
                             _INSQUE(kb0,kc->kc_kb);
                     }
                     lib$free_vm(&kb->kb_size,&kb);
                     return(kb0);
             }
             /*
              * HANDLER
              *
              *      The condition handler routine, which prevents TCPIP applications
              *      from fatal errors of filter routine.
              */
             static handler(sig,mec)
             u_long *sig;
             u_long *mec;
             {
                     if(sig[1] == SS$_UNWIND)
                             return;
                     Display("Filter routine has detected fatal condition.");
                     sys$putmsg(sig,0,0);
                     mec[3] = sig[1];
                     sys$unwind(&1,0);
             }