========================================================================
                        Kpathsea.DLL  for Win32
                          Version 2.00 Beta 3

                                                                桃薗幸信
                                              momozono@sdd3.mt.nec.co.jp
                                                    UDT30167@pcvan.or.jp
                                                               1997.5.14
========================================================================

1. はじめに

  ファイル探索ライブラリ Kpathsea の DLL 版です。Karl Berry 氏の
  Kpathsea 3.0 をベースにしています。
  本 DLL は、以下の環境での動作が確認されています。

    ・Microsoft Windows 95
    ・Microsoft Windows NT 4.0

2. オリジナルとの相違点

  ・ 設定ファイル texmf.cnf を使用しません。また、環境変数が設定されてい
     ても使用しません。その代用としてレジストリを使用します。
     設定は次のレジストリキーに保存されます。

         HKEY_LOCAL_MACHINE\Software\momo\Kpathsea\Config
         HKEY_CURRENT_USER\Software\momo\Kpathsea\Config

     Kpathsea.dll はユーザ毎の設定 HKEY_CURRENT_USER をサーチし、見つか
     らなければ、マシン固有の設定 HKEY_LOCAL_MACHINE をサーチします。

  ・ マルチスレッドに対応しています。MDI のプレビューアを作成することも
     可能です。Kpathsea.dll は C ランタイムライブラリ関数を使用している
     ため、スレッドを作成する場合は _beginthreadex 関数を、終了させる場
     合は _endthreadex 関数を使用してください。

  ・ プロセスの生成時、またはスレッドの生成時に、Kpathsea.dll 内部で使用
     する静的変数／グローバル変数の確保を行います。これらの変数はスレッド
     毎に確保されます。

  ・ Kpathsea.dll が確保したメモリは DLL が開放します。エクスポートして
     いる関数が文字列へのポインタを返す場合、それをアプリケーション側で
     開放する必要はありません。また返値を保存する場合は注意してください。
     DLL は、プロセスまたはスレッドの終了時にメモリの開放処理を行います。
     アプリケーション側で明示的にクリアを行いたい場合は、次の関数を呼び出
     してください（通常は呼び出す必要はありません）。

         VOID WINAPI kpse_clear_context(VOID);

  ・ 上述のとおり、Kpathsea.dll はスレッド単位で内部変数の管理を行って
     います。アプリケーションによってはスレッド終了時の内部変数の状態を
     保存しておき、再度使用したいという場合もあるかもしれません。以下の
     関数を用いれば、内部変数の管理をアプリケーション側で行うことができ
     ます。

         LPVOID WINAPI kpse_get_context(VOID);
         - カレントスレッドの内部変数へのポインタを取得します。この関数
           を呼び出すと、スレッドが終了しても内部変数の状態が開放されま
           せん。取得に失敗した場合は NULL を返します。開放する場合は
           kpse_free_context() 関数を使用します。kpse_get_context() 関
           数を呼び出した回数だけ kpse_free_context() 関数も呼び出さな
           ければなりません。

         LPVOID WINAPI kpse_set_context(LPVOID context);
         - kpse_get_context() 関数で取得したポインタを引数 context に
           セットして呼び出すと、カレントスレッドの内部変数を context
           と置き換えます。成功すると置き換える前の内部変数を返します。
           失敗した場合（NULL が渡された、カレントスレッドと同じポイ
           ンタが渡された）場合は NULL を返します。

         BOOL WINAPI kpse_free_context(LPVOID context);
         - 引数 context で渡された内部変数を開放します。成功すると TRUE
           を、失敗すると FALSE を返します。

     これらの関数は、複数のスレッドで内部変数を共有（同時使用）を保証す
     るものではありません。子スレッドの終了を待つ親スレッドからの継承、
     あるいは以前のスレッド終了状態を継承する場合のみ使用してください。
     また前者の場合、子スレッドで操作した内部変数の状態で親スレッドの実
     行が再開されます。

     [例 1] 親スレッドの内部変数を子スレッドに継承する場合

       DWORD WINAPI ChildThread(LPVOID lpvThreadParam)
       {
         /* 3. 親スレッドから受け取った内部変数をセット */
         LPVOID old_context = kpse_set_context(lpvThreadParam);
         /* 4. 子スレッド作成時に DLL が作成した内部変数を開放 */
         kpse_free_context(old_context);
         /* 5. 以下、子スレッドの処理を行う */
       }

       int WINAPI WinMain(...)
       {
         /* 1. 主スレッド作成時に DLL が作成した内部変数を取得 */
         LPVOID context = kpse_get_context();
         /* 2. 子スレッドを作成し、親（主）スレッドの内部変数を継承 */
         HANDLE hThread = _beginthreadex(..., ChildThread, context, ...);
         /* 6. 子スレッドの終了を待つ */
         WaitForSingleObject(hThread);
         /* 7. 以下、主スレッドの処理を行う */
       }

     [例 2] 以前のスレッド終了時の内部変数を継承する場合

       DWORD WINAPI ChildThread(LPVOID lpvThreadParam)
       {
         static LPVOID context = NULL;
         LPVOID old_context;
         /* 2. １回目の呼び出しで DLL が作成した内部変数を取得 */
         if (context == NULL)
           context = kpse_get_context();
         /* 3. ２回目以降では、保存しておいた内部変数を使用する */
         /*    DLL がスレッド作成時に作成した内部変数は開放する */
         else {
           old_context = kpse_set_context(context);
           kpse_free_context(old_context);
         }
         /* 4. 以下、子スレッドの処理を行う */
       }

       int WINAPI WinMain(...)
       {
         while (1) {
           /* 1. 子スレッドを作成 */
           HANDLE hThread = _beginthreadex(..., ChildThread, ...);
           /* 5. 子スレッドの終了を待つ */
           WaitForSingleObject(hThread);
         }
       }

  ・ getenv() 関数、putenv() 関数はプロセス全体に影響するため、それぞれ
     をスレッド単位で処理を行うようにしました。
     xgetenv() 関数は xputenv() 関数によりセットされた値を取得します。
     xputenv() 関数によりセットされた値が存在しない場合は、null を返しま
     す。SetEnvironmentVariable()関数や putenv() 関数によりセットされた
     値を取得することはありません。また、環境変数の値を取得することもあ
     りません。
     次の関数を用いると環境変数のみ継承させることができます。上記内部変数
     の継承と異なり、環境変数の複製を作成します。つまり親スレッドから継承
     したものを子スレッドで操作したとしても、親スレッドの環境変数の内容が
     変化することはありません。

         BOOL WINAPI kpse_set_environment(LPVOID context);
         - 引数 context で渡された環境変数を複製します。成功すると TRUE
           を、失敗すると FALSE を返します。

     [例]

       DWORD WINAPI ChildThread(LPVOID lpvThreadParam)
       {
         /* 3. 親スレッドから受け取った環境変数をセット */
         kpse_set_environment(lpvThreadParam);
         /* 4. 親スレッドから受け取った内部変数（使用しない）を開放 */
         kpse_free_context(lpvThreadParam);
         /* 5. 以下、子スレッドの処理を行う */
       }

       int WINAPI WinMain(...)
       {
         /* 1. 主スレッド作成時に DLL が作成した内部変数を取得 */
         LPVOID context = kpse_get_context();
         xputenv("FOO", "VAR");
         /* 2. 子スレッドを作成し、親（主）スレッドの内部変数を継承 */
         HANDLE hThread = _beginthreadex(..., ChildThread, context, ...);
         /* 6. 子スレッドの終了を待つ */
         WaitForSingleObject(hThread);
         /* 以下、主スレッドの処理を行う */
       }

  ・ DLL を呼び出すアプリケーションとの情報交換に、コールバックを利用する
     ことができます。コールバック関数を設定しなかった場合、Kpathsea.dll は
     デフォルトの処理をします。

         LONG WINAPI callback(UINT msg, DWORD param1, DWORD param2,
                              DWORD usr_param);

     コールバック関数は以下の値を返してください。

       - 成功した場合：正
       - デフォルトの処理をさせたい場合：０
       - 失敗した場合：負

     現在、以下のものがサポートされています。

       a). コンソールへの出力

           msg が KPSE_CONSOLE_WRITE のとき、コンソールへの出力を行いま
           す。param1 には出力文字列へのポインタが、param2 には文字列の
           長さが渡されます。
           デフォルトでは stderr への出力を行います。

       b). コンソールのフラッシュ

           msg が KPSE_CONSOLE_FLUSH のとき、コンソールのフラッシュを行
           います。param1, param2 は使用しません。
           デフォルトでは stderr をフラッシュします。

       c). 強制終了

           msg が KPSE_TERMINATE のとき、アプリケーションの強制終了を行
           います。param1 には終了コードが渡されます（あまり意味はありま
           せん）。param2 は使用しません。
           このメッセージでコールバック関数が呼び出された場合、アプリケー
           ション終了の手続きをとってください。コールバック関数から制御が
           戻り次第、DLL がアプリケーションを終了させます。
           また、主スレッドとは別のスレッドで呼び出された場合、そのスレッ
           ドだけを終了させれば、アプリケーションは継続して処理を続けるこ
           とができます。
           デフォルトでは Win32 の例外を発生（後述）します。

       d). MakeTeX... の実行

           msg が KPSE_MAKETEX のとき、MakeTeX... の実行を行います。コ
           ンソールを持たない GUI アプリケーションでは、pipe を用いた
           MakeTeX... の実行ができないため、その代用として用います。
           param1 には MakeTeX... 実行対象のフォーマットが渡されます。
           param2 は次のような構造体になっています。

               typedef struct {
                 kpse_file_format_type format;
                 LPCTSTR lpszCmdLine;
                 LPCTSTR lpszProgram;
                 LPCTSTR lpszFontName;
                 DWORD dwDpi;
                 DWORD dwModeDpi;
                 LPCTSTR lpszMag;
                 LPCTSTR lpszMode;
                 DWORD dwLen;
                 LPTSTR lpszPathName;
               } kpse_maketex_type;

           コールバック関数は param2 を元に MakeTeX... を実行し、成功
           した場合は、作成したファイルのフルパスをセットし 正の値を返
           します。失敗した場合は負の値を返します。０を返すと popen に
           よる MakeTeX... の実行を行います。
           lpszCmdLine には実行時のコマンドラインがそのまま渡されます。
           lpszProgname から kpszMode はそれを個別に切り出したものです。
           ファイル名を格納する領域 lpszPathNameは DLL 側で確保して渡し
           ます。ファイル名は len バイト以下の NULL で終了する文字列です。
           デフォルトでは popen() 関数による MakeTe... の呼び出しを行い
           ます。
             注）MakeTeX... のコールバック関数内でも Kpathsea.dll を
                 呼び出す場合は、別スレッドを作成してください。

     コールバック関数を指定する場合には、以下の関数を使用します。引数
     usr_param にセットした値は、コールバック関数の第４引数にそのまま
     渡されます。

         VOID WINAPI kpse_set_callback(KpseCallBack *func, DWORD usr_param);

     [例]

       DWORD WINAPI ChildThread(LPVOID lpvThreadParam)
       {
         kpse_maketex_type *kpse_maketex
             = (kpse_maketex_type *)lpvThreadParm;
         char *sep = " ";        /* セパレータはスペース */
         char *token;

         token = strtok(kpse_maketex->cmd, sep);
         while (token != NULL) {
           /* MakeTeX... 実行用の準備 */
           token = strtok(NULL, sep);
         }
         /* MakeTeX... を実行し、成功すれば絶対パスを格納 */
         if (do_maketex == true) {
           strcpy(kpse_maketex->path, ...);
           return 1;
         }
         return 0;
       }

       LONG WINAPI callback(UINT msg, DWORD param1, DWORD param2,
                            DWORD usr_param)
       {
         kpse_maketex_type *kpse_maketex;
         HANDLE hThread;
         DWORD dwExitCode;

         switch (msg) {
         case KPSE_CONSOLE_WRITE:
           fwrite((char *)param1, param2, 1, stdout);
           break;
         case KPSE_CONSOLE_FLUSH:
           fflush(stdout);
           break;
         case KPSE_MAKETEX:
           kpse_maketex = (kpse_maketex_type *)param2;
           HANDLE hThread =
               _beginthreadex(..., ChildThread, kpse_maketex, ...);
           WaitForSingleObject(hThread);
           if (GetExitCodeThread(hThread, &dwExitCode))
             return dwExitCode;
           else
             return 0;
           break;
         default:
           return 0;
         }
         return 1;
       }

       int main(int argc, char *argv)
       {
         kpse_set_callback(callback, 0);
         kpse_set_progname (progname);
         kpse_make_tex(...);
       }

  ・ PK or GF ファイルをサーチする際の検索パターンを設定できます。レジ
     ストリ (texmf.cnf) に BITPAM_SPECS で指定します。複数設定する場合
     は `;' で区切り、先に記述したものから順にサーチします。
     設定しない場合は、以下のパターンでサーチします（実際は１行で記述）。

       BITMAP_SPECS = $KPATHSEA_NAME.$KPATHSEA_DPI$KPATHSEA_FORMAT;
                      dpi$KPATHSEA_DPI/$KPATHSEA_NAME.$KPATHSEA_FORMAT
       （先に cmr10.300pk を検索し、見つからなければディレクトリ dpi300
         にある cmr10.pk を検索します。）

  ・ フォント検索に失敗した場合に、再検索を行う解像度を設定できます。
     レジストリ (texmf.cnf) に FONT_SIZES で指定します。複数設定する場
     合は `;' で区切ります。

       FONT_SIZES = 300;600

     設定しない場合は、コンパイル時に設定した解像度を使用します。リリー
     ス版では設定してありません。

  ・ Kpathsea.dll 内部でエラーが発生した際、コールバック関数が指定され
     ていない、またはコールバック関数から 0 が返された場合、DLL は Win32
     の例外を生成します。生成する例外コードを以下に示します（コードの意
     味はあまり重要ではありません）。これらの例外は再実行不可能です。

               KPSE_EXCEPTION_EXIT          0xE04B0001
               KPSE_EXCEPTION_ABORT         0xE04B0003
               KPSE_EXCEPTION_MALLOC        0xE04B004B
               KPSE_EXCEPTION_REALLOC       0xE04B0042

     例外フィルタは EXCEPTION_RECORD 構造体の NumberParameters、および
     ExceptionInformation メンバを使って、エラー情報を取得することがで
     きます。

         ExceptionInformation[0]
         - エラーメッセージ。NULL で終わる文字列です。LPTSTR 型にキャ
           ストしてください。

         ExceptionInformation[1]
         - ユーザ固有情報。kpse_set_callback() 関数の第２引数の値が、
           そのままセットされます。コールバック関数自体を用意しない
           場合は kpse_set_callback() 関数の第１引数に NULL をセット
           してください。

  ・ kpse_set_progname() 関数の呼び出しで、ファイルの存在チェックを行い
     ません。存在しない場合は、GetModuleHandle() 関数で呼び出し側 App
     のディレクトリをカレントとして扱います。

  ・ カレントディレクトリは、スレッド単位で持つことができます。ディレク
     トリの変更は、次の関数で行います。変更先のディレクトリ（NULL で終
     わる文字列）を dir にセットして呼び出します。成功すれば TRUE、失敗
     すると FALSE を返します。

         BOOL kpse_change_dir(LPCTSTR dir);

  ・ SJIS のディレクトリ名に対応しています。


3. 変更点一覧

  ・ absolute.c
     -エラー時の強制終了用コールバック関数、例外生成処理の追加。

  ・ basename.c
     -SJIS ディレクトリ名対応。

  ・ callback.c  <<NEW>>
     -コールバック関数の追加（例外生成処理を含む）。

  ・ cnf.c
     -texmf.cnf のレジストリ化。
     -静的変数のダイナミック TLS 化。
     -texmf.cnf の読み込みで、定義とコメントが同一行にあった場合の不具合
      対応（レジストリを使用するため実際は使用しない）。

  ・ config.h
     -windows.h 読み込み時、boolean 型が衝突しないようにした。

  ・ current.c <<NEW>>
     -スレッド毎のカレントディレクトリの変更用。

  ・ db.c
     -SJIS ディレクトリ名対応。
     -静的変数のダイナミック TLS 化。
     -dpi<dpi>/<name>.<type> を探す際、間違ったファイルと一致することが
      あるのを修正。また、開放されないメモリがあったのを修正。

  ・ debug.c
     -コンソール出力コールバック処理追加。

  ・ dir.c
     -静的変数のダイナミック TLS 化。

  ・ find_suffix.c
     -SJIS ディレクトリ名対応。

  ・ fontmap.c
     -静的変数のダイナミック TLS 化。

  ・ getopt.c  getopt.h
     -グローバル変数のダイナミック TLS 化。

  ・ hash.c
     -グローバル変数のダイナミック TLS 化。

  ・ kpse-api.h  <<NEW>>
     -インポート用ヘッダーファイル

  ・ kpse-dll.c  kpse-dll.h  <<NEW>>
     -DLL 初期化用コードなど。

  ・ line.c
     -スレッド単位のヒープ管理の対応（free() 関数のプロトタイプ宣言削除）。

  ・ make-suffix.c
     -SJIS ディレクトリ名対応。

  ・ path_elt.c
     -SJIS ディレクトリ名対応。
     -静的変数のダイナミック TLS 化。

  ・ pathsearch.c
     -静的変数のダイナミック TLS 化。

  ・ proginit.c
     -グローバル変数のダイナミック TLS 化。

  ・ progname.c  progname.h
     -SJIS ディレクトリ名対応。
     -グローバル変数のダイナミック TLS 化。
     -kpse_set_progname() 関数の呼び出しで、ファイルの存在チェックを
      行わないように変更。ディレクトリの取得は GetModuleHandle() 関数
      を使用する。また、取得したディレクトリをカレントディレクトリと
      する。
     -デバッグ用変数 KPATHSEA_DEBUG を texmf.cnf（レジストリ）に設定
      できるよう修正。

  ・ tilde.c
     -`~' 単独のときの展開で、環境変数 HOME が設定されていなかった場合、
      NULL で strlen() 関数を呼び出していたのを修正。

  ・ tex-file.c
     -グローバル変数のダイナミック TLS 化。
     -fallback resolution 用のフォントサイズを texmf.cnf（レジストリ）
      に設定できるよう修正。
     -PK フォントなどがバイナリーモードでオープンされていなかったのを
      修正。

  ・ tex-glyph.c
     -フォント検索パターンを texmf.cnf（レジストリ）に設定できるよう修正。

  ・ tex-make.c
     -グローバル変数のダイナミック TLS 化。
     -コールバック関数による MakeTeX... の実行対応。

  ・ truncate.c
     -SJIS ディレクトリ名対応。

  ・ variable.c
     -グローバル変数のダイナミック TLS 化。

  ・ xcalloc.c
     -スレッド単位のヒープ管理対応。

  ・ xfopen.c
     -エラー時の強制終了用コールバック関数、例外生成処理の追加。

  ・ xfseek.c
     -エラー時の強制終了用コールバック関数、例外生成処理の追加。

  ・ xftell.c
     -エラー時の強制終了用コールバック関数、例外生成処理の追加。

  ・ xmalloc.c
     -スレッド単位のヒープ管理対応。

  ・ xputenv.c
     -スレッド単位の環境変数管理対応

  ・ xrealloc.c
     -スレッド単位のヒープ管理対応。

  ・ xstat.c
     -エラー時の強制終了用コールバック関数、例外生成処理の追加。


4. 著作権・保証・再配布

  Kpathsea ライブラリは GNU general public license のもとに配布されて
  います。DLL 対応の改変／追加部分の著作権は桃薗にありますが、DLL 及び
  DLL 化部分のプログラムの配布は GNU general public license に従います。
  GNU general public license については付属の COPYING というファイルを
  ご覧ください。

  本パッケージは無保証です。本パッケージまたはその改変物を用いたことに
  よる直接・間接的ないかなる損害に対しても作者は責任を負いません。利用
  者の責任の元に使用してください。


5. 改訂履歴

  Version 1.00 Alpha                                       1996/11/18
  ・DLL 初期バージョン(kpathsea.lib Version 2.6)。
  ・texmf.cnf の代わりにレジストリを使用するように変更。
  ・内部変数をクリアする機能を追加。同時にマルチスレッドにも対応。
  ・dpi<dpi>/<name>.<type> および <dpi>/<name>.<type> を探す際の不具
    合を修正。

  Version 1.00 Alpha 2                                     1997/01/18
  ・関数の呼び出しを __cdecl() から __stdcall() へ変更。
  ・DLL 内で exit() および abort() している個所で Win32 の例外を生成
    するように変更。
  ・MakeTeXPK の呼び出しができないため、App 側でコールバック関数を指
    定できるように変更。
  ・ユーザが個別にレジストリ設定をできるように変更。
  ・NT4.0 では DLL で alloc() 関数により確保したヒープを App 側（DLL
    呼出側）で free() 関数により開放できないため、ヒープの管理をすべて
    DLL で行うように変更。

  Version 1.00 Beta                                        1997/02/09
  ・角藤さんによる VC++ 用 高速化対応を組み込んだ。
  ・レジストリのキーを変更

  Version 2.00 Alpha                                       1997/02/23
  ・Kpathsea.lib Version 3.0 対応。
  ・内部変数の確保を kpse_set_progname() 関数の呼び出しから、プロセス
    およびスレッドの生成時に変更。また、kpse_set_progname() 関数の呼び
    出しでクリアを行わないように変更。

  Version 2.00 Alpha 2                                     1997/03/02
  ・コールバック関数によるコンソール出力に対応。
  ・DLL 内部エラーによる強制終了を、Win32 の例外生成からコールバック関
    数の呼び出しに変更。
  ・コールバック関数による MakeTeXPK の呼び出し方法を変更（未実装）。
  ・texmf.cnf の読み込み不具合を修正（レジストリを使用するので特に問題
    はない）。

  Version 2.00 Alpha 3                                     1997/03/20
  ・内部変数の継承を行う関数を追加した。
  ・コールバック関数の返値が 0 のとき、デフォルトの処理をするように変更。
  ・DLL 内部エラーによる強制終了時に Win32 の例外を生成するように戻した。
    コールバック関数が指定されていないとき、例外を生成する。
  ・kpse_set_progname() 関数でファイルの存在チェック、Win95 における
    argv[0] が long filename とならない場合の対応を削除した。
  ・SJIS のディレクトリ名に対応した。
  ・HeapAlloc() 関数で確保したメモリを free() 関数で開放していた個所を
    修正。

  Version 2.00 Alpha 4                                     1997/03/31
  ・kpse_set_callback() 関数にユーザ固有情報をセットするようにした。こ
    こにセットされた値は、コールバック関数の第４引数にそのまま渡される。
  ・上記に伴い、コールバック関数の引数を変更。
  ・PK or GF ファイルをサーチする際の検索パターンを texmf.cnf で指定で
    きるようにした。
  ・TlsGetValue() 関数を呼び出すタイミングを変更し、不要なオーバーヘッ
    ドを減らすようにした。
  ・コールバック関数による MakeTeX... の実行を追加。
  ・Fallback Resolution を texmf.cnf で指定できるようにした。

  Version 2.00 Beta 1                                      1997/04/06
  ・スレッド毎にカレントディレクトリを管理するように変更。
  ・コールバック関数 (KPSE_MAKETEX) 呼び出しの引数を変更。
  ・コールバック関数 (KPSE_CONSOLE_WRITE) 呼び出しで、メモリ再確保が行
    われていなかったのを修正。
  ・MISSFONT_LOG および TEXMFLOG のファイル出力がコールバック関数
    (KPSE_CONSOLE_WRITE) で呼び出されていたのを修正。
  ・MISSFONT_LOG および TEXMFLOG の排他制御をミューテックスで行うよう
    にした。これらのファイルはプロセス単位に存在します。
  ・`~' 展開時の不具合修正。
  ・ここからベータ版とする。

  Version 2.00 Beta 2                                      1997/04/13
  ・デフォルトのカレントディレクトリが、モジュールの存在ディレクトリ
    となっていたので、プロセス起動時のディレクトリに修正。

  Version 2.00 Beta 3                                      1997/05/14
  ・kpse_fallback_resolutions_string_get() などの値を App から変更で
    きるように、ポインタのポインタを返すようにした。
