Syntax highlighter

2009-11-29

C++: BFDを使ってみる その2(たぶん最後)

昨日の続き。いろいろできそうだなと思ったが、少し落とし穴があった・・・

【落とし穴その1】
mprotectで取得した関数のアドレスを実行可能とか読み込み可能とかにしないと動かせない。
よく考えればあたりまえか・・・
っが、MingwとかCygwin(要するにWindows環境)にはそげなものがない・・・

【落とし穴その2】
dlopenとかdlsymとかその辺の話。ある意味当然ではあるが、共有ライブラリじゃないと読み込めない。
上記の問題から、BFDでシンボル読み込んで、シンボル名をデマングルして、呼び出し時にシンボル名に変換してやればいいかなとか思ったんだけど、BFDはWindowsのDLLに対応していない。Mingwの-sharedオプションで作ったにもかかわらずである。
(本当かどうかはよく知らん、調べてない。PEに変換しているからか?)

この辺を試してみよう。Windows限定の話になるけど・・・

余談
折角なので(備忘録も兼ねて)、BFDの使い方をメモ。
こんな感じの流れ。
bfd_init(); //初期化。一回だけでいい。
bfd* abfd = bfd_openr("hoge.o", NULL); // .a とか .soでもいいと思う
if (bfd == 0) {
  bfd_perror("failed to open"); // error
  return; // 失敗したので
}
// オブジェクトのフォーマットチェック
// アーカイブとかもヘッダの中にあるので、適当に必要なチェックで。
// .aとかのアーカイブだと、.oが複数個入っているので、それ用の処理がいる
if (!bfd_check_format(abfd, bfd_object)) { 
  bfd_perror("format error"); // .o ファイルじゃないよ
  return; // それじゃ!
}
// 中身を読み込む
if (!(bfd_get_file_flags(abfd) & HAS_SYMS)) {
  return; // シンボルなし
}
long storage = bfd_get_symbol_upper_bound(abfd); // サイズを取得
if (storage < 0) {
  bfd_perror("bfd_get_symbol_upper_bound"); //  中身なし?
  return;
}
asymbol** symbol = (asymbol**)malloc(storage); // メモリ確保(new じゃだめなのかね?)
int symbolCount = bfd_canonicalize_symtab(abfd, symbol);
if (symbolCount < 0) {
  bfd_perror("no symbol"); // シンボルがない
  return;
}
// シンボルを読み出す
for (int i = 0; i < symbolCount; i++) {
  asymbol asym = symbol[i];
  int value = bfd_asymbol_value(asym); // シンボルの値(何が入ってるんだろう?)
  const char* name = bfd_asymbol_name(asym); // シンボル名(名前マングルされてる)
  if (name == 0 || ::strlen(name) == 0) continue; // シンボル名が無ければ次
  symbol_info info;
  bfd_symbol_info(abfd, asym, &info); // シンボル情報を取得(中身はよく知らん)
  // 関数ポインタ
  int* fp = (int)file->contents // .o ファイルの中身(バイナリで読み込む)
            + asym->section->filepos // セクションの場所?
            + value;
  // 多分セクションデータとかを自分自身に配置しないと
  // (略)
  mprotect((void*)(((int)fp+4095) & ~4095 - 4096),
          4096, PROT_READ | PROT_WRITE | PROT_EXEC);
  /* こっちのが正しい?(どっちにしろMingwでは動かん
  long pagesize = sysconf(_SC_PAGESIZE);
  char *p = (char *)((long)s & ~(pagesize - 1L));
  mprotect(p, pagesize * 10L, PROT_READ|PROT_WRITE|PROT_EXEC);
  */
  //適当にキャストして、実行
  typedef void (*fnc)(); // とりあえず、戻り値、引数無しと仮定
  fnc fncP = (fnc)fp;
  fncP(); // 実行
}
多分こんな感じ。実際に動かせないので、正しいかどうかは保障できない。
(他人のコードから推測、というかほぼ丸写し、しただけだし・・・)

2009/11/30 追記

落とし穴その1は大嘘であった。
mprotectで実行可能にしなくてもWindowsだと普通に動いた。Cで作った関数だが。
C++側だとどうもいろいろ面倒なのだろう。コンストラクタとか、継承とか。
(確かに、仮想関数のアドレスとかどうやって取るとか、thisポインタを渡すとか、考えればいくらでも解決しないといけない問題がありそう)
憶測だが、コンストラクタのアドレスが分かったところで、クラス全体の情報が取れているわけではないのだろう。ヒープに取るメモリの量とかコンストラクタだけじゃ取れそうにないし。
構造体がBFDから作れるか試してから探した方がいいだろうか?
(C互換の構造体だと単なるメモリの塊というイメージだが・・・)
気合入れればいけそうなのだが、頭と気力が足りない感じ・・・前者が特に・・・orz

2009-11-28

C++: BFDを使ってみる

前にLHAの展開を書いていたが、それとはぜんぜん関係ない話。
LZHUFがいまいち分からなくて挫折したとも言う・・・orz

BFD、big fucking dealがBinary File Descriptorになったライブラリ。GCCに付属してくるもの。
何ができるかといえば、オブジェクトファイルとか、アーカイブファイルからいろんな情報が取ってこれる。

っで、これを使ってC++らしくないものを作ってみようと考えたのだが、上手くいかない。
ちなみに、らしくないものとは、リフレクションのことである。
BFDつかってシンボルを読み込んで、関数のアドレスは取れた。名前マングリングされた関数名で取れるので、デマングルするか、呼び出しの際にマングルする必要があるが・・・
(あぁ、取得したときにデマングルすればマングラーなど要らんのか、無駄なもん作った)
っで、ここからが問題。
C++なので、newして、確保したメモリに対してコンストラクタ呼ぶ必要があるのだが、上手くいかない。
いくつか理由が考えられるのだが、どれだろう?
1. そもそも無理。
2. 取得が上手くいっていなくて、変なアドレスを指してる。
3. その他
取れるアドレスは、単に関数のアドレスなので、適当に関数ポインタにキャストするのだが、
こんな感じであってるのか?
// operator new の関数ポインタ
typedef void* (newP)(size_t);
newP p = (newP)pointer; // pointerは取得したnewのシンボルアドレス
void* buf = p(size); // 予定通りなら、bufには確保したメモリが入るはず・・・
が、今のところ結果はセグメンテーションフォルト。
う~ん、なぜ?
BFD自体もあんまり知られて無いのか、ネットに情報があんまりないし・・・困った。

2009-11-25

おいしいスパゲッティの食べ方

ここで言うスパゲッティとはいわゆるプログラム上の話である。つまりそういうことだ・・・
よく分からない人は、ググってください。
一応Wikipediaへのリンク

自社のコンポーネントを使って、スマートカードのデータを管理するシステムを提供する会社なのだが、そのコンポーネントが何年も前からの代々受け継がれてきたようなつくりになっていて、涙が出そうになる。
しかも、困ったことにドキュメントの類がない。ないことはないが、肝心な部分がない。製品マニュアルをみて理解しろというにはちと作りが悪すぎる。
外面はものすごくよくできていると思う。ユーザーインターフェースは秀逸と言ってもいい。それに反比例して開発者用のその他もろもろは・・・まぁそういうことだ。
更に困ったことに、5年とか10年とか開発に携わっている人でもよく分かっていないらしく、無駄なコーディングをしてバグをつぶすとか普通にある。
(というか、それをしたのでこれを書いてる)
ちょっとXMLの設定ファイルに10文字足すだけで直るバグを、Javaクラスを1つ作って、既存のクラスに定数を足して、XMLも弄ってということした。
それで給料もらっているのでいいといえばいいのだが、確認含めて30分で済む作業を4時間かけて修正するのはいかがなものだろうか?
(ドキュメントがないので、デバッガでソースを追いながらだとこんなもんだよと自分を慰める)

次回のメジャーバージョンアップでspringとかHibernateとかその辺のフレームワークを使って、メンテナンスしやすくすると言っているので、それを信じて耐えるか・・・

オランダの不思議

2つくらい不思議なものをみた。

その1.
オランダにはクリスマスシーズンに、サンタクロースとは別にシンタクロース(Sintaklaas)なるものがいる。彼はトナカイではなく、黒人のプリーストをつれてきて、なんだかよく分からん呪文(オランダ語で喋ってただけ)を唱えたのち、子供たちにプレゼントを配っていた。
本来は12月15日くらいの行事らしいが、(多分その時期は休暇をとる人が多いため)、僕の会社では11月末に移動したらしい。会社が(おそらく)福利厚生の一環(単にオランダ人が祭り好きなのかもしれんが)で行っていたので、社員の家族とか子供とかきてた。
ちなみに、この行事、いつの頃からシンタクロースがつれてくる牧師が黒人に変更されたため、黒人の人たちには受けが悪いらしい。よく知らん。

その2.
この国で(自称)上流家庭の人たちはナイフとフォークでパンを食べる。
正直見ていて滑稽に映るのだが、そういうことらしい。育ちがいいことの証明なのか、その方がマナーがいいと思われるのかは知らんけど。ちなみに、徹底してる人は、食べ物に直接手を触れないそうだ。
つまり、ナイフとフォークでパンを袋から取り出し、皿に置かれたパンにバターを塗り、Beleg(パンにのせるもの全般)をナイフとフォークで取り、切って食べる。
不思議な光景であった。
試してみようかとも思ったが、あまりに抵抗があるのでやめた。どうやら僕は上流家庭の人間にはなれないらしい。

2009-11-21

C++: istreamのread

職場の環境でexe、zipのファイルがダウンロードできない。
っが、普段使っているエディタじゃないとどうも調子が出ない(エディタは重要だ)
ちなみに、xyzzyである。Emacsライクな素敵エディタ。
配布形式はlhaなので、ダウンロードはできた。っが展開できない・・・
なら、自力で展開してやろうと思い、Lhaの展開プログラムを書いているのだが、まさかファイルの読み込みでえらいことになるとは思わんなかった。
普段は固定長のバイナリデータなんて扱わないからなぁ・・・
問題になったのはこんな感じのコード。
-----
unsigned char* buffer = (unsigned char*)new char[size + 1];
in.read(buffer, size); 
-----
ちなみに、「in」はistream。
こんな感じでやったら、何故かセグメンテーションフォルトで死んだ。理由はよく分からない・・・
デバッガで追っかけてもread()の部分で死んでるし、意味不明。
しょうがないので、1バイトずつとって押し込めることにした。
それだと動いた・・・なぜだ?

2009年11月21日 追記

理由が分かった。
利便性を高めるために、こんなメソッドを一枚かませていたが、それがいけなかった。
-----
template<typename T>
int get_byte(T& t, int size)
{
  in.read(reinterpret_cast(&c), size);
  return in.gcount();
}
-----
だめな理由も一日寝てすっきりしたらよく分かった。ある意味当たり前。
渡してるのはポインタなのに、受け取る方式はリファレンス。何が起きるんだろう?
ポインタのポインタみたいな感じになっていたんだろう。そりゃ鼻から悪魔が出てくるわ・・・
自分の未熟さだけを露呈しただけだった・・・orz

2009-11-16

初日

今日は仕事の初日であった。
場所はロッテルダム。駅前といってぜんぜん問題ない場所なので、通勤には非常に便利。
(電車通勤で1時間を下回る職場はこれが初めてだ!)
職種は何を血迷ったのか再びプログラマー。ま、日本と違って残業はほとんどない(らしい)ので、特に問題は無いだろう。
(問題になるとすれば、言葉か・・・いや、英蘭どっちでもOKなので大丈夫なはず・・・)

個人的にいろいろ日本にいたときと比較すると環境はいい気がする。
(給料はそんなに高くはないが・・・)
初日が終わったばかりで浮かれているというのもあるだろうが、それを差し引いてもいい会社だと思う。
(と思いたい。自分の中で結論が出るのは分かるのは早くとも1ヶ月後だろうなぁ・・・)
まだ試用期間中だしぼろを出さないようにしないと・・・

2009-11-15

2012

観てきた。
感想、いまいち・・・
インデペンデンスデイとかアルマゲドンとかと同じ監督らしい(よく知らん)
まぁ、インデペンデンスデイで感動できるなら・・・きっと、多分・・・

話の概要は、要するに現代版ノアの方舟といったところかな。
2012年12月21日に太陽系の惑星が一直線に並んで、その重力場の影響で地球のマントルが暴れる→津波→世界が沈む
こんな感じ。
ぶっちゃけ、突っ込みどころ多すぎ。
例えば、
高さ6000メートルを超える津波は起き得るのか?
わずか3年でArcと呼ばれる超巨大な方舟を7隻も作れるのか?しかも極秘裏に?
なぜアメリカだけがそのことを知っているのか?
(この場合、世界中に優秀な科学者はいるという意味)
その他、たくさん。

あんまりネタ晴らししてもいかんのでこれくらいで。
個人的に話のネタ程度に観る価値はあるかもといいたかっただけ。

2009-11-11

C++: テトリス

ニコニコ動画(たまに見るんです)に1時間でテトリスを作るという動画があった。
これ↓

300行そこそこのソースコードでそこそこ動くテトリスができてた。すげ~。
っで、触発されたわけでもないが、ちとGUIプログラムを組んでみたくなり、なんかいいライブラリ無いかなと探してたりする(Win32APIを直接構う気力はない・・・)

有名どころで、Qt、wxWidgetなどがあるが、ためしにという割には巨大すぎる。
(最初は慣れようという意味合いもあり、上記のテトリスをC++的にしてみようと思うのだが・・・)
っで、よさ下なのがWTLだったのだけど、ATLというライブラリが必要で、ATLはVisualStudioに入っているという・・・
それだけのためにそんなものを入れる気力もなく(そもそも僕のノートPCの容量では入れたくないというか・・・)
う~ん、適当な何かはないだろうか・・・

2009-11-07

カレー

カレーを作ってみた。
といってもカレールーを入れてというのではなく、ゼロから。
(カレールー使って作るんならブログに書くようなことではないし)

こっちでカレールーを買うとなるとかなり高い。1パック(ゴールデンカレーの小さいの)5ユーロとかする。高すぎ!
ということで、スパイスから作ることに。
【材料】
ジャガイモ 大4つ
鶏肉 どんなもんだか知らん、500gくらい?
たまねぎ
トマトピューレ
クミンシード
ローリエ
唐辛子
マギーキューブ

胡椒
味の素
-- 以下 ホワイトカレーソース(?)
小麦粉
牛乳
マサラ粉
--

【作り方】
たまねぎをスライス。鍋に油、クミンシードをいれ、たまねぎを茶色になるまで炒める。鶏肉投入。塩コショウ投入。いい感じになったらジャガイモ、水をいれ、マギーキューブ、ローリエ、トマトピューレ、唐辛子を投入。煮る。
その間にカレーソースを作る。ホワイトソースにかなり大目のマサラ粉を入れるだけ。気合で作る。多めに作った方がとろみが出やすい。できたら鍋に投入。
煮る、煮る、煮る。
出来上がり。

ジャガイモのでんぷんと小麦粉のグルテンでとろみがでます。一日経つとマジでカレーになってます。
適当にスパイスを足すとより風味が出るかも。
後は適当に。
たまには手作りカレーもいいもんですぜ!!

2009-11-03

オランダ語学校

新参者かつオランダ語がしゃべれない人用にオランダ政府が超格安(?)で学校の手配をしてくれる。
拒否権はないので、行くしかない・・・

ということで昨日が初日だった。学校に行くまでには仕事が見つかっているだろうとの目論見から夜間の部を選択。
(実際は・・・見つかってはいたりするが、まだ働いてない・・・)

っで、行ってみてびっくりしたこと。
1. 新参者(オランダに1年以内に来た人)は僕一人
2. ほとんどの人はオランダ語がしゃべれてるじゃん!!
3. 19年オランダに住んでる人が同じクラス
4. クラスの7割がトルコ人

トルコ人たちは(当然?)英語が話せない。僕はトルコ語が話せない。彼らとコミュニケーションをとるかどうかは分からんが、やるとしたらオランダ語になるのだろうか?
いい環境にいると思い込むとして、勉強するか・・・

2009-11-01

Perl: CGI.pmで気づいたこと

PaypalでIPNを受信する件は無事何とかなった。
解決するまでに3時間くらい必要だったが・・・
(んでもって、失敗していた理由が送るはずのパラメータを送ってなかったとか、それが間違っていたとかそんな話だったりする・・・-_-;)

PaypalのIPNはデータをPostで送信してくるので、追加のパラメータ(自分とこで必要なもの)をクエリーストリングで追加することにした。
方法は、Paypalのショッピングカート画面を開く際のパラメータの一つ「notify_url」で、コールバックURLの後ろの「?key=value」ってやっただけ。まぁ、「?、&、=」辺りはお約束の「%~」に変換する必要はあるけど。

っで、RubyとかPythonとかPHPとか使えない(使わない)僕はPerlのCGI.pmを使って送信されたデータを取得しているわけだが、普通にCGI.pmのparamメソッドを使っても追加パラメータが取れない。
でも、URLの末尾には「?key=value」がくっついてる・・・
しょうがないので$ENV{"QUERY_STRING"}で取得して、自前でパースした。
試してない上に、ドキュメントも読んでいないので憶測に過ぎないが、
送信メソッドが「Post」の際、CGI.pmはクエリーストリングを取りに行かないのかな?
理由はなんとなくわかるし、それがただし動作な気はするが・・・
(逆をやったら、おかしなことが起きるだろうし・・・、GETの時に標準出力から読むっての)
おかげで、数年ぶりくらいにこんなコード書いた。
my @query = split("&", $ENV{"QUERY_STRING"});
my %hash;
foreach (@query) {
  my ($key, $value) = split("=");
  $hash{$key} = $value;
}
実際は、$value =~ s/%([0-9a-fA-F]{2})/pack('H2', $1)/eg とか入れる必要があるだろうけどね・・・

Paypal: よく分からん

玩具販売サイト構築の話。
支払方法としてPaypalを利用するというところが決まっていて、PaypalのPDTとIPNについて調べて動作確認しているとろこなのだが、いまいちよく分からん。
なんというか、う~ん。ぶっちゃけ何が送られてくるのかわからんのがいかん。
IPN simulatorでも使ってみるかな・・・

ちなみに、PDTとIPNの違いについてはこの辺が分かりやすかった。
同期通信か、非同期通信かの違いなんだけどね。
しかし、何とかしてIPNに追加パラメータを渡せないかな。
そもそも、今のところIPNを上手く受信できて無いが・・・

2009-10-31

MySQL: 涙が出そう・・・

最近、MySQLを使っている。自分用ではない。自分用なら間違いなくPostgreSQLを選ぶと思う・・

MySQLは他のRDBMSと違って、SQLにくせがある。拡張SQLというか制限SQLというかとにかく不便。Update関係で自己相関クエリが使えないのは以前書いたけど、Viewの中でselect句を使って結合ができないとは思わなかった・・・

こんなのはNG:
CREATE OR REPLACE VIEW adult_member AS
SELECT m.name, m.age
FROM (SELECT * FROM member WHERE age >= 20) AS m;
そんな・・・さすがに困るなぁこれ・・・
将来的にはOKになるらしい。ソースはここ

個人的Q&A
Q:将来まで待てない状態の人はどうしたらいいのでしょう?
A:from句の中を別viewにすればOKです。

もうね、涙がでるよ、マジで・・・

2009-10-27

IE6: フリーズする

玩具販売サイトの話。
経緯はこの辺
(といっても、2行しか書いてないが・・・)

通常はFirefoxで開発して、確認でIE6とかを使っている。
(Firebugいいよ~)
っで、持たせてたデータをファイルからMySQLに移行したら、IEがフリーズするようになった・・・orz
理由はいまいち分からない。
考えられそうな理由
  1. Javascriptで変なことがおきている
  2. CSSの解釈で起こしなことがおきている
  3. DB接続が遅すぎてTimeout
よく考えると、3はありえなかったりする。
単にAjaxでhtml取ってきてるだけだし・・・

なぜだ?
IE6だからか?

2009/10/28 追記

原因が分かった。
prototype.jsのAjax.Updater(たぶんRequestでも)で、asynchronous(非同期通信)をfalseにすると起きてた。
まぁ、Ajaxのいいとこを殺していたので(理由もあったのだが)オプションを除去。
そのページはAjax通信だけで4~5ほどあったので、なんとなく納得。っが、FirefoxはOKだったのはなぜだ?
同時通信数増やしてたっけ?

2009-10-26

SQL: MySQLで更新、削除時に起きた問題

こんな感じのクエリーが動かない。
delete from 
   child
where id in
    (select p.id as id
    from parent p
    left join child c
    on p.id = c.id
    where c.id is null);
SQLの内容自体はよくありそうな、親テーブルと子テーブルを左側外部結合して、親テーブルにはあるけど子テーブルにはない行の削除といった感じ。
Oracle、DB2、PostgreSQLでは動いた記憶があったので、当然MySQLでもいけるだろうと思ったら動かない。
こんなエラーが出た。
ERROR 1093 (HY000): You can't specify target table 'child' for update in FROM clause
(適当な)訳:更新にはFROM区で指定した特定のテーブル「child」を使えないよ~ん。

調べてみた。
どうやら、このタイプのクエリは自己相関サブクエリというらしい。
ソースはここ
鬼かと・・・

解決方法を考えてみた。
1.所詮はプログラムで行っているのだから、クエリーを2回投げればいいじゃん。
2.Viewを一個こしらえれば回避できるらしい。
3.そもそもこんなクエリ投げるってことはデータの持ち方がおかしいのでは?
4.気合で解決方法探してみる・・・
4は方法じゃないね。

誰かいい方法知りませんか?

2009-10-24

C++: MingwでWindowsDLLを使う

Mingw GCCでVCとかでコンパイルされたDLLを使う方法。
この辺参考。

pexportsを使ってDLLの中で定義されている関数を抜き出す。
その後、そいつを使ってDEFファイルを作る。
んで、Mingw付属のdlltoolを使って「.a」ファイルを作って完了。

字面は簡単、実際は面倒だった。
リンカ実行時に表示される、「undefined reference "hogehoge@4"」みたいなのを全部洗い出して、上記のDEFファイルに書き込む必要がある。しんどい。
この辺の互換性って何とかならんのかなぁ・・・

2009-10-17

ぼくらの

漫画の話。アニメではない。
実際のところ、この作品との出会いはアニメのオープニングテーマなのだが。
っで、全10巻読んでみた。

感想:よくこんなの思いついたな作者・・・
基本設定は、別次元の地球と存在をかけての戦い。方法はどっかから与えられたロボット。
操縦者はロボットを操る力を得る代わりに戦闘終了後に必ず死亡。
「勝って地球を守って死ぬか」「負けて地球と一緒に死ぬか」の2択。
選ばれた時点で(最終的には自分で契約する必要があるが)、「死」確定。

内容は面白い。というか考えさせられる。
しかし、パラレルワールドと戦うってどっかで見た設定だな。
ポンコツのヘルメット被って、木刀で戦う高校生だった気がするが、なんだっけ?
思い出せん・・・

2009-10-14

StyleSheet: 高さの異なるカラムを揃える

まさにタイトルどおりの話。
この辺を参考にした。

なるほど、:afterを隠しておいて、必要になったら勝手に表示といた感じかな?
かなり面白い。多分高さ32768pxまで対応してるんだろう。なぜこの数値なのかはよく分からんが?
ブラウザが認識する最大値かな?

ソースが載ってなかったので載せておこう。
#content {
    text-align: center;
    margin:0 auto;
    overflow:hidden;
    /* width: 700px; *//*これ僕は必要なかったので削除*/
}
#content:after {
    content:".";
    display:block;
    height:0;
    clear:both;
    visibility:hidden;
}

#column1, #column2, #column3{
    float:left;
    padding-bottom:32768px;
    margin-bottom:-32768px;
}

#column1 {
    float: left;
    width: 20%;
}

#column2 {
    float: left;
    width: 40%;
}

#column3 {
    float: left;
    width: 35%;
}
幅は適当に変えた。
後は、それぞれのIDを持つHTML要素を作るだけ。
ずっと探していたがようやっと見つかったわぁ。
(前にも見つけた気はするが・・・)

タグがprogramになってるけど、あまりそれ以外に選択肢がなかったから・・・
(増やしたくないという理由で・・・)

2009-10-12

C++: expatを使ってみた

激しく今更感があるがexpatを使ってみた。
ちなみに、expatはSAXでXMLを扱うためのライブラリ。C言語で実装されてるけど、問題なくC++で使える。

RSSを読み込んでデータ型に落とし込もうということをしてみたんだけど、意外と難しい。
SAXってイベント駆動型のAPIなので、全部自前で管理するのだが、結構どうしたもんかなと言うときがある。
基本の動きとしては、
開始エレメント -> 中身 -> 終端エレメント
という感じで動くんだけど、
こんな感じのXMLだとえらいことになる
<hoge>
  <fuga>中身</fuga>
</hoge>
XMLは性質上、空白文字とかもテキストノードとして扱うので、イベントがこんな感じになる。
hoge開始
 ↓
改行文字及び、空白文字
 ↓
fuga開始
 ↓
中身の文字
 ↓
fuga終了
 ↓
改行文字
 ↓
hoge終了

正直、無駄イベントが多すぎな印象。こんな場合個人的には、改行文字と空白文字を除いてほしいのだが、そうもいかんらしい。自前で無視するか、イベントハンドラを追加するか・・・悩ましい。

2009-10-10

Javascript: 苦労した話

JavascriptでIFrameを扱う話。
「tmpl.js」という誰かが作っているライブラリを見つけ、便利そうだったので使おうかと考えた。
この辺
incl.jsで外部HTMLを読み込んで、tmpl.jsで文字列の置換を行うつもりだった。
こんな感じ。

本体
<include id="navi.html"></include>

外側
{ヘッダー部分(tmpl.jsとかとか)}
<a href="hoge.html">{something}</a>

上手くいかなかった。
正確にはFirefoxでは動くがIEではだめといった感じ。
あきらめて、prototype.jsとAjaxにした。
読み込んだ後にごりごり文字列の置換を行っただけ。

同じようにIFrameで別ページを読み込んで、中身だけ取り出そうと試みた。
外側のHTMLではAjaxを使ってデータを取得し、中身だけ取り出す、そうすることでサイトの外観の定義を一箇所にできるかなぁなんて思ったり。
無理だった。
理由:遅延処理のせい。
IEのIFrameにはonreadystatechangeなんてのがあるし、Firefoxは単にonloadに入れればいいだけじゃん、外側はonloadで読み込んでるし。
こんな感じで。
if (/*@cc_on ! @*/ false) {
  iframe.onreadystatechange = function() {
    if (this.readyState == "complete") {
      doSomething(this);
    }
  }
} else {
  iframe.onclick = function() { doSomething(iframe);}
}
安易でした・・・orz
問題はdoSomethingの中の処理なんだけど、IFrameから中身の文書を取り出すときに、contentWindowをが必要になるんだけど、IEではnullになってる。
やり方が悪いんだと思うんだけど、あきらめて力技でやることにした。

IE7とか8ならいけるのだろうか・・・
未だにIE6が必要なのかも怪しいが・・・
(とはいっても、僕の環境はIE6。メインがFirefoxだからという理由)