<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>JeffHung.Blog &#187; Devel</title>
	<atom:link href="http://www.jeffhung.net/blog/categories/devel/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.jeffhung.net/blog</link>
	<description>(My smile insists of having nose. :-)</description>
	<lastBuildDate>Thu, 24 Nov 2011 07:25:31 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1.2-alpha</generator>
		<item>
		<title>VimWiki</title>
		<link>http://www.jeffhung.net/blog/articles/jeffhung/3087/</link>
		<comments>http://www.jeffhung.net/blog/articles/jeffhung/3087/#comments</comments>
		<pubDate>Thu, 22 Jul 2010 14:47:30 +0000</pubDate>
		<dc:creator>jeffhung</dc:creator>
				<category><![CDATA[Devel]]></category>

		<guid isPermaLink="false">http://www.jeffhung.net/blog/?p=3087</guid>
		<description><![CDATA[一直想要弄個 Wiki 整理各種知識，本來有試著用 dokuwiki，可是在 browser 裡面編輯，還是不甚方便，而且不是任何時候，都有網路可以用。後來發現了 vimwiki 這個東西，驚為天人，這正是我需要的啊。最近 vimwiki 1.0 版正式推出，所以來跟各位介紹一番。]]></description>
			<content:encoded><![CDATA[<p>一直想要弄個 wiki 整理各種知識，本來有試著用 <a href="http://www.dokuwiki.org/dokuwiki">dokuwiki</a>，可是在 browser 裡面編輯，還是不甚方便，而且不是任何時候，都有網路可以用。後來發現了 <a href="http://code.google.com/p/vimwiki/">vimwiki</a> 這個東西，驚為天人，這正是我需要的啊。最近 vimwiki 1.0 版正式推出，所以來跟各位介紹一番。</p>
<p>Vimwiki，簡言之，就是在 Vim 裡面架一個 wiki。對於 programmer 來說，vim 想必不陌生，用慣 vim 的人，如果也能同樣用 vim 編輯 wiki，因為操作方法都一樣，更加地方便。Vim 從第 7 版開始支援 tab，寫程式時若要記筆記，根本不必離開 vim，方便極了。</p>
<p>到網站上抓下來解開安裝到 <code class="inline_code">~/.vim</code> 裡即可。Vimwiki 可設定多個 wiki，使用時，只要連打 <code class="inline_code">&lt;leader&gt;ww</code> (<code class="inline_code">&lt;leader&gt;</code> 鍵預設為「<code class="inline_code">\</code>」)，就可以開啟預設的 wiki，或從多個設定好的 wiki 中選擇要開啟那一個。另外也有支援 diary 模式，改按 <code class="inline_code">&lt;leader&gt;w&lt;leader&gt;w</code>，就可開啟一個以今天日期命名的 diary page，拿來記會議記錄超方便。Diary 模式亦可與 <a href="http://www.vim.org/scripts/script.php?script_id=52">Vim Calendar</a> 整合，打開 calendar，那一天有 diary 一清二楚，按 <code class="inline_code">&lt;enter&gt;</code> 鍵就可打開。</p>
<p>Wiki 裡的 <a href="http://en.wikipedia.org/wiki/CamelCase">CamelCase</a> 自動成為 link，按 <code class="inline_code">&lt;enter&gt;</code> 鍵進入該頁，按 <code class="inline_code">&lt;backspace&gt;</code> 鍵回到前一頁。如果你用的是 GUI 版的 vim 的話，vimwiki 也可支援滑鼠。Vimwiki 有指令可以將本頁或整個 wiki 的內容，轉成 HTML 檔。也可以設定成存檔時自動轉成 HTML，這樣就不必煩惱同步的問題了。</p>
<p>Vimwiki 有自己的 wiki syntax，不過很好學，與大部份的 wiki 語法類似。另外 vimwiki 也可以設定成使用 <a href="http://www.mediawiki.org/wiki/MediaWiki">mediawiki</a> 語法，只不過這樣就不支援轉出成 HTML 檔。我現在還在找方法，看看能不能直接開啟另外架設的 wiki 站，這樣就不用靠 <a href="https://addons.mozilla.org/en-US/firefox/addon/4125/">It's All Text!</a> 了。Vimwiki 支援表格編輯，並且會隨著 cell 的切換，自動將表格排列整齊，非常方便。另外，我們也可以在 vimwiki 裡建立 todo list，按 <code class="inline_code">&lt;C-space&gt;</code> 即可切換完成與否，並會自動更新上層進度。所以，我根本可以直接用 vimwiki 來做簡單的 <a href="http://en.wikipedia.org/wiki/Getting_Things_Done">GTD</a>，一般的 outline 軟體可以丟掉了。</p>
<p>因為 vimwiki 使用純文字檔格式，除了可以用其它編輯器開啟瀏覽之外，也可以用版本控制軟體管理，如 <a href="http://subversion.apache.org/">Subversion</a>、<a href="http://git-scm.com/">Git</a> 等。不過我覺得 wiki 還要記錄所有歷史編輯記錄，很沒必要。會想用版本控制軟體，其實是看上了其可有多個 working copies，方便彼此之間的同步。不過，使用版本控制軟體，使用時還是很繁瑣，因此，最後的大絕是，我直接拿 <a href="https://www.dropbox.com/referrals/NTMwOTA4MDA5">Dropbox</a> 來管理這些 wiki 檔了。如此一來，任何時候只要一存檔，我的 wiki 內容就可以備份到雲端，同時我還可以在多台機器裡，完全自動同步內容，再加上 vim 在 windows、linux 與 mac 上都能用，因此不管我在那台機器裡，只要設定妥當，我的 wiki 就可以跟著我走，完全無須浪費心思在管理。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jeffhung.net/blog/articles/jeffhung/3087/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Unescape URL in Perl</title>
		<link>http://www.jeffhung.net/blog/articles/jeffhung/2424/</link>
		<comments>http://www.jeffhung.net/blog/articles/jeffhung/2424/#comments</comments>
		<pubDate>Sat, 24 Oct 2009 18:51:08 +0000</pubDate>
		<dc:creator>jeffhung</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[perl]]></category>

		<guid isPermaLink="false">http://www.jeffhung.net/blog/?p=2424</guid>
		<description><![CDATA[看 log 時快速解碼用的，一行搞定。]]></description>
			<content:encoded><![CDATA[<p>看 log 時快速解碼用的，一行搞定：</p>
<pre class="code">
SHELL&gt; echo &quot;%3A%22abc%22&quot; | perl -MURI::Escape -ne 'print uri_unescape($_)'
:&quot;abc&quot;
</pre>
<p>看來某程式碰到非 ASCII 字元就會爛掉。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jeffhung.net/blog/articles/jeffhung/2424/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ubuntu 真難用</title>
		<link>http://www.jeffhung.net/blog/articles/jeffhung/1086/</link>
		<comments>http://www.jeffhung.net/blog/articles/jeffhung/1086/#comments</comments>
		<pubDate>Fri, 02 Oct 2009 12:23:09 +0000</pubDate>
		<dc:creator>jeffhung</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[cpp]]></category>
		<category><![CDATA[linux]]></category>

		<guid isPermaLink="false">http://www.jeffhung.net/blog/?p=1086</guid>
		<description><![CDATA[兩個工作資歷加起來超過 15 年，可跨 UNIX/Windows 開發軟體的工程師，為了要在 Ubuntu 上編譯 C 的 hello world 程式，竟然要花上半小時。]]></description>
			<content:encoded><![CDATA[<p>兩個工作資歷加起來超過 15 年，可跨 UNIX/Windows 開發軟體的工程師，為了要在 <a href="http://zh.wikipedia.org/wiki/Ubuntu">Ubuntu</a> 上編譯 C 的 hello world 程式，竟然要花上半小時。</p>
<p>工程師 A：「B 你能不能來幫我看看，為甚麼 configure 不過。」</p>
<p>工程師 B 仔細地看了一下螢幕上的 error messages，發現是因為找不到 <code class="inline_code">crt1.o</code>。</p>
<p>工程師 B：「看起來像是 libc 沒有裝，我們可以試著編一個 hello world 來確認。」</p>
<p>於是工程師 A 寫了一個 <code class="inline_code">hello.c</code> 如下：</p>
<pre class="code">
#include &lt;stdio.h&gt;

int main()
{
    printf(&quot;Hello World\n&quot;);
    return 0;
}
</pre>
<p>用 gcc 編譯，gcc 會動，但跑出錯誤訊息，說找不到 <code class="inline_code">stdio.h</code>。</p>
<p>工程師 B：「果然。」</p>
<p>工程師 A 順手打了一下指令：</p>
<pre class="screen">
SHELL&gt; locate stdio.h
Not found.
</pre>
<p>工程師 A：「Ubuntu 應該是用 apt-get 安裝軟體吧？」</p>
<p>工程師 A 試著下指令：</p>
<pre class="screen">
SHELL&gt; sudo apt-get install libc
Cannot find package libc
</pre>
<p>工程師 B：「可能是叫做 glibc。」</p>
<p>工程師 A 試著再下指令：</p>
<pre class="screen">
SHELL&gt; sudo apt-get install glibc
Cannot find package glibc
</pre>
<p>工程師 A：「見鬼了，誰知道 libc 應該要叫什麼啊！要怎麼知道套件的名字是什麼？」</p>
<p>工程師 A 試著打下面的指令：</p>
<pre class="screen">
SHELL&gt; apt-get search libc
Invalid command 'search'.
</pre>
<p>工程師 B：「還是用 GUI 工具好了，至少應該會有個搜尋框可以用。」</p>
<p>工程師 A 從系統選單裡找到 <a href="http://en.wikipedia.org/wiki/Synaptic_%28software%29">synaptic</a> 這支程式，查了幾次， 用 <code class="inline_code">glibc</code> 找不到任何東西，後來改用 <code class="inline_code">libc</code> 當關鍵字找，終於找到 <code class="inline_code">libc6-dev</code> 這個套件。</p>
<p>實在無法理解，為什麼 <code class="inline_code">apt-get</code> 沒有提供搜尋的功能，誰知道到底套件叫做 <code class="inline_code">libc</code>、<code class="inline_code">glibc</code> 還是 <code class="inline_code">libc6-dev</code> 啊。後來我知道，似乎搜尋的指令下法是 <code class="inline_code">apt-cache search</code>，可是 cache 這個字眼，跟 search 感覺上就是沾不到邊，真是莫名其妙的組合。其實我覺得，<code class="inline_code">apt-get</code> 的 <code class="inline_code">get</code> 也很莫名其妙，感覺上就是功能越做越多，沒有一開始就設計完善，最後只好通通塞在一起。</p>
<p>用 synaptic 的過程也是挫折感十足。利用其搜尋功能，確實地找到了 <code class="inline_code">libc6-dev</code> 這個套件，可是勾選安裝後，就不曉得接下來要怎麼辦，才能真的開始安裝。樸素的視窗，兩個人硬是 try 了十分鐘，才終於明瞭，要按工具列的「Apply」按鈕，才能開始安裝。誰知道這個 Apply 是在 apply 什麼啊，難道不能用個「Start」或「Next」的按鈕嗎？又不是在搞 version control，還要下個 commit 才會真正改變 repository。</p>
<p>最後，總算成功地編譯了 hello world，花了半小時。XD</p>
<p>然後我還是不懂，為什麼預設裝好有 <code class="inline_code">gcc</code> 但沒有 <code class="inline_code">libc</code> 跟標準 C 的 include files 可以用。要嘛就通通不要有開發工具，要嘛就基本的要裝齊全。不是每個人都是 kernel developer 好嗎？</p>
<p>後記：後來我們又發現，從頭到尾，我們是在 live cd 上工作，而不是在真正已經安裝在硬碟裡的 ubuntu 裡工作。難怪網路怎麼設都不會通。-.-||</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jeffhung.net/blog/articles/jeffhung/1086/feed/</wfw:commentRss>
		<slash:comments>21</slash:comments>
		</item>
		<item>
		<title>Where to place mutable members in class?</title>
		<link>http://www.jeffhung.net/blog/articles/jeffhung/1191/</link>
		<comments>http://www.jeffhung.net/blog/articles/jeffhung/1191/#comments</comments>
		<pubDate>Thu, 01 Oct 2009 17:54:05 +0000</pubDate>
		<dc:creator>jeffhung</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[cpp]]></category>

		<guid isPermaLink="false">http://www.jeffhung.net/blog/?p=1191</guid>
		<description><![CDATA[在 C++ 裡，若 member data 被宣告為 mutable，表示即使是在「常數情境」下，如物件本身被宣告為 const，或執行於宣告成 const 的 member function 裡時，該 member data 仍然可以被修改...]]></description>
			<content:encoded><![CDATA[<p>在 C++ 裡，若 member data 被宣告為 mutable，表示即使是在「常數情境」下，如物件本身被宣告為 const，或執行於宣告成 const 的 member function 裡時，該 member data 仍然可以被修改。</p>
<p>這通常用於，如 mutex 這種，其實不屬於概念上的物件內容，但又需要存在於物件裡以維持正確運作的那些 member data。可是，這種「不屬於概念上的物件內容，但又需要存在於物件裡的」member data，該怎麼擺放於物件裡？</p>
<p>於是，在 <code class="inline_code">#cpp-tw</code> 裡，有了這樣的討論：</p>
<pre class="screen">
11:38 &lt;jeffhung&gt; 假設我們有一個 mutable mutex 的 member data，要放在 class 裡最前面，還是
                 最後面？
11:39 &lt;jeffhung&gt; 放最後面的好處是，這些 mutable 的 member，在轉成 persistent form 時，可
                 以直接 memcpy 然後把尾巴的 mutable members 去掉。
11:40 &lt;jeffhung&gt; 放最前面的好處是，sub object 的 construct order 是按順序來的，所以可以保
                 證 mutex object 比其他 member 還要早 construct，還要 晚 destruct。
11:40 &lt;jeffhung&gt; 這樣甚至可以在 initialization-list 裡 lock mutex。 (but how?!)
11:43 &lt;jeffhung&gt; (另一個擺法是，把 mutex 放在 parent)
11:43 &lt;l*&gt;       或者放在外頭.... ? XD
11:43 &lt;l*&gt;       (use a key-value table to store that....?)
11:44 &lt;jeffhung&gt; l*: 那這個 key-value table 可能也要 lock，會產生 bottleneck</pre>
<p>目前我傾向於擺在前頭。我認為，物件內容的正確性，是第一要務，使用方便與否，則在其次。但關於這個議題，可能還有還沒考慮到的地方，因此也暫時沒有定論。諸位覺得呢？</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jeffhung.net/blog/articles/jeffhung/1191/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SWT MVC Wrapper - Abandoned</title>
		<link>http://www.jeffhung.net/blog/articles/jeffhung/2134/</link>
		<comments>http://www.jeffhung.net/blog/articles/jeffhung/2134/#comments</comments>
		<pubDate>Wed, 09 Sep 2009 14:53:15 +0000</pubDate>
		<dc:creator>jeffhung</dc:creator>
				<category><![CDATA[Devel]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[swt]]></category>

		<guid isPermaLink="false">http://www.jeffhung.net/blog/?p=2134</guid>
		<description><![CDATA[逛到 SWT MVC Wrapper 這個 project，網頁一開頭就這麼寫著： ABANDONNED STATE This project is currently in an abandonned state. It works fine on Windows, but there are problems with the ComboBox on Linux. When this project was started, I hoped it would incite others to join, but this did not happened. Alone, there is not much motivation to [...]]]></description>
			<content:encoded><![CDATA[<p>逛到 <a href="http://swtmvcwrapper.sourceforge.net/">SWT MVC Wrapper</a> 這個 project，網頁一開頭就這麼寫著：</p>
<blockquote>
<p class="warning">ABANDONNED STATE</p>
<p class="warning">This project is currently in an abandonned state.         It works fine on Windows, but there are problems         with the ComboBox on Linux.  When this project was started,         I hoped it would incite others to join, but this did not happened.         Alone, there is not much motivation to persue.</p>
<p class="warning">I strongly suggest you do not waste anytime investigating this         library.  I will probably have it removed by 2005 from SourceForge.</p>
</blockquote>
<p>這個 project 還真是坦白。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jeffhung.net/blog/articles/jeffhung/2134/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Avoid anonymous namespace in header files</title>
		<link>http://www.jeffhung.net/blog/articles/jeffhung/2144/</link>
		<comments>http://www.jeffhung.net/blog/articles/jeffhung/2144/#comments</comments>
		<pubDate>Tue, 01 Sep 2009 14:29:59 +0000</pubDate>
		<dc:creator>jeffhung</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[cpp]]></category>

		<guid isPermaLink="false">http://www.jeffhung.net/blog/?p=2144</guid>
		<description><![CDATA[不過因為今天寫 C++ 程式的時候，碰到這樣的 warning：warning: 'Foo' has a field 'Foo::impl_' whose type uses the anonymous namespace. 原來是因為，我在 foo.hpp 這個 header 檔裡，寫了一個 anonymous namespace…]]></description>
			<content:encoded><![CDATA[<p>不過因為今天寫 C++ 程式的時候，碰到這樣的 warning：</p>
<pre class="code">
warning: 'Foo' has a field 'Foo::impl_' whose type uses the anonymous namespace.</pre>
<p>原來是因為，我在 <code class="inline_code">foo.hpp</code> 這個 header 檔裡，寫了一個 <a href="http://www.cppreference.com/wiki/keywords/namespace#anonymous_namespace">anonymous namespace</a>，如下：</p>
<pre class="code">
#ifndef FOO_HPP_INCLUDED
#define FOO_HPP_INCLUDED

namespace { // anonymous, so only library implementer know how to use it
    class FooImpl { ... };
}

class Foo
{
public:
    ...
private:
    FooImpl impl_;
};

#endif /* FOO_HPP_INCLUDED */
</pre>
<p>因為還沒有引入如 <code class="inline_code">boost::shard_ptr&lt;&gt;</code> 的機制，考量到 exception/thread safety，不想要讓 <code class="inline_code">impl_</code> 是個指標，因此利用 anonymous namespace 的方式，把 <code class="inline_code">FooImpl</code>「藏」起來。不過，這樣的寫法，有潛在的問題，因此 gcc 發出 warning 警告。</p>
<p>Compiler 在編譯時 anonymous namespace 時，相當於以 compilation unit 為單位，為裡面的 anonymous namespace，取一個獨一無二的名字，然後自動 using 之。若 header 檔被不同的 source 檔引入，成為不同的 compilation unit，則 anonymous namespace 所自動產生的名字，皆不相同，共同運作時，就會產生問題。</p>
<p>以上例來說，<code class="inline_code">foo.hpp</code> 可能被 <code class="inline_code">a.cpp</code> 與 <code class="inline_code">b.cpp</code> 分別引入，兩者分別建構了 Foo 類別的物件，依據以上說明，<code class="inline_code">a.cpp</code> 裡面的 <code class="inline_code">Foo</code> 類別的物件，其 <code class="inline_code">impl_</code> 成員的型別，可能是 <code class="inline_code">anonymous_a</code>；而 <code class="inline_code">b.cpp</code> 裡面的 <code class="inline_code">Foo</code> 類別的物件，其 <code class="inline_code">impl_</code> 成員的型別，則可能是 <code class="inline_code">anonymous_b</code>。同樣是 <code class="inline_code">Foo</code> 類別的物件，在不同的 compilation unit 裡，其 <code class="inline_code">impl_</code> 成員，型別卻不同，這個歧異，肯定會造成問題。</p>
<p>因此，我們應該避免在 header 檔，使用 anonymous namespace。</p>
<p>可是，若不能在 header 裡使用 anonymous namespace 的話，那 anonymous namespace 到底有甚麼存在的意義呢？畢竟，我們大可以直接在 source 檔裡宣告類別，反正其他 source 也看不到，不就有了 anonymous namespace 的效果了嗎？</p>
<p>其實，anonymous namespace 還是有其存在意義的，畢竟，anonymous namespace 依然是一個 namespace，而 namespace 的作用，就在於避免 name collision。好比說，我們永遠無法保證，source 檔所引入的其他程式庫的 header 檔，在未來版本裡，會不會冒出一個，名字跟我們想要藏起來自己用的類別、函式或變數。而有了 anonymous namespace，我們就可以保證，此時不會發生 name collision。</p>
<p><strong>參考資料：</strong></p>
<ul>
<li>comp.lang.c++.moderated &raquo; <a href="http://groups.google.com/group/comp.lang.c++.moderated/browse_thread/thread/39070498954c5781">warning: ... has a field ... whose type uses the anonymous namespace</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.jeffhung.net/blog/articles/jeffhung/2144/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Simple continuous test solution via make</title>
		<link>http://www.jeffhung.net/blog/articles/jeffhung/2156/</link>
		<comments>http://www.jeffhung.net/blog/articles/jeffhung/2156/#comments</comments>
		<pubDate>Mon, 31 Aug 2009 05:28:54 +0000</pubDate>
		<dc:creator>jeffhung</dc:creator>
				<category><![CDATA[Devel]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[cpp]]></category>
		<category><![CDATA[shellscript]]></category>

		<guid isPermaLink="false">http://www.jeffhung.net/blog/?p=2156</guid>
		<description><![CDATA[Perl hacker gugod demoed Test::Continuous in OSDC.tw 2008 lightning talk. This is a great idea that breaks the code/build/debug cycle so we can continuously focus on the code we're writing and let the build/debug stuffs go background (mentally). But Test::Continuous is a perl module that best suite for perl hacking. I'm a C/C++ programmer now [...]]]></description>
			<content:encoded><![CDATA[<p>Perl hacker gugod <a href="http://gugod.org/2008/04/osdctw.html">demo</a>ed <a href="http://www.slideshare.net/gugod/osdctw-2008-lightening-talk">Test::Continuous in OSDC.tw 2008 lightning talk</a>. This is a great idea that breaks the code/build/debug cycle so we can continuously focus on the code we're writing and let the build/debug stuffs go background (mentally). But Test::Continuous is a perl module that best suite for perl hacking. I'm a C/C++ programmer now and cannot benefit from his work. So I wrote a little script that brute forced the idea with the help of make.</p>
<p>The most complex part of Test::Continuous is to detect whether we should build and test, or just waiting for source file changes. I'm not sure how gugod did that in Perl, but this is absolutely what make(1) good at. The <code class="inline_code">-q</code> argument for GNU make will return an exit status indicating whether specified targets are already up to date or not. So we may write a<ins>n</ins> infinite loop and ask GNU make to check whether depended source <ins>is</ins> changed or not, and really do the build/test if <code class="inline_code">make -q</code> returns nonzero.</p>
<p>And, with the help of <a href="http://blogs.divisibleprime.com/ronin/articles/2008/03/10/command-line-gnome-notification">gnome-cli-notify.py</a>, it is easy to show a notification popup when build/test failed or vice versa.</p>
<p>So, here comes the script. Enjoy.</p>
<pre class="code">
#!/usr/bin/env bash
# ---------------------------------------------------------------------------
# Amarganth Development Environment
# Copyright (c) 2007, Jeff Hung
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
#  - Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
#  - Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
#  - Neither the name of the copyright holders nor the names of its
#    contributors may be used to endorse or promote products derived
#    from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# ---------------------------------------------------------------------------
# $Date: 2009-07-27 10:18:22 +0800 (Mon, 27 Jul 2009) $
# $Rev: 489 $
# $Author: jeffhung $
# ----------------------------------------------------------------------------
# revid: &quot;@(#) $Id: scm.old 489 2009-07-27 02:18:22Z jeffhung $&quot;
# ----------------------------------------------------------------------------

__exe_name__=`basename $0`;
__revision__=`echo '$Rev: 560 $' | cut -d' ' -f2`;
__rev_date__=`echo '$Date: 2007-07-19 11:07:45 +0800 (星期四, 19 七月 2007) $' | cut -d' ' -f2`;

continuous_timeout=5
error_stop_timeout=30

if [ $# -lt 3 ]; then
    echo &quot;\
Usage: continuous-test &lt;build-target&gt; &lt;test-target&gt; &lt;notify-cmd&gt; ...

The continuous-test script make(1) your &lt;test-target&gt; continuously while we
developing.  The script repeatedly asking GNU make(1) to determine whether
&lt;build-target&gt; need to be built or not.  If it needs to be built, build it
and then &lt;test-target&gt;.  If any of &lt;build-target&gt; or &lt;test-target&gt; failed,
run &lt;notify-cmd&gt; to notify we developer.  If build successed, &lt;build-target&gt;
no longer need to be built, and this script go back to check continuously.

This script requires GNU make(1) and bash(1).

Example:

  $ continuous-test all test \\
    \&quot;gnome-cli-notify.py 'Test Failed...' 'Check error console please.'\&quot; \\
    ;

Revision: r$__revision__ ($__rev_date__)&quot;;
    exit;
fi;
build_target=&quot;$1&quot;; shift;
test_target=&quot;$1&quot;; shift;
notify_cmd=&quot;$1&quot;; shift;
while [ $# -gt 0 ]; do
    notify_cmd=&quot;$notify_cmd '$1'&quot;;
    shift;
done;
#echo &quot;$notify_cmd&quot;;

while [ -z '' ]; do
    make -q &quot;$build_target&quot;;
    if [ $? -ne 0 ]; then
        echo &quot;Change detected, build and test!!&quot;;
        rm -f &quot;$temp_file&quot;;
        make &quot;$build_target&quot; &amp;&amp; make &quot;$test_target&quot;;
        if [ $? -ne 0 ]; then
            echo &quot;&gt;&gt;&gt; TEST FAILED!!&quot;;
            if [ -n &quot;$notify_cmd&quot; ]; then
                eval $notify_cmd;
            fi;
            read -n 1 -t $error_stop_timeout \
                 -p &quot;(`date '+%H:%M:%S'`+$error_stop_timeout) Stop continuous test (y/N)? &quot; \
                 ans;
#           if [ \( $? -ne 0 \) -o \( &quot;$ans&quot; = 'y' \) ]; then
            if [ \( $? -eq 0 \) -a \( &quot;$ans&quot; = 'y' \) ]; then
                echo;
                break; # while
            fi;
        fi;
    fi;
    printf &quot;\r&quot;;
    read -n 1 -t $continuous_timeout \
         -p &quot;(`date '+%H:%M:%S'`+$continuous_timeout) Stop continuous test (y/N)? &quot; \
         ans;
    if [ \( $? -eq 0 \) -a \( &quot;$ans&quot; = 'y' \) ]; then
        echo;
        break; # while
    fi;
done;
echo 'End.';
</pre>
<p>This script is written in Bash for the <code class="inline_code">read</code> builtin, cooperate with GNU make.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jeffhung.net/blog/articles/jeffhung/2156/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>API Name Postfix</title>
		<link>http://www.jeffhung.net/blog/articles/jeffhung/1846/</link>
		<comments>http://www.jeffhung.net/blog/articles/jeffhung/1846/#comments</comments>
		<pubDate>Wed, 01 Jul 2009 14:09:23 +0000</pubDate>
		<dc:creator>jeffhung</dc:creator>
				<category><![CDATA[Devel]]></category>
		<category><![CDATA[Murmuring]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[cpp]]></category>

		<guid isPermaLink="false">http://www.jeffhung.net/blog/?p=1846</guid>
		<description><![CDATA[Windows SDK API 裡有個奇怪的命名慣例 (naming convention)，學過 Windows Programming 應該都耳熟能詳：API 的加強版，通常是在原來的名字後面，加上個 Ex 後綴字尾以命名之。例如，CreateWindow() 的加強版，就叫做 CreateWindowEx()。]]></description>
			<content:encoded><![CDATA[<p>來聊聊 API 命名時，後綴字的處理。</p>
<p><strong>版號後綴字</strong></p>
<p>Windows SDK API 裡有個奇怪的命名慣例 (naming convention)，學過 Windows Programming 應該都耳熟能詳：API 的加強版，通常是在原來的名字後面，加上個 <code class="inline_code">Ex</code> 後綴字尾以命名之。例如，<code class="inline_code">CreateWindow()</code> 的加強版，就叫做 <code class="inline_code">CreateWindowEx()</code>。</p>
<p>之所以說這種命名慣例會「奇怪」是因為，如果還要對 <code class="inline_code">Ex</code> 版增強的時候，該怎麼辦？難道還要來一個 <code class="inline_code">CreateWindowExEx()</code> 嗎？那豈不沒完沒了？</p>
<p>針對這種問題，常見的解法有兩種。第一種比較簡單，就是棄 <code class="inline_code">Ex</code> 改數字。例如 <code class="inline_code"><a href="http://www.sqlite.org/c3ref/open.html">sqlite3_open</a>()</code> 與 <code class="inline_code"><a href="http://www.sqlite.org/c3ref/open.html">sqlite3_open_v2</a>()</code> 和 <code class="inline_code">xmlrpc_client_init()</code> 與 <code class="inline_code"><a href="http://xmlrpc-c.sourceforge.net/doc/libxmlrpc_client.html#client_init2">xmlrpc_client_init2</a>()</code>。<a href="http://www.sqlite.org/">SQLite</a> 的命名法比較囉唆，可是應該是因為還要支援 UTF-16 版的緣故；<a href="http://xmlrpc-c.sourceforge.net/">xmlrpc-c</a> 的方法比較常見，個人認為也比較簡潔方便。</p>
<p><strong>型別後綴字</strong></p>
<p>除了利用後綴字來表明版號之外，有時候，函式名稱後綴字也用來表明，其所處理的資料型別。舉例來說，Microsoft 的 <a href="http://www.jeffhung.net/blog/articles/jeffhung/522/">generic-text-mapping</a> 技術，利用 <code class="inline_code">A</code> 或 <code class="inline_code">W</code> 後綴，來區分輸出入使用 <code class="inline_code">char</code> 或 <code class="inline_code">wchar_t</code> 型別。</p>
<p>前述提到 <code class="inline_code">sqlite3_open()</code> 有 UTF-16 版本，命名為 <code class="inline_code"><a href="http://www.sqlite.org/c3ref/open.html">sqlite3_open16</a>()</code>，也是類似的手法。</p>
<p>我個人覺得，這種後綴字還算可以接受，可是如果是在用 C++，那就很搞笑了。事實上，若有機會用 C++ 把這類 C 的 API 包裝起來的話，我都會利用 overloading 機制，把型別後綴字幹掉，圖個清爽。</p>
<p><strong>行為後綴字</strong></p>
<p>另一種常見的 API 後綴字，代表著函式的行為不太一樣。例如很多 non-thread-safe 的 API，其 <a href="http://en.wikipedia.org/wiki/Reentrant_(subroutine)">reentrant</a> 版，也就是可安全地重複使用的版本，會在名稱後面加上 <code class="inline_code">_r</code> 的後綴字。例如 <code class="inline_code">strtok()</code> 的 reentrant 版叫 <code class="inline_code">strtok_r()</code>。通常加上 <code class="inline_code">_r</code> 的 API，其參數都會不太一樣，否則直接解掉問題即可，沒必要再另外發明一個 API。</p>
<p>Microsoft 在 Visual C++ 裡，對這類 non-thread-safe 的 API，解法不太一樣。使用 multithread 版 run-time library 時，若要從 non-thread-safe 變成 thread-safe 時，參數可以一樣不變，則同上述直接改掉實作，解掉問題，API 不變。可是，當碰到需要修改 prototype 更動參數時，Microsoft 用的是骯髒的手段，如利用 <a href="http://en.wikipedia.org/wiki/Thread-local_storage">TLS</a> 儲存需要增加的參數，使得 API 還是不變。原本因呼叫了 non-thread-safe API 的程式，立地成佛變成 thread-safe。</p>
<p>這其實會產生一些問題，<a href="http://blog.hubert.tw/2009/04/18/%E5%BE%9E-inet_ntoa-%E7%9C%8B-thread-safe-%E7%9A%84-api/">妨礙 porting</a> 我認為問題還小，讓 programmer 自以為安全，才是真正的隱憂。我認為，Microsoft 應該要做的，其實是當使用 multithread 版 run-time library 時，像 security enhanced crt 那樣，在 compile 時產生 deprecation warning，建議使用 reentrant 版 API 才對。</p>
<p>講到 VC 的 <a href="http://msdn.microsoft.com/en-us/library/8ef0s5kh.aspx">security enhanced crt</a> 就好笑，Microsoft 會在有安全疑慮的 API 後面，加上個 <code class="inline_code">_s</code> 後綴字。但問題是，M$ 根本沒有在管，參數是否相同，只要有安全疑慮，即使參數相同，也會發明一個對應的 <code class="inline_code">_s</code> 版 API。若目的是為了讓 programmer 可以認知道其實這個 API 並不安全，那就很搞笑了，參數相同時，讓 API 實作能夠安全，不正是 vendor 的責任嗎？更別提，<a href="http://fsfoundry.org/codefreak/2008/09/15/security-crt-safer-than-standard-library/">實際上 <code class="inline_code">_s</code> 版 API，並沒有多安全</a>的問題了。</p>
<p><strong>隨便亂選後綴字</strong></p>
<p>講了這麼多，其實我是想碎碎念，新同事你實作 thread-safe 版 API，在後面加上 <code class="inline_code">_s</code> 後綴字是想怎樣？畫虎不成反類犬，真是厲害。</p>
<p>還好我不再需要面對這種隨便亂選後綴字的 API 了。阿彌陀佛，善哉，善哉。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jeffhung.net/blog/articles/jeffhung/1846/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>libcurl, openssl, and ca-bundle - on Windows</title>
		<link>http://www.jeffhung.net/blog/articles/jeffhung/1966/</link>
		<comments>http://www.jeffhung.net/blog/articles/jeffhung/1966/#comments</comments>
		<pubDate>Tue, 30 Jun 2009 14:18:35 +0000</pubDate>
		<dc:creator>jeffhung</dc:creator>
				<category><![CDATA[Devel]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[cpp]]></category>

		<guid isPermaLink="false">http://www.jeffhung.net/blog/?p=1966</guid>
		<description><![CDATA[整理一下在 Windows 上，應付 libcurl、openssl 與 ca-bundle 的筆記。]]></description>
			<content:encoded><![CDATA[<p>整理一下在 Windows 上，應付 libcurl、openssl 與 ca-bundle 的筆記。</p>
<p>我們需要讓使用的 libcurl 支援 SSL，目標是要讓後續的開發，只在 IDE 進行即可，必須要做到從 repository 裡 checkout 出來，只要打開 IDE 就可以做完所有的事。</p>
<p>原本 curl 的 source tarball 裡，有包含了 <code class="inline_code">lib/curllib.dsp</code> 這個 VC6 的 project 檔，但很可惜的，這是給 <a href="http://en.wikipedia.org/wiki/Newbie">newbie</a> 用的，所以不包含 3rd-party 組件，如 OpenSSL。見 <code class="inline_code">docs/INSTALL</code> 檔：</p>
<blockquote>
<p>Intentionally, these reference VC++ 6.0 projects and configurations don't use third party libraries, such as OpenSSL or Zlib, to allow proper compilation and configuration for all new users without further requirements.</p>
</blockquote>
<p>但是我們已經使用這個 <code class="inline_code">curllib.dsp</code> 建立好了 for IDE 的開發環境，所以必須想辦法，把「老鳥的手段」放進「菜鳥的籃子」裡。</p>
<p>為了少編譯一個 OpenSSL 套件，我選擇使用 <a href="http://gnuwin32.sourceforge.net/packages/openssl.htm">GnuWin32 預先編譯好的 native openssl package</a>，抓下安裝程式，安裝到預設的目錄即可。</p>
<p>OpenSSL 共有兩個 DLL 檔：<code class="inline_code">libeay32.dll</code> 與 <code class="inline_code">libssl32.dll</code>。可是，GnuWin32 這個預先編譯好的套件，雖然說包含了 development files，但沒有包含 VC6 用的 DLL import library 或 def 檔，所以必須自己生出來。</p>
<p>一開始我先試著從 GnuWin32 版 OpenSSL 的 source tarball (<code class="inline_code">openssl-0.9.8h-1-src.zip</code>)，解出裡面的 libeay32.def 與 ssleay32.def，以製作對應的 import libraries：</p>
<pre class="code">
SHELL&gt; RENAME ssleay32.def libssl32.def
SHELL&gt; &quot;C:\Program Files\Microsoft VisualStudio\VC98\Bin\VCVARS32.BAT&quot;
SHELL&gt; LIB /DEF:libeay32.def
SHELL&gt; LIB /DEF:libssl32.def
</pre>
<p>其中，<code class="inline_code">ssleay32.def</code> 其實是 <code class="inline_code">libssl32.dll</code> 對應的 <code class="inline_code">DEF</code> 檔，故先正名之。然後引入 VC6 開發環境，呼叫 <code class="inline_code">LIB.exe</code> 工具，從 <code class="inline_code">DEF</code> 檔做出 import libraries。</p>
<p>測試結果發現，程式一啟動，就跳出視窗抱怨，找不到 <code class="inline_code">libeay32.dll</code> 序號 968 的 API。用 <code class="inline_code">depends.exe</code> 查，ordinal 968 這個 API 根本就是 N/A，從 <code class="inline_code">libeay32.def</code> 裡也找不到編號 968。</p>
<p>所以只好自己來，利用 <code class="inline_code">DUMPBIN.exe</code> 工具，直接從 DLL 裡列出 exported symbols，如下：</p>
<pre class="code">
SHELL&gt; DUMPBIN /EXPORTS libeay32.dll &gt; libeay32.def
SHELL&gt; DUMPBIN /EXPORTS libssl32.dl
</pre>
<p>然後編輯這兩個 <code class="inline_code">.DEF</code> 檔，把無關的東西去掉，僅剩下 exported symbols，弄成下面這個樣子：</p>
<pre class="code">
EXPORTS
        symbol1
        symbol2
        ...
</pre>
<p>從第二行開始，使用 TAB 字元縮排。</p>
<p>然後重複上面的程序，利用 <code class="inline_code">LIB.exe</code> 工具，製作出 import libraries，這次就可以正常使用了。把產生的 <code class="inline_code">.def</code>、<code class="inline_code">.lib</code> 與 <code class="inline_code">.exp</code> 檔，放到 <code class="inline_code">%ProgramFiles%\GnuWin32\lib</code> 目錄下，把兩個 DLL，放到 <code class="inline_code">%ProgramFiles%\GnuWin32\bin</code> 目錄下，然後如下修改 <code class="inline_code">curllib.dsp</code> 的 project setting，即可正常編譯出具備 SSL 功能的 libcurl：</p>
<ul>
<li>Add preprocessor definition: <code class="inline_code">USE_SSLEAY</code>；</li>
<li>Add include directories: <code class="inline_code">%ProgramFiles%\GnuWin32\include</code> 與 <code class="inline_code">%ProgramFiles%\GnuWin32\include\openssl</code>；</li>
<li>Add additional library path: <code class="inline_code">%ProgramFiles%\GnuWin32\lib</code>；</li>
<li>Add additional libraries: <code class="inline_code">libeay32.lib</code> 與 <code class="inline_code">libssl32.lib</code>。</li>
</ul>
<p>不過，要正常使用 SSL 功能，還是必須想辦法搞到 <a href="http://en.wikipedia.org/wiki/Certificate_Authority">CA</a> 給 curl 用才行。目前最新的 curl 版本，已經不再內附 CA certifications 了，所以我們要自己生才行。查 curl 文件，我們需要 <code class="inline_code">PEM</code> 格式的 CA。本來想說直接開 IE 或 firefox 把裡面用的 CA 匯出，可是發現沒辦法匯出成 <code class="inline_code">PEM</code> 格式。還好翻查 FreeBSD 裡灌的 curl，在 <code class="inline_code">/usr/local/share/curl</code> 目錄下，可以找到 <code class="inline_code">curl-ca-bundle.crt</code> 檔，將之如下傳給 CURLOPT_CAINFO 選項即可：</p>
<pre class="code">
curl_easy_setopt(handle, CURLOPT_CAINFO, &quot;/path/to/curl-ca-bundle.crt&quot;);
</pre>
<p>至此，大功告成。</p>
<p>參考資料：</p>
<ul>
<li><a href="http://www.vividreflection.com/blog/secret-to-curl-in-php-on-windows/">The Secret to cURL in PHP on Windows...</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.jeffhung.net/blog/articles/jeffhung/1966/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>用程式檢查程式 - 一定要引入的 header</title>
		<link>http://www.jeffhung.net/blog/articles/jeffhung/1205/</link>
		<comments>http://www.jeffhung.net/blog/articles/jeffhung/1205/#comments</comments>
		<pubDate>Mon, 29 Jun 2009 14:25:20 +0000</pubDate>
		<dc:creator>jeffhung</dc:creator>
				<category><![CDATA[Devel]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[cpp]]></category>
		<category><![CDATA[perl]]></category>

		<guid isPermaLink="false">http://www.jeffhung.net/blog/?p=1205</guid>
		<description><![CDATA[專案一大，就會設定一些「慣例」，以簡化專案複雜度。但是我們無法叫 compiler 幫我們檢查「慣例」，久而久之，這些「慣例」反而會成為混亂的來源。因此，最終還是得想個辦法，自動檢查這些「慣例」是否有被遵守才行。例如，檢查某個一定要被引入的 header 有否被引入。]]></description>
			<content:encoded><![CDATA[<p>專案一大，就會設定一些「慣例」，以簡化專案複雜度。但是我們無法叫 compiler 幫我們檢查「慣例」，久而久之，這些「慣例」反而會成為混亂的來源。因此，最終還是得想個辦法，自動檢查這些「慣例」是否有被遵守才行。例如，檢查某個一定要被引入的 header 有否被引入。</p>
<p>我習慣一個函式庫，會有一個 <code class="inline_code">config.h</code>，將所有 compile-time options 放在裡面，並規定函式庫裡的所有 header/source files 都一定要引入此 <code class="inline_code">config.h</code>，這樣子裡面的設定，才能廣為周知。</p>
<p>假設這個函式庫叫 <code class="inline_code">messy</code>，則 <code class="inline_code">config.h</code> 會位於 <code class="inline_code">include/messy/config.h</code>，平常以 <code class="inline_code">#include &lt;messy/config.h&gt;</code> 引入。那我們可以用以下的 perl 程式片段，檢查是否每個 header/source files 皆有引入 <code class="inline_code">config.h</code>：</p>
<pre class="code">
use File::Grep;
use File::Find::Rule;

print &quot;CHECK: C/C++ sources must include &lt;messy/config.h&gt;.\n&quot;;
print join(
    &quot;\n&quot;,
    map { &quot;| $_-&gt;{'filename'}&quot; }
    grep { $_-&gt;{'count'} == 0 }
    File::Grep::fgrep { /^\s*#\s*include\s+&lt;messy\/config.h&gt;/ }
    grep { $_ !~ m/messy\/config.h$/o }
    File::Find::Rule-&gt;or(
        File::Find::Rule-&gt;directory-&gt;name('.svn')-&gt;prune-&gt;discard,
        File::Find::Rule-&gt;file()-&gt;name(qr/\.(h|hpp|c|cpp)$/i)
    )-&gt;in('include', 'src')
) || &quot;[ok]&quot;;
print &quot;\n\n&quot;;</pre>
<p>把這段程式，放在 post-build 裡，每次編譯函式庫時，最後就會執行，檢查除了 <code class="inline_code">include/messy/config.h</code> 以外的所有 header/source 檔案，是否皆有引入 <code class="inline_code">include/messy/config.h</code>，沒有引入的檔名，就會列出來，若統統都有引入，就會印出 <code class="inline_code">[ok]</code> 字樣。如下：</p>
<pre class="code">
CHECK: C/C++ sources must include &lt;messy/config.h&gt;.
| include/messy/debug_tool/func_trace.hpp
| src/messy.debug_tool.func_trace.cpp
</pre>
<p>修正後就會變成如下：</p>
<pre class="code">
CHECK: C/C++ sources must include &lt;messy/config.h&gt;.
[ok]
</pre>
<p>檢查結果會一併出現在 build log 的最後面，有需要時，就可以依據指定的「慣例」，去修正那些有問題的檔案。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jeffhung.net/blog/articles/jeffhung/1205/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Help Online and 404</title>
		<link>http://www.jeffhung.net/blog/articles/jeffhung/1985/</link>
		<comments>http://www.jeffhung.net/blog/articles/jeffhung/1985/#comments</comments>
		<pubDate>Mon, 08 Jun 2009 14:26:45 +0000</pubDate>
		<dc:creator>jeffhung</dc:creator>
				<category><![CDATA[Devel]]></category>
		<category><![CDATA[http]]></category>

		<guid isPermaLink="false">http://www.jeffhung.net/blog/?p=1985</guid>
		<description><![CDATA[自從網際網路普及之後，寫 desktop application 的人，就把腦筋動到了這上面，試著將軟體的說明系統，移到 WWW 上。打的主意，當然是希望讓說明系統「活」起來，在軟體釋出之後，依然可以新增、修改內容。畢竟，使用文件只能依靠人力撰寫修訂，通常也得等到開發後期，才能開始動工。不過…]]></description>
			<content:encoded><![CDATA[<p>自從網際網路普及之後，寫 desktop application 的人，就把腦筋動到了這上面，試著將軟體的說明系統，移到 WWW 上。打的主意，當然是希望讓說明系統「活」起來，在軟體釋出之後，依然可以新增、修改內容。畢竟，使用文件只能依靠人力撰寫修訂，通常也得等到開發後期，才能開始動工。</p>
<p>不過，不將說明文件附在軟體套件裡，而是另外提供於網站上，最大的問題就是，如果當下沒有連上網，怎麼辦？因此，後來的 Visual Studio 有個選項就是，讓使用者選擇 help content 的來源，可以是「try online first, then local」、「Try local first, then onlie」或是「Try local only, not online」。</p>
<p>可是，沒有連上網，問題還好解決，連上網就是了，反正這年頭不連著網路，做什麼都不方便。更大的問題，應該是：軟體公司會不會倒？萬一推出桌面程式的軟體公司倒了，亦或是收手放棄該軟體，線上的說明文件，很可能也將不再提繼續提供。畢竟，要把東西一直放在網路上，也是要成本的。屆時，當初花了錢買的軟體，就得哭爸哭媽找不到地方求助了。</p>
<p>這絕對不是在危言聳聽。SQL Server 2005 算是 Microsoft 的主力產品之一，也幾乎是最新的版本，可是當我從主選單的「社群」&gt;「詢問問題」按下去：</p>
<p style="text-align: center;"><a target="_blank" href="http://www.flickr.com/photos/jeffhung/3606789704/"><img alt="" src="http://farm4.static.flickr.com/3603/3606789704_ea4b8fc6d2.jpg" /></a></p>
<p>得到的卻是，自動開啟 Document Explorer 之後，顯示了 http://social.microsoft.com/error/error404.aspx 這個網址：</p>
<p style="text-align: center;"><a href="http://www.flickr.com/photos/jeffhung/3606789852/" target="_blank"><img src="http://farm4.static.flickr.com/3382/3606789852_a7b862c783.jpg" alt="" /></a></p>
<p>這時候，我該苦笑自嘲，這個「Page Not Found」有放搜尋框，勉強有應了「詢問問題」這個功能名稱嗎？XD</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jeffhung.net/blog/articles/jeffhung/1985/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Building VC Projects in Console Mode</title>
		<link>http://www.jeffhung.net/blog/articles/jeffhung/1922/</link>
		<comments>http://www.jeffhung.net/blog/articles/jeffhung/1922/#comments</comments>
		<pubDate>Fri, 08 May 2009 09:52:13 +0000</pubDate>
		<dc:creator>jeffhung</dc:creator>
				<category><![CDATA[Devel]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[cpp]]></category>

		<guid isPermaLink="false">http://www.jeffhung.net/blog/?p=1922</guid>
		<description><![CDATA[通常我們在 Visual C++ 裡開發，是以其圖形介面的 IDE 為主要操作環境。若為了要把一些工作自動化，就必須要找到方法，在 console mode 下編譯建置專案。]]></description>
			<content:encoded><![CDATA[<p>通常我們在 Visual C++ 裡開發，是以其圖形介面的 IDE 為主要操作環境。若為了要把一些工作自動化，就必須要找到方法，在 console mode 下編譯建置專案。</p>
<p>因為工作氛圍之故，無法擺脫 Visual C++ IDE 那一套 build configuration 機制，所以只好寫了這一個 vc-build.bat 的批次檔，直接在 console mode 下進行原本要按按鈕、點選單，才能做的事。</p>
<p>程式碼在此：<a href="http://github.com/jeffhung/blog-share/blob/8cb0d589e7415582204167e7d5d61083db7bfda5/vc-build.bat">vc-build.bat on github</a>，使用起來很簡單：</p>
<pre class="code">
------------------------------------------------------------------------------
Usage: vc-build.bat [vc] [solution] [project] [configuration]
Usage: vc-build.bat [vc] [solution] [project] [configuration] [action]
------------------------------------------------------------------------------
            [vc] could be vc6, vc8, or vc9.
      [solution] is the .dsw or .sln file.
       [project] is the project to build.
 [configuration] could be Debug or Release, normally.
        [action] could be BUILD, REBUILD, or CLEAN (case insentively).</pre>
<p>依據以上的參數說明，執行即可。包括於 project 檔裡設定好的 pre/post events 的外部程式，都會正確執行。除了可以與 <a href="http://buildbot.net/">buildbot</a> 這類 <a href="http://en.wikipedia.org/wiki/Continuous_integration">continuous integration</a> 工具整合之外，設定進 <a href="http://www.vim.org">vim</a> 的 <code class="inline_code">makeprg</code> 參數，亦是擺脫 IDE 的好方法。</p>
<p>參考資料：</p>
<ul>
<li><a href="http://avhacker.blogspot.com/2007/07/incredibuild-console-build-project.html">Incredibuild 在 console 模式 build project 的語法</a></li>
<li>MSDN - <a href="http://msdn.microsoft.com/en-us/library/xee0c8y7.aspx">Devenv Command Line Switches</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.jeffhung.net/blog/articles/jeffhung/1922/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>wp2docbook.pl - DocBook from wordpress export</title>
		<link>http://www.jeffhung.net/blog/articles/jeffhung/1006/</link>
		<comments>http://www.jeffhung.net/blog/articles/jeffhung/1006/#comments</comments>
		<pubDate>Thu, 07 May 2009 14:55:06 +0000</pubDate>
		<dc:creator>jeffhung</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[perl]]></category>
		<category><![CDATA[web]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://www.jeffhung.net/blog/?p=1006</guid>
		<description><![CDATA[看到 gslin 最近連續寫了兩篇文章，談論 wordpress 的 export 檔，就想起之前在 wordpress 2.3 的時候，寫過一個 wp2docbook.pl，可以將 wordpress export 檔，轉成 DocBook 格式。]]></description>
			<content:encoded><![CDATA[<p>看到 <a href="http://blog.gslin.org/about/">gslin</a> 最近連續寫了兩篇<a href="http://blog.gslin.org/archives/2009/04/24/2002/">文章</a>，談論 <a href="http://blog.gslin.org/archives/2009/05/07/2016/">wordpress 的 export 檔</a>，就想起之前在 <a href="http://www.wordpress.org/">wordpress</a> 2.3 的時代，寫過一個 <code class="inline_code">wp2docbook.pl</code>，可以將 wordpress export 檔，轉成 <a href="http://www.google.com/url?sa=t&amp;source=web&amp;ct=res&amp;cd=1&amp;url=http%3A%2F%2Fwww.docbook.org%2F&amp;ei=DXwCSq6WA5uG6AO1-4GYAw&amp;usg=AFQjCNHtErWInFJy1-AwBBy3I2J3NS2ZoA&amp;sig2=vMWJRAXlTRNSiHuoyjayjg">DocBook</a> 格式。</p>
<p>轉成 DocBook 格式有很多好處，除了是一種 wordpress independent 備份方式外，亦可以再輸出成 PDF、Word 等做更進一步的處理。有時候要把文章給別人的時候，不方便直接把網頁印下來，若有 DocBook 版，就可以先轉成 word，再修補一下就搞定了。</p>
<p>這個 <code class="inline_code">wp2docbook.pl</code>，讀入 wordpress export 後，會試著理解文章裡的 HTML 碼，轉換成對應的 DocBook 標籤。可以輸出成一個超級大 DocBook 檔，裡面有很多 <code class="inline_code">&lt;article&gt;</code>，也可以每一個 <code class="inline_code">&lt;article&gt;</code> 輸出一個檔，方便備份整理。我用自己的 blog 測試過，六百多篇文章，沒什麼問題。</p>
<p>不過那是在那個時候。XD</p>
<p>如同 gslin 所述，wordpress 的 export 檔，格式問題很多。在寫 <code class="inline_code">wp2docbook.pl</code> 的時候，就搞了很多 hacks，試著解決格式問題。這些 hacks 雖然沒有像 gslin 那樣暴力，但也差不多了。最後發現，export 檔格式一直在變，隨著版本更新，有的欄位修好了，有的欄位又爛了。後來覺得，跟著 wordpress 一直修修補補轉檔程式，實在很沒意思，就放棄更新了。</p>
<p>本來那時就要撰文記錄之，但標題有了就擺在 draft 好久。現在既然提到了，那就釋出吧，順便練練 <a href="http://git-scm.com/">git</a> 與 <a href="http://github.com/">github </a>的使用。這個版本已經不能處理目前最新的 wordpress 2.7.1 版的 export 檔了，不過以 <a href="http://www.opensource.org/licenses/bsd-license.php">BSDL</a> 釋出，有需要的人就自己再 hack 吧。</p>
<p>請享用：<a href="http://github.com/jeffhung/blog-share/blob/233b461d10eb48d8141cc7f12421b157d07fd030/wp2docbook.pl">wp2docbook on github</a>。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jeffhung.net/blog/articles/jeffhung/1006/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>字串處理風格</title>
		<link>http://www.jeffhung.net/blog/articles/jeffhung/1870/</link>
		<comments>http://www.jeffhung.net/blog/articles/jeffhung/1870/#comments</comments>
		<pubDate>Tue, 21 Apr 2009 14:44:01 +0000</pubDate>
		<dc:creator>jeffhung</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[cpp]]></category>
		<category><![CDATA[visualbasic]]></category>

		<guid isPermaLink="false">http://www.jeffhung.net/blog/?p=1870</guid>
		<description><![CDATA[最近有在用 wxWidgets 寫一些東西練功，初步的感想是…]]></description>
			<content:encoded><![CDATA[<p>最近有在用 <a href="http://www.wxwidgets.org/">wxWidgets </a>寫一些東西練功，初步的感想是，wxWidgets 其實走得不是 <a href="http://en.wikipedia.org/wiki/Microsoft_Foundation_Class_Library">MFC</a> 風格，而是 <a href="http://en.wikipedia.org/wiki/Visual_Basic">VB</a> 風格。然後我看到了這篇《<a href="http://www.planet-source-code.com/vb/scripts/ShowCode.asp?txtCodeId=169&amp;lngWId=10">_ A String manipulation example in VB.NET, EQUIVALENTS: Len, Mid, Replace, InStr, UCase, Split etc _ </a>》，就想到，對啊，這也是證據之一，<code class="inline_code"><a href="http://docs.wxwidgets.org/stable/wx_wxstring.html">wxString</a></code> 的介面，幾乎就跟 VB 一樣嘛。</p>
<p>不過我還是不習慣 VB/wxWidgtes 的字串處理風格，感覺上太沒有效率了，邊寫就會邊想，這如果是在 C/C++，可以怎樣寫，效率可以好上多少倍。</p>
<p>所以我還是直接用 <code class="inline_code">std::string</code> 寫好了，字串處理完畢，再轉成 <code class="inline_code">wxString</code> 送回去。</p>
<p>實際上，用 MFC 的 CString 也是一整個彆扭，個人感覺甚至比 VB 的字串、<code class="inline_code">wxString</code> 還要來的更糟。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jeffhung.net/blog/articles/jeffhung/1870/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>650 行的 constructor</title>
		<link>http://www.jeffhung.net/blog/articles/jeffhung/1838/</link>
		<comments>http://www.jeffhung.net/blog/articles/jeffhung/1838/#comments</comments>
		<pubDate>Mon, 13 Apr 2009 06:51:04 +0000</pubDate>
		<dc:creator>jeffhung</dc:creator>
				<category><![CDATA[Devel]]></category>
		<category><![CDATA[Murmuring]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Work]]></category>
		<category><![CDATA[database]]></category>

		<guid isPermaLink="false">http://www.jeffhung.net/blog/?p=1838</guid>
		<description><![CDATA[原來我也會寫出 650 行的 constructor。XD]]></description>
			<content:encoded><![CDATA[<p><span class="status-body"><span class="entry-content">原來我也會寫出 650 行的 constructor，滾輪轉半天，還看不到放在下面的 destructor。XD</span></span></p>
<p><span class="status-body"><span class="entry-content">哼哼，一切都是註解太多的錯。</span></span></p>
<p><span class="status-body"><span class="entry-content">另一個錯的是</span></span> Windows Programming 的 style，要不是已經把 error handling 另外濃縮處理過了，否則不含註解的部份，還要再膨脹個 5 倍左右。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jeffhung.net/blog/articles/jeffhung/1838/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Who&#039;s code caught the error, who deal with it?</title>
		<link>http://www.jeffhung.net/blog/articles/jeffhung/1016/</link>
		<comments>http://www.jeffhung.net/blog/articles/jeffhung/1016/#comments</comments>
		<pubDate>Sun, 05 Apr 2009 14:53:14 +0000</pubDate>
		<dc:creator>jeffhung</dc:creator>
				<category><![CDATA[Devel]]></category>
		<category><![CDATA[Murmuring]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Work]]></category>

		<guid isPermaLink="false">http://www.jeffhung.net/blog/?p=1016</guid>
		<description><![CDATA[這是一個很久很久以前就有的 murmur。在工作上，有時候會聽到這樣的怒吼：「吼～又是你的 assertion 把程式當掉。」可是…]]></description>
			<content:encoded><![CDATA[<p>這是一個很久很久以前就有的 murmur。</p>
<p>在工作上，有時候會聽到這樣的怒吼：「吼～又是你的 assertion 把程式當掉。」可是，細查之後卻又發現，之所以會 assertion failure，是某個應該存在的值不存在，或某件事情在之前就失敗了，於是當程式執行到 assertion 處，一檢查就發現問題，然後把程式當掉。</p>
<p>Assertion 之所以存在，為的就是希望能夠揪出，所有不應該存在的異常情形，是故，assertion 其實應該是多多益善，埋的越多，越有機會揪出程式的不良之處。所以，我很喜歡埋 assertion，凡是無法處理的特殊輸入、必須存在的情境參數，甚至是失敗就等於整個程式根本無法運作的 API 呼叫，我都會使用 assertion 以便盡早地把程式當掉，輔助我們揪出錯誤的發生點。</p>
<p>問題是，當 assertion 發生時，總是要有某個人負責去找出問題的成因，而理所當然地，在只有 assertion failure 這條線索的情況下，問題就被丟給寫 assertion 的人。但因為 assertion 通常是用來抓「不是在此處發生的錯誤」，因此產生了這麼一個吊詭：</p>
<p><strong>越認真地(寫程式)使錯誤顯現的人，反而越容易領到爛攤子，必須承擔解決(多半)不是其程式所造成之錯誤的責任。</strong></p>
<p>一般來說，程式設計師比較喜歡寫新程式，而不喜歡維護舊程式，更討厭的就是負責維護不是他寫的舊程式，所以上述的吊詭，等於是在懲罰認真的人，而且是越認真(埋 assertion 炸彈)，等著的是越多的爛攤子。</p>
<p>也就是說，可以討論的，應該是 assertion 的標的是否合適，而不是 assertion 是否應該把程式當掉。只要標的合適，當程式當掉時，我們該慶幸，assertion 讓我們發現，程式會當掉，而不是等到移交給客戶後，隱藏的炸彈才一個一個爆發。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jeffhung.net/blog/articles/jeffhung/1016/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Marginal Leak vs. Fixed Leak</title>
		<link>http://www.jeffhung.net/blog/articles/jeffhung/1787/</link>
		<comments>http://www.jeffhung.net/blog/articles/jeffhung/1787/#comments</comments>
		<pubDate>Sun, 29 Mar 2009 14:44:06 +0000</pubDate>
		<dc:creator>jeffhung</dc:creator>
				<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://www.jeffhung.net/blog/?p=1787</guid>
		<description><![CDATA[在實務上，一般我們將 resource leak 分成兩大類，一種是程式執行一次，僅會發生一次的 leak，另一種則會隨著每次運算而屢次發生的 leak。今天我突發奇想，這兩者，是否可稱之為「fixed leak」與「marginal leak」？]]></description>
			<content:encoded><![CDATA[<p>在實務上，一般我們將 <a href="http://en.wikipedia.org/wiki/Resource_leak">resource leak</a> 分成兩大類，一種是程式執行一次，僅會發生一次的 leak，另一種則會隨著每次運算而屢次發生的 leak。今天我突發奇想，這兩者，是否可稱之為「fixed leak」與「marginal leak」？<strong><br />
</strong></p>
<p>在經濟學裡，「<a href="http://en.wikipedia.org/wiki/Marginal_cost">邊際成本 (marginal cost)</a>」指會隨著每單位生產的新產品而增加的成本，例如製作每個麵包，所需要之麵粉的購買成本。<a href="http://zh.wikipedia.org/w/index.php?title=%E8%BE%B9%E9%99%85%E6%88%90%E6%9C%AC&amp;variant=zh-tw">Wikipedia 如是說</a>：</p>
<blockquote>
<p>在經濟學和金融學中，邊際成本指的是每一單位新增生產的產品（或者購買的產品）帶來到總成本的增量。</p>
</blockquote>
<p>與之相對的則是「<a href="http://en.wikipedia.org/wiki/Fixed_cost">固定成本 (fixed cost)</a>」，不會隨著業務量而變化的成本，如烘培麵包所需之烤爐的購置成本。<strong><br />
</strong></p>
<p>而當在寫程式的時候，可能會碰到的 resource leak，其行為也可以分成兩大類：程式執行一次，不管做了多少事，固定會洩漏一定量的 leak，以及隨著做的事情越多，洩漏的量越多的 leak。</p>
<p>套用經濟學的概念，我在想，其實可以把上面這兩大類 resource leak，稱呼為：</p>
<ul>
<li>fixed leak：程式執行一次，不管做了多少事，固定會洩漏一定量的 leak；</li>
<li>marginal leak：隨著做的事情越多，洩漏的量越多的 leak。</li>
</ul>
<p>其中，marginal leak 較為嚴重，會隨著程式執行越久，吃掉越多的資源，最後導致資源不足，使程式當掉，甚至當掉整台電腦。</p>
<p>而 fixed leak 問題較小，若時程不夠，通常我們會忽略之。不過要小心的就是，若程式支援某種 reset 機制，如某些 server 收到 <code class="inline_code">SIGHUP</code> 會重讀設定檔，則可能某些 fixed leak 會現出真面目，其實是 marginal leak，會隨著 reset 而增加洩漏的量。</p>
<p>好奇，用加雙引號的 &quot;marginal leak&quot; 查了一下 google，發現只有 160 筆。區分這兩種 leak，一般都是用什麼專有名詞啊？</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jeffhung.net/blog/articles/jeffhung/1787/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Code Review 什麼時候沒有用？</title>
		<link>http://www.jeffhung.net/blog/articles/jeffhung/1776/</link>
		<comments>http://www.jeffhung.net/blog/articles/jeffhung/1776/#comments</comments>
		<pubDate>Mon, 23 Mar 2009 01:49:53 +0000</pubDate>
		<dc:creator>jeffhung</dc:creator>
				<category><![CDATA[Murmuring]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Work]]></category>

		<guid isPermaLink="false">http://www.jeffhung.net/blog/?p=1776</guid>
		<description><![CDATA[今天早上一上班，看到上禮拜下班前跑的測試，果然還是死掉了。 面對體無完膚，多個臟器破裂，到處都是還沒找到的破洞，在這個情況之下，這種內出血嚴重的程式模組，code review 已經沒有用了。 更別提原作者在會中，一直嚷嚷，看起來都沒問題啊。XD 2009-03-23 13:00 更新：補一下這篇《The only valid measurement of code quality: WTF/m》。]]></description>
			<content:encoded><![CDATA[<p>今天早上一上班，看到上禮拜下班前跑的測試，果然還是死掉了。</p>
<p>面對體無完膚，多個臟器破裂，到處都是還沒找到的破洞，在這個情況之下，這種內出血嚴重的程式模組，code review 已經沒有用了。</p>
<p>更別提<a href="http://www.jeffhung.net/blog/articles/jeffhung/861/">原作者</a>在會中，一直嚷嚷，看起來都沒問題啊。XD</p>
<p><strong>2009-03-23 13:00 更新：</strong>補一下這篇《<a href="http://www.osnews.com/story/19266/WTFs_m">The only valid measurement of code quality: WTF/m</a>》。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jeffhung.net/blog/articles/jeffhung/1776/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>真㊣的 porting</title>
		<link>http://www.jeffhung.net/blog/articles/jeffhung/1744/</link>
		<comments>http://www.jeffhung.net/blog/articles/jeffhung/1744/#comments</comments>
		<pubDate>Thu, 19 Mar 2009 13:17:14 +0000</pubDate>
		<dc:creator>jeffhung</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[cpp]]></category>
		<category><![CDATA[socket]]></category>
		<category><![CDATA[tcpip]]></category>

		<guid isPermaLink="false">http://www.jeffhung.net/blog/?p=1744</guid>
		<description><![CDATA[在工作上，常常需要把同樣的功能，porting 到不同的平台上去。有些 porting 很簡單，找出對應的 API 代換即可，但有些 porting，就真的很需要對各個平台，非常細緻的理解與熟習。]]></description>
			<content:encoded><![CDATA[<p>在工作上，常常需要把同樣的功能，porting 到不同的平台上去。有些 porting 很簡單，找出對應的 API 代換即可，但有些 porting，就真的很需要對各個平台，非常細緻的理解與熟習。</p>
<p>對應的 API 代換很簡單，例如 <code class="inline_code">pthread_create()</code> 換到 Win32 平台，可以用 <code class="inline_code">_beginthreadex()</code> 代替，頂多需要注意一下參數的不同即可。</p>
<p>有些 API 代換則比較複雜一些，牽涉到程式邏輯的不同。不過因為在功能面上是對等的，只是寫法不同，所以也不是什麼大問題。</p>
<p>例如，「列出目錄內容」這件事，在 UNIX 上要用 <code class="inline_code">opendir</code>/<code class="inline_code">readdir</code>/<code class="inline_code">closedir</code> 這組函式：</p>
<pre class="code">
void list_dir(const char* dir)
{
    DIR* d = opendir(dir);
    dirent* e;
    while ((e = readdir(d)) != NULL) {
        printf(&quot;%s\n&quot;, e-&gt;d_name);
    }
    closedir(d);
}
</pre>
<p>但是到了 Windows 上，則要用 <code class="inline_code">FindFirstFile</code>/<code class="inline_code">FindNextFile</code>/<code class="inline_code">FindClose</code> 這組函式：</p>
<pre class="code">
void list_dir(const char* dir)
{
    // prepare wildcard path
    char wild[MAX_PATH];
    strcpy(wild, dir);
    strcat(wild, &quot;\\*&quot;);

    WIN32_FIND_DATA wfd;
    memset(&amp;wfd, 0, sizeof(wfd));
    HANDLE h = FindFirstFile(wild, &amp;wfd);
    if (h == INVALID_HANDLE_VALUE) {
        throw &quot;FindFirstFile() failed.&quot;;
    }
    do {
        printf(&quot;%s\n&quot;, wfd.cFileName);
    } while (FindNextFile(h, &amp;wfd));
    FindCloseFile(h);
}
</pre>
<p>兩組函式的寫法不太一樣，差別在於，第一筆資料在 UNIX 上，同其他筆資料，係由 <code class="inline_code">readdir()</code> 取得，但在 Windows 上，卻是第一筆資料由 <code class="inline_code">FindFirstFile()</code> 取得，其他筆資料由 <code class="inline_code">FindNextFile()</code> 取得。這點差異，導致了兩邊的程式寫法不太一樣。</p>
<p>不過如何，最近我碰到的這個例子，才真的叫難。</p>
<p>話說 socket programming 是由 BSD (UNIX) 發展出來的，之後才移植到各個平台，如 Windows 上的 WinSock。當一條 TCP 連線使用完畢時，我們可以呼叫 <code class="inline_code">close()</code> 將這個 socket 關閉，也可以用 <code class="inline_code">shutdown()</code> 取代 <code class="inline_code">close()</code>。</p>
<p>在 UNIX 裡，<code class="inline_code">close()</code> 會做 reference counting，若有多個 socket 對應到同一條 TCP connection，則只有當最後一個 socket 被 <code class="inline_code">close()</code> 時，這條 TCP connection 才真的會被結束掉。這通常發生於使用 <code class="inline_code">fork()</code> 來處理 incoming connection 時，母行程 <code class="inline_code">accept()</code> 得到 socket 後，會呼叫 <code class="inline_code">fork()</code> 複製出子行程來處理。此時，母行程與子行程各自擁有一個 socket，同時對應到這條 TCP connection。當母行程 <code class="inline_code">fork()</code> 完畢後，會馬上呼叫 <code class="inline_code">close()</code> 將 socket 關閉，因為母行程再也不需要用到這條 TCP connection。如果這個 <code class="inline_code">close()</code> 真的把 TCP connection 給結束掉，那子行程就沒戲唱了。所以，<code class="inline_code">close()</code> 會做 reference counting，只有在子行程也 <code class="inline_code">close()</code> 時，才會真的把 TCP connection 關閉。</p>
<p>在 Windows 裡，socket 不能用 <code class="inline_code">close()</code> 關閉，要用一個特別版本的 <code class="inline_code">closesocket()</code> 才行。<code class="inline_code">closesocket()</code> 與 UNIX 上的 <code class="inline_code">close()</code>，功能相同。</p>
<p>至此，porting 仍處在 API 對應的等級，很簡單。可是，問題就出在可以取代 <code class="inline_code">close()</code> 的 <code class="inline_code">shutdown()</code>。</p>
<p>兩者之間的差別在於，<code class="inline_code">shutdown()</code> 將不理會 socket 的 reference counting，馬上送出 <code class="inline_code">FIN</code> 將 TCP connection 結束。使用 <code class="inline_code">shutdown()</code> 的好處顯而易見，我們可以確定這個&nbsp;TCP connection 立刻結束，可加強資源控管。</p>
<p>依據《UNIX Network Programming》這本 socket programming 的聖經級書本所述：</p>
<blockquote>
<p>If we really want to send a <code class="inline_code">FIN</code> on a TCP connection, the <code class="inline_code">shutdown</code> function can be used instead of <code class="inline_code">close</code>.</p>
</blockquote>
<p>我們可以用 <code class="inline_code">shutdown()</code> 完全取代 <code class="inline_code">close()</code>：用了 <code class="inline_code">close()</code> 就不要用 <code class="inline_code">shutdown()</code>，用了 <code class="inline_code">shutdown()</code> 就不要用 <code class="inline_code">close()</code>。</p>
<p>可是，MSDN 卻說：</p>
<blockquote>
<p>The <code class="inline_code">shutdown</code> function does not close the socket. Any resource attached to the socket will <em>not</em> be freed until <code class="inline_code">closesocket</code> is invoked.</p>
</blockquote>
<p>意思是說，在 WinSock 裡，用了 <code class="inline_code">shutdown()</code> 之後，還要用 <code class="inline_code">closesocket()</code>，才能「關乾淨」把資源全部釋放。</p>
<p>就是因為這一點細節的不同，若是忽略了，就會產生 leak。要不是不小心看到 MSDN 的這一句，我也會疏忽掉，產生極難追蹤的 bug。</p>
<p>唯有通曉這類精微的細節，才能做到「真㊣的 porting」。面對浩如瀚海的 Windows APIs，我也只能兢兢業業地，一步一腳印，細讀 MSDN 的每一字每一句，希望能夠捕捉到，這些會害死人不償命的微光掠影。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jeffhung.net/blog/articles/jeffhung/1744/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>好大的嵌入式資料庫</title>
		<link>http://www.jeffhung.net/blog/articles/jeffhung/1712/</link>
		<comments>http://www.jeffhung.net/blog/articles/jeffhung/1712/#comments</comments>
		<pubDate>Wed, 04 Mar 2009 13:06:16 +0000</pubDate>
		<dc:creator>jeffhung</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[database]]></category>

		<guid isPermaLink="false">http://www.jeffhung.net/blog/?p=1712</guid>
		<description><![CDATA[剛剛在裝 MySQL 5.1 for Windows，直接選 msi 檔安裝，然後就看到下面這個畫面…]]></description>
			<content:encoded><![CDATA[<p>剛剛在裝 MySQL 5.1 for Windows，直接選 msi 檔安裝，然後就看到下面這個畫面：</p>
<p style="text-align: center;"><a href="http://flickr.com/photos/jeffhung/3327991680/"><img alt="" src="http://farm4.static.flickr.com/3588/3327991680_9a74412bf8.jpg" /></a></p>
<p>有趣的是 Feature Description：</p>
<blockquote>
<p>The MySQL Embedded Server offers the MySQL-Server functionality in a small library that can be bundled with other applications.</p>
<p>This feature requires 151MB on your hard drive.</p>
</blockquote>
<p>真是厲害，embedded server 要 151 MB，還說明是 a small library，不曉得是小到哪裡去了。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jeffhung.net/blog/articles/jeffhung/1712/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

