Fork me on GitHub

2008/02/28

はてな
結構難しかった...
オリジナル作者はLDRizeやMinibufferを作られたsnj14さん。
初めてminibufferbookmarkcommandを使った時は「スゲー」と感動しました。その後ソースがCodeReposで管理される用になりプラガブルな仕組みに修正させて頂き、gooブックマークや、niftyクリップ、pookmark等のプラグインも動くようになりました。
ただFirefoxでは動くけど、Operaでは動かなかった。
Firefoxだけでしか使えないってのが擬かしい程、使い勝手はめちゃめちゃ良くて
「minibufferBookmarkcommandのボタン一発ブックマークが気軽すぎてタグ付けとかしなくなる」
とおっしゃる方もいる位。ポップアップも出ないし別画面に飛ばされる訳でもないから、記事を読んでる最中に「ぶくま!」と思ったら「b」一発。
タグやコメントが打ちたくなったら「B」。常用しだすと手放せなくなります。
で、この快感をOperaユーザにも伝えたい。そう思いました。
Operaでは通常の作りをしていてはドメインを越えた通信(JSON以外)は出来ないのですが、postMessageというAPIを使うことでコンテンツ間のメッセージングが行えるようになります。
これを使用して、GM_xmlhttpRequestもどきを実装しています。ただし困ったのがこのpostMessageに送り出す文字列(HTML)を取得する為にはオブジェクトをメインコンテンツに追加する必要がありかつ追加するという事はGET限定、つまりPOSTを実行させる為にはドメインを越えられる別のPOST実装が必要になるって事に。
で、結局やったのが動的にiframeを生成して、その中にformを作りポストするという方法。
いろいろやっている内に、DOM追加で動くGET版とiframeを使うPOST版を纏めたGM_xmlhttpRequestみたいな物がなんとなく出来上がりました。
(完全ではありません)

これで行ける!と思ったのですが今度はdel.icio.usのタグを取得する方法で困った。このpostMessageに送り出すにはDOMContentLoadedをフックするのだけれど、del.icio.usのAPIからXML形式のタグ一覧を読み込んだ時にはDOMContentLoadedが走らない。
悩んだ挙句、一度「http://del.icio.us/」にアクセスし、ユーザ名称を見つけ、「http://feeds.delicious.com/feeds/json/tags/XXXX」にアクセスし、JSONを取得するという方法で実装しました。
ようやく
が使えるminibufferbookmarkcommandが出来上がりました。ふぅ
Operaユーザの方で、SBMをお使いの方は一度試して見て下さい。
minibufferbookmarkcommand.js
なお作成にあたっては、Opera版のLDR Full Feedを作成されたos0xさんのコードをふんだんに参考にさせて頂いております。感謝。

2008/02/27

はてな
追記
都合上、キーを「g」から「z」に変更させて頂いています。
以下読み替えて頂く様お願い致します。

まぁ、お約束って事で。
しかしまぁLDRで全文取得表示するグリモン便利だなぁ。
OperaでLDR Full Feed - 0x集積蔵

id:Constellation さん作の、LDR Full Feed - Userscripts.orgをOperaに移植してみた。
移植早ぇぇぇぇぇ!!!

って事で、os0xさんのOpera版をベースにGoogle Reader版を作ってみました。
そんなに大きな変更してません。要はos0xさんのを参考に昨日のグリモンをOperaに対応させただけ。

またまた操作は同じく、[G]のアイコンが付いてたら「g」を押下で全文取得。
とりあえず、dankogai氏のサイトでチェックして問題なさげ。(またか!)

ライセンスはLDR Full Feedに委ねます。さらにOpera固有部に関してはos0xさんのLDR Full Feed Operaに委ねます。

ダウンロード:googlereaderfullfeed.js

追記
2008/02/28

2008/02/26

はてな
まぁ、ぶっちゃけ(なくても)「はてブちゃんねる」のパクリなんですが...
単純にwith_friendsのRSSをGoogle Ajax Feed API使ってパースしてるだけです。
コードはこんな感じ。
<script type="text/javascript" src="http://www.google.com/jsapi?key=ABQIAAAAS_2fKEdj-fsDOrnYqd4nthQCjALL2TOLFFIzEhjgebS4V6SjnhTxtlSoL0NJ-Fa6B7tsqLuiiPI9Pg"></script>
<style type="text/css">
.twitter-2ch {
    background-color: #efefef;
    width: 400px;
    color: #000000;
    font-family: 'MS PGothic',sans-serif;
    padding: 1.0em;
}
#twitter_2ch_container a:visited {
    color: #660099;
}
#twitter_2ch_container a:active {
    color: #ff0000;
}
.twitter-2ch-title {
    color: red;
}
</style>
<script type="text/javascript"><!--
function twitter_2ch() {
  var container = document.getElementById("twitter_2ch_container");
  container.innerHTML = "";
  var img = document.createElement('img');
  img.src='http://mattn.kaoriya.net/images/ajax-loader.gif';
  container.appendChild(img);

  var twitterId = document.getElementById("twitterId").value;
  var feed = new google.feeds.Feed('http://twitter.com/statuses/friends_timeline/' + twitterId + '.rss');
  feed.setNumEntries(10);
  setTimeout(function() {
    feed.load(function(result) {
      if (!result.error) {
        var html = "";
        for (var i = 0; i < result.feed.entries.length; i++) {
          var entry = result.feed.entries[i];
          var link = entry["link"];
          var pubDate = new Date(entry["publishedDate"]).toLocaleString();
          var content = entry["content"];
          var author = content.replace(/:.+$/, '');
          var status = content.replace(/^[^:]+: /, '');
        html += (i+1) + ':<a href="' + link + '">以下、名無しにかわりましてfollowerがお送りします。</a>:' + pubDate + ' ID:' + author + '<br />';
        html += '<blockquote>' + status + '</blockquote>';
        }
        container.innerHTML = html;
      }
    });
  }, 100);
}
google.load("feeds", "1");
--></script>
<div class="twitter-2ch">
<span class="twitter-2ch-title">今何してる?</span>
twitter id:<input type="text" id="twitterId" value="mattn_jp"/>
<input type="button" onclick="twitter_2ch();" value="twitter→2ch"/><br />
<br />
<div id="twitter_2ch_container"></div>
</div>
で、実行画面は以下の通り

続きを読む...


はてな
vimのオライリー本が出るようです。

Learning the vi and Vim Editors Learning the vi and Vim Editors
Arnold Robbins
Oreilly & Associates Inc / ¥ 2,917 (2008-07)
 
発送可能時間:通常9~13日以内に発送


これまでに私が買ったvi/vim本は

viデスクトップリファレンス (UNIX text processing) viデスクトップリファレンス (UNIX text processing)
Arnold Robbins
オライリー・ジャパン / ¥ 840 (1999-06-15)
 
発送可能時間:在庫あり。


vi (Linux magazine books) vi (Linux magazine books)
金光 雅夫
アスキー / (2000-09)
 
発送可能時間:


ViIMproved‐Vim完全バイブル ViIMproved‐Vim完全バイブル
Steve Oualline
技術評論社 / (2004-05)
 
発送可能時間:


くらいかな。
誰か翻訳してくれ。

素のviって1冊もあれば基本は網羅出来てしまうんで、vim本には基本部分(viコンパチな部分)って書かなくてもいいよ。
特にvi/vimの歴史とか、もういらんし。
Posted at 10:56 in ソフトウェア::vim | WriteBacks (0)
Tagged as: book, vi, vim
Bookmarks: add to hatena add to hatena | add to delicious.com | add to livedoor.clip add to livedoor.clip | add to buzzurl add to buzzurl | add to fc2bookmark add to fc2bookmark | add to Yahoo Bookmark add to Yahoo Bookmark | add to Pookmark add to Pookmark

2008/02/25

はてな
追記
都合上、キーを「g」から「z」に変更させて頂いています。
以下読み替えて頂く様お願い致します。
LDRで全文取得表示するグリモン便利だなぁ。
LDR Full Feed 0.0.6
gをぺちって押してLDRで全部全文読んじゃおう。
「g」押すだけなんて!!!
でもLDR使ってない!!!

って事で、Google Readerにサクサクっと移植してみました。
そんなに大きな変更してません。SITEINFOも同じ場所を使っています。
オリジナル作者様、もし同じSITEINFOを見る事に問題があれば、ご連絡下さい。
即効でグリモン毎、削除させて頂きます。


操作は同じく、[G]のアイコンが付いてたら「g」を押下で全文取得。
とりあえず、dankogai氏のサイトでチェックして問題なさげ。

ライセンスはLDR Full Feedに委ねます。

ダウンロード:googlereaderfullfeed.user.js

googlereaderfullfeed
dankogai氏のサイトの全文です。dankogai氏問題があればご連絡下さい。
キャプチャを削除させて頂きます。

はてな
私の場合、xargsの引数がオーバーする程のファイルを扱う時は、少し怖いので一度別のディレクトリに移動してから削除するなりをやってます。
また、数十個の場合ならばfindだけでやってしまいますね。その方が思考が止まらないし...。
ただ、findとxargsの組み合わせで結構多いのが
  • さらにその中から間引きたい
  • 実行は並び替えた結果で行いたい
といった場合が少なからずあるのです。
例えばYYYYMMDD等といった日付形式のファイル名で散乱しているファイルを日付通りに処理したい。
と言った場合、やはりsortやgrepのお世話になるのが楽ですよね。
sortやgrepを使う場合、findで-print0した結果ではフィルタフィルタ実行する事が出来ません。
こんな場合には、findでは-print0せずに
find . -name "*.txt" | grep '/[0-9]¥{8¥}¥.txt' | sort -n | tr ¥¥n ¥¥0 | xargs -0 ...
といった感じにxargsに渡す寸前でtrを使って改行コードを¥0に置き換えてやる。

もう少し手間になってきたらawkとか使うけど、ちょっとしたものならこれでもOK。例が良く無いか...
Posted at 12:53 in ソフトウェア::lang::shell | WriteBacks (0)
Tagged as: find, unix
Bookmarks: add to hatena add to hatena | add to delicious.com | add to livedoor.clip add to livedoor.clip | add to buzzurl add to buzzurl | add to fc2bookmark add to fc2bookmark | add to Yahoo Bookmark add to Yahoo Bookmark | add to Pookmark add to Pookmark

2008/02/22

はてな
最近は、Shift_JIS(Windowsでいうならcp932)には2バイト目に「¥」(0x5C)が混じった文字がある事すら知らない人が居るようで...
すこしカルチャーショックを受けたオジサンmattnです。
職場でUNIXからWindowsに移植したソースコードでコンパイルが通らない!と悩んでいらっしゃる。
そしてその原因がオリジナルを書いた人のコードが悪いと...
まぁ確かにソースコード内に日本語書いてた人が悪いのかもしれませんが...
今日はみんな知ってそうな話。知らなかったら知っといてねくらいの話。

そんなに珍しい話じゃないんですよね。ソースコード内に埋め込みの日本語って。まぁ理由はポータビリティだったり、ソースコードを簡潔に書く為だったり、単純に面倒臭かっただけだったりと(爆)...

昔は結構あったんですよ。ソースコードがeuc-JPなソースとか。

ただそれは、昔は普通にあった話で開発者なら知っておきたい事かな。
まぁここでボヤいても、その担当者には伝わらないんだろうけど。

euc-JPとは違い、Shift_JISには後続するバイトとして0x5Cが来る事があります。
例えば、「ソ」「表」「噂」「貼」など。あと「―」(DASH)もそうですね。
ソースコードの中で罫線などを書く場合によく埋め込みでDASHが書かれたソースコードってのもありました。

で、これが何故問題になるか。もうわかりますね。
C言語等のソースコードでは「¥」(0x5C)はエスケープ文字のリーダとして働くからです。
コンパイラは通常、そのソースがeuc-JPなのかShift_JISなのかUTF-8なのか知りません。javac(gcj)等では「--encoding」なんてオプションで入力ソースのエンコーディングを指定出来たりもしますが、通常のCコンパイラではそうは行きません。
Microsoft Visual C++(日本語版)のコンパイラはShift_JIS(もしくはUnicode)を特例として許しているだけです。
ソースコードは世界の誰がコンパイルしても同じモジュールを作ることが出来るべきであって、日本製のコンパイラでしかビルド出来ないソースってのは異端児もいいところかと。
まぁソースコードに生マルチバイト書くなんて...ってのが本筋ですが。

今日は、古き良き(?)時代のジョークプログラムをWindowsに移植する時の注意点を示してみます。

昔、UNIXで「ls」を「sl」とタイプミスした時に、端末上にSLが突っ走るジョークプログラムがありました。
私も気に入って入れたりもしました。
「sl」も気に入っていたのですが、改変版の「quit」がさらに好きでした。
さすがにshellをsqlplusなんかと間違う事は無かったので本気でshellに「quit」と打ち込むことは無かったですが、「もう来ねぇよ!」と端末を走るAAが気が和んで楽しかったです。
で、そのquitですが私が確認した所
福地さんののページにある
ショートショートプログラムの部屋
にバージョン1.2aとして置いてありました。
さっそくダウンロードし解凍。
まずeuc-JPで書かれているソースをShift_JISに変換するのですが、ここで問題が起きます。
上でも述べた様に、Shift_JISには後続するバイトに「¥」(0x5C)を持つ物があるのですが、このquitのソースに記述されている「―」(DASH)は、Shift_JISで表すと「0x81 0x5C」というバイト列。つまりうかつに変換してしまうとC言語のエスケープ文字を自ら作ってしまう事になるのです。
案の定、以下の様にnkfで変換したソースはそのままコンパイルする事が出来ません。
C:¥temp¥quit-1.2a>nkf -g *
Makefile:ASCII (LF)
quit.1:EUC-JP (LF)
quit.c:EUC-JP (LF)
quit.h:EUC-JP (LF)
quit.txt:ASCII (LF)
README:EUC-JP (LF)

C:¥temp¥quit-1.2a>mkdir tmp

C:¥temp¥quit-1.2a>copy quit.c + quit.h tmp
quit.c
quit.h
        1 個のファイルをコピーしました。

C:¥temp¥quit-1.2a>nkf -EsX quit.c > sjis_quit.c

C:¥temp¥quit-1.2a>nkf -EsX quit.h > sjis_quit.h

C:¥temp¥quit-1.2a>del quit.c quit.h

C:¥temp¥quit-1.2a>rename sjis_quit.* quit.*

C:¥temp¥quit-1.2a>mingw32-make CC=gcc CFLAGS="-O -DJAPANESE=1"
gcc -O -DJAPANESE=1 -o quit quit.c -lncurses
quit.c:47:49: warning: unknown escape sequence '¥|'
quit.c:47:49: warning: unknown escape sequence '¥|'
quit.c:47:49: warning: unknown escape sequence: '¥201'
quit.c:47:49: warning: unknown escape sequence '¥|'
quit.c:238: error: stray '¥26' in program
quit.c:238:2: warning: no newline at end of file
mingw32-make: *** [quit] Error 1
※ギコ猫版をビルドするには「-DJAPANESE=1」が必要です。
※コンパイルはMinGWで行っています。(pdcursesも必要)

で、これを修正するには「0x5C」が後続する文字の後に「¥」を付けてコンパイラがエスケープ開始文字と混同しないように教えてあげます。
例えば「―」(DASH)であれば「―¥」となります。
コンパイル結果から、一つずつ直していっても良いのですが、実はこれコンパイルエラーとなっていない場合もあります。
例えば「―t」という表示があった場合、コンパイラは変な1文字と「¥t」(タブ文字)があるかの様に振るいます。
実際の例で言えば
#include <stdio.h>
#include <string.h>

    int
main(int argc, char* argv[]) {
    const char* s = "―t";
    printf("'%s' = %d\n", s, strlen(s));
    return 0;
}
のソース(Shift_JIS保存)は、Microsoft Visual C++では「―」の2バイトと「t」の1バイトで計3バイトという結果が返りますがMinGWでは「0x81」の1バイトと「¥t」の1バイトで計2バイトの結果となります。

まぁ、MSVCでコンパイルするからいいや...という方はこのままでも良いのですが、今回扱うquitはUNIX流のソース。ヘッダに「unistd.h」もincludeしてますからそのままのソースコードではビルド出来ません。
mingwならば例えば以下の様なフィルタプログラムを使うのが良いでしょう。
#include <stdio.h>
#include <string.h>

    int
main(argc, argv)
    int    argc;
    char   **argv;
{
    char buffer[BUFSIZ];
    char *p;

    while (fgets(buffer, BUFSIZ, stdin) != NULL) {
        for (p = buffer; *p != 0; p++) {
            if (*p & 0x80) {
                putchar(*p++);
                if (*p == '\\') putchar(*p);
            }
            putchar(*p);
        }
    }
    return 0;
}
このソース、実はvimのpoディレクトリにあるsjiscorr.cからパクってます。
(とは言ってもsjiscorr.cも元はと言えば私がbram氏に送ったソースですが...)

これを
C:¥temp¥quit-1.2a>type quit.c | sjiscorr > esc_quit.c

C:¥temp¥quit-1.2a>type quit.h | sjiscorr > esc_quit.h

C:¥temp¥quit-1.2a>del quit.c quit.h

C:¥temp¥quit-1.2a>rename esc_quit.* quit.*
の様にすればOK。一連の流れを一回でやるならば
C:\temp\quit-1.2a>nkf -EsX quit.c | sjiscorr > sjis_quit.c

C:\temp\quit-1.2a>nkf -EsX quit.h | sjiscorr > sjis_quit.h

C:\temp\quit-1.2a>del quit.c quit.h

C:\temp\quit-1.2a>rename sjis_quit.* quit.*
ってやった方が速いですね。

あとはビルド。GNUWin32にあるPDCursesのページにある「Developer files」、「Binaries」をダウンロードしてMinGW環境に入れた後、Makefile内にある「-lncurses」を「-lcurses」に修正し
C:\temp\quit-1.2a>mingw32-make CC=gcc CFLAGS="-O -DJAPANESE=1"
とすれば出来上がり。
かと思いきや、usleepがリンクエラー。こればっかりは仕方ありませんね。
--- quit.c.orig Fri Feb 22 12:14:24 2008
+++ quit.c  Fri Feb 22 12:14:53 2008
@@ -6,6 +6,10 @@
 #include <ncurses.h>
 #include <signal.h>
 #include <unistd.h>
+#ifdef _WIN32
+# include <windows.h>
+# define usleep(x) Sleep(x/1000)
+#endif
 
 #include "quit.h"
 
こんなパッチでusleepをSleep(1000分の1)で誤魔化してビルド。
見事以下の様にquitがネイティブ実行出来る様になりましたとさ。
※但しcurses2.dllは実行PATH環境に必要

quit-win32

で、何の話でしたっけ...

追記
いわたさんからご意見頂きました。
いわた @mattn_jp -finput-charset=cp932 -fexec-charset=cp932 への言及もおながいします。
って事でコンパイルを、いわたさんの言う様に「--finput-charset」指定でする事も重要ですね。特に「¥uXXXX」な文字列や「L"XXX"」なんかは上の方法では変換出来ませんしね。
また最近のUNIX環境ではオリジナルソースのまま「--finput-charset=euc-JP」、「--fexec-charset=utf-8」指定で(setlocaleもいるかな?)コンパイルする事が出来ますね。

今回の上の方は他の(MSVC以外の)Windows用コンパイラで有用だ...って事で。
Posted at 12:39 in ソフトウェア | WriteBacks (0)
Tagged as: tomb
Bookmarks: add to hatena add to hatena | add to delicious.com | add to livedoor.clip add to livedoor.clip | add to buzzurl add to buzzurl | add to fc2bookmark add to fc2bookmark | add to Yahoo Bookmark add to Yahoo Bookmark | add to Pookmark add to Pookmark

2008/02/21

はてな
はてなスクリーンショットに微笑むblosxomプラグイン作りました。
普段は微笑みませんが、はてなスクリーンショットに「ハイ!ポーズ!」と言われるとスマイルを振りまくのです。

以下証拠写真
はてなスクリーンショット - http://mattn.kaoriya.net
で、blosxomプラグインのソース
package hatenascreenshot;
use strict;

use vars qw($smile);
my $photo = '<img src="お好きな画像">';

sub start {
  $smile = $photo if ($ENV{'HTTP_USER_AGENT'} =~ /HatenaScreenshot/);
}

1;
あとはフレーバに$hatenascreenshot::smileを入れるだけ。
お好きな画像で微笑んでみてはどうでしょうか?

決してウンコとかは辞めましょう。
※まぁネタですから...

2008/02/18

はてな
実はこのサイトは昔、私専用のローカル環境に用意した非公開なウェブサイトでした。
そして、そのサイトは今と同じくblosxomというブログツールで構築されていました。
私はその頃、今の様にvimで直接HTMLを書くのではなく、emacs環境から生まれた
howm: 一人お手軽 Wiki もどき
というメモ取り環境のvimクローン、「howm_mode.vim」を使い、その書き込みをblosxomに食わせる(拡張子をtxtでなくhowmにする)という方法で使用していました。

最近はhowm_mode.vimを使わなくなったのですが、先日howm_mode.vimを改造しておられる方を見つけ、ひっそりとウォッチしていました。
で、本日どうやら公開された様です。
48 howm-mode.vim (2-25) パッチの公開とそのあてかた
以前からぐずぐず言ってたパッチを公開。ついでに Windows 環境でのパッチのあてかたを書いた。
試しに本体をhowm_vimのサイトから、パッチをパッチ作者殿のページから落とし当ててみました。

始めは動きませんでしたが、少し弄った所すこぶる快適に動き出しました。
日本語での検索や、migemo/cmigemoを使った検索、空白を含んだhowm_dirディレクトリでも問題なく動作しました。
ありがとうございます。またしばらくはメモ取りとしてhowmを使ってみようかなぁ...って思いました。

で、今回修正したパッチはmatchendを使ってディレクトリを掘る部分。
matchendの第2引数は正規表現が入力可能なので、以下の様にescapeしました。
diff -cr howm_vim.orig\plugin\howm-mode.vim howm_vim\plugin\howm-mode.vim
*** howm_vim.orig\plugin\howm-mode.vim  Mon Feb 18 16:41:24 2008
--- howm_vim\plugin\howm-mode.vim   Mon Feb 18 16:15:40 2008
***************
*** 440,446 ****
  
    if editing != filepath
      let howm_dir = s:HowmExpand(g:howm_dir)
!     let idx = matchend(filepath, howm_dir)
      if idx != -1
        " 存在しないディレクトリ下のファイルを指定されたら,ディレクトリを作る
        call s:MakeDirectory(substitute(strpart(filepath, idx), '[^/]*$', '', ''))
--- 440,447 ----
  
    if editing != filepath
      let howm_dir = s:HowmExpand(g:howm_dir)
!     let g:hoge = howm_dir
!     let idx = matchend(filepath, escape(howm_dir, ' \~'))
      if idx != -1
        " 存在しないディレクトリ下のファイルを指定されたら,ディレクトリを作る
        call s:MakeDirectory(substitute(strpart(filepath, idx), '[^/]*$', '', ''))
注意:このパッチは、オリジナルからパッチ作者殿のパッチを当てた物からの差分です。

皆さんもメモ取り環境としてhowm_mode.vimを使ってみられてはどうでしょうか。
ちなみに、以前私が使っていた頃のtips。私はmigemoでなくcmigemoを使っているので
let howm_migemoprg='cmigemo'
let howm_migemoopt=' -q -d "'.globpath(&runtimepath,'dict/migemo-dict').'" | nkf -Ew'
としています。
また検索で全部出て欲しい場合もあったので、「¥,A」で検索かつ<c-n>,<c-p>で移動、さらに「o」で開ける様
nmap <silent> <leader>,A <leader>,g^=.*<cr>
autocmd BufEnter howm\ Search\ result nmap <buffer> <c-p> kp
autocmd BufEnter howm\ Search\ result nmap <buffer> <c-n> jp
autocmd BufEnter howm\ Search\ result nmap <buffer> o :exec "sp " . b:file{line('.')}<cr>
と設定しています。
vimぽいmapleaderや、GNUWin32ツールなんかを組み合わせていますので、howm関連だと全体で
let g:howm_mapleader='\'
if has('win32')
  let howm_grepprg='grep'
  let howm_findprg='find'
  let howm_html2txtcmd='c:/cygwin/bin/w3m -dump -cols 78 %s'
endif
let howm_migemoprg='cmigemo'
let howm_migemoopt=' -q -d "'.globpath(&runtimepath,'dict/migemo-dict').'" | nkf -Ew'
let howm_quotemark='> '
nmap <silent> <leader>,A <leader>,g^=.*<cr>
autocmd BufEnter howm\ Search\ result nmap <buffer> <c-p> kp
autocmd BufEnter howm\ Search\ result nmap <buffer> <c-n> jp
autocmd BufEnter howm\ Search\ result nmap <buffer> o :exec "sp " . b:file{line('.')}<cr>
こんな感じに設定しています。(私はcygwinにはパスを通さない派です)
使い始めると、意外とやみつきになりますよ。

追記
パッチ作成者殿へのリンクが間違っていました。
Posted at 17:31 in ソフトウェア::vim | WriteBacks (3)
Tagged as: howm, howm_vim, vim
Bookmarks: add to hatena add to hatena | add to delicious.com | add to livedoor.clip add to livedoor.clip | add to buzzurl add to buzzurl | add to fc2bookmark add to fc2bookmark | add to Yahoo Bookmark add to Yahoo Bookmark | add to Pookmark add to Pookmark

2008/02/14

はてな
なんだかtwitterではハート祭りが繰り広げられている様で...
twitter-heart
どうやら「<3」でハートマークが付くようです。
今日はバレンタインデーって事で、こんなもん作ってみました。
WWW::Mechanize::AutoPagerでfriends全員をハッシュ一覧化し、Net::Twitterで全員にこのハートを送るperlスクリプトを作ってみました。
宜しければどうぞ!
って私はやりませんが...
※ちなみに本気でやるなら、ちゃんとsleep入れて下さいね。

#!/usr/bin/perl

use warnings;
use strict;
use WWW::Mechanize;
use WWW::Mechanize::AutoPager;
use Web::Scraper;
use Net::Twitter;

my $username = 'username';
my $password = 'password';

my $twitter_friends = scraper {
    process 'tr.vcard',
        'friends[]' => scraper {
            process 'td strong a', name => 'TEXT';
        };
    result 'friends';
};

my $u = 'http://twitter.com/friends/';

my $mech = WWW::Mechanize->new(timeout => 10);
$mech->add_header('Accept-Encoding', 'identity');
$mech->get('http://twitter.com/login');
$mech->submit_form(
    form_number => 2,
    fields    => {
        username_or_email  => $username,
        password           => $password,
    },
    button    => 'commit',
);

$mech->autopager->load_siteinfo();
my $friends;
while($u) {
    my $res = $twitter_friends->scrape( $mech->get($u)->content );
    eval { push @$friends, @{$res}; };
    last if ( $@ or !defined($mech->next_link) );
    $u = $mech->next_link;
}

my $twit = Net::Twitter->new( username => $username, password => $password );
foreach my $friend (@$friends) {
    my $name = $friend->{name};
    $result = $twit->update("\@$name <3");
}
って俺、男だ。

はてな
Flickr Uploadrがオープンソースで公開された模様です。
Flickr Uploadr: Open Source and Powered by XULRunner (Yahoo! Developer Network blog)
Flickr Uploadrは昔からあったのですが、XULを使ったオープンソースアプリケーションとして公開されました。
ライセンスはGPLv2で、ライセンスに従えば改造して公開する事も出来る様になりました。

ただし日本語ロケールがない。
中身を見るとそんなに量がなかったので、えいや!と翻訳してみました。
mattnが「日本だったらこういう言い回しだよなぁ」っていう感じで意訳しています。間違ってたら教えてください。
以下その翻訳物のインストール方法です。Windowsの場合のみ説明しますが、おそらく他の環境でも同じ様な作業になるかと思います。

続きを読む...


2008/02/13

はてな
ShareOnTumblr
「CShellExt::QueryContextMenu」でやれば出来なく無いけどコストがデカイし別のシェルエクステンション混ぜると落ちたりするんですよね。
Gyazowin tumblr for Windowsにファイルのアップロード機能を追加して名前をGyamblr for Windowsに変更 « ZeroMemory
Windowsのコンテキストメニューのコピーとかにcopy to tumblrみたいなのを追加できないかなと思ったんだけど、標準のやつはともかくアプリケーションの右クリックはアプリケーション管轄で制御されていてWindowsシロウト同然の自分には外からいじれなそうだったのであきらめました。
本当は「CShellExt::QueryContextMenu」でやるのがいいんだろうけど、今回はコマンドラインユーザでも使える様にコマンド形式で「送る」に登録する方法にした。

続きを読む...


2008/02/12

はてな
id:miyagawa氏のはてなブックマークからyowlという物を見つけました。
yowl - Google Code
yowlとは、Mac OS X上で実装されている通知システムのアプリケーション実装「Growl」をYahooライブラリYUIを使ってWeb実装した物です。
さっそくダウンロードして使ってみましたが、やっぱりYUIは良く出来てますね。
Windows用にシステムトレイ常駐の通知アプリケーションと連携すれば、Webからデスクトップアプリケーションとして何かしらを通知出来るという事になります。
通知時のアクションが決められれば、夢の広がるアプリケーションになるでしょうね。
今日はサンプルとして、以前つくった「はてブでアーーーーッ!!!」をYOWLでやってみたいと思います。

少し色を付けて、JSDeferredとjQueryを使い、del.icio.usとパラレルで動かそうかと思いましたが、あまり面白くないのでやめて、結局JSDeferredのcall/waitのみ使わせて頂いています。

実行結果、ソースは以下から...

続きを読む...


2008/02/08

はてな
まぁ、id:tokuhirom氏が作ったwassr-todo.plがあるんですが...
(いいんです。C言語が書きたいんです!)

でっかく記事いっぱいにコードだけ...


ちなみに、json-cというライブラリとcURLを使っています。
昨日のパッチを使えばVC6でもビルド出来ます。
よろしければどうぞ。

最新ソースはCodeReposのコノ辺におきました。

#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <curl/curl.h>
#include <json.h>

#define APP_NAME                   "wassr_todo"

#ifdef _WIN32
# ifndef snprintf
#  define snprintf _snprintf
# endif
#endif

#define TODO_MODIFY_URL "http://api.wassr.jp/todo/"
#define TODO_JSON_EXT ".json"

static char* response_cond = NULL;  /* response condition */
static char* response_mime = NULL;  /* response content-type. ex: "text/html" */
static char* response_data = NULL;  /* response data from server. */
static size_t response_size = 0;    /* response size of data */

static void initialize_http_response() {
    response_cond = NULL;
    response_mime = NULL;
    response_data = NULL;
    response_size = 0;
}

static void terminate_http_response() {
    if (response_cond) free(response_cond);
    if (response_mime) free(response_mime);
    if (response_data) free(response_data);
    response_cond = NULL;
    response_mime = NULL;
    response_data = NULL;
    response_size = 0;
}

static size_t handle_returned_data(char* ptr, size_t size, size_t nmemb, void* stream) {
    if (!response_data)
        response_data = (char*)malloc(size*nmemb);
    else
        response_data = (char*)realloc(response_data, response_size+size*nmemb);
    if (response_data) {
        memcpy(response_data+response_size, ptr, size*nmemb);
        response_size += size*nmemb;
    }
    return size*nmemb;
}

static size_t handle_returned_header(void* ptr, size_t size, size_t nmemb, void* stream) {
    char* header = NULL;

    header = (char*)malloc(size*nmemb + 1);
    memcpy(header, ptr, size*nmemb);
    header[size*nmemb] = 0;
    if (strncmp(header, "Content-Type: ", 14) == 0) {
        char* stop = header + 14;
        stop = strpbrk(header + 14, "\r\n;");
        if (stop) *stop = 0;
        if (response_mime) free(response_mime);
        response_mime = strdup(header + 14);
    }
    if (strncmp(header, "Last-Modified: ", 15) == 0) {
        char* stop = strpbrk(header, "\r\n;");
        if (stop) *stop = 0;
        if (response_cond) free(response_cond);
        response_cond = strdup(header);
    }
    if (strncmp(header, "ETag: ", 6) == 0) {
        char* stop = strpbrk(header, "\r\n;");
        if (stop) *stop = 0;
        if (response_cond) free(response_cond);
        response_cond = strdup(header);
    }
    free(header);
    return size*nmemb;
}

char* get_http_data(char* url, char* user, char* pass) {
    CURLcode res;
    CURL* curl;
    char* ret = NULL;
    int status = 0;
    char auth[512];

    initialize_http_response();

    memset(auth, 0, sizeof(auth));
    snprintf(auth, sizeof(auth)-1, "%s:%s", user, pass);

    curl = curl_easy_init();
    if (!curl) return NULL;
    curl_easy_setopt(curl, CURLOPT_URL, url);
    curl_easy_setopt(curl, CURLOPT_USERPWD, auth);
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, handle_returned_data);
    curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, handle_returned_header);
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
    curl_easy_setopt(curl, CURLOPT_USERAGENT, APP_NAME);
    res = curl_easy_perform(curl);
    res = res == CURLE_OK ? curl_easy_getinfo(curl, CURLINFO_HTTP_CODE, &status) : res;
    curl_easy_cleanup(curl);
    if (res == CURLE_OK && status == 200) {
        ret = (char*)malloc(response_size+1);
        memset(ret, 0, response_size+1);
        memcpy(ret, (char*)response_data, response_size);
    }

    terminate_http_response();

    return ret;
}

char* post_http_data(char* url, char* user, char* pass, char* data) {
    CURLcode res;
    CURL* curl;
    char* ret = NULL;
    int status = 0;
    char auth[512];

    initialize_http_response();

    memset(auth, 0, sizeof(auth));
    snprintf(auth, sizeof(auth)-1, "%s:%s", user, pass);

    curl = curl_easy_init();
    if (!curl) return NULL;
    curl_easy_setopt(curl, CURLOPT_URL, url);
    curl_easy_setopt(curl, CURLOPT_USERPWD, auth);
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, handle_returned_data);
    curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, handle_returned_header);
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
    curl_easy_setopt(curl, CURLOPT_USERAGENT, APP_NAME);
    curl_easy_setopt(curl, CURLOPT_POST, 1);
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, (void*)data);
    res = curl_easy_perform(curl);
    res = res == CURLE_OK ? curl_easy_getinfo(curl, CURLINFO_HTTP_CODE, &status) : res;
    curl_easy_cleanup(curl);
    if (res == CURLE_OK && status == 200) {
        ret = (char*)malloc(response_size+1);
        memset(ret, 0, response_size+1);
        memcpy(ret, (char*)response_data, response_size);
    }

    terminate_http_response();

    return ret;
}

char* string_to_utf8_alloc(const char* str) {
    if (!str) return NULL;
#ifdef WIN32
    UINT codePage;
    size_t in_len = strlen(str);
    codePage = GetACP();
    size_t wcssize = MultiByteToWideChar(codePage, 0, str, in_len,  NULL, 0);
    wchar_t* pszStrWC = (wchar_t*)malloc(sizeof(wchar_t)*(wcssize + 1));
    wcssize = MultiByteToWideChar(codePage, 0, str, in_len, pszStrWC, wcssize + 1);
    pszStrWC[wcssize] = '\0';

    codePage = CP_UTF8;
    size_t mbssize = WideCharToMultiByte(codePage, 0, pszStrWC, -1, NULL, 0, NULL, NULL);
    char* pszStrMB = (char*)malloc(mbssize + 1);
    mbssize = WideCharToMultiByte(codePage, 0, pszStrWC, -1, pszStrMB, mbssize, NULL, NULL);
    pszStrMB[mbssize] = '\0';

    free(pszStrWC);

    return pszStrMB;
#else
    return strdup(str);
#endif
}

char* utf8_to_string_alloc(const char* str) {
    if (!str) return NULL;
#ifdef WIN32
    UINT codePage = CP_UTF8;
    const char* ptr = str;
    if (str[0] == (char)0xef && str[1] == (char)0xbb && str[2] == (char)0xbf)
        ptr += 3;
    size_t wcssize = MultiByteToWideChar(codePage, 0, ptr, -1,  NULL, 0);
    wchar_t* pszStrWC = (wchar_t*)malloc(sizeof(wchar_t)*(wcssize + 1));
    wcssize = MultiByteToWideChar(codePage, 0, ptr, -1, pszStrWC, wcssize + 1);
    pszStrWC[wcssize] = '\0';

    codePage = GetACP();
    size_t mbssize = WideCharToMultiByte(codePage, 0, pszStrWC,-1, NULL, 0, NULL, NULL);
    char* pszStrMB = (char*)malloc(mbssize + 1);
    mbssize = WideCharToMultiByte(codePage, 0, pszStrWC, -1, pszStrMB, mbssize, NULL, NULL);
    pszStrMB[mbssize] = '\0';

    free(pszStrWC);

    return pszStrMB;
#else
    return strdup(str);
#endif
}

static char* url_encode_alloc(const char* str) {
    static const int force_encode_all = TRUE;
    const char* hex = "0123456789abcdef";

    char* buf = NULL;
    unsigned char* pbuf = NULL;
    int len = 0;

    if (!str) return NULL;
    len = strlen(str)*3;
    buf = (char*)malloc(len+1);
    memset(buf, 0, len+1);
    pbuf = (unsigned char*)buf;
    while(*str) {
        unsigned char c = (unsigned char)*str;
        if (c == ' ')
            *pbuf++ = '+';
        else if (c & 0x80 || force_encode_all) {
            *pbuf++ = '%';
            *pbuf++ = hex[c >> 4];
            *pbuf++ = hex[c & 0x0f];
        } else
            *pbuf++ = c;
        str++;
    }
    return buf;
}

char* add_todo(char* user, char* pass, char* body) {
    int size;
    char* body_utf8;
    char* body_data;
    char* post;
    char* data;

    body_utf8 = string_to_utf8_alloc(body);
    if (!body_utf8) return NULL;
    body_data = url_encode_alloc(body_utf8);
    free(body_utf8);
    size = 5 + strlen(body_data);
    post = (char*)malloc(size + 1);
    memset(post, 0, size + 1);
    strcpy(post, "body=");
    strcat(post, body_data);
    free(body_data);

    data = post_http_data("http://api.wassr.jp/todo/add.json", user, pass, post);
    free(post);
    return data;
}

char* modify_todo(char* user, char* pass, char* command, char* todo_rid) {
    int size;
    char* url;
    char* post;
    char* data;

    size = 9 + strlen(todo_rid);
    post = (char*)malloc(size + 1);
    memset(post, 0, size + 1);
    strcpy(post, "todo_rid=");
    strcat(post, todo_rid);

    size = strlen(TODO_MODIFY_URL) + strlen(command) + strlen(TODO_JSON_EXT);
    url = (char*)malloc(size + 1);
    memset(url, 0, size + 1);
    strcpy(url, TODO_MODIFY_URL);
    strcat(url, command);
    strcat(url, TODO_JSON_EXT);

    data = post_http_data(url, user, pass, post);
    free(post);
    free(url);
    return data;
}

char* list_todo(char* user, char* pass, int done_fg) {
    char* data;

    if (done_fg)
        data = get_http_data("http://api.wassr.jp/todo/list.json?done_fg=1", user, pass);
    else
        data = get_http_data("http://api.wassr.jp/todo/list.json?done_fg=0", user, pass);
    if (!data) {
        perror("Unknown server response(server down or invalid authenticate?)");
        return NULL;
    }
    return data;
}

int main(int argc, char* argv[]) {
    FILE* fp = NULL;
    char* home = NULL;
    char* user = NULL;
    char* pass = NULL;
    char conf[_MAX_PATH];
    char buff[BUFSIZ];
    char* data = NULL;
    struct json_object* obj = NULL;
    struct json_object* res = NULL;
    int i;

    home = getenv("HOME");
    if (!home) home = getenv("USERPROFILE");
    snprintf(conf, sizeof(conf), "%s/.wassr-todo", home);
    fp = fopen(conf, "rt");
    if (!fp) {
        perror("404 ~/.wassr-todo NOT FOUND");
        goto error;
    }
    while(fgets(buff, sizeof(buff), fp)) {
        char *ptr = strpbrk(buff, "\r\n");
        if (*ptr) *ptr = 0;
        if (!strncmp(buff, "username: ", 10))
            user = strdup(buff + 10);
        if (!strncmp(buff, "password: ", 10))
            pass = strdup(buff + 10);
    }
    fclose(fp);

    if (argc == 1)
        data = list_todo(user, pass, FALSE);
    else {
        if (argc == 2 && !strcmp(argv[1], "list"))
            data = list_todo(user, pass, FALSE);
        else
        if (argc == 2 && !strcmp(argv[1], "listdone"))
            data = list_todo(user, pass, TRUE);
        else
        if (argc == 3 && !strcmp(argv[1], "add"))
            data = add_todo(user, pass, argv[2]);
        else
        if (argc == 3 && (
                !strcmp(argv[1], "delete") ||
                !strcmp(argv[1], "start") ||
                !strcmp(argv[1], "stop") ||
                !strcmp(argv[1], "done")))
            data = modify_todo(user, pass, argv[1], argv[2]);
        else {
            puts("usage: wassr_todo [command] [argument]");
            puts("\t* command");
            puts("\t\tlist\t\tlist todo.");
            puts("\t\tlistdone\tlist todo which is done.");
            puts("\t\tadd [body]\tpost new todo to wassr.");
            puts("\t\tdelete [rid]\tdelete the todo.");
            puts("\t\tstart [rid]\tstart the todo.");
            puts("\t\tstop [rid]\tstop the todo.");
            puts("\t\tdone [rid]\tdone the todo.");
            goto error;
        }
    }

    if (!data) {
        perror("Unknown server response(server down or invalid authenticate?)");
        goto error;
    }
    obj = json_tokener_parse(data);
    free(data);

    if (is_error(obj)) {
        perror("Unknown server response(not json?)");
        goto error;
    }

    if (json_object_is_type(obj, json_type_object)) {
        res = json_object_object_get(obj, "error");
        if (!is_error(res)) {
            char* _res = utf8_to_string_alloc(json_object_get_string(res));
            if (_res) {
                printf("error: %s\n", _res);
                free(_res);
                goto error;
            }
        }
        res = json_object_object_get(obj, "message");
        if (!is_error(res)) {
            char* _res = utf8_to_string_alloc(json_object_get_string(res));
            if (_res) {
                printf("message: %s\n", _res);
                free(_res);
            }
        }
    }

    if (json_object_is_type(obj, json_type_array)) {
        for(i = 0; i < json_object_array_length(obj); i++) {
            struct json_object *item = json_object_array_get_idx(obj, i);
            struct json_object* todo_rid = json_object_object_get(item, "todo_rid");
            struct json_object* body = json_object_object_get(item, "body");
            if (!is_error(todo_rid) && !is_error(body)) {
                char* _todo_rid = utf8_to_string_alloc(json_object_get_string(todo_rid));
                char* _body = utf8_to_string_alloc(json_object_get_string(body));
                printf("TODO-%03d [%s] %s\n", i+1, _todo_rid, _body);
                free(_todo_rid);
                free(_body);
            }
        }
    } else
    if (json_object_is_type(obj, json_type_object)) {
        struct json_object* todo_rid = json_object_object_get(obj, "todo_rid");
        if (!is_error(todo_rid)) {
            char* _todo_rid = utf8_to_string_alloc(json_object_get_string(todo_rid));
            if (_todo_rid) {
                printf("%s\n", _todo_rid);
                free(_todo_rid);
            }
        }
    }
    return 0;

error:
    if (user) free(user);
    if (pass) free(pass);
    return -1;
}

2008/02/07

はてな
JSON-Cという、C言語からJSONを扱う為のライブラリを見つけました。
Index of /json-c
C言語って言いながら、実際もともと/TPオプションでCPPビルドしてるし、それJSON-CPPちゃうんかいという気もしなくないですが...。
foreachなんかもあり、結構使い勝手は良さそうです。

ただ、同梱されている物の中には*.vcprojしか入っておらず、Makefileでゴニョゴニョするのが好きな私には絶えられないものであったり...
最近はMakefileを書く習慣って無くなってきたんですかねぇ...
で、VC6でビルドしようと思ったけどエラーがワンサカ。
どうやら
  • キャスト漏れ
  • 変数名に「this」を使用
  • C99の可変個引数マクロを使用
とはっきり言ってVC6を捨てているコードだったりしました。
なにくそーとパッチを書いたので、公開しておきます。
ただ大したパッチでもないので、オフィシャルに送るのはやめときます。
しかもトリッキーな事やってます。
デバッグ用の可変個引数マクロ
#define MC_DEBUG(x, ...) mc_debug(x, ##__VA_ARGS__)
#define MC_DEBUG if (0)
みたくして無理やり殺しています。
で、できたパッチは以下の通り。
Index: json_object.c
===================================================================
--- json_object.c   (revision 21)
+++ json_object.c   (working copy)
@@ -28,7 +28,9 @@
   char* strndup(const char* str, size_t n);
 #endif /* !HAVE_STRNDUP */
 
+#if _MSC_VER >= 1400
 #define REFCOUNT_DEBUG 1
+#endif
 
 char *json_number_chars = "0123456789.+-eE";
 char *json_hex_chars = "0123456789abcdef";
@@ -160,7 +162,7 @@
 
 static struct json_object* json_object_new(enum json_type o_type)
 {
-  struct json_object *this = calloc(sizeof(struct json_object), 1);
+  struct json_object *this = (struct json_object*)calloc(sizeof(struct json_object), 1);
   if(!this) return NULL;
   this->o_type = o_type;
   this->_ref_count = 1;
Index: json_tokener.c
===================================================================
--- json_tokener.c  (revision 21)
+++ json_tokener.c  (working copy)
@@ -57,7 +57,7 @@
 
 struct json_tokener* json_tokener_new()
 {
-  struct json_tokener *tok = calloc(1, sizeof(struct json_tokener));
+  struct json_tokener *tok = (struct json_tokener*)calloc(1, sizeof(struct json_tokener));
   tok->pb = printbuf_new();
   json_tokener_reset(tok);
   return tok;
@@ -97,7 +97,7 @@
   tok = json_tokener_new();
   obj = json_tokener_parse_ex(tok, str, -1);
   if(tok->err != json_tokener_success)
-    obj = error_ptr(-tok->err);
+    obj = (struct json_object*)error_ptr(-tok->err);
   json_tokener_free(tok);
   return obj;
 }
Index: linkhash.c
===================================================================
--- linkhash.c  (revision 21)
+++ linkhash.c  (working copy)
@@ -42,7 +42,7 @@
 unsigned long lh_char_hash(void *k)
 {
    unsigned int h = 0;
-   const char* data = k;
+   const char* data = (const char*)k;
  
    while( *data!=0 ) h = h*129 + (unsigned int)(*data++) + LH_PRIME;
 
@@ -62,12 +62,12 @@
    int i;
    struct lh_table *t;
 
-   t = calloc(1, sizeof(struct lh_table));
+   t = (struct lh_table*)calloc(1, sizeof(struct lh_table));
    if(!t) lh_abort("lh_table_new: calloc failed\n");
    t->count = 0;
    t->size = size;
    t->name = name;
-   t->table = calloc(size, sizeof(struct lh_entry));
+   t->table = (struct lh_entry*)calloc(size, sizeof(struct lh_entry));
    if(!t->table) lh_abort("lh_table_new: calloc failed\n");
    t->free_fn = free_fn;
    t->hash_fn = hash_fn;
Index: json_util.c
===================================================================
--- json_util.c (revision 21)
+++ json_util.c (working copy)
@@ -62,11 +62,11 @@
   if((fd = open(filename, O_RDONLY)) < 0) {
     MC_ERROR("json_object_from_file: error reading file %s: %s\n",
         filename, strerror(errno));
-    return error_ptr(-1);
+    return (struct json_object*)error_ptr(-1);
   }
   if(!(pb = printbuf_new())) {
     MC_ERROR("json_object_from_file: printbuf_new failed\n");
-    return error_ptr(-1);
+    return (struct json_object*)error_ptr(-1);
   }
   while((ret = read(fd, buf, JSON_FILE_BUF_SIZE)) > 0) {
     printbuf_memappend(pb, buf, ret);
@@ -76,7 +76,7 @@
     MC_ABORT("json_object_from_file: error reading file %s: %s\n",
         filename, strerror(errno));
     printbuf_free(pb);
-    return error_ptr(-1);
+    return (struct json_object*)error_ptr(-1);
   }
   obj = json_tokener_parse(pb->buf);
   printbuf_free(pb);
Index: debug.h
===================================================================
--- debug.h (revision 21)
+++ debug.h (working copy)
@@ -21,6 +21,7 @@
 extern void mc_error(const char *msg, ...);
 extern void mc_info(const char *msg, ...);
 
+#if _MSC_VER >= 1400
 #ifdef MC_MAINTAINER_MODE
 #define MC_SET_DEBUG(x) mc_set_debug(x)
 #define MC_GET_DEBUG() mc_get_debug()
@@ -38,5 +39,14 @@
 #define MC_ERROR(x, ...) if (0) mc_error(x, ##__VA_ARGS__)
 #define MC_INFO(x, ...) if (0) mc_info(x, ##__VA_ARGS__)
 #endif
+#else
+#define MC_SET_DEBUG(x)
+#define MC_GET_DEBUG()
+#define MC_SET_SYSLOG(x)
+#define MC_ABORT if (0)
+#define MC_DEBUG if (0)
+#define MC_ERROR if (0)
+#define MC_INFO if (0)
+#endif
 
 #endif
Index: arraylist.c
===================================================================
--- arraylist.c (revision 21)
+++ arraylist.c (working copy)
@@ -28,11 +28,11 @@
 {
   struct array_list *this;
 
-  if(!(this = calloc(1, sizeof(struct array_list)))) return NULL;
+  if(!(this = (struct array_list*)calloc(1, sizeof(struct array_list)))) return NULL;
   this->size = ARRAY_LIST_DEFAULT_SIZE;
   this->length = 0;
   this->free_fn = free_fn;
-  if(!(this->array = calloc(sizeof(void*), this->size))) {
+  if(!(this->array = (void**)calloc(sizeof(void*), this->size))) {
     free(this);
     return NULL;
   }
@@ -64,7 +64,7 @@
   if(max < this->size) return 0;
   new_size = max(this->size << 1, max);
   if(!(t = realloc(this->array, new_size*sizeof(void*)))) return -1;
-  this->array = t;
+  this->array = (void**)t;
   (void)memset(this->array + this->size, 0, (new_size-this->size)*sizeof(void*));
   this->size = new_size;
   return 0;
Index: json.h
===================================================================
--- json.h  (revision 21)
+++ json.h  (working copy)
@@ -13,8 +13,10 @@
 #define _json_h_
 
 #ifdef __cplusplus
+#if _MSC_VER >= 1400
 extern "C" {
 #endif
+#endif
 
 #include "bits.h"
 #include "debug.h"
@@ -25,7 +27,9 @@
 #include "json_tokener.h"
 
 #ifdef __cplusplus
+#if _MSC_VER >= 1400
 }
 #endif
+#endif
 
 #endif
Index: printbuf.c
===================================================================
--- printbuf.c  (revision 21)
+++ printbuf.c  (working copy)
@@ -29,10 +29,10 @@
 {
   struct printbuf *p;
 
-  if(!(p = calloc(1, sizeof(struct printbuf)))) return NULL;
+  if(!(p = (struct printbuf*)calloc(1, sizeof(struct printbuf)))) return NULL;
   p->size = 32;
   p->bpos = 0;
-  if(!(p->buf = malloc(p->size))) {
+  if(!(p->buf = (char*)malloc(p->size))) {
     free(p);
     return NULL;
   }
@@ -50,7 +50,7 @@
         "bpos=%d wrsize=%d old_size=%d new_size=%d\n",
         p->bpos, size, p->size, new_size);
 #endif /* PRINTBUF_DEBUG */
-    if(!(t = realloc(p->buf, new_size))) return -1;
+    if(!(t = (char*)realloc(p->buf, new_size))) return -1;
     p->size = new_size;
     p->buf = t;
   }
@@ -70,7 +70,7 @@
 /* CAW: compliant version of vasprintf */
 static int vasprintf(char **buf, const char *fmt, va_list ap)
 {
-#ifndef WIN32
+#if !defined(WIN32) || _MSC_VER < 1400
    static char _T_emptybuffer = '\0';
 #endif /* !defined(WIN32) */
    int chars;
@@ -78,7 +78,7 @@
 
    if(!buf) { return -1; }
 
-#ifdef WIN32
+#if defined(WIN32) && _MSC_VER >= 1400
    chars = _vscprintf(fmt, ap)+1;
 #else /* !defined(WIN32) */
    /* CAW: RAWR! We have to hope to god here that vsnprintf doesn't overwrite
さらにVC6でビルドする為のMakefile
CFLAGS = -DWIN32 -Dthis=o_this -O2 -MT -W3 -nologo -TP -EHsc
SRC = arraylist.c json_object.c json_tokener.c json_util.c linkhash.c printbuf.c
OBJ = $(SRC:.c=.obj)

all : json.lib

json.lib : $(OBJ)
    lib /out:json.lib $(OBJ)

hoge.exe : hoge.obj
    cl /Fohoge.exe hoge.obj json.lib

clean :
    del /Q *.obj *.lib
あと、サンプル「hoge.c」
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>

#include "json.h"

int main(int argc, char **argv)
{
    struct json_object *obj;
    int i;

    obj = json_tokener_parse("[1,2,3]");
    for(i=0; i < json_object_array_length(obj); i++) {
        struct json_object *a = json_object_array_get_idx(obj, i);
        printf("\t[%d]=%s\n", i, json_object_to_json_string(a));
    }
    obj = json_tokener_parse("{'a':1,'b':2,'c':3}");
    json_object_object_foreach(obj, key, val) {
        printf("\t%s: %s\n", key, json_object_to_json_string(val));
    }

    return 0;
}
「hoge.c」の実行結果は
    [0]=1
    [1]=2
    [2]=3
    a: 1
    b: 2
    c: 3
こんな感じ。
うむ。これでgtkwassrにTODO機能が付けれるかも...
Posted at 20:55 in ソフトウェア::lang::c | WriteBacks (0)
Tagged as: c, c++, json, json-c, vc6
Bookmarks: add to hatena add to hatena | add to delicious.com | add to livedoor.clip add to livedoor.clip | add to buzzurl add to buzzurl | add to fc2bookmark add to fc2bookmark | add to Yahoo Bookmark add to Yahoo Bookmark | add to Pookmark add to Pookmark

はてな
あわせて読みたいがRSSとJSONを出されている様です。
試しに使ってみました。
コードはこんな感じ。
<script type="text/javascript"><!--
function awasete_yomitai(data) {
    var d = document;
    var container = d.getElementById('awasete_content');
    while(container.hasChildNodes())
        container.removeChild(container.firstChild);

    var ol = d.createElement('ol');
    for(var n = 0; n < data.length; n++) {
        var li = d.createElement('li');
        var favicon = d.createElement('img');
        favicon.src = data[n].favicon;
        li.appendChild(favicon);
        li.appendChild(d.createTextNode(' '));
        var anchor = d.createElement('a');
        anchor.appendChild(d.createTextNode(data[n].title));
        anchor.href = data[n].url;
        li.appendChild(anchor);
        li.appendChild(d.createTextNode(' '));
        var awasete = d.createElement('a');
        awasete.appendChild(d.createTextNode('[ナビゲーション]'));
        awasete.href = data[n].navigation;
        li.appendChild(awasete);
        li.appendChild(d.createTextNode(' '));
        var more = d.createElement('a');
        more.appendChild(d.createTextNode('[もっと見る]'));
        more.href = data[n].more;
        li.appendChild(more);
        ol.appendChild(li);
    }
    container.appendChild(ol);
}
function awasete_yomitai_do(url) {
    var s = document.createElement('script');
    s.charset = 'utf-8';
    s.src = 'http://api.awasete.com/showjson.phtml?u=' + encodeURIComponent(url);
    document.body.appendChild(s);
}
--></script>
<a href="javascript:awasete_yomitai_do('http://mattn.kaoriya.net');void 0">あわせて読みたい</a>
<div id="awasete_content"></div>
実行確認。
[あわせて読みたい]を表示

callback指定出来ないのが少し悲しい。

2008/02/06

はてな
たぶんこんなんでいけるはず。
Control-C - ロックスターになりたい
あと日本語文字化けする。VBからSJISで送ってサーバでutf8で読んでるとかだろうか。
パッチ
diff -u winsource.orig/modUrlEncode.bas winsource/modUrlEncode.bas
--- winsource.orig/modUrlEncode.bas Tue Jan 08 02:14:04 2008
+++ winsource/modUrlEncode.bas  Wed Feb 06 18:12:35 2008
@@ -1,6 +1,57 @@
 Attribute VB_Name = "modUrlEncode"
 Option Explicit
 
+Private Declare Function WideCharToMultiByte Lib "kernel32" ( _
+    ByVal CodePage As Long, _
+    ByVal dwFlags As Long, _
+    ByVal lpWideCharStr As Long, _
+    ByVal cchWideChar As Long, _
+    ByRef lpMultiByteStr As Any, _
+    ByVal cchMultiByte As Long, _
+    ByVal lpDefaultChar As String, _
+    ByVal lpUsedDefaultChar As Long) As Long
+    
+Private Const CP_UTF8 = 65001
+
+Private Function EncodeUTF8(ByRef strUni As String) As Byte()
+    On Error GoTo ErrHandler
+
+    Dim lngUniLen As Long
+    Dim lngBufLen As Long
+    Dim lngRtn As Long
+    Dim bytOut() As Byte
+
+    lngUniLen = Len(strUni)
+    If lngUniLen = 0 Then
+        Exit Function
+    End If
+    lngBufLen = lngUniLen * 5
+    ReDim bytOut(lngBufLen - 1)
+    lngRtn = WideCharToMultiByte( _
+        CP_UTF8, _
+        0, _
+        StrPtr(strUni), _
+        lngUniLen, _
+        bytOut(0), _
+        lngBufLen, _
+        vbNullString, _
+        0)
+    If lngRtn Then
+        ReDim Preserve bytOut(lngRtn - 1)
+        EncodeUTF8 = bytOut
+    End If
+    
+    Exit Function
+ErrHandler:
+End Function
+
+Private Function SafeUBound(ByRef arr() As Byte) As Long
+    On Error Resume Next
+    Dim lngLen As Long
+    lngLen = UBound(arr) - LBound(arr) + 1
+    SafeUBound = lngLen
+End Function
+
 Public Function UrlEncode(ByRef strSource As String) As String
 
  Dim lngLength As Long                                          '???????(S-JIS ???)?????
@@ -11,10 +62,13 @@
  Dim lngReadCount As Long                                       'bytSource ??????????
  Dim lngWriteCount As Long                                      'strBuffer ??????????
  
-    lngLength = LenB(StrConv(strSource, vbFromUnicode))         'ANSI/S-JIS ???????????
-    If Not CBool(lngLength) Then Exit Function                  '0 ????????????
-    ReDim bytSource(lngLength - 1)                              'ANSI/S-JIS ???????????????
-    bytSource = StrConv(strSource, vbFromUnicode)               'ANSI/S-JIS ???? bytSource ???
+    'lngLength = LenB(StrConv(strSource, vbFromUnicode))         'ANSI/S-JIS ???????????
+    'If Not CBool(lngLength) Then Exit Function                  '0 ????????????
+    'ReDim bytSource(lngLength - 1)                              'ANSI/S-JIS ???????????????
+    'bytSource = StrConv(strSource, vbFromUnicode)               'ANSI/S-JIS ???? bytSource ???
+    bytSource = EncodeUTF8(strSource)
+    lngLength = SafeUBound(bytSource)
+    If Not CBool(lngLength) Then Exit Function
    
     strBuffer = String$(lngLength * 3, vbNullChar)              'URL ???????????????????
     strSingleHex = "%00"                                        '16 ?????????????????????

あ、Control-Cのアカウント持ってなかった
Posted at 18:20 in その他 | WriteBacks (2)
Tagged as: control-c, patch
Bookmarks: add to hatena add to hatena | add to delicious.com | add to livedoor.clip add to livedoor.clip | add to buzzurl add to buzzurl | add to fc2bookmark add to fc2bookmark | add to Yahoo Bookmark add to Yahoo Bookmark | add to Pookmark add to Pookmark

2008/02/05

はてな
なかなか1日2個のリリースはキツイすね。苦笑
他のgtkXXXシリーズと違い、WassrにはXMLフォーマットが無いので少し困りましたがRSSパースする方法で解決しました。
アイコンはRSSのlink要素からユーザ領域までを分割し
http://wassr.jp/user/mattn/profile_img.png.32
という画像URLを作っています。
途中、このURLで「.32」が無かったり「:32」としていた為、オフィシャルのπなんちゃらさんに
http://wassr.jp/user/tokuhirom/statuses/id5xrHj4jd
tokuhirom @mattn gtkwassr が妙な URL をたたいている様子

http://wassr.jp/user/tokuhirom/statuses/0ZYaWVhBtM
tokuhirom @mattn プロフィール画像のパスがまちがってます。profile_img.png ではなく profile_img.png.32 等と画像のサイズを指定していただきたく。
とご指摘を受けながら完成。
http://wassr.jp/user/tokuhirom/statuses/6n4YjNSdux
tokuhirom @mattn ktkr!
とktkrを頂きました。
コードはCodeReposに置いてあります。
Revision 6229: /lang/c/gtkwassr

はてな
まぁ、こういうのは鮮度が命って事で...
nowa開発ブログ - twitter互換のAPIを公開しました
ぶっちゃけ、gtktwitterのソースちょっと弄っただけなんですけどね...

gtknowa-20080205
使うには、nowaの設定画面でAPIパスワードを設定する必要があります。
nowa-api-setting
14:00ちょうど頃にos0xさんのブクマを見て、作ってこの記事を書くまでなので、実質30分!

鮮度としてはピチピチかと...
gtknowa - Google Code
Posted at 14:33 in ソフトウェア::nowa | WriteBacks (0)
Tagged as: gtknowa, nowa, ノワ
Bookmarks: add to hatena add to hatena | add to delicious.com | add to livedoor.clip add to livedoor.clip | add to buzzurl add to buzzurl | add to fc2bookmark add to fc2bookmark | add to Yahoo Bookmark add to Yahoo Bookmark | add to Pookmark add to Pookmark