Tclのトークン分割機能をC/C++から直接呼び出してみるテスト
Tcl を C/C++ で活用する・・・というと、Tcl_Eval で Tcl の各種コマンドを呼び出す方法をまず思いつきますが、
Tcl_Eval を使う以外にも、文字列処理や、ファイル処理、参照カウンタ式のオブジェクト管理等、
色々便利そうな API が結構揃っていて、純粋に C/C++ 用のライブラリとしても使えそうな感じです。
Tcl_Eval を使う以外にも、文字列処理や、ファイル処理、参照カウンタ式のオブジェクト管理等、
色々便利そうな API が結構揃っていて、純粋に C/C++ 用のライブラリとしても使えそうな感じです。
<実験コード>
void tokenize_test(){
const char *some_tcl_script[] = {
"hello {ABC DEF GHI} [hoge AA BB $CC] $def OKOK # comment start",
"hello {ABC DEF \nGHI} [hoge AA BB $CC] $def OKOK #comment start"
};
for (int j = 0; j < 2; ++j){
std::printf("[%d]\n", j+1);
Tcl_Parse parse;
::Tcl_ParseCommand(0, some_tcl_script[j], -1, 0, &parse);
std::printf("command:");
std::fwrite(parse.commandStart, parse.commandSize, 1, stdout);
std::printf("\n");
for (int i = 0; i < parse.numTokens; ++i){
Tcl_Token &tok = parse.tokenPtr[i];
std::printf("token[%d] (%d):", i + 1, tok.type);
std::fwrite(tok.start, tok.size, 1, stdout);
std::printf("\n");
}
std::printf("comment:%s\n", parse.commentStart);
::Tcl_FreeParse(&parse);
}
}
const char *some_tcl_script[] = {
"hello {ABC DEF GHI} [hoge AA BB $CC] $def OKOK # comment start",
"hello {ABC DEF \nGHI} [hoge AA BB $CC] $def OKOK #comment start"
};
for (int j = 0; j < 2; ++j){
std::printf("[%d]\n", j+1);
Tcl_Parse parse;
::Tcl_ParseCommand(0, some_tcl_script[j], -1, 0, &parse);
std::printf("command:");
std::fwrite(parse.commandStart, parse.commandSize, 1, stdout);
std::printf("\n");
for (int i = 0; i < parse.numTokens; ++i){
Tcl_Token &tok = parse.tokenPtr[i];
std::printf("token[%d] (%d):", i + 1, tok.type);
std::fwrite(tok.start, tok.size, 1, stdout);
std::printf("\n");
}
std::printf("comment:%s\n", parse.commentStart);
::Tcl_FreeParse(&parse);
}
}
<結果>
[1]
command:hello {ABC DEF GHI} [hoge AA BB $CC] $def OKOK # comment start
token[1] (2):hello
token[2] (4):hello
token[3] (2):{ABC DEF GHI}
token[4] (4):ABC DEF GHI
token[5] (1):[hoge AA BB $CC]
token[6] (16):[hoge AA BB $CC]
token[7] (1):$def
token[8] (32):$def
token[9] (4):def
token[10] (2):OKOK
token[11] (4):OKOK
token[12] (2):#
token[13] (4):#
token[14] (2):comment
token[15] (4):comment
token[16] (2):start
token[17] (4):start
comment:(null)
[2]
command:hello {ABC DEF
GHI} [hoge AA BB $CC] $def OKOK #comment start
token[1] (2):hello
token[2] (4):hello
token[3] (2):{ABC DEF
GHI}
token[4] (4):ABC DEF
GHI
token[5] (1):[hoge AA BB $CC]
token[6] (16):[hoge AA BB $CC]
token[7] (1):$def
token[8] (32):$def
token[9] (4):def
token[10] (2):OKOK
token[11] (4):OKOK
token[12] (2):#comment
token[13] (4):#comment
token[14] (2):start
token[15] (4):start
comment:(null)
()内の数字は トークンの type を表していて、tcl.h に次のように定義されています。command:hello {ABC DEF GHI} [hoge AA BB $CC] $def OKOK # comment start
token[1] (2):hello
token[2] (4):hello
token[3] (2):{ABC DEF GHI}
token[4] (4):ABC DEF GHI
token[5] (1):[hoge AA BB $CC]
token[6] (16):[hoge AA BB $CC]
token[7] (1):$def
token[8] (32):$def
token[9] (4):def
token[10] (2):OKOK
token[11] (4):OKOK
token[12] (2):#
token[13] (4):#
token[14] (2):comment
token[15] (4):comment
token[16] (2):start
token[17] (4):start
comment:(null)
[2]
command:hello {ABC DEF
GHI} [hoge AA BB $CC] $def OKOK #comment start
token[1] (2):hello
token[2] (4):hello
token[3] (2):{ABC DEF
GHI}
token[4] (4):ABC DEF
GHI
token[5] (1):[hoge AA BB $CC]
token[6] (16):[hoge AA BB $CC]
token[7] (1):$def
token[8] (32):$def
token[9] (4):def
token[10] (2):OKOK
token[11] (4):OKOK
token[12] (2):#comment
token[13] (4):#comment
token[14] (2):start
token[15] (4):start
comment:(null)
#define TCL_TOKEN_WORD 1
#define TCL_TOKEN_SIMPLE_WORD 2
#define TCL_TOKEN_TEXT 4
#define TCL_TOKEN_BS 8
#define TCL_TOKEN_COMMAND 16
#define TCL_TOKEN_VARIABLE 32
#define TCL_TOKEN_SUB_EXPR 64
#define TCL_TOKEN_OPERATOR 128
#define TCL_TOKEN_EXPAND_WORD 256
#define TCL_TOKEN_SIMPLE_WORD 2
#define TCL_TOKEN_TEXT 4
#define TCL_TOKEN_BS 8
#define TCL_TOKEN_COMMAND 16
#define TCL_TOKEN_VARIABLE 32
#define TCL_TOKEN_SUB_EXPR 64
#define TCL_TOKEN_OPERATOR 128
#define TCL_TOKEN_EXPAND_WORD 256
スペースやタブをトークン区切りにして、各トークンを純粋に取り出したい、といった場合は、
TCL_TOKEN_WORD、または TCL_TOKEN_SIMPLE_WORD のトークンだけを処理して、それ以外の
トークンは無視すれば使えそうな感じでしょうか。
TCL_TOKEN_WORD、または TCL_TOKEN_SIMPLE_WORD のトークンだけを処理して、それ以外の
トークンは無視すれば使えそうな感じでしょうか。
parse.commentStart がコメント開始箇所を見つけ出せてない理由が謎ですが・・・
Ghostscriptを使ってPDFにしおりをつける
しおりの文字列を日本語にしたい場合は、BOM付きのUTF16(BigEndian)を8進数表記にすれば
よいようなので、文字列=>UTF16 8進数表記変換をするついでにGhostscriptに渡すpdfmarkの
書式をある程度作るHTAツールを作ってみました。
よいようなので、文字列=>UTF16 8進数表記変換をするついでにGhostscriptに渡すpdfmarkの
書式をある程度作るHTAツールを作ってみました。
<手順>
手順1. 下記内容を拡張子 .hta にして保存し、実行する。
手順2. 左側の欄にしおりの文字列を1項目1行で記入して"convert->"ボタンを押す。
手順3. 右側の欄の内容をテキストファイルに保存する。
手順4. テキストファイルの /Count や /Page の数値を適宜変更して上書き保存する。
手順5. 下側の欄の引数を参考にして Ghostscript を起動する (pdfmarks.txt のところに、作成したテキストファイルを指定する)
手順1. 下記内容を拡張子 .hta にして保存し、実行する。
手順2. 左側の欄にしおりの文字列を1項目1行で記入して"convert->"ボタンを押す。
手順3. 右側の欄の内容をテキストファイルに保存する。
手順4. テキストファイルの /Count や /Page の数値を適宜変更して上書き保存する。
手順5. 下側の欄の引数を参考にして Ghostscript を起動する (pdfmarks.txt のところに、作成したテキストファイルを指定する)
<HTAプログラム>
<html>
<body>
<textarea id="src" cols=40 rows=30>
</textarea>
<input type="button" id="convert" value="convert ->"></input>
<textarea id="dest" cols=80 rows=30>
</textarea>
<br/>
<textarea id="cmd" cols=120 rows=3>
gswin32c -dBATCH -dNOPAUSE -sDEVICE=pdfwrite -sOutputFile=output.pdf input.pdf pdfmarks.txt
</textarea>
<script>
var txt_src = document.getElementById("src");
var txt_dest = document.getElementById("dest");
var btn_convert = document.getElementById("convert");
btn_convert.onclick = function(){
var lines = txt_src.value.split("\n");
var sz = lines.length;
for(var j = 0; j < sz; ++j){
var l_src = lines[j].replace("\r", "");
var l_dst = "\\376\\377"; // UTF16 (BE の BOM)
var ln = l_src.length;
for (var i = 0; i < ln; ++i){
var c = l_src.charCodeAt(i);
l_dst += "\\" + parseInt(c / 256).toString(8) + "\\" + (c & 255).toString(8);
}
lines[j] = "[/Page x /Count y /Title (" + l_dst + ") /OUT pdfmark";
}
txt_dest.value = lines.join("\n");
}
</script>
</body>
</html>
<body>
<textarea id="src" cols=40 rows=30>
</textarea>
<input type="button" id="convert" value="convert ->"></input>
<textarea id="dest" cols=80 rows=30>
</textarea>
<br/>
<textarea id="cmd" cols=120 rows=3>
gswin32c -dBATCH -dNOPAUSE -sDEVICE=pdfwrite -sOutputFile=output.pdf input.pdf pdfmarks.txt
</textarea>
<script>
var txt_src = document.getElementById("src");
var txt_dest = document.getElementById("dest");
var btn_convert = document.getElementById("convert");
btn_convert.onclick = function(){
var lines = txt_src.value.split("\n");
var sz = lines.length;
for(var j = 0; j < sz; ++j){
var l_src = lines[j].replace("\r", "");
var l_dst = "\\376\\377"; // UTF16 (BE の BOM)
var ln = l_src.length;
for (var i = 0; i < ln; ++i){
var c = l_src.charCodeAt(i);
l_dst += "\\" + parseInt(c / 256).toString(8) + "\\" + (c & 255).toString(8);
}
lines[j] = "[/Page x /Count y /Title (" + l_dst + ") /OUT pdfmark";
}
txt_dest.value = lines.join("\n");
}
</script>
</body>
</html>
<参考にしたサイト>
http://www.physics.drexel.edu/~wking/unfolding-disasters-old/posts/PDF_bookmarks_with_Ghostscript/
http://partners.adobe.com/public/developer/en/acrobat/sdk/pdf/pdf_creation_apis_and_specs/pdfmarkReference.pdf
http://milan.kupcevic.net/ghostscript-ps-pdf/
https://github.com/kmuto/pdf-addbookmark/blob/master/README-rb.ja.rdoc
http://www.physics.drexel.edu/~wking/unfolding-disasters-old/posts/PDF_bookmarks_with_Ghostscript/
http://partners.adobe.com/public/developer/en/acrobat/sdk/pdf/pdf_creation_apis_and_specs/pdfmarkReference.pdf
http://milan.kupcevic.net/ghostscript-ps-pdf/
https://github.com/kmuto/pdf-addbookmark/blob/master/README-rb.ja.rdoc
VS2008でTclVFSをtcl.8.5.15に対応させる方法 (VS2012、tcl 8.6.8 追記)
不具合現象
Tcl 8.5 系の現在の最新版である Tcl 8.5.15 と TclVFS 20080503 を VS2008 Express Edition 32bitモードでビルドしようとしたところ、下記エラーが出てしまいました。<Tcl 8.5.15 + TclVFS 20080503 32bit モードでのビルドエラー内容>
===============================================================================
*** Compiler has 'Optimizations'
*** Compiler does not have 'Pentium 0x0f fix'
*** Linker has 'Win98 alignment problem'
*** Intermediate directory will be '.\Release_VC9\vfs_ThreadedDynamic'
*** Output directory will be '.\Release_VC9'
*** Suffix for binaries will be ''
*** Optional defines are '-DTCL_CFGVAL_ENCODING=\"cp1252\" -DSTDC_HEADERS -DTCL_THREADS=1 -DTCL_CFG_OPTIMIZED'
*** Compiler version 9. Target machine is IX86
*** Compiler options '-W3 -Ot -Oi -fp:strict -Gs -GS -GL -RTC1 -W3'
*** Link options '-ltcg'
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\wtime.inl(37) : warning C4133: '関数' : 'const time_t *' と 'const __time32_t *' の間で型に互換性がありません。
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\wtime.inl(43) : warning C4133: '関数' : 'const time_t *' と 'const __time32_t *' の間で型に互換性がありません。
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\time.inl(32) : warning C4244: '関数' : 'time_t' から '__time32_t' への変換です。データが失われる可能性があります。
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\time.inl(32) : warning C4244: '関数' : 'time_t' から '__time32_t' への変換です。データが失われる可能性があります。
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\time.inl(38) : warning C4133: '関数' : 'const time_t *' と 'const __time32_t *' の間で型に互換性がありません。
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\time.inl(44) : warning C4133: '関数' : 'const time_t *' と 'const __time32_t *' の間で型に互換性がありません。
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\time.inl(51) : warning C4133: '関数' : 'const time_t *' と 'const __time32_t *' の間で型に互換性がありません。
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\time.inl(57) : warning C4133: '関数' : 'const time_t *' と 'const __time32_t *' の間で型に互換性がありません。
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\time.inl(64) : warning C4133: '関数' : 'const time_t *' と 'const __time32_t *' の間で型に互換性がありません。
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\time.inl(69) : warning C4133: '関数' : 'const time_t *' と 'const __time32_t *' の間で型に互換性がありません。
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\time.inl(81) : warning C4133: '関数' : 'time_t *' と '__time32_t *' の間で型に互換性がありません。
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\sys/stat.inl(44) : error C2466: サイズが 0 の配列を割り当てまたは宣言しようとしました。
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\sys/stat.inl(49) : error C2466: サイズが 0 の配列を割り当てまたは宣言しようとしました。
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\sys/timeb.inl(46) : error C2466: サイズが 0 の配列を割り当てまたは宣言しようとしました。
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\sys/utime.inl(39) : error C2466: サイズが 0 の配列を割り当てまたは宣言しようとしました。
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\sys/utime.inl(44) : error C2466: サイズが 0 の配列を割り当てまたは宣言しようとしました。
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\sys/utime.inl(49) : error C2466: サイズが 0 の配列を割り当てまたは宣言しようとしました。
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\sys/utime.inl(78) : error C2466: サイズが 0 の配列を割り当てまたは宣言しようとしました。
*** Compiler has 'Optimizations'
*** Compiler does not have 'Pentium 0x0f fix'
*** Linker has 'Win98 alignment problem'
*** Intermediate directory will be '.\Release_VC9\vfs_ThreadedDynamic'
*** Output directory will be '.\Release_VC9'
*** Suffix for binaries will be ''
*** Optional defines are '-DTCL_CFGVAL_ENCODING=\"cp1252\" -DSTDC_HEADERS -DTCL_THREADS=1 -DTCL_CFG_OPTIMIZED'
*** Compiler version 9. Target machine is IX86
*** Compiler options '-W3 -Ot -Oi -fp:strict -Gs -GS -GL -RTC1 -W3'
*** Link options '-ltcg'
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\wtime.inl(37) : warning C4133: '関数' : 'const time_t *' と 'const __time32_t *' の間で型に互換性がありません。
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\wtime.inl(43) : warning C4133: '関数' : 'const time_t *' と 'const __time32_t *' の間で型に互換性がありません。
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\time.inl(32) : warning C4244: '関数' : 'time_t' から '__time32_t' への変換です。データが失われる可能性があります。
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\time.inl(32) : warning C4244: '関数' : 'time_t' から '__time32_t' への変換です。データが失われる可能性があります。
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\time.inl(38) : warning C4133: '関数' : 'const time_t *' と 'const __time32_t *' の間で型に互換性がありません。
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\time.inl(44) : warning C4133: '関数' : 'const time_t *' と 'const __time32_t *' の間で型に互換性がありません。
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\time.inl(51) : warning C4133: '関数' : 'const time_t *' と 'const __time32_t *' の間で型に互換性がありません。
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\time.inl(57) : warning C4133: '関数' : 'const time_t *' と 'const __time32_t *' の間で型に互換性がありません。
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\time.inl(64) : warning C4133: '関数' : 'const time_t *' と 'const __time32_t *' の間で型に互換性がありません。
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\time.inl(69) : warning C4133: '関数' : 'const time_t *' と 'const __time32_t *' の間で型に互換性がありません。
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\time.inl(81) : warning C4133: '関数' : 'time_t *' と '__time32_t *' の間で型に互換性がありません。
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\sys/stat.inl(44) : error C2466: サイズが 0 の配列を割り当てまたは宣言しようとしました。
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\sys/stat.inl(49) : error C2466: サイズが 0 の配列を割り当てまたは宣言しようとしました。
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\sys/timeb.inl(46) : error C2466: サイズが 0 の配列を割り当てまたは宣言しようとしました。
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\sys/utime.inl(39) : error C2466: サイズが 0 の配列を割り当てまたは宣言しようとしました。
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\sys/utime.inl(44) : error C2466: サイズが 0 の配列を割り当てまたは宣言しようとしました。
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\sys/utime.inl(49) : error C2466: サイズが 0 の配列を割り当てまたは宣言しようとしました。
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\sys/utime.inl(78) : error C2466: サイズが 0 の配列を割り当てまたは宣言しようとしました。
また、多少エラー内容は違いますが、同じような現象が、Windows SDK .Net 3.5 SP1 (VC9 相当) の 64bitモードで Tcl 8.5.11 と TclVFS 20080503 を ビルドしても発生しました。
<Tcl 8.5.11 + TclVFS 20080503 64bit モードでのビルドエラー内容>
===============================================================================
*** Compiler has 'Optimizations'
*** Intermediate directory will be '.\Release_AMD64_VC9\vfs_ThreadedDynamic'
*** Output directory will be '.\Release_AMD64_VC9'
*** Suffix for binaries will be ''
*** Optional defines are '-DTCL_CFGVAL_ENCODING=\"cp1252\" -DSTDC_HEADERS -DTCL_THREADS=1 -DTCL_CFG_OPTIMIZED -DTCL_CFG_DO64BIT'
*** Compiler version 9. Target machine is AMD64
*** Compiler options '-W3 -Ot -Oi -fp:strict -Gs -GS -GL -RTC1 -W3'
*** Link options '-ltcg'
cl -DPACKAGE_NAME="\"vfs\"" -DPACKAGE_VERSION="\"1.3\"" -DBUILD_vfs -nologo -c -W3 -W3 -D _CRT_SECURE_NO_DEPRECATE -D _CRT_NONSTDC_NO_DEPRECATE -Fp.\Release_AMD64_VC9\vfs_ThreadedDynamic\ -DUSE_TCL_STUBS -Ot -Oi -fp:strict -Gs -GS -GL -MD -I"..\..\tcl8.5.15\generic" -I"..\..\tcl8.5.15\win" -I"..\win" -I"..\generic" -DTCL_CFGVAL_ENCODING=\"cp1252\" -DSTDC_HEADERS -DTCL_THREADS=1 -DTCL_CFG_OPTIMIZED -DTCL_CFG_DO64BIT -DBUILD_vfs -Fo.\Release_AMD64_VC9\vfs_ThreadedDynamic\ @C:\Users\keita\AppData\Local\Temp\nm6691.tmp
vfs.c
..\generic\vfs.c(1108) : error C2037: left of 'st_mode' specifies undefined struct/union '__stat64'
..\generic\vfs.c(1122) : error C2037: left of 'st_dev' specifies undefined struct/union '__stat64'
..\generic\vfs.c(1129) : error C2037: left of 'st_ino' specifies undefined struct/union '__stat64'
..\generic\vfs.c(1136) : error C2037: left of 'st_mode' specifies undefined struct/union '__stat64'
..\generic\vfs.c(1143) : error C2037: left of 'st_nlink' specifies undefined struct/union '__stat64'
..\generic\vfs.c(1150) : error C2037: left of 'st_uid' specifies undefined struct/union '__stat64'
..\generic\vfs.c(1157) : error C2037: left of 'st_gid' specifies undefined struct/union '__stat64'
..\generic\vfs.c(1164) : error C2037: left of 'st_size' specifies undefined struct/union '__stat64'
..\generic\vfs.c(1171) : error C2037: left of 'st_atime' specifies undefined struct/union '__stat64'
..\generic\vfs.c(1178) : error C2037: left of 'st_mtime' specifies undefined struct/union '__stat64'
..\generic\vfs.c(1185) : error C2037: left of 'st_ctime' specifies undefined struct/union '__stat64'
..\generic\vfs.c(1190) : error C2037: left of 'st_mode' specifies undefined struct/union '__stat64'
..\generic\vfs.c(1192) : error C2037: left of 'st_mode' specifies undefined struct/union '__stat64'
..\generic\vfs.c(1195) : error C2037: left of 'st_mode' specifies undefined struct/union '__stat64'
*** Compiler has 'Optimizations'
*** Intermediate directory will be '.\Release_AMD64_VC9\vfs_ThreadedDynamic'
*** Output directory will be '.\Release_AMD64_VC9'
*** Suffix for binaries will be ''
*** Optional defines are '-DTCL_CFGVAL_ENCODING=\"cp1252\" -DSTDC_HEADERS -DTCL_THREADS=1 -DTCL_CFG_OPTIMIZED -DTCL_CFG_DO64BIT'
*** Compiler version 9. Target machine is AMD64
*** Compiler options '-W3 -Ot -Oi -fp:strict -Gs -GS -GL -RTC1 -W3'
*** Link options '-ltcg'
cl -DPACKAGE_NAME="\"vfs\"" -DPACKAGE_VERSION="\"1.3\"" -DBUILD_vfs -nologo -c -W3 -W3 -D _CRT_SECURE_NO_DEPRECATE -D _CRT_NONSTDC_NO_DEPRECATE -Fp.\Release_AMD64_VC9\vfs_ThreadedDynamic\ -DUSE_TCL_STUBS -Ot -Oi -fp:strict -Gs -GS -GL -MD -I"..\..\tcl8.5.15\generic" -I"..\..\tcl8.5.15\win" -I"..\win" -I"..\generic" -DTCL_CFGVAL_ENCODING=\"cp1252\" -DSTDC_HEADERS -DTCL_THREADS=1 -DTCL_CFG_OPTIMIZED -DTCL_CFG_DO64BIT -DBUILD_vfs -Fo.\Release_AMD64_VC9\vfs_ThreadedDynamic\ @C:\Users\keita\AppData\Local\Temp\nm6691.tmp
vfs.c
..\generic\vfs.c(1108) : error C2037: left of 'st_mode' specifies undefined struct/union '__stat64'
..\generic\vfs.c(1122) : error C2037: left of 'st_dev' specifies undefined struct/union '__stat64'
..\generic\vfs.c(1129) : error C2037: left of 'st_ino' specifies undefined struct/union '__stat64'
..\generic\vfs.c(1136) : error C2037: left of 'st_mode' specifies undefined struct/union '__stat64'
..\generic\vfs.c(1143) : error C2037: left of 'st_nlink' specifies undefined struct/union '__stat64'
..\generic\vfs.c(1150) : error C2037: left of 'st_uid' specifies undefined struct/union '__stat64'
..\generic\vfs.c(1157) : error C2037: left of 'st_gid' specifies undefined struct/union '__stat64'
..\generic\vfs.c(1164) : error C2037: left of 'st_size' specifies undefined struct/union '__stat64'
..\generic\vfs.c(1171) : error C2037: left of 'st_atime' specifies undefined struct/union '__stat64'
..\generic\vfs.c(1178) : error C2037: left of 'st_mtime' specifies undefined struct/union '__stat64'
..\generic\vfs.c(1185) : error C2037: left of 'st_ctime' specifies undefined struct/union '__stat64'
..\generic\vfs.c(1190) : error C2037: left of 'st_mode' specifies undefined struct/union '__stat64'
..\generic\vfs.c(1192) : error C2037: left of 'st_mode' specifies undefined struct/union '__stat64'
..\generic\vfs.c(1195) : error C2037: left of 'st_mode' specifies undefined struct/union '__stat64'
どうやら、 __stat64 をうまく認識できていないようです。
__stat64 は、 #include <sys/types.h> や #include <sys/stat.h> を C ソースに記述することで
使うことができるようになります。
Tcl では、#include "tclPort.h" の中で、 __stat64 を Tcl_StatBuf に typedef しています。
使うことができるようになります。
Tcl では、#include "tclPort.h" の中で、 __stat64 を Tcl_StatBuf に typedef しています。
TclVFSのソース vfs.c を見てみると、先頭に
<vfs.c ソースの先頭部分>
<vfs.c ソースの先頭部分>
#include <tcl.h>
/* Required to access the 'stat' structure fields, and TclInExit() */
#include "tclInt.h"
#include "tclPort.h"
/* Required to access the 'stat' structure fields, and TclInExit() */
#include "tclInt.h"
#include "tclPort.h"
と書いてありますので、 Tcl_StatBuf (=__stat64) の定義をしようとはしているようです。
対策
色々試してみたところ、 #include <tcl.h> よりも先に #include "tclPort.h" を記述することでビルドが通るようになりました。
つまり、 vfs.c の上記箇所を、下記のように変更すればOKです。
<vfs.c ソース修正例>
#include "tclPort.h" /* ← tcl.h の前に移動してきた */
#include <tcl.h>
/* Required to access the 'stat' structure fields, and TclInExit() */
#include "tclInt.h"
#include <tcl.h>
/* Required to access the 'stat' structure fields, and TclInExit() */
#include "tclInt.h"
<VS2012、Tcl 8.6.8では下記手順も追加>
1661行目 (VfsFileAttrStrings 関数定義の戻り値の型)を
1661行目 (VfsFileAttrStrings 関数定義の戻り値の型)を
static CONST char **
↓static CONST char * CONST86 *
と書き換えこの変更により、下記組み合わせのビルドがそれぞれ通るようになったことを確認済です。
- Tcl 8.5.11 + TclVFS 20080503 64bit モード (Windows SDK .Net 3.5 SP1)
- Tcl 8.5.15 + TclVFS 20080503 32bit モード (Visual Studio 2008 Express Edition)
- Tcl 8.5.15 + TclVFS 20080503 64bit モード (Windows SDK .Net 3.5 SP1)
- Tcl 8.6.8 + TclVFS 20080503 64bit モード (Visual Studio 2012 Express Edition)
Base16kエンコーダ/デコーダ
文字列にバイナリを埋め込む方法としてbase64が良く使われていますが、
バイナリを埋め込んだ文字列の 転送/格納にUTF16を使用する場合、
base64文字列をUTF16で扱うことになるため、上位8ビットが丸々0になり、
転送/格納効率が非常に悪くなります。
バイナリを埋め込んだ文字列の 転送/格納にUTF16を使用する場合、
base64文字列をUTF16で扱うことになるため、上位8ビットが丸々0になり、
転送/格納効率が非常に悪くなります。
UTF16の場合は、base64のようにアルファベットや数字を使うよりも、
より多くの種類がある漢字を使った方が 効率が良くなるはずです。
というわけで、既存技術を探してみたところ、 base16kというものを発見しました。
より多くの種類がある漢字を使った方が 効率が良くなるはずです。
というわけで、既存技術を探してみたところ、 base16kというものを発見しました。
base64では半角アルファベットや数字等、64種類の文字を使用するに対し、
base16kでは、Unicodeのうち、U+5000 - U+8fff の範囲にある、16384種類の文字を使用します。
base16kでは、Unicodeのうち、U+5000 - U+8fff の範囲にある、16384種類の文字を使用します。
この領域はCJK統合漢字と呼ばれるようで、みっちり漢字が詰まってます。
luaで、luaの関数を呼ぶC++の関数をluaから呼んでみた
試した環境は LuaJIT-2.0.0、Visual Studio 2008です。
lua側
print('callfunc:' ..
callfunc(
function(a, b)
print('Hello');
print('a=' .. a);
print('b=' .. b);
return a + b;
end
)
);
callfunc(
function(a, b)
print('Hello');
print('a=' .. a);
print('b=' .. b);
return a + b;
end
)
);
C++側
#include <cstdio>
extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}
int l_callfunc(lua_State *L){
luaL_checktype(L, -1, LUA_TFUNCTION);
lua_pushnumber(L, 5); // 第一引数
lua_pushnumber(L, 15); // 第二引数
lua_pcall(L, 2, 1, 0); // 引数2つ、戻り値1つとして積まれている関数を呼ぶ
double result = lua_tonumber(L, -1);
printf("result:%f\n", result);
lua_pop(L, 1);
lua_pushnumber(L, result * 2);
return 1; // 戻り値の数
}
int main(int argc, char *argv[]){
if (argc < 2) return 0;
lua_State *L = luaL_newstate();
luaL_openlibs(L);
lua_register(L, "callfunc", l_callfunc);
if (luaL_loadfile(L, argv[1])){
printf("load失敗\n");
return 1;
}
if (lua_pcall(L, 0, 0, 0)){
printf("実行失敗\n");
return 1;
}else{
printf("最後の戻り値:%f\n", lua_tonumber(L, -1));
}
lua_close(L);
return 0;
}
extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}
int l_callfunc(lua_State *L){
luaL_checktype(L, -1, LUA_TFUNCTION);
lua_pushnumber(L, 5); // 第一引数
lua_pushnumber(L, 15); // 第二引数
lua_pcall(L, 2, 1, 0); // 引数2つ、戻り値1つとして積まれている関数を呼ぶ
double result = lua_tonumber(L, -1);
printf("result:%f\n", result);
lua_pop(L, 1);
lua_pushnumber(L, result * 2);
return 1; // 戻り値の数
}
int main(int argc, char *argv[]){
if (argc < 2) return 0;
lua_State *L = luaL_newstate();
luaL_openlibs(L);
lua_register(L, "callfunc", l_callfunc);
if (luaL_loadfile(L, argv[1])){
printf("load失敗\n");
return 1;
}
if (lua_pcall(L, 0, 0, 0)){
printf("実行失敗\n");
return 1;
}else{
printf("最後の戻り値:%f\n", lua_tonumber(L, -1));
}
lua_close(L);
return 0;
}
結果
Hello
a=5
b=15
result:20.000000
callfunc:40
最後の戻り値:0.000000
a=5
b=15
result:20.000000
callfunc:40
最後の戻り値:0.000000
BLTのgraphのmarkerでグラフにお絵かき
BLTのgraphを使うと、グラフをtcltkのウィンドウ上に描画できます。
また、graphコマンドのsnapコンポーネント(サブコマンド的な位置づけ?)で、
emfファイルに書き出したり、emfをクリップボードに入れることができるようです。
また、graphコマンドのsnapコンポーネント(サブコマンド的な位置づけ?)で、
emfファイルに書き出したり、emfをクリップボードに入れることができるようです。
普通にグラフを書く方法は他のページにあるので、ここでは、graphコマンドのmarkerコンポーネント
で、axisが付いたグラフ内にお絵かきをしてみたいと思います。
サンプルコードは、「塗りつぶした四角形を描いてクリップボードにemfをコピーする」というものです。
markerを使えば、他にも、画像を追加したり、線を書いたりサブウィンドウをグラフの中に挿入
したりできるみたいです。
この方法を応用すれば、コンター図とか、ボロノイ図とか、2Dカラーマップとかも
描けるはずです(このあたりはもっと簡単にできる方法があるかもしれませんが…)。
で、axisが付いたグラフ内にお絵かきをしてみたいと思います。
サンプルコードは、「塗りつぶした四角形を描いてクリップボードにemfをコピーする」というものです。
markerを使えば、他にも、画像を追加したり、線を書いたりサブウィンドウをグラフの中に挿入
したりできるみたいです。
この方法を応用すれば、コンター図とか、ボロノイ図とか、2Dカラーマップとかも
描けるはずです(このあたりはもっと簡単にできる方法があるかもしれませんが…)。
サンプルコード
package require BLT
namespace import blt::*
wm title . "マーカーでお絵かき"
pack [set g [graph .g -plotbackground black]]
$g configure -title "マーカーでお絵かき"
$g axis configure x -title {X Axis} -min 0 -max 20
$g axis configure y -title {Y Axis} -min 0 -max 20
$g marker create polygon -fill red -coords { 5 5 5 10 10 10 10 5 }
$g marker create polygon -fill blue -coords { 10 5 10 10 15 10 15 5 }
$g marker create polygon -fill #404080 -coords { 15 5 15 10 20 10 20 5 }
$g marker create text -outline white -text {Hello world!} -rotate 10 -coords { 15 20 }
after 100 {$g snap -format emf CLIPBOARD}
namespace import blt::*
wm title . "マーカーでお絵かき"
pack [set g [graph .g -plotbackground black]]
$g configure -title "マーカーでお絵かき"
$g axis configure x -title {X Axis} -min 0 -max 20
$g axis configure y -title {Y Axis} -min 0 -max 20
$g marker create polygon -fill red -coords { 5 5 5 10 10 10 10 5 }
$g marker create polygon -fill blue -coords { 10 5 10 10 15 10 15 5 }
$g marker create polygon -fill #404080 -coords { 15 5 15 10 20 10 20 5 }
$g marker create text -outline white -text {Hello world!} -rotate 10 -coords { 15 20 }
after 100 {$g snap -format emf CLIPBOARD}