2007年12月28日金曜日

レジストリを読み出す(advapi32)

advapi32を利用したレジストリ読み出し。HSP3標準エディタの「起動時のカレントディレクトリ」を読み出します。

事前にデータの大きさを知ることができる分、hspextよりも便利かもしれません。
ここでは利用していませんが、エラーの原因を詳しく追及することもできます。// 参考(というか丸写し)
//   ちょくとのページ:レジストリに保存してみる
//   http://yokohama.cool.ne.jp/chokuto/urawaza/registry.html

#uselib "advapi32.dll"
#func global RegCloseKey "RegCloseKey" sptr
#func global RegOpenKeyExA "RegOpenKeyExA" sptr,sptr,sptr,sptr,sptr
#func global RegQueryValueExA "RegQueryValueExA" sptr,sptr,sptr,sptr,sptr,sptr

#const  HKEY_CURRENT_USER   0x80000001
#const  KEY_QUERY_VALUE     0x0001

    // レジストリキーをオープン
    name = "Software\\OnionSoftware\\hsed3"
    RegOpenKeyExA HKEY_CURRENT_USER, name, 0KEY_QUERY_VALUEvarptr(hkey)
    if stat != 0 {
        dialog "キーをオープンできません。"1
        end
    }

    // データのサイズを取得
    RegQueryValueExA hkey, "startdir"000varptr(size) 
    if stat != 0 {
        mes "データサイズを取得できませんでした。"
    } else {
        mes strf("データサイズは%dバイトです。", size)

        // 文字列データを取得
        sdim result, size
        RegQueryValueExA hkey, "startdir"00varptr(result), varptr(size) 
        if stat != 0 {
            mes "データを取得できませんでした。"
        } else {
            mes result
        }
    }

    // レジストリキーのハンドルをクローズ
    RegCloseKey hkey
    stop

レジストリを読み出す(hspext)

レジストリを読み出すスクリプト。
HSP3標準エディタの「起動時のカレントディレクトリ」を読み出します。#include "hspext.as"
#const HKEY_CURRENT_USER 0

    // HSP3標準スクリプトエディタの設定を指定する
    regkey HKEY_CURRENT_USER"Software\\OnionSoftware\\hsed3"0
    if stat != 0 {
        dialog "何らかのエラーが発生しました。"1
        end
    }

    // 起動時のカレントディレクトリを取得
    sdim result, 256
    getreg result, "startdir"1256
    if stat != 0 {
        dialog "何らかのエラーが発生しました。"1
        end
    }

    // 結果を表示
    mes result

    stop

2007年12月26日水曜日

文字列の分割と結合

ActionScript3(AS3)にあるメソッド、split(文字列の分割)とjoin(文字型配列変数の結合)をHSP標準の文字列操作命令で実装。
splitの方は正規表現で何とかできそうな気がしますが……VBScriptのRegExpにはsplitメソッドが備わっていないようなので、少し難しいのでしょうか。ただいま調査中です。

区切り文字の数が多く、さらに区切り文字で終わる文字列をsplitできなかった不具合を修正。
#module
// 文字列の分割
#deffunc split array arr, str target, str devider
    if devider = "" {
        // 分割する目印は空文字であってはならない
        return 1
    }

    dim part_strlen, 10             // 分割結果の長さ
    part_strlen_max = 0             // 分割結果の長さの最大値
    parts_num = 1                   // 分割結果の数
    _target = target                // instr,strmidを使うために変数に代入する
    target_strlen = strlen(target)  // 分割する文字列の長さ
    devider_strlen = strlen(devider)// 分割する目印の長さ

    // いくつに分割できるか調べる
    repeat
        ins = instr(_target, cnt, devider)
        if ins == -1 {
            part_strlen(parts_num - 1) = target_strlen - cnt
            if part_strlen_max < part_strlen(parts_num - 1) {
                part_strlen_max = part_strlen(parts_num - 1)
            }
            break
        } else {
            part_strlen(parts_num - 1) = ins
            if part_strlen_max < ins {
                part_strlen_max = ins
            }
            parts_num++
            continue cnt + ins + devider_strlen
        }
    loop

    // 分割結果代入用の配列を確保
    sdim arr, part_strlen_max + 1, parts_num

    // 分割の開始
    position = 0
    foreach arr
        arr(cnt) = strmid(_target, position, part_strlen(cnt))
        position += part_strlen(cnt) + devider_strlen
    loop
    return 0

// 文字列の結合
#deffunc join var result, array target, str connecter
    if vartype(target) != 2 {
        // 結合する配列変数は文字列型でなければならない
        return 1
    }

    connecter_strlen = strlen(connecter)
    // 連結結果の長さを調べる
    result_strlen = connecter_strlen * (length(target) - 1)
    repeat length(target)
        target_strlen(cnt) = strlen(target(cnt))
        result_length += target_strlen(cnt)
    loop

    // 連結結果代入用の変数を確保
    sdim result, result_length + 1

    // 連結の開始
    position = 0
    foreach target
        if cnt {
            poke result, position, connecter
            position += connecter_strlen
        }
        poke result, position, target(cnt)
        position += target_strlen(cnt)
    loop
    return 0

// ちょっと遠回りな置換
#deffunc replace var target, str before, str after
    split tmparr, target, before
    if stat : return stat
    join target, tmparr, after
    return stat
#global

// サンプルスクリプト
    font msgothic14
    s = "Hot Soup Processor"
    mes s

    mes "\n半角スペースで分割"
    split arr, s, " "
    foreach arr
        mes "{"+cnt+"}:"+arr(cnt)
    loop

    mes "\nエクスクラメーションマークで結合"
    join result, arr, "!"
    mes result

    mes "\nsplitとjoinを組み合わせで置換"
    replace s, " ""!"
    mes s
    stop

2007年12月25日火曜日

正規表現を利用したURL&メールアドレスのタグ付け

テキストに含まれるURLやメールアドレスにリンクタグ(aタグ)をつけます。
当初は1バイトずつ切りだして判定する方法を利用していたのですが、分かりづらい上に作りにくかったので正規表現を利用したものに切り替えました。ロジックを書かなくて済む分、かなりシンプルなスクリプトになっています。独自のWikiやBBSなどに利用できるかもしれません。
// 正規表現を利用したURL&メルアドのタグ付け
#module
// 置換処理のメイン部分
#deffunc do_cnv str before, var after, str pattern, str replace
    newcom regexp, "VBScript.RegExp"
    comres after
    regexp("Pattern") = pattern
    regexp("Global") = 1
    regexp -> "Replace" before, replace
    delcom regexp
    return

// URLのタグ付け
#defcfunc add_link str before
    do_cnv before, after, "(http://[-/.~_#0-9a-zA-Z]+)""<a href=\"$1\">$1</a>"
    return after

// メールアドレスのタグ付け
#defcfunc add_mailto str before
    do_cnv before, after, "([-/.~_0-9a-zA-Z]+@[-.~_0-9a-zA-Z]+)""<a href=\"mailto:$1\">$1</a>"
    return after
#global

// URLにリンク(日本語ドメイン非対応)
    before = {"文字列中のURL(URI)にリンクします
HSPTV!(http://hsp.tv/)
HSP開発wiki(http://hspdev-wiki.net/)
http://だけではリンクされません"}

    after1 = add_link(before)
    mesbox after1, ginfo_winxginfo_winy / 2

// メールアドレスにリンク
    before = {"文字列中のメールアドレスにリンクします
例えばsample2007@yaboo.co.jpとか!"}

    after2 = add_mailto(before)
    mesbox after2, ginfo_winxginfo_winy / 2
    stop

2007年12月20日木曜日

3D画像ビューア サンプル

Flashなどでありそうな3Dの画像ビューア。のサンプル。
マウスのホイールに連動して回転します。
#include "d3m.hsp"
#include "hspmath.as"
#const TILE_NUM 16
#const SHIFT_TURN 5
#const BUFFER_WIDTH 200
#const BUFFER_HEIGHT 200

    // タイルを表示するための配列変数
    tile_x = 100300300100
    tile_y =   0,   0,   0,   0
    tile_z = 200200,   0,   0

    // タイル用のバッファを作成
    repeat TILE_NUM1
        buffer cntBUFFER_WIDTHBUFFER_HEIGHT
        color , 255 : boxf
        color 255255255
        font msgothic32font_bold
        mes cnt
    loop

    // メイン画面の初期化・カメラ設定
    screen 0240200screen_normal
    title "ホイールで回転"
    d3setcam -250,-300,100250,0,100

    // 各種初期化作業
    gmode GMODE_ALPHA, , , 128
    theta_shift = 0.0                   // タイルの回転量
    theta_add = 0.0                     // タイルの角速度
    moving = 0                          // 回転中フラグ
    need_to_draw = 1                    // 描画フラグ

// ★メインループ
*main
    gosub *move
    gosub *draw
    wait 5
    goto *main

// 移動計算
*move
    mw = mousew
    if moving > 0 {
        // 移動中
        moving--
        theta_shift += theta_add
    } else : if mw != 0 {
        // 静止中かつホイールが動いたとき
        moving = SHIFT_TURN             // SHIFT_TURN回動く
        need_to_draw = 1                // 描画フラグON

        // 角速度を決定
        theta_add = M_PI * 2.0 * sgn(mw) / SHIFT_TURN / TILE_NUM
    }
    return

// 描画処理
*draw
    if need_to_draw == 0 : return
    if moving == 0 : need_to_draw = 0

    redraw 0
    color : boxf

    vect_x = cos(theta_shift)
    vect_y = sin(theta_shift)
    // 2.0 * M_PI / TILE_NUMだけ角度(位置)を変えながら、タイルをTILE_NUM個描画
    repeat TILE_NUM
        d3rotate vect_x, vect_y, vect_x, vect_y, 2.0 * M_PI / TILE_NUM
        d3setlocal 0,0,0, vect_x,vect_y,0, -vect_y,vect_x,00,0,1
        d3texture tile_x, tile_y, tile_z, cnt + 100BUFFER_WIDTHBUFFER_HEIGHT1
    loop

    redraw 1
    return

2007年12月16日日曜日

高速な文字列の結合(連結)

pokeとmemexpandを利用した文字列の結合(連結)。
HSP標準の+=やnoteaddよりも高速に実行することができます。

このモジュール最大の利点は、memexpandによる変数の自動拡張にあります。(X)HTMLコンバータのように出力結果の大きさが分からないスクリプトで重宝するでしょう。
サンプルスクリプトのように決まった文字列を結合(連結)し続ける場合(リフレイン)、この命令よりもFujiさんのブログの記事で紹介されている方法の方がより高速です。

先日の(X)HTML変換スクリプトの他、開発wikiの置換モジュールでも似たような処理が使われています。

#module
#const EXPAND_SIZE 1024
// 文字列の初期値を設定する
#deffunc set_string str str_to_set
    string_length = strlen(str_to_set)
;   string_size = EXPAND_SIZE * (1 + string_length / EXPAND_SIZE)
    string_size = 64            // 測定のために公平化
    sdim string, string_size
    poke string, 0, str_to_set
    return

// 文字列を返す
#deffunc get_string var target
    target = string
    return

// 文字列の長さを返す
#defcfunc get_string_length
    return string_length

// 文字列を連結する
#deffunc add_string str str_to_add
    len = strlen(str_to_add)
    if string_size <= string_length + len {
        string_size += EXPAND_SIZE
        memexpand string, string_size
    }
    poke string, string_length, str_to_add
    string_length += len
    return
#global

#const TRIAL_TIME 10000
#uselib "winmm.dll"
    #cfunc timeGetTime "timeGetTime"

    mes "充分なサイズを確保せずに文字列の結合(連結)を実行。"

    mes "独自命令版計測中……"
    set_string ""
    time_start = timeGetTime()
    repeat TRIAL_TIME
        add_string "sample string\n"
    loop
    time(0) = timeGetTime() - time_start
    mes strf("独自命令を使用:%d[ms]", time(0))
    mes "独自命令版計測終了。\n"

    mes "+=使用版計測開始……"
    string = ""
    time_start = timeGetTime()
    repeat TRIAL_TIME
        string += "sample string\n"
    loop
    time(1) = timeGetTime() - time_start
    mes strf("標準の+=を使用:%d[ms]", time(1))
    mes "+=使用版計測終了。\n"

    mes "noteadd使用版計測開始……"
    notesel string
    sdim string, 64
    time_start = timeGetTime()
    repeat TRIAL_TIME
        noteadd "sample string"
    loop
    time(2) = timeGetTime() - time_start
    mes strf("noteaddを使用:%d[ms]", time(2))
    mes "noteadd使用版計測終了。"
    stop

2007年12月15日土曜日

HDLのデータベースを利用したスクリプトの(X)HTML変換

SQLeleとHDLのデータベースを利用した、HSPスクリプトの(X)HTMLコンバータ……のモジュール。サンプルスクリプト付き。
ブログにアップするような量じゃない(約1000行!)のですが、折角できたので公開。そのうち正式にHPに置くと思います。ヘルプも作ってないので使いにくいと思いますが、使い道がありましたらどうぞご自由にお使いください。

このモジュールを利用したコンバータはHSPにHDLとSQLeleが標準でつくようになったら配布を開始したいと思います。

このスクリプト自身の変換で約3秒かかります。不必要な外部ファイルは解析しない処理を組み込んだこともあり、2秒近い高速化が行えているようです。
// HSPスクリプトを(X)HTMLへ変換するモジュール(HTXmodule)
// 【動作条件】
//   ・HDL用データベース(hdlbase.xdb)が作成されていること
//   ・sqlele.hspがcommonフォルダにあること
// HDL用データベース内のCacheテーブルを使用します。
#ifndef HTX_MSG
#include "sqlele.hsp"
#module HSPtoXHTML


// 変換設定
#const global HTX_HTML          0x00000000  // HTML形式で変換
#const global HTX_XHTML         0x00000001  // XHTML形式で変換
#const global HTX_ADD_BR        0x00000002  // 改行時に<br>または<br />を追加
#const global HTX_TAB_TO_SPACE  0x00000004  // タブをスペースに変換
#const global HTX_SPACE_TO_NBSP 0x00000008  // スペースを&nbsp;に変換
#const global HTX_SEARCH_OTHER  0x00000010  // 外部のスクリプト(includeしたファイル)を検索

// マークアップ(MarkUp)する要素
#const global HTX_MU_CMD        0x00000100  // 命令
#const global HTX_MU_FUNC       0x00000200  // 関数
#const global HTX_MU_COMMENT    0x00000400  // コメント
#const global HTX_MU_PREPRO     0x00000800  // プリプロセッサ
#const global HTX_MU_SYSVAR     0x00001000  // システム変数
#const global HTX_MU_LABEL      0x00002000  // ラベル
#const global HTX_MU_BASIC      0x00003F00  // HSP3.1付属スクリプトエディタでマークアップされるすべての要素
#const global HTX_MU_STRING     0x00004000  // 文字列
#const global HTX_MU_MACRO      0x00008000  // マクロ
#const global HTX_MU_NUMBER     0x00010000  // 数値
#const global HTX_MU_SCODE      0x00020000  // 文字コード
#const global HTX_MU_ALL        0x00FFFF00  // すべての要素

// エラー
#enum global HTX_ERR_NOERROR = 0    // エラーなし・正常終了
#enum global HTX_ERR_NODB           // データベースが見つからない
#enum global HTX_ERR_NOFILE         // ファイルが見つからない
#enum global HTX_ERR_NODIR          // ディレクトリが見つからない
#enum global HTX_ERR_CONSTRUCTION   // 構文に誤りがある or 循環インクルード

// 定数
#const  CP_ACP                  0
#define DB_HEADER               "_TABLE_FOR_HTX_"   // ヘッダ
#const  HTX_DEFAULT_TAB_WIDTH   4                   // タブ幅 デフォルト値
#const  HTX_EXPAND_SIZE         1024                // スクリプト保存用変数 メモリ確保量・拡張量
#const  HTX_DEFAULT_NEST        5                   // インクルードネスト

#const global HTX_MSG           0xB000

// 改行コード
#const CR   0x0D
#const LF   0x0A
#const CRLF 0x0A0D

// タグ
#define ctype tag_start(%1%2="") _tag_start@HSPtoXHTML(%1%2) + ">"
#defcfunc _tag_start@HSPtoXHTML str tag_name, str class_name
    if class_name != "" {
        return "<" + tag_name + " class=\"" + class_name + "\""
    } else {
        return "<" + tag_name
    }
#define ctype tag_end(%1"</" + (%1) + ">"
#define tag_alone(%1%2="") _tag_alone@HSPtoXHTML(%1%2="")
#deffunc _tag_alone@HSPtoXHTML str tag_name, str class_name
    if mode_xhtml {
        return _tag_start(tag_name, class_name) + " />"
    } else {
        return _tag_start(tag_name, class_name) + ">"
    }

// 状態
#enum STATE_NORMAL = 1
#enum STATE_COMMENT
#enum STATE_MULTILINE_COMMENT
#enum STATE_STRINGS
#enum STATE_MULTILINE_STRINGS

// 状態(行)
#enum LSTATE_NORMAL = 1
#enum LSTATE_DEFFUNC
#enum LSTATE_DEFCFUNC
#enum LSTATE_UNDEF
#enum LSTATE_MACRO
#enum LSTATE_INCLUDE
#enum LSTATE_ADDITION

// データベース名
#define DB_HDL                  "hdlbase.xdb"

// デフォルトクラス名
#define DEFAULT_CLASS_CMD       "cmd"       // 命令
#define DEFAULT_CLASS_FUNC      "func"      // 関数
#define DEFAULT_CLASS_COMMENT   "comment"   // コメント
#define DEFAULT_CLASS_PREPRO    "prepro"    // プリプロセッサ
#define DEFAULT_CLASS_SYSVAR    "sysvar"    // システム変数
#define DEFAULT_CLASS_LABEL     "label"     // ラベル
#define DEFAULT_CLASS_STRING    "str"       // 文字列
#define DEFAULT_CLASS_MACRO     "macro"     // マクロ
#define DEFAULT_CLASS_NUMBER    "num"       // 数値
#define DEFAULT_CLASS_SCODE     "scode"     // 文字コード

#uselib "kernel32.dll"
    #cfunc global IsDBCSLeadByteEx "IsDBCSLeadByteEx" sptr, sptr

// ***************************************************
// 内部で使用する命令

#deffunc insert_data@HSPtoXHTML int markup

    num = stat
    repeat num
        sql_q "INSERT INTO Cache (Key, Data) VALUES ('" + sqesc(sql_v("Name")) + "'," + markup + ")"
        sql_next
    loop
    return

#define ctype to_lower(%1getpath(%116)

// ***************************************************
// 変換で使用する命令

// 文字がスペースかどうか(キーワードとして利用できない文字かどうか)調べる
#defcfunc is_space@HSPtoXHTML int iTarget
    if IsDBCSLeadByteEx(CP_ACP, iTarget)     : return 0
    if ('0' <= iTarget) & (iTarget <= '9') : return 0
    if ('a' <= iTarget) & (iTarget <= 'z') : return 0
    if ('A' <= iTarget) & (iTarget <= 'Z') : return 0
    if (iTarget == '_') : return 0
    return 1


// 文字が数字かどうか調べる
#defcfunc is_number@HSPtoXHTML int iTarget
    return ('0' <= iTarget) & (iTarget <= '9')


// 文字列の追加
#define add_string@HSPtoXHTML(%1,%2=0) _add_string@HSPtoXHTML %1%2
#deffunc _add_string@HSPtoXHTML str str_to_add, int _width_to_add
    if num_include == 0 {
        len = strlen(str_to_add)
        width_to_add = _width_to_add
        if width_to_add == 0 : width_to_add = len
        if code_after_size <= code_after_pos + len {
            code_after_size += HTX_EXPAND_SIZE
            memexpand code_after, code_after_size
        }
        poke code_after, code_after_pos, str_to_add
        code_after_pos += len
        code_after_x += width_to_add
    }
    return

// ***************************************************

// HTXmodule用データベースを作成(更新)する(Cacheテーブルを利用)
// htx_make_DB target_dir
//   target_dir : データベースがあるディレクトリ
#deffunc htx_make_DB str target_dir
    sql_open target_dir + "/" + DB_HDL

    // Cacheテーブルを初期化
    sql_q "DELETE FROM Cache"
    sql_q "BEGIN"
    // HTX用に初期化されていることを判別するためのデータを書きこむ
    sql_q "INSERT INTO Cache (ID, Key) VALUES (1, '" + DB_HEADER + "')"

    // 命令の登録
    sql_q "SELECT Name FROM Help WHERE Prm NOT LIKE '(%' AND Group3 NOT LIKE '%マクロ%' AND Group3 NOT LIKE '%システム変数%' AND Group3 NOT LIKE '%プリプロセッサ%'"
    insert_data@HSPtoXHTML HTX_MU_CMD

    // 関数の登録
    sql_q "SELECT Name FROM Help WHERE Prm LIKE '(%' AND Group3 NOT LIKE '%マクロ%' AND Group3 NOT LIKE '%システム変数%' AND Group3 NOT LIKE '%プリプロセッサ%'"
    insert_data@HSPtoXHTML HTX_MU_FUNC

    // システム変数の登録
    sql_q "SELECT Name FROM Help WHERE Group3 LIKE '%システム変数%'"
    insert_data@HSPtoXHTML HTX_MU_SYSVAR

    // マクロの登録
    sql_q "SELECT Name FROM Help WHERE Group3 LIKE '%マクロ%'"
    insert_data@HSPtoXHTML HTX_MU_MACRO

    // プリプロセッサの登録
    sql_q "SELECT Name FROM Help WHERE Group3 LIKE '%プリプロセッサ%'"
    insert_data@HSPtoXHTML HTX_MU_PREPRO

    sql_q "COMMIT"
    sql_close
    return HTX_ERR_NOERROR


// データベースの存在確認・変数初期化
// 変換実行前に必ず1度実行すること
// path_DB : hdlbase.xdbがあるディレクトリ(デフォルトでdir_exe)
//   stat == HTX_ERR_NOERROR : ロード成功
//   stat == HTX_ERR_NODB    : データベースが見つからない
//   stat == HTX_ERR_NODIR   : ディレクトリが見つからない
#define global htx_init(%1=dir_exe) _htx_init@HSPtoXHTML %1
#deffunc _htx_init@HSPtoXHTML str path_DB

    // ディレクトリの存在を確認する
    dirlist tmp, path_DB, 5
    if stat == 0 {
        // ディレクトリが見つからない
        return HTX_ERR_NODIR
    }

    // データベースの存在を確認する
    dir_current = dir_cur               // 命令実行時のカレントディレクトリを記録
    chdir path_DB : exist DB_HDL
    if strsize == -1 {
        // データベースファイルが見つからない
        // 命令実行時のカレントディレクトリに戻る
        gosub *back_to_first_dir_cur
        return HTX_ERR_NODB
    }

    // CacheテーブルがHTXmodule用かどうか判別し、そうでなければ
    // HDL用データベースからHTXmodule用データベースを作成
    need_to_make = 0
    sql_open DB_HDL
    sql_q "SELECT Key FROM Cache WHERE ID = 1"
    if stat == 0 {
        // ID1のレコードが存在しない
        need_to_make = 1
    } else : if sql_v("Key") != DB_HEADER {
        // ID1のレコードがHTXmodule用のヘッダと異なる
        need_to_make = 1
    }
    sql_close
    if need_to_make : htx_make_DB path_DB

    // 各種変数の初期化
    gosub *init_setting

    // 命令実行時のカレントディレクトリに戻る
    gosub *back_to_first_dir_cur

    return HTX_ERR_NOERROR


// 各種変数の初期化
*init_setting

    // タブ幅を設定
    tab_width = HTX_DEFAULT_TAB_WIDTH

    // データベース名をフルパスで記録
    DB_name = path_DB +"/" + DB_HDL

    // クラス名を設定
    class_cmd     = DEFAULT_CLASS_CMD
    class_func    = DEFAULT_CLASS_FUNC
    class_comment = DEFAULT_CLASS_COMMENT
    class_prepro  = DEFAULT_CLASS_PREPRO
    class_sysvar  = DEFAULT_CLASS_SYSVAR
    class_label   = DEFAULT_CLASS_LABEL
    class_string  = DEFAULT_CLASS_STRING
    class_macro   = DEFAULT_CLASS_MACRO
    class_number  = DEFAULT_CLASS_NUMBER
    class_scode   = DEFAULT_CLASS_SCODE
    return


// 命令実行時のカレントディレクトリに戻る
*back_to_first_dir_cur

    chdir dir_current
    return


// タブ幅を設定
//   幅が1未満の時は強制的にHTX_DEFAULT_TAB_WIDTHにする
#deffunc htx_set_tab_width int _new_width

    new_width = _new_width
    if new_width < 1 : new_width = HTX_DEFAULT_TAB_WIDTH
    tab_width = new_width
    return HTX_ERR_NOERROR


// htx_set_class new_class, mode
// クラス名を設定
//   new_class : 新しいクラス名
//   mode      : 設定するクラスを指す数値(HTX_MU_???)
#deffunc htx_set_class str new_class, int mode

    if mode & HTX_MU_CMD     : class_cmd     = new_class
    if mode & HTX_MU_FUNC    : class_func    = new_class
    if mode & HTX_MU_COMMENT : class_comment = new_class
    if mode & HTX_MU_PREPRO  : class_prepro  = new_class
    if mode & HTX_MU_SYSVAR  : class_sysvar  = new_class
    if mode & HTX_MU_LABEL   : class_label   = new_class
    if mode & HTX_MU_STRING  : class_string  = new_class
    if mode & HTX_MU_MACRO   : class_macro   = new_class
    if mode & HTX_MU_NUMBER  : class_number  = new_class
    if mode & HTX_MU_SCODE   : class_scode   = new_class
    return HTX_ERR_NOERROR


// htx_cnv code, mode, path_code, path_common
// 変換を実行(Shift-JIS限定)
//   source : 変換するスクリプトが代入された変数
//   mode   : 変換モード(HTX_???およびHTX_MU_???の論理和)
//   path_code   : スクリプトのあるパス(デフォルトでdir_exe)
//   path_common : コモンフォルダのパス(デフォルトでdir_exe + "/common")
//   stat == HTX_ERR_NOERROR : 変換成功
//   stat == HTX_ERR_NODB    : データベースが作成されていない・htx_open未実行
//   stat == HTX_ERR_NOFILE  : インクルードするファイルが見つからない
//   stat == HTX_ERR_CONSTRUCTION : 文法が間違っている
#define global htx_cnv(%1%2%3=dir_exe%4="") _htx_cnv@HSPtoXHTML %1%2%3%4
#deffunc _htx_cnv@HSPtoXHTML var source, int mode, str path_code, str _path_common
    exist DB_name
    if strsize == -1 {
        // データベースファイルがない あるいは htx_open未実行
        return HTX_ERR_NODB
    }

    path_common = _path_common
    if path_common == "" : path_common = dir_exe + "\\common"

    gosub *before_cnv                   // 変換の準備
    gosub *convert                      // 変換の実行
    gosub *after_cnv                    // 変換の後処理

    return error

*before_cnv
    sql_open DB_name
    sql_q "BEGIN"

    notesel code
    code_before = source                // 変換前のスクリプトを保存する変数
    code = source                       // 解析対象のスクリプトを保存する変数
    error = HTX_ERR_NOERROR
    first_char_of_prm = 1               // ラベルの判定に使用
    need_to_add = 0
    need_to_del = 0

    sdim code_name, 256HTX_DEFAULT_NEST   // ファイル名(フルパス)
    dim code_size,   HTX_DEFAULT_NEST       // ファイルサイズ
    dim code_pos,    HTX_DEFAULT_NEST       // 解析地点
    dim code_state,  HTX_DEFAULT_NEST       // 状態
    dim code_lstate, HTX_DEFAULT_NEST       // 状態(行)
    num_include = 0                         // 外部ファイル ネスト数

    code_name(0)   = path_code + "\\"
    code_size(0)   = strlen(code_before)
    code_pos(0)    = 0
    code_state(0)  = STATE_NORMAL
    code_lstate(0) = LSTATE_NORMAL

    sdim code_after, EXPAND_SIZE        // 変換結果を保存する変数
    code_after_x = 0
    code_after_pos = 0                  // 変換結果 文字列挿入地点
    code_after_size = EXPAND_SIZE

    // 変換モードの抽出
    mode_xhtml  = (mode & HTX_XHTML) != 0
    mode_add_br = (mode & HTX_ADD_BR) != 0
    mode_tab_to_space  = (mode & HTX_TAB_TO_SPACE) != 0
    mode_space_to_nbsp = (mode & HTX_SPACE_TO_NBSP) != 0
    mode_search_other  = (mode & HTX_SEARCH_OTHER) != 0

    // マークアップする要素の抽出
    markup_cmd     = (mode & HTX_MU_CMD) != 0
    markup_func    = (mode & HTX_MU_FUNC) != 0
    markup_comment = (mode & HTX_MU_COMMENT) != 0
    markup_prepro  = (mode & HTX_MU_PREPRO) != 0
    markup_sysvar  = (mode & HTX_MU_SYSVAR) != 0
    markup_label   = (mode & HTX_MU_LABEL) != 0
    markup_string  = (mode & HTX_MU_STRING) != 0
    markup_macro   = (mode & HTX_MU_MACRO) != 0
    markup_number  = (mode & HTX_MU_NUMBER) != 0
    markup_scode   = (mode & HTX_MU_SCODE) != 0

    return

// まだ書き換え終わっていない
*convert
    repeat
        if error != HTX_ERR_NOERROR : break

        code_pos(num_include) = cnt
        c = peek(code, code_pos(num_include))
        switch c
        case 0
            // ファイル終了
            break
            swbreak
        case CR
        case LF
            // 改行
            gosub *start_new_line
            // 自分自身にメッセージを送信する
            sendmsg hwndHTX_MSG100 * code_pos(num_include) / code_size(num_include), num_include

            if strmid(code, cnt2) == "\n" {
                continue cnt + 2
            }
            swbreak
        case '/'
            if (strmid(code, cnt2) == "/*") & (code_state(num_include) == STATE_NORMAL) {
                // 複数行コメント開始
                gosub *start_multiline_comment
                add_string "/*"
                continue cnt + 2
            }
            if (strmid(code, cnt2) == "//") & (code_state(num_include) == STATE_NORMAL) {
                // 単一行コメント開始
                gosub *start_singleline_comment
                add_string "//"
                continue cnt + 2
            }
            add_string "/"
            swbreak
        case '*'
            // ラベル
            if (first_char_of_prm) & (code_state(num_include) == STATE_NORMAL) {
                gosub *first_char_finished
                gosub *add_label
                continue code_pos(num_include)
            }
            // 複数行コメントの終了
            if (strmid(code, cnt2) == "*/") & (code_state(num_include) == STATE_MULTILINE_COMMENT) {
                add_string "*/"
                gosub *end_multiline_comment
                continue cnt + 2
            }
            add_string "*"
            swbreak
        case ';'
            // 単一行コメント開始
            if (code_state(num_include) == STATE_NORMAL) {
                gosub *start_singleline_comment
            }
            add_string ";"
            swbreak
        case '{'
            // 複数行文字列の開始
            if (strmid(code, cnt2) == "{\"") & (code_state(num_include) == STATE_NORMAL) {
                gosub *start_multiline_strings
                add_string "{\""
                continue cnt + 2
            }
            add_string "{"
            swbreak
        case '\"'
            // 単一行文字列開始
            if (code_state(num_include) == STATE_NORMAL) {
                gosub *start_singleline_strings
                add_string "\""
                continue
            }
            // 単一行文字列終了
            if (code_state(num_include) == STATE_STRINGS) {
                add_string "\""
                gosub *end_singleline_strings
                continue cnt + 1
            }
            if (strmid(code, cnt2) == "\"}") & (code_state(num_include) == STATE_MULTILINE_STRINGS) {
                add_string "\"}"
                gosub *end_multiline_strings
                continue cnt + 2
            }
            add_string "\""
            swbreak
        case '\t'
            if mode_tab_to_space & (code_state(num_include) != STATE_STRINGS) & (code_state(num_include) != STATE_MULTILINE_STRINGS) {
                // タブをスペースへ変換する
                if mode_space_to_nbsp {
                    s = "&nbsp;"
                } else {
                    s = " "
                }
                repeat tab_width - (code_after_x \ tab_width)
                    add_string s, 1
                loop
            } else {
                add_string "\t", tab_width - (code_after_x \ tab_width)
            }
            swbreak
        case ' '
            if mode_space_to_nbsp {
                // 半角スペースを変換(文字列中・コメント中でも実行)
                add_string "&nbsp;"1
            } else {
                add_string " "
            }
            swbreak
        case ':'
            // 文の区切れ
            add_string ":"
            if code_state(num_include) == STATE_NORMAL : gosub *end_line
            swbreak
        case ',' : case '='
            // パラメータの区切れ
            add_string strf("%c", c)
            if code_state(num_include) == STATE_NORMAL : gosub *end_area
            swbreak
        case '\\'
            if (code_state(num_include) == STATE_STRINGS) | (code_state(num_include) == STATE_MULTILINE_STRINGS) {
                if (strmid(code, cnt2) == "\\\\") | (strmid(code, cnt2) == "\\\"") {
                    add_string strmid(code, cnt2)
                    continue cnt + 2
                }
            }
            add_string "\\"; : x++
            swbreak
        case '&' : add_string "&amp;"1 : swbreak
        case '<' : add_string "&lt;"1  : swbreak
        case '>' : add_string "&gt;"1  : swbreak
        default
            // 命令・関数などキーワードの可能性
            if IsDBCSLeadByteEx(CP_ACP, c) {
                // 2バイト文字の場合

                // 現在のバージョンでは変数をマークアップしないので、
                // このように扱ってもOK。
                add_string strmid(code, cnt2); : x += 2
                continue cnt + 2
            }
            // 1バイト文字の場合
            if code_state(num_include) == STATE_NORMAL {
                // 文字列中やコメント中でなければ、数値や命令・関数としてマークアップできるかどうか調べる
                if is_number(c) | (c == '%') | (c == '$') | (c == '-') {
                    // 数値の挿入
                    gosub *add_number
                    continue code_pos(num_include)
                }
                if c == '\'' {
                    // 文字コード
                    gosub *add_stringing_code
                    continue code_pos(num_include)
                }
                if (is_space(c) == 0) | (c == '#') {
                    // 命令・プリプロセッサ・関数etc.の挿入
                    gosub *add_word
                    continue code_pos(num_include)
                }
            }
            // 命令などを構成する文字列ではなかった場合(@,|,(,)など)
            gosub *first_char_finished
            add_string strf("%c", c); : x++
            swbreak
        swend
    loop
    gosub *start_new_line
    return

// 変数の処理
*first_char_finished
    // 空白でない文字を取り出した場合
    first_char_of_prm = 0
    return

*end_line
    // (マルチステートメントを含む論理的な)行の終了に伴う変数の変化
*end_area
    // パラメータの終了に伴う変数の変化
    first_char_of_prm = 1
    return

// *****************************************************************

// 単行コメントの開始
*start_singleline_comment
    code_state(num_include) = STATE_COMMENT
    if markup_comment {
        add_string tag_start("span", class_comment)
    }
    return

// コメント行を終了
*end_singleline_comment
    code_state(num_include) = STATE_NORMAL
    if markup_comment {
        add_string tag_end("span")
    }
    return

// 複数行コメントの開始
*start_multiline_comment
    code_state(num_include) = STATE_MULTILINE_COMMENT
    if markup_comment {
        add_string tag_start("span", class_comment)
    }
    return

// 複数行コメントの終了
*end_multiline_comment
    code_state(num_include) = STATE_NORMAL
    if markup_comment {
        add_string tag_end("span")
    }
    return

// 単行文字列の開始
*start_singleline_strings
    code_state(num_include) = STATE_STRINGS
    if markup_string {
        add_string tag_start("span", class_string)
    }
    if mode_search_other & ((code_lstate(num_include) == LSTATE_INCLUDE) | (code_lstate(num_include) == LSTATE_ADDITION)) {
        // インクルードするファイル名の開始
        inc_filename_pos = code_pos(num_include) + 1
    }
    return

// 単行文字列の終了
*end_singleline_strings
    code_state(num_include) = STATE_NORMAL
    if markup_string {
        add_string tag_end("span")
    }
    if mode_search_other & ((code_lstate(num_include) == LSTATE_INCLUDE) | (code_lstate(num_include) == LSTATE_ADDITION)) {
        // インクルードするファイル名の終了
        inc_filename = strmid(code, inc_filename_pos, code_pos(num_include) - inc_filename_pos)

        // hsファイルがありそうなら検索しない(高速化)
        sql_q "SELECT COUNT(*) FROM Help WHERE Mod LIKE '" + getpath(inc_filename, 9) + "'"
        if sql_i("COUNT(*)") > 0 : return

        exist getpath(code_name(num_include), 32) + inc_filename
        if strsize < 0 {
            // 今のスクリプトと同じフォルダに見つからない場合
            exist path_common + "\\" + inc_filename
            if strsize < 0 {
                if code_lstate(num_include) == LSTATE_ADDITION {
                    // #additionの場合、ファイルが見つからないくても問題ない
                    return
                }
                if code_lstate(num_include) == LSTATE_INCLUDE {
                    // #includeの場合、ファイルが見つからないのは問題
                    error = HTX_ERR_NOFILE
                    return
                }
            } else {
                // commonフォルダにありました
                code_name(num_include + 1) = path_common + "\\" + inc_filename
            }
        } else {
            // 今のスクリプトと同じフォルダにありました
            code_name(num_include + 1) = getpath(code_name(num_include), 32) + inc_filename
        }

        // インクルードするファイル名が求まった!

        // 多重インクルード防止
        // 同じファイルをインクルードしている状態なら、エラーを発行(無限ループ防止)
        repeat num_include + 1
            if code_name(cnt) == code_name(num_include + 1) {
                error = HTX_ERR_CONSTRUCTION
                break
            }
        loop
        if error != HTX_ERR_NOERROR : return
        
        num_include++
        exist code_name(num_include)
        code_size(num_include) = strsize
        code_pos(num_include) = 0
        code_state(num_include) = STATE_NORMAL
        code_lstate(num_include) = LSTATE_NORMAL

        noteload code_name(num_include)
        wait 1

        gosub *convert

        num_include--
        if num_include {
            exist inc_filename(num_include)
            sdim code, strsize + 1
            noteload inc_filename(num_include)
        } else {
            sdim code, code_size(0) + 1
            code = code_before
        }
        wait 1
    }
    return

// 複数行文字列の開始
*start_multiline_strings
    code_state(num_include) = STATE_MULTILINE_STRINGS
    if markup_string {
        add_string tag_start("span", class_string)
    }
    return

// 複数行文字列の終了
*end_multiline_strings
    code_state(num_include) = STATE_NORMAL
    if markup_string {
        add_string tag_end("span")
    }
    return

// *****************************************************************

// code_pos(num_include)の位置以降をラベルとして挿入
*add_label
    label_length = code_size(num_include) - code_pos(num_include)
    repeat code_size(num_include) - code_pos(num_include) - 1, code_pos(num_include) + 1
        if (code_size(num_include) <= cnt) {
            label_length = code_size(num_include) - code_pos(num_include)
            break
        }
        j = peek(code, cnt)
        if IsDBCSLeadByteEx(CP_ACP, j) : continue cnt + 2
        if (cnt == code_pos(num_include) + 1) & is_number(j) {
            label_length = cnt - code_pos(num_include)
            break
        }
        if is_space(j) {
            label_length = cnt - code_pos(num_include)
            break
        }
    loop
    if markup_label & (1 < label_length) {
        add_string tag_start("span", class_label)
    }
    add_string strmid(code, code_pos(num_include), label_length)
    code_pos(num_include) += label_length
    if (markup_label) & (1 < label_length) {
        add_string tag_end("span")
    }
    return

// code_pos(num_include)の位置以降を数字として挿入
*add_number
    if markup_number {
        add_string tag_start("span", class_number)
    }
    number_length = 0
    repeat -11
        j = peek(code, code_pos(num_include) + cnt)
        if is_number(j) | (j == '.') {
            continue
        }
        if (cnt == 1) : if (peek(code, code_pos(num_include)) == '0') & ((j == 'x') | (j == 'b')) {
            continue
        }
        if (j == 'e') | (j == 'E') {
            if code_pos(num_include) + cnt + 1 < code_size(num_include) {
                n = peek(code, code_pos(num_include) + cnt + 1)
                if (n == '+') | (n == '-') : continue cnt + 2
            }
            continue
        }
        if (('a' <= j) & (j <= 'f')) | (('A' <= j) & (j <= 'F')) {
            if ((to_lower(strmid(code, code_pos(num_include), 2)) == "0x") | (peek(code, code_pos(num_include)) == '$')) {
                // 16進数
                continue
            }
        }
        number_length = cnt
        break
    loop
    add_string strmid(code, code_pos(num_include), number_length)
    code_pos(num_include) += number_length
    if markup_number {
        add_string tag_end("span")
    }
    return

// 文字コード
*add_stringing_code
    if markup_scode {
        add_string tag_start("span", class_scode)
    }
    scode_length = 0
    repeat -11
        j = peek(code, code_pos(num_include) + cnt)
        if j == '\\' {
            continue cnt + 2
        }
        if (j == '\'') | (j == 0) {
            scode_length = cnt + 1
            break
        }
    loop
    add_string strmid(code, code_pos(num_include), scode_length)
    code_pos(num_include) += scode_length
    if markup_scode {
        add_string tag_end("span")
    }
    return

// 命令・関数・システム変数など
*add_word
    repeat -11
        if code_pos(num_include) + cnt >= code_size(num_include) {
            keyword = strmid(code, code_pos(num_include), cnt)
            break
        }
        if is_space(peek(code, code_pos(num_include) + cnt)) {
            keyword = strmid(code, code_pos(num_include), cnt)
            break
        }
    loop
    lower_keyword = to_lower(keyword)

    sql_q "SELECT * FROM Cache WHERE Key = '" + sqesc(keyword) + "' LIMIT 1"
    if stat {
        // データベースに載っている文字列は適切なタグで囲む

        // doubleのみ別(データベースに載っているため)
        if (tmp_stock == "#const") & (lower_keyword == "double") & (code_lstate(num_include) == LSTATE_MACRO) {
            gosub *add_word_sub
            return
        }
        need_to_add = 0     // hsファイルなどで先に定義されていた場合を考慮

        switch sql_i("Data")
            case HTX_MU_CMD
                add_string tag_start("span", class_cmd)
                swbreak
            case HTX_MU_FUNC
                if (code_lstate(num_include) == LSTATE_NORMAL) | ((lower_keyword!="int") & (lower_keyword!="str") & (lower_keyword!="double")) {
                    add_string tag_start("span", class_func)
                }
                swbreak
            case HTX_MU_SYSVAR
                add_string tag_start("span", class_sysvar)
                swbreak
            case HTX_MU_PREPRO
                if markup_prepro : add_string tag_start("span", class_prepro)
                if (lower_keyword == "#deffunc") | (lower_keyword == "#modfunc") | (lower_keyword == "#func") {
                    code_lstate(num_include) = LSTATE_DEFFUNC
                    tmp_stock = lower_keyword
                    if markup_cmd : need_to_add = 1
                }
                if (lower_keyword == "#modinit") {
                    code_lstate(num_include) = LSTATE_DEFFUNC
                }
                if (lower_keyword == "#defcfunc") | (lower_keyword == "#cfunc") {
                    code_lstate(num_include) = LSTATE_DEFCFUNC
                    if markup_func : need_to_add = 1
                }
                if (lower_keyword == "#enum") | (lower_keyword == "#const") | (lower_keyword == "#define") {
                    code_lstate(num_include) = LSTATE_MACRO
                    tmp_stock = lower_keyword
                    if markup_macro : need_to_add = 1
                }
                if lower_keyword == "#cmpopt" : tmp_stock = lower_keyword
                if (lower_keyword == "#include") {
                    code_lstate(num_include) = LSTATE_INCLUDE
                }
                if (lower_keyword == "#addition") {
                    code_lstate(num_include) = LSTATE_ADDITION
                }
                if (lower_keyword == "#undef") {
                    code_lstate(num_include) = LSTATE_UNDEF
                    need_to_del = 1
                }
                swbreak
            case HTX_MU_MACRO
                add_string tag_start("span", class_macro)
                swbreak
        swend

        add_string keyword

        switch sql_i("Data")
            case HTX_MU_CMD
            case HTX_MU_SYSVAR
            case HTX_MU_MACRO
                add_string tag_end("span")
                swbreak
            case HTX_MU_PREPRO
                if markup_prepro : add_string tag_end("span")
                swbreak
            case HTX_MU_FUNC
                if (code_lstate(num_include) == LSTATE_NORMAL) | ((lower_keyword != "int") & (lower_keyword != "str") & (lower_keyword != "double")) {
                    add_string tag_end("span")
                }
            swbreak
        swend

        // データベースに載っていてundefする→データベースから一時的に削除
        if need_to_del {
            if code_lstate(num_include) == LSTATE_UNDEF {
                sql_q "DELETE FROM Cache WHERE Key = '" + sqesc(keyword) + "'"
                need_to_del = 0
            }
        }
    } else {
        // データベースに載っていないのにundefする→無効
        if need_to_del {
            if (code_lstate(num_include) == LSTATE_UNDEF) {
                need_to_del = 0
            }
        }
        // データベースに載っていない文字列はそのまま
        if (tmp_stock == "#cmpopt") {
            gosub *add_word_sub : tmp_stock = ""
            return
        }
        if need_to_add {
            if (code_lstate(num_include) == LSTATE_MACRO) & (lower_keyword == "global") {
                gosub *add_word_sub
                return
            }
            if ((code_lstate(num_include) == LSTATE_DEFFUNC) | (code_lstate(num_include) == LSTATE_DEFCFUNC)) & (lower_keyword == "local") {
                gosub *add_word_sub
                return
            }
            if ((code_lstate(num_include) == LSTATE_DEFFUNC) | (code_lstate(num_include) == LSTATE_DEFCFUNC)) & (lower_keyword == "global") & ((tmp_stock != "#deffunc") & (tmp_stock != "#defcfunc")) {
                gosub *add_word_sub
                return
            }
            if (tmp_stock == "#define") & (lower_keyword == "ctype") & (code_lstate(num_include) == LSTATE_MACRO) {
                gosub *add_word_sub
                return
            }

            switch code_lstate(num_include)
                case LSTATE_DEFFUNC
                    sql_q "INSERT INTO Cache (Key, Data) VALUES ('" + sqesc(keyword) + "'," + HTX_MU_CMD + ")"
                    swbreak
                case LSTATE_DEFCFUNC
                    sql_q "INSERT INTO Cache (Key, Data) VALUES ('" + sqesc(keyword) + "'," + HTX_MU_FUNC + ")"
                    swbreak
                case LSTATE_MACRO
                    sql_q "INSERT INTO Cache (Key, Data) VALUES ('" + sqesc(keyword) + "'," + HTX_MU_MACRO + ")"
                    code_lstate(num_include) == LSTATE_NORMAL
                    swbreak
            swend
            need_to_add = 0
            return
        }
        add_string keyword
    }
    gosub *first_char_finished
    if (sql_i("Data") == HTX_MU_CMD) : gosub *end_area
    code_pos(num_include) += strlen(keyword)
    return

*add_word_sub
    if markup_prepro {
        add_string tag_start("span", class_prepro) + keyword + tag_end("span")
    } else {
        add_string keyword
    }
    code_pos(num_include) += strlen(keyword)
    return


// 新しい行の開始(マルチステートメントを除く、物理的に新しい行)
*start_new_line
    if code_state(num_include) == STATE_COMMENT {
        gosub *end_singleline_comment
    }
    if (code_state(num_include) == STATE_STRINGS) {
        error == HTX_ERR_CONSTRUCTION
        return
    }
    code_lstate(num_include) = LSTATE_NORMAL
    need_to_add = 0 : need_to_del = 0
    if mode_add_br {
        add_string tag_alone("br")
    }
    add_string "\n"
    if num_include == 0 : code_after_x = 0
    gosub *end_line
    return


*after_cnv
    sql_q "ROLLBACK"
    sql_close
    if error != HTX_ERR_NOERROR {
        // 何らかのエラーが発生した
        code_after = ""
    }
    source = code_after
    sdim code, 4
    sdim code_after, 4
    sdim code_before, 4
    return


#global
#endif
// テスト用
#if 1
#const STEP 5
#const BROGBAR_HEIGHT 22
#include "hsp3util.as"

    oncmd gosub *jumpHTX_MSG
    notesel code

    // 対象となるスクリプトの選択
    dialog "hsp",16
    if stat == 0 : end
    file_name = refstr

    // GUIコンポーネントの配置
    mesbox code, ginfo_winx / 2ginfo_winy - BROGBAR_HEIGHT
    id_mesbox = stat

    progbar ginfo_winxBROGBAR_HEIGHT
    id_progbar = stat
    progbar_set id_progbar, STEP
    prog_step = 0

    pos ginfo_winx / 20
    axobj ie, "Shell.Explorer.2"ginfo_winx / 2ginfo_winy - BROGBAR_HEIGHT
    if stat == -1 {
        dialog "ActiveXコントロールの配置に失敗しました。"1
    }
    id_ie = stat

    // スクリプトのロード
    noteload file_name

    // 変換の準備
    title "変換の準備をしています..."
    htx_init
    if stat == HTX_ERR_NODB {
        dialog "データベースファイルが見つかりません。"1
        end
    } else : if stat == HTX_ERR_NODIR {
        dialog "ディレクトリが見つかりません。"1
        end
    }

    // 変換実行
    title "変換中..."
    htx_cnv code, HTX_MU_ALL | HTX_SEARCH_OTHERgetpath(file_name, 32)  // すべての属性をマークアップする
    if stat == HTX_ERR_NODB {
        dialog "データベースファイルが見つかりません。"1
        end
    } else : if stat == HTX_ERR_NOFILE {
        dialog "インクルードするファイルが見つかりません。"1
        end
    } else : if stat == HTX_ERR_CONSTRUCTION {
        dialog "構文が異常です。解析できません。"1
        end
    }

    title "変換が終了しました。"
    objprm id_mesbox, code
    gosub *make_html
    stop

// 変換の進行度合いによってプログレスバーを進める(100/5=20段階)
*jump
    if lparam == 0 {
        title strf("変換中(%d%%)..."wparam)
        while(prog_step < wparam)
            prog_step += STEP
            progbar_step id_progbar
        wend
    }
    return

// HTMLファイルの作成
*make_html
    ie -> "Navigate" "about:blank"
    doc = ie("Document")

    header = {"<html><head><style TYPE='text/css'>
<!--
body {color : #ffffff;background-color : #000000;}
.comment {color : olive;}
.str {color : #5f9ea0;}
.cmd {color : #c71585;}
.sysvar {color : yellow;}
.macro {color : #cd853f;}
.prepro {color : orange;}
.func {color : #ff0000;}
.label {color : cyan;}
.num {color : #fff0e0;}
-->
</style></head><body><pre>"}

    doc -> "write" header
    doc -> "write" code
    doc -> "write" "</pre></body></html>"
    return
#endif
機能:

  • HTML・XHTML両対応
  • &lt;,&gt;,&amp;への変換
  • 命令やマクロなど要素のマークアップ(任意)
  • マークアップ時のクラス名変更
  • タブのスペースへの変換(任意)
  • タブ幅の指定
  • &nbsp;への変換(任意)
  • 改行タグの追加(任意)
  • 変換進行状況に応じた処理(ウィンドウメッセージの送信を利用)