#include "tcl.h"
#include "tk.h"
#include "TTW.h"

#include <cstring>

#if defined(_WIN32) || defined(_WIN64)
#include <windows.h>
#endif

/// ===================================
/// Tcl_DString を扱いやすくするクラス

// ====== インスタンス生成 ======
TTW_DString::TTW_DString(){
	::Tcl_DStringInit(&dstr);
}

TTW_DString::TTW_DString(int length){
	::Tcl_DStringInit(&dstr);
	::Tcl_DStringSetLength(&dstr, length);
}

TTW_DString::TTW_DString(const char *str){
	::Tcl_DStringInit(&dstr);
	::Tcl_DStringAppend(&dstr, str, -1);
}

TTW_DString::TTW_DString(const char *str, int length){
	::Tcl_DStringInit(&dstr);
	::Tcl_DStringAppend(&dstr, str, length);
}

TTW_DString::TTW_DString(const Tcl_DString &rhs){
	::Tcl_DStringInit(&dstr);
	::Tcl_DStringAppend(&dstr, Tcl_DStringValue(&rhs), Tcl_DStringLength(&rhs));
}

TTW_DString::TTW_DString(const TTW_DString &rhs){
	::Tcl_DStringInit(&dstr);
	::Tcl_DStringAppend(&dstr, Tcl_DStringValue(&rhs.dstr), Tcl_DStringLength(&rhs.dstr));
}

TTW_DString::TTW_DString(Tcl_Obj *obj){
	::Tcl_DStringInit(&dstr);
	if (!obj) return;
	int length; const char *str = TTW_GetString(obj, length);
	::Tcl_DStringAppend(&dstr, str, length);
}

TTW_DString &TTW_DString::operator =(const char *rhs){
	::Tcl_DStringFree(&dstr);
	::Tcl_DStringAppend(&dstr, rhs, -1);
	return *this;
}
TTW_DString &TTW_DString::operator =(const Tcl_DString &rhs){
	::Tcl_DStringFree(&dstr);
	::Tcl_DStringAppend(&dstr, Tcl_DStringValue(&rhs), Tcl_DStringLength(&rhs));
	return *this;
}
TTW_DString &TTW_DString::operator =(const TTW_DString &rhs){
	::Tcl_DStringFree(&dstr);
	::Tcl_DStringAppend(&dstr, Tcl_DStringValue(&rhs.dstr), Tcl_DStringLength(&rhs.dstr));
	return *this;
}
TTW_DString &TTW_DString::operator =(Tcl_Obj *obj){
	::Tcl_DStringFree(&dstr);
	if (!obj) return *this;
	int length; const char *str = TTW_GetString(obj, length);
	::Tcl_DStringAppend(&dstr, str, length);
	return *this;
}

TTW_DString::~TTW_DString(){
	::Tcl_DStringFree(&dstr);
}

// ====== 文字のセット、追加 ======
TTW_DString &TTW_DString::Move(Tcl_DString &rhs){
	::Tcl_DStringFree(&dstr);
	dstr = rhs;
	// shallow copy のため、rhs を Free すると、
	// 自インスタンスの内容が消える。
	// 渡された後に rhs で何かされても大丈夫なように、
	// Free の代わりに Init する。
	::Tcl_DStringInit(&rhs);
	return *this;
}

TTW_DString &TTW_DString::Move(TTW_DString &rhs){
	::Tcl_DStringFree(&dstr);
	dstr = rhs.dstr;
	::Tcl_DStringInit(&rhs.dstr);
	return *this;
}

TTW_DString &TTW_DString::Set(const char *rhs, int length){
	::Tcl_DStringFree(&dstr);
	::Tcl_DStringAppend(&dstr, rhs, length);
	return *this;
}
TTW_DString &TTW_DString::Append(const char *rhs, int length){
	::Tcl_DStringAppend(&dstr, rhs, length);
	return *this;
}

TTW_DString &TTW_DString::operator << (const char *rhs){
	::Tcl_DStringAppend(&dstr, rhs, -1);
	return *this;
}

TTW_DString &TTW_DString::operator << (const Tcl_DString &rhs){
	::Tcl_DStringAppend(&dstr, Tcl_DStringValue(&rhs), Tcl_DStringLength(&rhs));
	return *this;
}

TTW_DString &TTW_DString::operator << (const TTW_DString &rhs){
	::Tcl_DStringAppend(&dstr, rhs, rhs.Length());
	return *this;
}

TTW_DString &TTW_DString::operator << (Tcl_Obj *obj){
	if (!obj) return *this;
	int length; const char *str = TTW_GetString(obj, length);
	::Tcl_DStringAppend(&dstr, str, length);
	return *this;
}

// ====== 文字コード変換 ======
TTW_DString &TTW_DString::SysToUtf8(const char *str, bool append){
	if (!append) ::Tcl_DStringFree(&dstr);
	::Tcl_ExternalToUtfDString(0, str, -1, &dstr);
	return *this;
}
TTW_DString &TTW_DString::SysToUtf8(const char *str, int length, bool append){
	if (!append) ::Tcl_DStringFree(&dstr);
	::Tcl_ExternalToUtfDString(0, str, length, &dstr);
	return *this;
}
TTW_DString &TTW_DString::SysToUtf8(const Tcl_DString &str, bool append){
	if (!append) ::Tcl_DStringFree(&dstr);
	::Tcl_ExternalToUtfDString(0, Tcl_DStringValue(&str), Tcl_DStringLength(&str), &dstr);
	return *this;
}
TTW_DString &TTW_DString::SysToUtf8(const TTW_DString &str, bool append){
	if (!append) ::Tcl_DStringFree(&dstr);
	::Tcl_ExternalToUtfDString(0, str, str.Length(), &dstr);
	return *this;
}

TTW_DString &TTW_DString::ToUtf8(Tcl_Encoding enc, const char *str, bool append){
	if (!append) ::Tcl_DStringFree(&dstr);
	::Tcl_ExternalToUtfDString(enc, str, -1, &dstr);
	return *this;
}
TTW_DString &TTW_DString::ToUtf8(Tcl_Encoding enc, const char *str, int length, bool append){
	if (!append) ::Tcl_DStringFree(&dstr);
	::Tcl_ExternalToUtfDString(enc, str, length, &dstr);
	return *this;
}
TTW_DString &TTW_DString::ToUtf8(Tcl_Encoding enc, const Tcl_DString &str, bool append){
	if (!append) ::Tcl_DStringFree(&dstr);
	::Tcl_ExternalToUtfDString(enc, Tcl_DStringValue(&str), Tcl_DStringLength(&str), &dstr);
	return *this;
}
TTW_DString &TTW_DString::ToUtf8(Tcl_Encoding enc, const TTW_DString &str, bool append){
	if (!append) ::Tcl_DStringFree(&dstr);
	::Tcl_ExternalToUtfDString(enc, str, str.Length(), &dstr);
	return *this;
}

/// 引数で与えられた UTF8 文字列をシステムエンコーディングに変換して格納する
TTW_DString &TTW_DString::Utf8ToSys(const char *str, bool append){
	if (!append) ::Tcl_DStringFree(&dstr);
	::Tcl_UtfToExternalDString(0, str, -1, &dstr);
	return *this;
}

TTW_DString &TTW_DString::Utf8ToSys(const char *str, int length, bool append){
	if (!append) ::Tcl_DStringFree(&dstr);
	::Tcl_UtfToExternalDString(0, str, length, &dstr);
	return *this;
}

TTW_DString &TTW_DString::Utf8ToSys(const Tcl_DString &str, bool append){
	if (!append) ::Tcl_DStringFree(&dstr);
	::Tcl_UtfToExternalDString(0, Tcl_DStringValue(&str), Tcl_DStringLength(&str), &dstr);
	return *this;
}

TTW_DString &TTW_DString::Utf8ToSys(const TTW_DString &str, bool append){
	if (!append) ::Tcl_DStringFree(&dstr);
	::Tcl_UtfToExternalDString(0, str, str.Length(), &dstr);
	return *this;
}

TTW_DString &TTW_DString::Utf8ToSys(Tcl_Obj *obj, bool append){
	if (!append) ::Tcl_DStringFree(&dstr);
	if (!obj) return *this;
	int length; const char *str = TTW_GetString(obj, length);
	::Tcl_UtfToExternalDString(0, str, length, &dstr);
	return *this;
}

/// 引数で与えられた UTF8 文字列を指定されたエンコーディングに変換して格納する
TTW_DString &TTW_DString::Utf8To(Tcl_Encoding dst_enc, const char *utf8_str, bool append){
	if (!append) ::Tcl_DStringFree(&dstr);
	::Tcl_UtfToExternalDString(dst_enc, utf8_str, -1, &dstr);
	return *this;
}

TTW_DString &TTW_DString::Utf8To(Tcl_Encoding dst_enc, const char *utf8_str, int length, bool append){
	if (!append) ::Tcl_DStringFree(&dstr);
	::Tcl_UtfToExternalDString(dst_enc, utf8_str, length, &dstr);
	return *this;
}

TTW_DString &TTW_DString::Utf8To(Tcl_Encoding dst_enc, const Tcl_DString &utf8_str, bool append){
	if (!append) ::Tcl_DStringFree(&dstr);
	::Tcl_UtfToExternalDString(dst_enc, Tcl_DStringValue(&utf8_str), Tcl_DStringLength(&utf8_str), &dstr);
	return *this;
}

TTW_DString &TTW_DString::Utf8To(Tcl_Encoding dst_enc, const TTW_DString &utf8_str, bool append){
	if (!append) ::Tcl_DStringFree(&dstr);
	::Tcl_UtfToExternalDString(dst_enc, utf8_str, utf8_str.Length(), &dstr);
	return *this;
}

TTW_DString &TTW_DString::Utf8To(Tcl_Encoding dst_enc, Tcl_Obj *obj, bool append){
	if (!append) ::Tcl_DStringFree(&dstr);
	if (!obj) return *this;
	int length; const char *str = TTW_GetString(obj, length);
	::Tcl_UtfToExternalDString(dst_enc, str, length, &dstr);
	return *this;
}

// ====== 生文字列取得 ======
TTW_DString::operator const char *() const{
	return Tcl_DStringValue(&dstr);
}

TTW_DString::operator char *(){
	return Tcl_DStringValue(&dstr);
}

const char *TTW_DString::Value() const{
	return Tcl_DStringValue(&dstr);
}

char *TTW_DString::Value(){
	return Tcl_DStringValue(&dstr);
}

TTW_DString::operator Tcl_DString &(){
	return dstr;
}

// ====== 文字列長取得、変更 ======
int TTW_DString::Length() const{
	return Tcl_DStringLength(&dstr);
}

void TTW_DString::SetLength(int len){
	::Tcl_DStringSetLength(&dstr, len);
}

void TTW_DString::Clear(){
	::Tcl_DStringFree(&dstr);
}

// ====== Tcl List関連 ======
void TTW_DString::StartSubList(){
	::Tcl_DStringStartSublist(&dstr);
}

void TTW_DString::EndSubList(){
	::Tcl_DStringEndSublist(&dstr);
}

TTW_DString &TTW_DString::AppendElement(const char *rhs){
	::Tcl_DStringAppendElement(&dstr, rhs);
	return *this;
}

TTW_DString &TTW_DString::AppendElement(const Tcl_DString &rhs){
	::Tcl_DStringAppendElement(&dstr, Tcl_DStringValue(&rhs));
	return *this;
}

TTW_DString &TTW_DString::AppendElement(const TTW_DString &rhs){
	::Tcl_DStringAppendElement(&dstr, rhs);
	return *this;
}

TTW_DString &TTW_DString::AppendElement(Tcl_Obj *obj){
	if (!obj) return *this;
	::Tcl_DStringAppendElement(&dstr, TTW_GetString(obj));
	return *this;
}

TTW_DString &TTW_Format(Tcl_Interp *interp, TTW_DString &utf8_lhs, const char *utf8_fmt, const TTW_ListObj &rhs){
	int objc;
	Tcl_Obj **objv;
	::Tcl_ListObjGetElements(interp, const_cast<TTW_ListObj &>(rhs), &objc, &objv);
	Tcl_Obj *obj = ::Tcl_Format(interp, utf8_fmt, objc, objv);
	utf8_lhs << obj;
	Tcl_DecrRefCount(obj);
	return utf8_lhs;
}

TTW_DString &TTW_Format(TTW_DString &utf8_lhs, const char *utf8_fmt, const TTW_ListObj &rhs){
	return TTW_Format(0, utf8_lhs, utf8_fmt, rhs);
}

/// 文字列を任意のデリミタで Split するクラス
TTW_SplitUTF8String::TTW_SplitUTF8String(const char *utf8str_, const char *utf8delimiter_){
	iter = utf8str = utf8str_;
	utf8delimiter = utf8delimiter_;
	utf8str_e = utf8str + std::strlen(utf8str_);
	delimiter_len = std::strlen(utf8delimiter_);
}
bool TTW_SplitUTF8String::Next(const char *&tok_start, int &tok_len){
	if (!iter || !(*iter)) return false;
	if (delimiter_len == 0){
		tok_start = iter;
		tok_len = static_cast<int>(utf8str_e - utf8str);
		iter = 0;
	}else{
		const char *iter_e = 0;
		int found_delim_ulen = 0;
		if (delimiter_len == 1){
			tok_start = iter;
			iter_e = std::strchr(iter, *utf8delimiter);
			found_delim_ulen = 1;
		}else{
			tok_start = iter;
			const char *delim_iter = 0, *utf8delimiter_e = utf8delimiter + delimiter_len;
			while(iter < utf8str_e){
				Tcl_UniChar uc;
				int str_ulen = TTW_UtfToUniChar(iter, &uc);
				for (delim_iter = utf8delimiter; delim_iter < utf8delimiter_e; delim_iter += found_delim_ulen) {
					Tcl_UniChar delim_uc;
					found_delim_ulen = TTW_UtfToUniChar(delim_iter, &delim_uc);
					if (uc == delim_uc) {
						iter_e = iter; goto end_search_delim;
					}
				}
				iter += str_ulen;
			}
		}
end_search_delim:
		if (iter_e == 0){
			tok_len = static_cast<int>(utf8str_e - tok_start);
			iter = 0;
		}else{
			tok_len = static_cast<int>(iter_e - tok_start);
			iter = iter_e + found_delim_ulen;
		}
	}
	return true;
}

TTW_SplitUTF8String::~TTW_SplitUTF8String(){
}

/// ===================================
/// Tcl_ListObj を扱いやすくするクラス
/// ====== インスタンス生成 ======
TTW_ListObj::TTW_ListObj() : interp(0){
	listObj = 0;
	borrowed = false;
}
TTW_ListObj::TTW_ListObj(int objc, Tcl_Obj *objv[]) : interp(0){
	if (objc && objv){
		listObj = ::Tcl_NewListObj(objc, objv);
		Tcl_IncrRefCount(listObj);
	}else{
		listObj = 0;
	}
	borrowed = false;
}
TTW_ListObj::TTW_ListObj(const TTW_ListObj &rhs) : interp(0){
	if (rhs.listObj){
		listObj = ::Tcl_DuplicateObj(rhs.listObj);
		Tcl_IncrRefCount(listObj);
	}else{
		listObj = 0;
	}
	borrowed = false;
}
TTW_ListObj & TTW_ListObj::operator = (const TTW_ListObj &rhs){
	if (!borrowed && listObj) Tcl_DecrRefCount(listObj);
	if (rhs.listObj){
		listObj = ::Tcl_DuplicateObj(rhs.listObj);
		Tcl_IncrRefCount(listObj);
	}else{
		listObj = 0;
	}
	borrowed = false;
	return *this;
}
TTW_ListObj & TTW_ListObj::Borrow(Tcl_Obj *rhs){
	if (!borrowed && listObj) Tcl_DecrRefCount(listObj);
	listObj = rhs;
	borrowed = true;
	return *this;
}
TTW_ListObj & TTW_ListObj::Copy(Tcl_Obj *rhs){
	if (!borrowed && listObj) Tcl_DecrRefCount(listObj);
	listObj = ::Tcl_DuplicateObj(rhs);
	Tcl_IncrRefCount(listObj);
	borrowed = false;
	return *this;
}

TTW_ListObj::~TTW_ListObj(){
	if (!borrowed && listObj) Tcl_DecrRefCount(listObj);
}

/// ====== エラー情報設定 ======
void TTW_ListObj::SetInterp(Tcl_Interp *interp_){
	interp = interp_;
}
Tcl_Interp *TTW_ListObj::GetInterp(){
	return interp;
}

/// ====== 生リスト要素取得 ======
TTW_ListObj::operator Tcl_Obj *(){
	if (!listObj) listObj = ::Tcl_NewObj();
	return listObj;
}
/*
TTW_ListObj::operator Tcl_Obj *() const{
	if (!listObj) listObj = ::Tcl_NewObj();
	return listObj;
}
*/
Tcl_Obj *TTW_ListObj::operator [](int idx){
	if (!listObj) return 0;
	Tcl_Obj *obj = 0;
	::Tcl_ListObjIndex(interp, listObj, idx, &obj);
	return obj;
}
const Tcl_Obj *TTW_ListObj::operator [](int idx) const{
	if (!listObj) return 0;
	Tcl_Obj *obj = 0;
	::Tcl_ListObjIndex(interp, listObj, idx, &obj);
	return obj;
}

int TTW_ListObj::Count() const{
	if (!listObj) return 0;
	int cnt = -1;
	::Tcl_ListObjLength(interp, listObj, &cnt);
	return cnt;
}

/// ====== スタック風の処理 ======
Tcl_Obj *TTW_ListObj::Push(Tcl_Obj *obj){
	if (!listObj) Tcl_IncrRefCount(listObj = ::Tcl_NewObj());
	::Tcl_ListObjAppendElement(interp, listObj, obj);
	return obj;
}
Tcl_Obj *TTW_ListObj::Push(bool b){
	Tcl_Obj *obj;
	if (!listObj) Tcl_IncrRefCount(listObj = ::Tcl_NewObj());
	::Tcl_ListObjAppendElement(interp, listObj, obj = ::Tcl_NewBooleanObj(b ? 1 : 0));
	return obj;
}
Tcl_Obj *TTW_ListObj::Push(int i){
	Tcl_Obj *obj;
	if (!listObj) Tcl_IncrRefCount(listObj = ::Tcl_NewObj());
	::Tcl_ListObjAppendElement(interp, listObj, obj = ::Tcl_NewIntObj(i));
	return obj;
}
Tcl_Obj *TTW_ListObj::Push(long l){
	Tcl_Obj *obj;
	if (!listObj) Tcl_IncrRefCount(listObj = ::Tcl_NewObj());
	::Tcl_ListObjAppendElement(interp, listObj, obj = ::Tcl_NewLongObj(l));
	return obj;
}
Tcl_Obj *TTW_ListObj::Push(double d){
	Tcl_Obj *obj;
	if (!listObj) Tcl_IncrRefCount(listObj = ::Tcl_NewObj());
	::Tcl_ListObjAppendElement(interp, listObj, obj = ::Tcl_NewDoubleObj(d));
	return obj;
}
Tcl_Obj *TTW_ListObj::Push(Tcl_WideInt &wi){
	Tcl_Obj *obj;
	if (!listObj) Tcl_IncrRefCount(listObj = ::Tcl_NewObj());
	::Tcl_ListObjAppendElement(interp, listObj, obj = ::Tcl_NewWideIntObj(wi));
	return obj;
}
Tcl_Obj *TTW_ListObj::Push(mp_int &mp){
	Tcl_Obj *obj;
	if (!listObj) Tcl_IncrRefCount(listObj = ::Tcl_NewObj());
	::Tcl_ListObjAppendElement(interp, listObj, obj = ::Tcl_NewBignumObj(&mp));
	return obj;
}
Tcl_Obj *TTW_ListObj::Push(const char *utf8){
	Tcl_Obj *obj;
	if (!listObj) Tcl_IncrRefCount(listObj = ::Tcl_NewObj());
	::Tcl_ListObjAppendElement(interp, listObj, obj = ::Tcl_NewStringObj(utf8, -1));
	return obj;
}
Tcl_Obj *TTW_ListObj::Push(Tcl_DString &utf8){
	Tcl_Obj *obj;
	if (!listObj) Tcl_IncrRefCount(listObj = ::Tcl_NewObj());
	::Tcl_ListObjAppendElement(interp, listObj, obj = ::Tcl_NewStringObj(Tcl_DStringValue(&utf8), Tcl_DStringLength(&utf8)));
	return obj;
}
Tcl_Obj *TTW_ListObj::Push(const TTW_DString &utf8){
	Tcl_Obj *obj;
	if (!listObj) Tcl_IncrRefCount(listObj = ::Tcl_NewObj());
	::Tcl_ListObjAppendElement(interp, listObj, obj = ::Tcl_NewStringObj(utf8, utf8.Length()));
	return obj;
}


Tcl_Obj *TTW_ListObj::Last(){
	if (!listObj) return 0;
	int cnt = -1;
	::Tcl_ListObjLength(interp, listObj, &cnt);
	if (cnt < 0) return 0;
	Tcl_Obj *obj;
	::Tcl_ListObjIndex(interp, listObj, cnt-1, &obj);
	return obj;
}
void TTW_ListObj::Pop(){
	if (!listObj) return;
	int cnt = -1;
	::Tcl_ListObjLength(interp, listObj, &cnt);
	if (cnt < 0) return;
	::Tcl_ListObjReplace(interp, listObj, cnt-1, 1, 0, 0);
}

/// ====== 要素追加 ======
TTW_ListObj &TTW_ListObj::operator << (bool b){
	Push(b);
	return *this;
}
TTW_ListObj &TTW_ListObj::operator << (int i){
	Push(i);
	return *this;
}
TTW_ListObj &TTW_ListObj::operator << (long l){
	Push(l);
	return *this;
}
TTW_ListObj &TTW_ListObj::operator << (double d){
	Push(d);
	return *this;
}
TTW_ListObj &TTW_ListObj::operator << (Tcl_WideInt &wi){
	Push(wi);
	return *this;
}
TTW_ListObj &TTW_ListObj::operator << (mp_int &mp){
	Push(mp);
	return *this;
}
TTW_ListObj &TTW_ListObj::operator << (const char *utf8){
	Push(utf8);
	return *this;
}
TTW_ListObj &TTW_ListObj::operator << (Tcl_DString &utf8){
	Push(utf8);
	return *this;
}
TTW_ListObj &TTW_ListObj::operator << (const TTW_DString &utf8){
	Push(utf8);
	return *this;
}
TTW_ListObj &TTW_ListObj::operator << (Tcl_Obj *obj){
	Push(obj);
	return *this;
}
TTW_ListObj &TTW_ListObj::operator << (TTW_ListObj &obj){
	Push(obj.listObj);
	return *this;
}

/// ====== 要素変更 ======
Tcl_Obj *TTW_ListObj::Set(int idx, bool b){
	if (idx < 0 || idx >= Count()) return 0;
	Tcl_Obj *new_obj = ::Tcl_NewBooleanObj(b ? 1 : 0);
	::Tcl_ListObjReplace(interp, listObj, idx, 1, 1, &new_obj);
	return new_obj;
}
Tcl_Obj *TTW_ListObj::Set(int idx, int i){
	if (idx < 0 || idx >= Count()) return 0;
	Tcl_Obj *new_obj = ::Tcl_NewIntObj(i);
	::Tcl_ListObjReplace(interp, listObj, idx, 1, 1, &new_obj);
	return new_obj;
}
Tcl_Obj *TTW_ListObj::Set(int idx, long l){
	if (idx < 0 || idx >= Count()) return 0;
	Tcl_Obj *new_obj = ::Tcl_NewLongObj(l);
	::Tcl_ListObjReplace(interp, listObj, idx, 1, 1, &new_obj);
	return new_obj;
}
Tcl_Obj *TTW_ListObj::Set(int idx, double d){
	if (idx < 0 || idx >= Count()) return 0;
	Tcl_Obj *new_obj = ::Tcl_NewDoubleObj(d);
	::Tcl_ListObjReplace(interp, listObj, idx, 1, 1, &new_obj);
	return new_obj;
}
Tcl_Obj *TTW_ListObj::Set(int idx, const Tcl_WideInt &wi){
	if (idx < 0 || idx >= Count()) return 0;
	Tcl_Obj *new_obj = ::Tcl_NewWideIntObj(wi);
	::Tcl_ListObjReplace(interp, listObj, idx, 1, 1, &new_obj);
	return new_obj;
}
Tcl_Obj *TTW_ListObj::Set(int idx, mp_int &mp){
	if (idx < 0 || idx >= Count()) return 0;
	Tcl_Obj *new_obj = ::Tcl_NewBignumObj(&mp);
	::Tcl_ListObjReplace(interp, listObj, idx, 1, 1, &new_obj);
	return new_obj;
}
Tcl_Obj *TTW_ListObj::Set(int idx, const char *utf8){
	if (idx < 0 || idx >= Count()) return 0;
	Tcl_Obj *new_obj = ::Tcl_NewStringObj(utf8, -1);
	::Tcl_ListObjReplace(interp, listObj, idx, 1, 1, &new_obj);
	return new_obj;
}
Tcl_Obj *TTW_ListObj::Set(int idx, Tcl_DString &utf8){
	if (idx < 0 || idx >= Count()) return 0;
	Tcl_Obj *new_obj = ::Tcl_NewStringObj(Tcl_DStringValue(&utf8), Tcl_DStringLength(&utf8));
	::Tcl_ListObjReplace(interp, listObj, idx, 1, 1, &new_obj);
	return new_obj;
}
Tcl_Obj *TTW_ListObj::Set(int idx, const TTW_DString &utf8){
	if (idx < 0 || idx >= Count()) return 0;
	Tcl_Obj *new_obj = ::Tcl_NewStringObj(utf8, utf8.Length());
	::Tcl_ListObjReplace(interp, listObj, idx, 1, 1, &new_obj);
	return new_obj;
}
Tcl_Obj *TTW_ListObj::Set(int idx, Tcl_Obj *obj){
	if (idx < 0 || idx >= Count()) return 0;
	::Tcl_ListObjReplace(interp, listObj, idx, 1, 1, &obj);
	return obj;
}
Tcl_Obj *TTW_ListObj::Set(int idx, TTW_ListObj &obj){
	if (idx < 0 || idx >= Count()) return 0;
	::Tcl_ListObjReplace(interp, listObj, idx, 1, 1, &(obj.listObj));
	return obj;
}

void TTW_ListObj::Clear(){
	if (!listObj) return;
	::Tcl_SetListObj(listObj, 0, 0);
}

Tcl_Obj *TTW_ListObj::Eval(Tcl_Interp *interp, int flags){
	if (!listObj) return 0;
	::Tcl_EvalObjEx(interp, listObj, flags);
	return ::Tcl_GetObjResult(interp);
}

// ===================================
// Tcl_DictObj を扱いやすくするクラス
/// ====== インスタンス生成 ======
TTW_DictObj::TTW_DictObj() : interp(0){
	dictObj = 0;
	borrowed = false;
}
TTW_DictObj::TTW_DictObj(const TTW_DictObj &rhs) : interp(0){
	if (rhs.dictObj){
		dictObj = ::Tcl_DuplicateObj(rhs.dictObj);
		Tcl_IncrRefCount(dictObj);
	}else{
		dictObj = 0;
	}
	borrowed = false;
}
TTW_DictObj & TTW_DictObj::operator = (const TTW_DictObj &rhs){
	if (!borrowed && dictObj) Tcl_DecrRefCount(dictObj);
	if(rhs.dictObj){
		::Tcl_DuplicateObj(rhs.dictObj);
		Tcl_IncrRefCount(dictObj);
	}else{
		dictObj = 0;
	}
	borrowed = false;
	return *this;
}
TTW_DictObj & TTW_DictObj::Borrow(Tcl_Obj *rhs){
	if (!borrowed && dictObj) Tcl_DecrRefCount(dictObj);
	dictObj = rhs;
	borrowed = true;
	return *this;
}
TTW_DictObj & TTW_DictObj::Copy(Tcl_Obj *rhs){
	if (!borrowed && dictObj) Tcl_DecrRefCount(dictObj);
	if (rhs){
		dictObj = ::Tcl_DuplicateObj(rhs);
		Tcl_IncrRefCount(dictObj);
	}else{
		dictObj = 0;
	}
	borrowed = false;
	return *this;
}

TTW_DictObj::~TTW_DictObj(){
	if (!borrowed && dictObj) Tcl_DecrRefCount(dictObj);
}

/// ====== エラー情報設定 ======
void TTW_DictObj::SetInterp(Tcl_Interp *interp_){
	interp = interp_;
}
Tcl_Interp *TTW_DictObj::GetInterp(){
	return interp;
}

int TTW_DictObj::Count() const{
	if (!dictObj) return 0;
	int cnt = -1;
	::Tcl_DictObjSize(interp, dictObj, &cnt);
	return cnt;
}

/// ====== 生リスト要素取得 ======
TTW_DictObj::operator Tcl_Obj *(){
	if (!dictObj) dictObj = ::Tcl_NewObj();
	return dictObj;
}

/// ====== キーから値を取得。見つからない場合は NULLを返す ======
Tcl_Obj *TTW_DictObj::operator [](const char *key){
	if (!dictObj) return 0;
	Tcl_Obj *keyObj = ::Tcl_NewStringObj(key, -1);
	Tcl_Obj *obj = (*this)[keyObj];
	return obj;
}
Tcl_Obj *TTW_DictObj::operator [](Tcl_Obj *key){
	if (!dictObj) return 0;
	Tcl_Obj *obj = 0;
	if (::Tcl_DictObjGet(interp, dictObj, key, &obj) != TCL_OK) return 0;
	return obj;
}
const Tcl_Obj *TTW_DictObj::operator [](const char *key) const{
	if (!dictObj) return 0;
	Tcl_Obj *keyObj = ::Tcl_NewStringObj(key, -1);
	const Tcl_Obj *obj = (*this)[keyObj];
	return obj;
}
const Tcl_Obj *TTW_DictObj::operator [](const Tcl_Obj *key) const {
	if (!dictObj) return 0;
	Tcl_Obj *obj = 0;
	if (::Tcl_DictObjGet(interp, dictObj, const_cast<Tcl_Obj *>(key), &obj) != TCL_OK) return 0;
	return obj;
}

/// ====== 要素の列挙 ======
TTW_DictObj::Iter::Iter(TTW_DictObj &host){
	dictObj = host.dictObj;
	::Tcl_DictObjFirst(host.interp, dictObj, &searchPtr, &keyObj, &valObj, &done);
};
TTW_DictObj::Iter::~Iter(){
	if (!done) ::Tcl_DictObjDone(&searchPtr);
}

bool TTW_DictObj::Iter::Done() const{
	return done ? true : false;
}

bool TTW_DictObj::Iter::Next(){
	::Tcl_DictObjNext(&searchPtr, &keyObj, &valObj, &done);
	return done ? false : true;
}

Tcl_Obj *TTW_DictObj::Iter::Key(){
	return keyObj;
}

Tcl_Obj *TTW_DictObj::Iter::Value(){
	return valObj;
}

/// ====== 要素の追加/書き換え ======
Tcl_Obj *TTW_DictObj::Put(const char *key, Tcl_Obj *val){
	if (!dictObj) return 0;
	Tcl_Obj *keyObj = ::Tcl_NewStringObj(key, -1);
	Tcl_Obj *obj = Put(keyObj, val);
	return obj;
}
Tcl_Obj *TTW_DictObj::Put(const char *key, bool b){
	if (!dictObj) return 0;
	Tcl_Obj *keyObj = ::Tcl_NewStringObj(key, -1);
	Tcl_Obj *obj = Put(keyObj, b);
	return obj;
}
Tcl_Obj *TTW_DictObj::Put(const char *key, int i){
	if (!dictObj) return 0;
	Tcl_Obj *keyObj = ::Tcl_NewStringObj(key, -1);
	Tcl_Obj *obj = Put(keyObj, i);
	return obj;
}
Tcl_Obj *TTW_DictObj::Put(const char *key, long l){
	if (!dictObj) return 0;
	Tcl_Obj *keyObj = ::Tcl_NewStringObj(key, -1);
	Tcl_Obj *obj = Put(keyObj, l);
	return obj;
}
Tcl_Obj *TTW_DictObj::Put(const char *key, double d){
	if (!dictObj) return 0;
	Tcl_Obj *keyObj = ::Tcl_NewStringObj(key, -1);
	Tcl_Obj *obj = Put(keyObj, d);
	return obj;
}
Tcl_Obj *TTW_DictObj::Put(const char *key, Tcl_WideInt &wi){
	if (!dictObj) return 0;
	Tcl_Obj *keyObj = ::Tcl_NewStringObj(key, -1);
	Tcl_Obj *obj = Put(keyObj, wi);
	return obj;
}
Tcl_Obj *TTW_DictObj::Put(const char *key, mp_int &mp){
	if (!dictObj) return 0;
	Tcl_Obj *keyObj = ::Tcl_NewStringObj(key, -1);
	Tcl_Obj *obj = Put(keyObj, mp);
	return obj;
}
Tcl_Obj *TTW_DictObj::Put(Tcl_Obj *key, Tcl_Obj *val){
	if (!dictObj) return 0;
	::Tcl_DictObjPut(interp, dictObj, key, val);
	return val;
}
Tcl_Obj *TTW_DictObj::Put(Tcl_Obj *key, bool b){
	if (!dictObj) return 0;
	Tcl_Obj *val = ::Tcl_NewBooleanObj(b ? 1 : 0);
	::Tcl_DictObjPut(interp, dictObj, key, val);
	return val;
}
Tcl_Obj *TTW_DictObj::Put(Tcl_Obj *key, int i){
	if (!dictObj) return 0;
	Tcl_Obj *val = ::Tcl_NewIntObj(i);
	::Tcl_DictObjPut(interp, dictObj, key, val);
	return val;
}
Tcl_Obj *TTW_DictObj::Put(Tcl_Obj *key, long l){
	if (!dictObj) return 0;
	Tcl_Obj *val = ::Tcl_NewLongObj(l);
	::Tcl_DictObjPut(interp, dictObj, key, val);
	return val;
}
Tcl_Obj *TTW_DictObj::Put(Tcl_Obj *key, double d){
	if (!dictObj) return 0;
	Tcl_Obj *val = ::Tcl_NewDoubleObj(d);
	::Tcl_DictObjPut(interp, dictObj, key, val);
	return val;
}
Tcl_Obj *TTW_DictObj::Put(Tcl_Obj *key, Tcl_WideInt &wi){
	if (!dictObj) return 0;
	Tcl_Obj *val = ::Tcl_NewWideIntObj(wi);
	::Tcl_DictObjPut(interp, dictObj, key, val);
	return val;
}
Tcl_Obj *TTW_DictObj::Put(Tcl_Obj *key, mp_int &mp){
	if (!dictObj) return 0;
	Tcl_Obj *val = ::Tcl_NewBignumObj(&mp);
	::Tcl_DictObjPut(interp, dictObj, key, val);
	return val;
}

Tcl_Obj *TTW_DictObj::Put(const char *key, const char *utf8){
	if (!dictObj) return 0;
	Tcl_Obj *keyObj = ::Tcl_NewStringObj(key, -1);
	Tcl_Obj *obj = Put(keyObj, utf8);
	return obj;
}
Tcl_Obj *TTW_DictObj::Put(const char *key, Tcl_DString &utf8){
	if (!dictObj) return 0;
	Tcl_Obj *keyObj = ::Tcl_NewStringObj(key, -1);
	Tcl_Obj *obj = Put(keyObj, utf8);
	return obj;
}
Tcl_Obj *TTW_DictObj::Put(const char *key, const TTW_DString &utf8){
	if (!dictObj) return 0;
	Tcl_Obj *keyObj = ::Tcl_NewStringObj(key, -1);
	Tcl_Obj *obj = Put(keyObj, utf8);
	return obj;
}
Tcl_Obj *TTW_DictObj::Put(Tcl_Obj *key, const char *utf8){
	if (!dictObj) return 0;
	Tcl_Obj *val = ::Tcl_NewStringObj(utf8, -1);
	::Tcl_DictObjPut(interp, dictObj, key, val);
	return val;
}
Tcl_Obj *TTW_DictObj::Put(Tcl_Obj *key, Tcl_DString &utf8){
	if (!dictObj) return 0;
	Tcl_Obj *val = ::Tcl_NewStringObj(Tcl_DStringValue(&utf8), Tcl_DStringLength(&utf8));
	::Tcl_DictObjPut(interp, dictObj, key, val);
	return val;
}
Tcl_Obj *TTW_DictObj::Put(Tcl_Obj *key, const TTW_DString &utf8){
	if (!dictObj) return 0;
	Tcl_Obj *val = ::Tcl_NewStringObj(utf8, utf8.Length());
	::Tcl_DictObjPut(interp, dictObj, key, val);
	return val;
}

/// ====== 要素全削除 ======
void TTW_DictObj::Clear(){
	::Tcl_SetListObj(dictObj, 0, 0);
}

/// ===================================
/// Tcl_Obj から値を取得する関数群

bool TTW_GetBoolean(Tcl_Interp *interp, Tcl_Obj *obj, bool when_null){
	if (!obj) return when_null;
	int b; ::Tcl_GetBooleanFromObj(interp, obj, &b);
	return (b != 0);
}

bool TTW_GetBoolean(Tcl_Obj *obj, bool when_null){
	if (!obj) return when_null;
	int b; ::Tcl_GetBooleanFromObj(0, obj, &b);
	return (b != 0);
}

// ByteArray

double TTW_GetDouble(Tcl_Interp *interp, Tcl_Obj *obj, double when_null){
	if (!obj) return when_null;
	double d; if (::Tcl_GetDoubleFromObj(interp, obj, &d) != TCL_OK) d = when_null;
	return d;
}

double TTW_GetDouble(Tcl_Obj *obj, double when_null){
	if (!obj) return when_null;
	double d; if (::Tcl_GetDoubleFromObj(0, obj, &d) != TCL_OK) d = when_null;
	return d;
}

// Index
int TTW_GetInt(Tcl_Interp *interp, Tcl_Obj *obj, int when_null){
	if (!obj) return when_null;
	int i; if (::Tcl_GetIntFromObj(interp, obj, &i) != TCL_OK) i = when_null;
	return i;
}
int TTW_GetInt(Tcl_Obj *obj, int when_null){
	if (!obj) return when_null;
	int i; if (::Tcl_GetIntFromObj(0, obj, &i) != TCL_OK) i = when_null;
	return i;
}

long TTW_GetLong(Tcl_Interp *interp, Tcl_Obj *obj, long when_null){
	if (!obj) return when_null;
	long l; if (::Tcl_GetLongFromObj(interp, obj, &l) != TCL_OK) l = when_null;
	return l;
}

long TTW_GetLong(Tcl_Obj *obj, long when_null){
	if (!obj) return when_null;
	long l; if (::Tcl_GetLongFromObj(0, obj, &l) != TCL_OK) l = when_null;
	return l;
}

const char *TTW_GetString(Tcl_Obj *obj, const char *when_null){
	if (!obj) return when_null;
	return ::Tcl_GetStringFromObj(obj, 0);
}

const char *TTW_GetString(Tcl_Obj *obj, int &length, const char *when_null){
	if (!obj) return when_null;
	return ::Tcl_GetStringFromObj(obj, &length);
}

Tcl_UniChar *TTW_GetUnicode(Tcl_Obj *obj, Tcl_UniChar *when_null){
	if (!obj) return when_null;
	return ::Tcl_GetUnicodeFromObj(obj, 0);
}

Tcl_UniChar *TTW_GetUnicode(Tcl_Obj *obj, int &length, Tcl_UniChar *when_null){
	if (!obj) return when_null;
	return ::Tcl_GetUnicodeFromObj(obj, &length);
}

Tcl_WideInt TTW_GetWideInt(Tcl_Interp *interp, Tcl_Obj *obj, Tcl_WideInt when_null){
	if (!obj) return when_null;
	Tcl_WideInt wi; if (::Tcl_GetWideIntFromObj(interp, obj, &wi) != TCL_OK) wi = when_null;
	return wi;
}

Tcl_WideInt TTW_GetWideInt(Tcl_Obj *obj, Tcl_WideInt when_null){
	if (!obj) return when_null;
	Tcl_WideInt wi; if (::Tcl_GetWideIntFromObj(0, obj, &wi) != TCL_OK) wi = when_null;
	return wi;
}

#if 0
mp_int TTW_GetBignum(Tcl_Interp *interp, Tcl_Obj *obj){
	mp_int bn; ::Tcl_GetBignumFromObj(interp, obj, &bn);
	return bn;
}

mp_int TTW_GetBignum(Tcl_Obj *obj, mp_int when_null){
	if (!obj) return when_null;
	mp_int bn; ::Tcl_GetBignumFromObj(0, obj, &bn);
	return bn;
}
#endif

// RegExp

/// ===================================
/// ファイル操作関連
Tcl_Obj *TTW_FSJoinToPath (Tcl_Obj *pathPtr, TTW_ListObj &list){
	int objc;
	Tcl_Obj **objv;
	::Tcl_ListObjGetElements(list.GetInterp(), list, &objc, &objv);
	return ::Tcl_FSJoinToPath(pathPtr, objc, objv);
}

/// ===================================
/// 時間処理関連
struct TTW_LapTimeWatch::Impl {
	TTW_ListObj laps;
	TTW_ListObj r_seq, r_loop_pt, r_loop_rng;
#if defined(_WIN32) || defined(_WIN64)
	LARGE_INTEGER freq;
#endif
	Impl(){
#if defined(_WIN32) || defined(_WIN64)
		::QueryPerformanceFrequency(&freq);
#endif
	}
};

TTW_LapTimeWatch::TTW_LapTimeWatch(){
	pimpl = new TTW_LapTimeWatch::Impl();
}
TTW_LapTimeWatch::~TTW_LapTimeWatch(){
	delete pimpl;
}
void TTW_LapTimeWatch::Reset(){
	pimpl->laps.Clear();
}

void TTW_LapTimeWatch::Lap(const char *name, Type type){
	pimpl->laps << name;
	pimpl->laps << static_cast<int>(type);
#if defined(_WIN32) || defined(_WIN64)
	LARGE_INTEGER c;
	::QueryPerformanceCounter(&c);
	pimpl->laps << c.QuadPart;
#else
	Tcl_Time tm;
	::Tcl_GetTime(&tm);
	Tcl_WideInt c = tm.sec;
	c *= 1000000;
	c += tm.usec;
	pimpl->laps << c;
#endif
}

TTW_ListObj &TTW_LapTimeWatch::AnalyzeSequenceResult(){
	TTW_ListObj &result = pimpl->r_seq, &laps = pimpl->laps;
	result.Clear();
	int cnt = laps.Count();
	bool first = true;
	Tcl_WideInt prev;
	for (int j = 0; j < cnt - 2; j += 3){
		Type type = static_cast<Type>(TTW_GetInt(laps[j+1]));
		if (type != Sequence) continue;
		result << laps[j];
		Tcl_WideInt cur = TTW_GetWideInt(laps[j+2]);
		if (first){
			result << 0;
			first = false;
		}else{
			double dif = static_cast<double>(cur - prev);
#if defined(_WIN32)
			dif *= 1000.0 / static_cast<double>(pimpl->freq.QuadPart);
#else
			dif /= 1000.0;
#endif
			result << dif;
		}
		prev = cur;
	}
	return result;
}

TTW_ListObj &TTW_LapTimeWatch::AnalyzeLoopPoint(){
	TTW_ListObj &result = pimpl->r_loop_pt, &laps = pimpl->laps;
	result.Clear();
	int cnt = laps.Count();
	TTW_ListObj raii;
	Tcl_Obj *sum = ::Tcl_NewDictObj();
	raii << sum;
	for (int j = 0; j < cnt - 2; j += 3){
		Type type = static_cast<Type>(TTW_GetInt(laps[j+1]));
		if (type != LoopPoint) continue;
		Tcl_WideInt cur = TTW_GetWideInt(laps[j+2]);
		Tcl_Obj *item;
		::Tcl_DictObjGet(0, sum, laps[j], &item);
		if (item == 0){
			TTW_ListObj cur_itm;
			item = ::Tcl_NewObj();
			::Tcl_DictObjPut(0, sum, laps[j], item);
			cur_itm.Borrow(item);
			cur_itm << 0;    // 計測回数
			cur_itm << cur;  // 前回の時間
			cur_itm << 0;    // 合計計測値
		}else{
			TTW_ListObj cur_itm;
			cur_itm.Borrow(item);
			Tcl_WideInt prev = TTW_GetWideInt(cur_itm[1], 0);
			cur_itm.Set(0, TTW_GetInt(cur_itm[0], 0) + 1); // 計測回数
			cur_itm.Set(1, cur);                           // 前回の時間
			cur_itm.Set(2, TTW_GetWideInt(cur_itm[2], 0) + cur - prev); // 合計計測値
		}
	}
	TTW_ListObj sum_r;
	sum_r.Borrow(sum);
	cnt = sum_r.Count();
	for (int j = 0; j < cnt - 1; j += 2){
		TTW_ListObj cur_itm;
		result << sum_r[j];
		cur_itm.Borrow(sum_r[j+1]);
		int cnt = TTW_GetInt(cur_itm[0], 0);
		result << cur_itm[0];
		if (cnt == 0){
			TTW_DString err; err << TTW_GetString(cur_itm[2], "") << " / ?"; 
			result << err;
		}else{
			double quot = cnt;
#if defined(_WIN32) || defined(_WIN64)
			quot *= static_cast<double>(pimpl->freq.QuadPart) / 1000.0;
#else
			quot *= 1000.0;
#endif
			double sum = TTW_GetDouble(cur_itm[2], 0);
			result << (sum / quot);
		}
	}
	return result;
}

TTW_ListObj &TTW_LapTimeWatch::AnalyzeLoopRange(){
	// 処理ルール : 同じ名前の LoopStart、LoopEnd は、最初に呼び出されたものから順に処理して、一番近いもの同士でペアにする。
	//  対応しない LoopStart/LoopEnd は下記ルールで処理する。
	//  * LoopStart を呼び出す前に出現する LoopEnd は無視。
	//  * LoopStart の後に LoopEnd が出現しない LoopStart は無視。
	//  * 同じ名前で連続して LoopStart を呼び出した場合は、先に呼び出した方の LoopStart を無視。
	//  * 同じ名前で連続して LoopEnd を呼び出した場合は、後に呼び出した方の LoopEnd を無視。
	TTW_ListObj &result = pimpl->r_loop_rng, &laps = pimpl->laps;
	result.Clear();
	int cnt = laps.Count();
	TTW_ListObj raii;
	Tcl_Obj *sum = ::Tcl_NewDictObj();
	raii << sum;
	for (int j = 0; j < cnt - 2; j += 3){
		Type type = static_cast<Type>(TTW_GetInt(laps[j+1]));
		if (type != LoopStart && type != LoopEnd) continue;
		Tcl_WideInt cur = TTW_GetWideInt(laps[j+2]);
		Tcl_Obj *item;
		::Tcl_DictObjGet(0, sum, laps[j], &item);
		if (item == 0){
			if (type == LoopEnd) continue;
			TTW_ListObj cur_itm;
			item = ::Tcl_NewObj();
			::Tcl_DictObjPut(0, sum, laps[j], item);
			cur_itm.Borrow(item);
			cur_itm << 0;    // 計測回数
			cur_itm << cur;  // 前回の時間
			cur_itm << 0;    // 合計計測値
		}else{
			TTW_ListObj cur_itm;
			cur_itm.Borrow(item);
			if (type == LoopStart){
				cur_itm.Set(1, cur);                           // 前回の時間
			}else if (type == LoopEnd){
				Tcl_WideInt prev = TTW_GetWideInt(cur_itm[1], 0);
				if (prev < 0) continue;
				cur_itm.Set(0, TTW_GetInt(cur_itm[0], 0) + 1); // 計測回数
				cur_itm.Set(1, -1);                           // 前回の時間
				cur_itm.Set(2, TTW_GetWideInt(cur_itm[2], 0) + cur - prev); // 合計計測値
			}
		}
	}
	TTW_ListObj sum_r;
	sum_r.Borrow(sum);
	cnt = sum_r.Count();
	for (int j = 0; j < cnt - 1; j += 2){
		TTW_ListObj cur_itm;
		result << sum_r[j];
		cur_itm.Borrow(sum_r[j+1]);
		int cnt = TTW_GetInt(cur_itm[0], 0);
		result << cur_itm[0];
		if (cnt == 0){
			TTW_DString err; err << TTW_GetString(cur_itm[2], "") << " / ?"; 
			result << err;
		}else{
			double quot = cnt;
#if defined(_WIN32) || defined(_WIN64)
			quot *= static_cast<double>(pimpl->freq.QuadPart) / 1000.0;
#else
			quot *= 1000.0;
#endif
			double sum = TTW_GetDouble(cur_itm[2], 0);
			result << (sum / quot);
		}
	}
	return result;
}

/// ===================================
/// Tcl_ObjType 取得
namespace {
const Tcl_ObjType *dict_type = 0, *list_type = 0, *int_type = 0, *wideint_type = 0, *double_type = 0, *booleanString_type = 0, *string_type = 0;
struct gt{
	gt(){
		// Tcl_Init より前に Tcl_Obj を解放すると、実行エラーが発生する。
		TTW_ListObj lst;lst.Borrow(::Tcl_NewObj());
		Tcl_Obj *int_obj = lst.Push(1);
		int_type = int_obj->typePtr;

		Tcl_WideInt wi = 1234567890123;
		Tcl_Obj *wi_obj = lst.Push(wi);
		wideint_type = wi_obj->typePtr;

		Tcl_Obj *bool_obj = lst.Push("true");
		int bv; ::Tcl_GetBooleanFromObj(0, bool_obj, &bv);
		booleanString_type = bool_obj->typePtr;

		Tcl_Obj *double_obj = lst.Push(1.1);
		double_type = double_obj->typePtr;

		Tcl_Obj *str_obj = lst.Push("hoge");
		int cl = ::Tcl_GetCharLength(str_obj);
		string_type = bool_obj->typePtr;

		list_type = static_cast<Tcl_Obj *>(lst)->typePtr;

		TTW_DictObj dct; dct.Borrow(::Tcl_NewObj());
		dct.Put("hoge", 1);
		dict_type = static_cast<Tcl_Obj *>(dct)->typePtr;
	}
}get_types;
}
const Tcl_ObjType *TTW_GetDictType(){
	return dict_type;
}
const Tcl_ObjType *TTW_GetListType(){
	return list_type;
}
const Tcl_ObjType *TTW_GetIntType(){
	return int_type;
}
const Tcl_ObjType *TTW_GetWideIntType(){
	return wideint_type;
}
const Tcl_ObjType *TTW_GetDoubleType(){
	return double_type;
}
const Tcl_ObjType *TTW_GetBooleanType(){
	return booleanString_type;
}
const Tcl_ObjType *TTW_GetStringType(){
	return string_type;
}


