もっちー備忘録

プログラミングが趣味な人のブログです。最近はオープンソースライブラリにはまってます。

プログラミング

[ リスト | 詳細 ]

記事検索
検索

全5ページ

[1] [2] [3] [4] [5]

[ 次のページ ]

Tcl を C/C++ で活用する・・・というと、Tcl_Eval で Tcl の各種コマンドを呼び出す方法をまず思いつきますが、
Tcl_Eval を使う以外にも、文字列処理や、ファイル処理、参照カウンタ式のオブジェクト管理等、
色々便利そうな API が結構揃っていて、純粋に C/C++ 用のライブラリとしても使えそうな感じです。

さらに欲張って、Tcl がスクリプトを内部形式に変換する際に使用している
トークン分割処理を使えないか調べてみたのでその結果をちょっと書いてみます。

Tcl のトークン分割処理は、 Tcl_ParseCommand という C API から呼び出せるようです。
Tcl の文法に沿った文字列を試しに入れて、結果を表示してみます。

<実験コード>
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);
  }
}

<結果>
[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 に次のように定義されています。
#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

スペースやタブをトークン区切りにして、各トークンを純粋に取り出したい、といった場合は、
TCL_TOKEN_WORD、または TCL_TOKEN_SIMPLE_WORD のトークンだけを処理して、それ以外の
トークンは無視すれば使えそうな感じでしょうか。

parse.commentStart がコメント開始箇所を見つけ出せてない理由が謎ですが・・・

開く コメント(0)

フリーソフトでPDFにしおりを付加する機能のあるものがなかなか見つからなかった
のですが、実はGhostscriptを使えば結構簡単にできるということがわかりました。

しおりの文字列を日本語にしたい場合は、BOM付きのUTF16(BigEndian)を8進数表記にすれば
よいようなので、文字列=>UTF16 8進数表記変換をするついでにGhostscriptに渡すpdfmarkの
書式をある程度作るHTAツールを作ってみました。

<手順>
手順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>

開く コメント(0)

不具合現象

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 の配列を割り当てまたは宣言しようとしました。

また、多少エラー内容は違いますが、同じような現象が、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'

どうやら、 __stat64 をうまく認識できていないようです。

__stat64 は、 #include <sys/types.h> や #include <sys/stat.h> を C ソースに記述することで
使うことができるようになります。
Tcl では、#include "tclPort.h" の中で、 __stat64 を Tcl_StatBuf に typedef しています。

TclVFSのソース vfs.c を見てみると、先頭に
<vfs.c ソースの先頭部分>
#include <tcl.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"

<VS2012、Tcl 8.6.8では下記手順も追加>
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)

開く コメント(0)

ソート済配列に対して2分探索をしたり、昇順(または降順)の状態を維持したまま配列に要素を挿入したいといった場合、C++ではstd::lower_bound や std::upper_boundを活用すると便利ですが、それぞれが返すイテレータがどこを指すのか理解が曖昧だったので、イラスト化してみました。
イメージ 1

開く コメント(0)

文字列にバイナリを埋め込む方法としてbase64が良く使われていますが、
バイナリを埋め込んだ文字列の 転送/格納にUTF16を使用する場合、
base64文字列をUTF16で扱うことになるため、上位8ビットが丸々0になり、
転送/格納効率が非常に悪くなります。

UTF16の場合は、base64のようにアルファベットや数字を使うよりも、
より多くの種類がある漢字を使った方が 効率が良くなるはずです。
というわけで、既存技術を探してみたところ、 base16kというものを発見しました。

base64では半角アルファベットや数字等、64種類の文字を使用するに対し、
base16kでは、Unicodeのうち、U+5000 - U+8fff の範囲にある、16384種類の文字を使用します。

この領域はCJK統合漢字と呼ばれるようで、みっちり漢字が詰まってます。

base16kエンコーダ/デコーダのサンプルプログラムを作ってみました。
boostライセンスとして公開します。


開く コメント(0)

全5ページ

[1] [2] [3] [4] [5]

[ 次のページ ]


.


プライバシー -  利用規約 -  メディアステートメント -  ガイドライン -  順守事項 -  ご意見・ご要望 -  ヘルプ・お問い合わせ

Copyright (C) 2019 Yahoo Japan Corporation. All Rights Reserved.

みんなの更新記事