2. 内部コードの扱いと、制御の流れ

  skf は、内部構造上は、入力から読み込んだコードを 「言語+ Unicode のコードポイント (UTF-32 範囲)」の組に変換し、それを所定のコード系に変換する構造になっている。処理の都合 (速度的な判断) から、入力の口 (すべて in_converter.c で定義) は複数あり、上記の組が一旦すべて oconv.c の oconv() 関数を通過して、genoconv.c の各コード系の処理を通した後、実際の所定のコードに変換するためのルーチン (oconv.h と oconv,c で定義) が呼ばれるようになっている。
  また、genoconv で処理できないものは一旦 plug_convert.c に渡されて、または genoconv.c 中で直接変換されて再度 Unicode → genoconv のルートを通る。1.94 までではこの入り口も oconv() であったが、1.95 からは post_oconv() と入り口が分離されている。
  現在言語は announce 以外で外部から直接は見えることはないが、内部ではすでに特にコード判定論理で見ているため、注意が必要である。言語の扱いに関しては、関連の章を参照のこと。
  また、内部で渡されている skf_ucode は 32bit の符号付き整数が格納できる変数である。ここで、符号付きであることに注意。UCS-4 の文字はそのままは格納できず、かつ EOF を符号付きのまま後段の処理に送ることができる。UTF-32 範囲内であることは入力
時にチェックされ、範囲外のコードは捨てられる (--uncheck-utf32-range で抑止可)。
  
2.1 変換処理
2.1.1 変換処理概要
  skf では、次節で説明するとおり codeset 毎にエンコーディングが定義されている。
  読み込まれた入力を、入力エンコーディング及び codeset に従って所定の処理を行い、上記の通り「言語+ Unicode のコードポイント (UTF-32 範囲)」に変換し、それを所定の出力エンコーディング及び codeset に従って指定された形式の出力に変換している。この処理について、まず実際のデータの流れ、各部位での具体的な処理の概要の順に説明する。
  
2.1.2 制御の流れ
  入力のバイトストリームは、以下の制御フローで変換される。SWIG 経由の LWL 時も
同様。
  
  (unsigned char のバッファ)
  ↓
  rvGETC (skf_fileio.c またはマクロ)
  ↓ (16 bit integer)
  デコード指定があるときは、デコーダ (in_decoder.c)
  ↓ (16 bit integer)
  *_in (in_converter.c)
  ↓ (skf_ucode)
  oconv (oconv.c)
  ↓ (skf_ucode)
  o_*_conv (genoconv.c)
  ↓ (16 bit integer)  ↓ (skf_ucode)
  ↓                  (plug_convert)
  ↓                   ↓ (skf_ucode)
  ↓                  post_oconv (oconv.c)
  ↓                   ↓ (skf_ucode)
  ↓                  o_*_conv (genconv.c)
  ↓                   ↓ (16 bit integer)
  SKF_*_OUT* (oconv.c またはマクロ)
  ↓ (16 bit integer)  ↓
  ↓                  o_c_encode/o_p_encode (encode 処理)
  ↓                   ↓
  SKFputc (skf_fileio.c)
  
2.1.3 変換処理と codeset
  skf では入力のエンコーディング処理を二段階に分けている。前段は MIME などのエンコーディング処理であり、in_decoder 内で処理される。この処理を行った結果が (原則として)、codeset により指定されたエンコーディングスキームを持つデータである。in_decorder 内で処理されるものは --decode で処理されるもの (MIME, RFC2231, PUNYCODE, uri など。但し rot は除く)、UTF-7/8 である。逆にデコード類似処理で in_converter 側で行われているのは VNI, VIQR などのベトナム語組み合わせ文字変換、ISCII 処理、ROT47 などである。
  
  この decode 処理後、in_converter 内の所定のルーチン (2.2 節参照) で UTF-32 化の処理が行われる。この変換処理は以下の三種類に大別される。
  
  (1) テーブル検索により変換するもの (下記以外)
  (2) 計算処理で変換するもの (Unicode, 透過入力)
  (3) 両者の混在するもの
    (3-1) コーナーケースのみ計算処理 (or プログラム) で、ほとんどテーブル検索
       (GBK, MS cp51932, 5022x)
    (3-2) 前段に変換処理が噛むもの
       (VNI, VIQR, VIMN, SJIS-X0213-2000/2004)
    (3-3) 専用処理を持つもの
       (Johab hangul, GB18030, B-Right/V, KEIS, JEF, ROT-JIS)

2.2 内部コードへの入り口
  上記説明の通り、in_converter.c にすべて集約されている。1.95 では入り口は以下の 7つである。どの入り口を使うかは preconvert.c で振り分けられる。
  
  (1) e_in:	EUC, iso-2022 系コードセットなどを受ける。詳細は別途記載のテー
		ブル参照。
  (2) s_in:	Shift_JIS, Big5 グループ、GBK/GB18030 などを受ける。詳細は別途
		記載のテーブル参照。
  (3) ks_in:	EBCDIC 関連コードセットを扱う。
  (4) u_in:	Unicode(TM) の各種エンコーティングを扱う。UTF-8/UTF-7 用のエン
		コーディング向け入り口が別個に存在するが、1.95 ではエンコーディ
		ング関連の設定直後 u_in が呼ばれている。
  (5) b_in:	B-Right/V 入力を扱う。きわめて試験的。
  (6) t_in:	透過入力を扱う。
  (7) be_in:	rot および ESC が落ちた JIS を扱う。nkf 互換モード専用処理
  
  入り口数は preconvert で判定するコードセット種別依存であり、両方を同期して変更することにより変更可能である。


2.3 内部特殊コード
2.3.1 変換時の特殊コード
  内部コードは UTF-32 であるため、入力起因では U+d800 - U+dfff は現れない。このため v1.95 以降では skf 内部で特殊な処理をする場合の代替文字として流用している。この文字は変換表に登録されており、in_converter.c の入り口関数で生成される。
  この文字自体は *_in() 中で生成された後 oconv() は素通しで、*_private_oconv() 中で所定の変換処理が呼ばれる。v1.95 では oconv() 中ではこの文字は一文字として扱われているので注意。二文字の方が妥当かも知れないため、バージョン間の互換性は保証しない。
  v1.94 以前にはこのようなコードの扱いはない。

2.3.2 EOF 群
  skf は 0 以下の文字コードは EOF として扱われる。但し、内部の処理としては入力から与えられた EOF と、処理の過程で発生した擬似的な EOF があり、値として区別されている。以下に個々の種別と、用法を示す。
  
  (1) sEOF:	入力起因の EOF である。oconv に渡された場合は EOF がそのまま出
		力されるが、in_convert.c 中の関数で EOF を検出した場合には、複
		数ファイルを結合する関係で、oconv() が直接呼び出されることはな
		く一旦 skf.c に制御が戻される。
  (2) sOCD:	MIME などのデコーダ判定の、特定文字集合の文字列の終端文字を検
		出したことを示す。出力は oconv() で握りつぶされる。また、sEOF 
		同様一旦 skf.c に制御が戻り、in_codeset を更新した上で、後続文
		字を処理するため再度 preconvert() が呼び出される。
  (3) sFLSH:	oconv() でバッファしている文字を出力させるためのダミー文字。
		oconv() の呼び出し時のみに使われる。バッファされた文字がない場
		合、何も出力されない。  
  (4) mFLSH:	mime 処理でバッファしている文字を出力させるためのダミー文字。
		バッファされた文字がない場合、何も出力されない。
  (5) sABRT, sRETY, sCONT: in_converter 内の処理渡しで用いる。oconv() には渡ら
		ない。

