星期四, 12月 17, 2009

vim plugin: autocomplpop (acp)

vim 內建的 omni c complete function 其實算是堪用,但不方便的就是每次都要自己按 ^P, ^N 或是 ^X^O 等組合才會跳出來讓你選。這兩天在 Vim taiwan 的 mailing list 看到 acp 這個 plugin,試用了以後愛不釋手,安裝方法跟其他vim plugin 沒兩樣:
到這邊下載最新版的 autocomplpop: http://www.vim.org/scripts/script.php?script_id=1879
然後解壓縮在 ~/.vim 就可以了:
unzip -d ~/.vim vim-autocomplpop.zip
這樣就算是安裝好了,開 vim 也會自動執行。
autocomplpop 簡單的說就是你每輸入一個超過長度的word(預設2個字元) 他就開始用 keyword/omni 找可能的補全單字然後顯示在pmenu,多說無益,試過才知道!

不過剛裝好的時候有點不習慣,因為他預設的搜尋範圍不包括 include 近來的檔案,所以以前慣用的 ^N, ^P (或是 ^X^i) 就只能用 ^X^I 呼叫出來,要讓 acp 也搜尋include 的檔案的話只要在 ~/.vimrc 加入下面的設定:(vim 預設 .,w,b,u,t,i ; acp 預設 .,w,b,k)
let g:acp_completeOption = '.,w,b,u,t,i,k'
每個選項的功用可以參考 :help complete
這樣邊打字就也會邊出現 api 的 auto complete popup,挺實用的!
------------------
另外這個也是在 mailing list 上看到的(其實是包含在acp 的help file裡,只是大家沒注意到):
acp 也提供 snipMate 一個接口,讓 snipMate 的補全也變成 menu 的樣式讓你選,啟動的方法只要在 ~/.vim/plugin/snipMate.vim 加入

  fun! GetSnipsInCurrentScope()
    let snips = {}
    for scope in [bufnr('%')] + split(&ft, '\.') + ['_']
      call extend(snips, get(s:snippets, scope, {}), 'keep')
      call extend(snips, get(s:multi_snips, scope, {}), 'keep')
    endfor
    return snips
  endf
然後在 ~/.vimrc:
let g:acp_behaviorSnipmateLength=1
這樣輸入大寫字母的時候他就會去找 snipMate 的 template 看有沒有符合的項目並整理到menu 顯示,有興趣的人可以試看看。

星期三, 12月 16, 2009

load balance in difference internet interfaces

如果你有兩張網卡都是連上外部網路的話,可以透過 ip route 來做 load balance,方法很簡單,基本上就是把 default route 改成 multipath route。當然在這之前需要先把 ip route 設好讓一個 IP (TCP/UDP)連線只經由該連線存在的 interface 送出。

當然這只是很簡單的提供 load balance 的機制.. 有時候並不是那麼有用,不過將就點用吧 XD

其實設定上也很簡單,network split 的部份我就不再重複紀錄了,跟我之前寫過的這篇 差不多。
balance 的部份就是把default route 分成兩個 channel 依照 weight 決定連線走哪一條。步驟大概是這樣:

ip route del default #把目前 defualt route 刪掉
ip route add default scope global nexthop via [gw1] dev [if1] weight [weight1] \
nexthop via [gw2] dev [if2] weight [weight2]
假如我要從兩個 ISP 出去, 一個ip 是 A 另一個 B,分別透過 eth0 跟 eth1 連線,而 A 的連線速度比較快,可能是 B 的兩倍,那麼我可以這樣設定:(gateway 可以用 route -n 看)
ip route del default
ip route add default scope global nexthop via gw1 dev eth0 weight 2 \
nexthop via gw2 dev eth1 weight 1

這樣就設定好了,如果看 ip route 的話會看到下面這樣的結果

default
    nexthop via gw1  dev eth0 weight 2
    nexthop via gw2  dev eth0 weight 1
觀察流量的話也可以大略用 iptraf 看一下各個network interface 上面的流量。

星期日, 12月 06, 2009

Monaco font (pixelsize <= 14) & hinting

一直覺得很奇怪,我的Debian 上面的monospace 字體跟 Ubuntu 上面的一樣都用 Monaco 但是當看到 terminal 中 bold (高亮)的字體時,Debian 上有些英文字就會縮水:




但是 Ubuntu 上的不會,今天研究了一下發現原來不是字體的問題,是font hinting 的問題,把小字的hinting 關掉的話就不會這樣了(Ubuntu 上預設就有把字體較小的自行的font hinting, antialias 關掉)。怎麼關呢?還蠻簡單的,如果你有root 權限可以直接在 /etc/fonts/conf.avail 加入新的 font config file,如果沒有,也可以編輯 ~/.fonts.conf (不存在就自創)。
目標是要把字型size 較小時,font hinting 的功能關掉,只要在...裡面加入下面這個設定就可以了:
<match target="pattern">
<test compare="less_eq" name="pixelsize" qual="any">
<int>14</int>
</test>
<edit mode="assign" name="hinting">
<bool>false</bool>
</edit>
</match>

應該還蠻容易懂的,就是找到 pixelsize <= 14 的設定,然後把hinting 設成false。換了以後效果應該馬上會看到(重新開一個terminal) 如果沒有的話重新登入應該也就可以了。附上一張關掉hinting 後正常的:



順便看一下在字體大一點的時候,hinting 有無的差別:
pixelsize=15, with hinting:




pixelsize=15, without hinting:



我想hinting 主要是要讓字看得清晰一點(尖銳化之類的),從上面這兩張就可以看出差蠻多的,但是我個人這樣看起來好像也沒有特別喜歡哪一種,看個人吧!總而言之,字體小的時候還是需要關掉hinting 才比較正常。

星期一, 11月 30, 2009

踩到grub 地雷

前幾天在更新debian (sid) 的時候有看到grub 的更新,每次看到這個就心有餘悸,好像更新grub 都沒什麼好事會發生,但我還是把 /boot remount 為 rw 給他更新下去了。
昨天重開機才發現這果然是bad idea,grub 整個壞掉,出現的訊息是:

Error: the symbol 'grub_gettext' not found
好險我都還有留安裝用的 usb flash,啟動 rescue mode 以後到他要你選擇 root partition 時,切到tty2 (Alt+F2),把系統mount 起來並chroot 進去:
mkdir /tmp/mnt
mount /dev/sda2 /tmp/mnt
mount --bind /dev /tmp/mnt
chroot /tmp/mnt
接下來就相當於用原本的系統開機了。重新安裝 grub :
/usr/sbin/grub-install /dev/sda
 這樣grub 應該就裝好了。 但是我 reboot 後發現還是不行,他會說 "you need to load kernel first" 也就是沒有找到 kernel image 的意思。問題在於我的 /boot 是分開一個 ext3 的 partition,所以 grub 自動安裝的時候,root 會選錯。這裡只要把 /boot/grub/grub.cfg 裡面的
/boot/initrd.img-2.6.xxxx

/boot/vmlinuz-2.6.xxxx

改為
/initrd.img-2.6.xxx
/vmlinuz-2.6.xx
就可以用正確的路徑 boot 了, hooray!

星期六, 11月 28, 2009

userChrome.css of firefox

我相信喜歡用 Firefox 的人大都是因為 fx 的擴充性很高,雖然說速度來說(在我的電腦) google chrome (or chromium) 的確跑的比較快,但是fx 帶來的彈性遠高於 chrome (至少目前是,不過 chrome 也才剛開始幾年,以後難說)。

目前 firefox 是建立在 xulrunner 上的,而 xulrunner 把 fx 的介面用類似網頁的方法 render 出來,也就是說,我們可以把 fx 本身看成一個可以瀏覽網頁的網頁?! (甚至用 DOM inspector 也可以看到 UI 的 properties),也因為類似這種機制,用來做網頁排版的 css  也可以套用在 fx 的 UI 上面,這也是 fx theme 的作法(一堆css)。

fx 提供了 userChrome.css 讓每個 user 可以自己設定一些簡單的 UI 排版,比如說我我前一陣子想在 tab 上加上編號,這樣比較方便看自己要跳到哪個 tab,這個功能用 userChrome.css 就可以達到:
http://gist.github.com/244455
把這個加入到你的 userChrome.css 裡面就可以了 ( ~/.mozilla/firefox/xxxx.default/userChrome.css )
這個方法本來是在 Box of Chocolates 找到的可是現在找無了,好險當初有留下來。


這只是一個小範例,今天在找相關資料時還找到這個把 fx 外觀改成像chrome 一樣的:
https://addons.mozilla.org/en-US/firefox/addon/10091

這讓我聯想到遊戲公司 Blizzard Entertainment 當年成功的 Starcraft 跟現在還是很紅的 Warcraft3,開放一些空間讓玩家自己產生地圖、設計遊戲內容,甚至可以加入自制的3D model,讓遊戲有無限的發展空間。我想這也是為什麼我喜歡 fx, 而且也是為什麼我喜歡 Linux。

星期六, 10月 31, 2009

xmonad in Debian Sid

最近更新了筆電上的 xmonad 結果重開發現開不了, 原來是套件相依的一些問題(畢竟是 sid 阿阿阿~) ,後來決定不用套件庫裡面的 xmonad,用 Cabal 裝。

Cabal 是專門用來裝 haskell 的套件的軟體 (有點像 cpan) ,好處是可以把 haskell package 裝在 user 自己的 home dir 下面,這樣系統也比較乾淨。

參考這篇文章Install Xmonad on Debian Lenny,照著做就可以了,不過要把 .xsession 或 .xinitrc 裡面 xmonad 路徑改成 /home//.cabal/bin/xmonad 才能啟動,以下紀錄一下過程。


sudo apt-get install ghc libghc6-network-dev libghc6-mtl-dev zlib1g-dev
wget http://hackage.haskell.org/packages/archive/cabal-install/0.6.2/cabal-install-0.6.2.tar.gz
tar -xzvf cabal-install-0.6.2.tar.gz
cd cabal-install-0.6.2
./bootstrap.sh
export PATH="$HOME/.cabal/bin:$PATH"
sudo aptitude install libx11-dev libxft-dev

cabal update
cabal install xmonad
cabal install xmonad-contrib

也是可以寫成 script 啦.. 可是好像很久才會用一次,所以暫時沒動力.. XD

星期一, 10月 19, 2009

gcin & vimperator

Vimperator 用了一段時間覺得很不錯,不過總覺得怪怪的, hint 的 timeout 怎麼改都沒用,要是 hint number 是三位數我就要非常非常快地輸入才行。後來在我的筆電上發現沒有這個問題,怎麼找我看vimperator 都是 clean install 沒有什麼差別,firefox 的版本也一樣,後來才發現是gcin 的問題。

因為IM frame 有點複雜我不是很熟悉,所以暫時只好先改用 scim 。(gcin 哭哭)

星期三, 9月 09, 2009

Ubuntu C270 setup (續)

昨天晚上試了一下,把ip route 的部分寫成 pppd post-up script,也就是pppd up 以後會執行的script。由於pppd 的up script 是共用的,所以我用 ipparam 來指定是否需要執行ip routing 的設定。
這個設定是基於上一篇 的下半部,所以如果需要可能要看一下。
首先先在 /etc/ppp/ip-up.d/ 加入下面這個檔案 (以下以 root 身份執行)
iproute:
#!/bin/bash

if [ ${6} == "AUTOROUTE" ]
then
IP_ADDR=${4}
IP_GW=${5}
ip route add default via ${IP_GW} table c270
ip rule add from ${IP_ADDR} table c270
fi
並設定為可執行
chmod +x /etc/ppp/ip-up.d/iproute
同樣在 /etc/ppp/ip-down.d/ 加入以下檔案
iproute
#!/bin/bash

if [ ${6} == "AUTOROUTE" ]
then
IP_ADDR=${4}
ip rule del from ${IP_ADDR}
fi

同樣設定為可執行
chmod +x /etc/ppp/ip-down.d/iproute
然後在 wvdial 的地方,加上 ipparam 的參數,在pppd up 以後會傳給script 的。
/etc/ppp/peers/wvdial:
加上
ipparam AUTOROUTE
這樣就會在連線建立完以後自動加上ip rule, route table,連線完也會自己刪除

星期二, 9月 08, 2009

Ubuntu C270 setup

最近手養跟同學借了 3(.5)G 的無限網卡 Bandluxe C270, 然後去申請了Hinet 3G, 3天的. 主要是因為我宿舍這邊網路是用NAT,外面根本連不進來,網管大概也是外面請來的我也沒辦法要求什麼。所以想說如果辦了3G 平常出去可以上網,到學校的時候有無限網路,網卡就可以插在家裡PC 透過3G 連進來。

總而言之,去申請了3天250的方案(好貴)試看看。第一部分先是網卡&播號...

sudo eject /dev/sr1 #原本的光碟機是 sr0, 網卡的是 sr1)
#下完指令成功以後要等一下 等device 切換模式
sudo modprobe usbserial vendor=0x1a8d product=0x1009 #(可以用 lsusb 看)

成功的話在這邊看 dmesg|tail 應該可以看到ttyUSB0, 1, 2 被產生出來(可能需要等個幾秒),然後使用 wvdial:
如果懶的自己設定, 可以用 wvdialconf, 他會自動偵測然後寫入/etc/wvdial.conf, 不過我想大部分的設定並不會差到哪裡去,用寫好的就可以了,這邊是我的設定:
[Dialer pin]
Init1 = AT+CPIN=0000
Baud = 9600
Modem = /dev/ttyUSB0

[Dialer Defaults]
Init3 = ATQ0 V1 E1 +FCLASS=0
Init4 = AT+CGDCONT=1,"IP","internet"
Modem Type = Analog Modem
Phone = *99#
ISDN = 0
Username = "123"
Init2 =
ATZ
Password = "456"
Modem = /dev/ttyUSB0
Baud = 9600
New PPPD = 1
Auto DNS = off
Auto Reconnect = on

因為每一次接上電腦都需要先輸入pin code,可是又不是每次都需要,所以分成兩個:剛接上以後,eject 了,就用 wvdial pin 來播號,之後直接 wvdial 就可以了。
播號了以後會產生另一個 pppd,在我的電腦以 ppp0 的裝置顯示,同時如果看 route -n 會看到類似這樣的結果
10.64.64.64 0.0.0.0 255.255.255.255 UH 0 0 0 ppp0
這邊10.64.64.64 就是要用ppp0 連出去時的 gateway。
由於我的宿舍是用NAT,本身電腦就接著NAT,開機時自動設的gateway 也是經由宿舍出去,這樣別人就算想要由3G device 進來建立連線時,出去的封包還是會經由NAT,甚至被濾掉,這不是我想要的,於是我問了朋友該怎麼辦,他跟我講的解法是用ip route:
我要讓從 ppp0 連進來的連線中傳送出去的封包也透過 ppp0 而不是 default gateway (eth0),這相當於"source 是 ppp0 的封包要由 ppp0 送出,而不是 eth0 (接NAT)",這樣的規則透過 ip route 可以解決。
首先建立一個 ip route table (root):
在 /etc/iproute2/rt_tables 增加一個 ip route table
1 c270
然後在裡面設定 default gateway:
ip route add default via 10.64.64.64 dev ppp0 table c270
再來只要把 source 是 ppp0 的封包都套用 c270 就可以了:
ip rule add from [addr] table rt1
其中addr 是你撥接後對外的 ip,這個用 ifconfig ppp0 | perl -ne 'print "$1\n" if /inet addr:([\d\.]*)/' 可以取得,這樣就可以由外面連進來了。
不過因為過程中需要知道撥接取得的ip,所以要在撥接後設定才有用,而且pppd 結束了以後route table 會被清掉(找不到ppp0),ip rule 的設定卻會殘留(沒用的設定),如果能寫成 pppd 的 post-up script, post-down script 應該會很方便... 有時間來寫..

星期六, 9月 05, 2009

libfreemsn

最近手養,著手寫了一個 msn 的 library。
目前我找到的 msn library 要嘛就是叫高階語言寫的(C#, Java.. 其實有些都寫的很完整了) 要不然就是用 GPL 釋出的。當然用 GPL 沒什麼不好,就是限制多了點。我希望能用 C 寫一個 Library,這樣 port 到 Perl 也很方便(有萬能XSUB)。

總而言之,我就刻了一個 library ,目前放在github,以 BSD Licence 釋出的。還在開發階段,只能傳送/收訊息而已,不過有興趣的人可以看看。

code 寫的很亂不要笑我 :p

github: http://github.com/freehaha/libfreemsn/tree/master

星期四, 8月 27, 2009

Audio CD

今天同學請我燒個音樂CD,當然二話不說直接開了gnomebaker (我也只會用這個 :p) 選一選 mp3 ,燒好了以後想說來聽看看到底有沒有成功。結果我嘗試把它mount 起來,發現不能mount,一急之下想說燒壞了,就又燒了一張,發現還是一樣。最後喪氣的 google 了一下才發現... 原來 audio cd 根本就沒有 file system !! 難怪 mount 不起來,後來把cd 放進去直接用mplayer 播放就可以了。

不過, mplayer 似乎在播放cd 的時候沒有buffer 或是 buffer 太小,會導致跳針的現象很嚴重,只要加上 -cache 的選項設定大一點點的buffer 就可以了:
mplayer cdda:// -cache 5000
真是學了一課阿 XD

星期一, 8月 17, 2009

vim: text-object

這幾天去 COSCUP 聽到蠻多有趣的東西,身為一個 vim, perl 狂熱者當然是要聽聽 c9s 的演講。雖說我從高中就開始用 vim 到現在少說也用了4~5 年,可是還是有很多好玩未發覺的功能阿!

--正題--
vim 將每個段落,或是block, word 分成一個個 "text object" 可以說就像是 HTML 裡面分成一層層的 tags 一樣,並且設計了描述方法針對某種 text object 做出動作。

我想,用了vim 一段時間的人都知道 'c' 很好用,直接替換文字而不用刪掉以後再進入 insert mode,c 搭配 text-object 的方法就像這樣:

ciw: 更換一整個 word, 跟 cw 不同的是,他會把目前游標在的整個 word 換掉而不是word 在游標以後的部分,可以說有點像是 b cw 的組合。

cib: 更換一個 block (由小括號括起來的)
ciB: 更換一個 Block (由大括號包起來的)

中間那個 i 代表的是 inner ,另外可以用的modifier 是 'a' (代表 一個),對於不同的 text-object 這兩種的分別不太一樣,不過大致上差別在於包覆 text-object 的 delimiter 是否一起被選取到。
例如 cab 的話會把括號也一起換掉,而 cib 只換括號裡面的東西。

敘述有點亂,如果要瞭解更多可以參考 vim 的 document

星期日, 8月 09, 2009

perl xsub compiling warning: unused variable 'items'

在compile xsub 的時候,perl 會自動生成 bootstrap function, 執行時透過呼叫這個bootstrap 把其他 subroutine 生出來. 但是由於 perl 的機制,會在產生出來的bootstrap 裡面加上 item 這個變數卻又不用他,當開發時打開 -Wall 就會覺得很惱人。上網找了一下,在 DBI 的原始碼裡面看到了用這樣的方法:

BOOT:
items = items; /* avoid 'unused variable' warning */

只要在 .xs 裡面加入這兩行,在xsubpp 轉換出來的 bootstrap 裡面就會有 items = items; 的 statement,compile 以後也就不會有 warning 了。

星期二, 8月 04, 2009

readline callback, key binding bug

今天發現readline 的bug, 是因為在 vi-mode (callback) 我不管怎麼 bind pageup/down (\e[5~, \e[6) 都不成功,trace 了一下,發現是 _rl_dispatch_callback 裡面有個 bug (應該是bug .. :p)

readline 的 callback 為了要避免block,可是又要能夠吃 key sequence 的 binding ,所以設計了一個類似 stack 的結構,模仿一個 non-blocking 的 recursive call.

裡面一樣是呼叫 _rl_dispatch_keyseq 但因為有設定 RL_STATE_CALLBACK,做完一次的 dispatch 就會直接回傳,等下一次 rl_callback_read_key() 被呼叫才會再來 dispatch。 這時候 _rl_dispaych_keyseq 的回傳值有4 種 -3 ~ 0 分別是指下面這幾種意思:

0: 成功 match 到 key sequence
-1: key 沒有match, 所以最後一個之前有match 到的 keyseq 會被執行
-2: match, 但是是 keymap 裡的 ANYOTHERKEY, 也就是說大概還有同個長度的keyseq 存在,不過總而言之就是有match 到
-3: 「還」沒有match,還要看後續讀入的key

bug 是在,當回傳是 -3 的時候,readline 會看上上一個有沒有被 match (當輸入到 \e[6 的時候,會看 \e 有沒有match),為什麼會這樣設計我不清楚,不過bug 就在這邊了。解法呢.. 很簡單,只要在 r == -3 的時候跳過 _rl_keyseq_result 的檢查就行了。下面附上非長短的 patch,手動改就可以了 :p

http://moon.cse.yzu.edu.tw/~s961449/readline-callback.patch

使用方法:
到readline 的 source directory 裡面, 用patch
cd readline-6.0 && wget http://moon.cse.yzu.edu.tw/~s961449/readline-callback.patch && patch -p1 < readline-callback.patch


寫的好亂 XDDD

星期一, 8月 03, 2009

custom keymap in readline

readline 的功能強大,也包括了很好用的 vi mode ,在 .inputrc 裡面就可以設定,不過這是使用者自己的設定,若程式想要直接指定,那就要設定 keymap 了。
我翻了一下 readline 的 原始碼,發現使用者若是設定了 vi mode (set editing-mode vi) 那麼程式自訂的 keymap 會失效,不知道這算不算 bug,因為在初始化的時候會看如果有設定 vi-mode 就會把keymap 覆蓋掉變成 vi_insertion_keymap。
所以要嘛就把所有的設定全部綁在 vi_insertion_keymap, vi_movement_keymap 上面,不然就是設定 rl_pre_input_hook 在使用者之前再把自訂 keymap 加載上去。我是選擇後者.. 實作起來大概就是這樣:
int reset_keymap()
{
  rl_set_keymap(custom_keymap);
}
rl_pre_input_hook = reset_keymap;
這樣應該就能保證不管使用者的設定如何都能夠套用自己的keymap 才對。

星期日, 8月 02, 2009

Debian netinst on AOD250

最近買了台Acer 的 Aspire One D250,入手第一件事當然很急著想換成 Ubuntu/Debian,斟酌之下,決定使用 Debian,於是下載了lenny 的 netinst cd 裝到隨身碟來,開了機正要安裝的時候居然發現 lenny 的 kernel 不支援我的 ethernet card (AR8132),於是只好自己抓AR8132 的 nic driver 來給installer 用。

[459]AR813X-linux-v1.0.0.9.tar.gz 抓下來以後解開, 在我的 VM (Lenny) 下 compile:
sudo apt-get install linux-headers-2.6.26-2-486
mkdir AR813X && mv '[459]AR813X-linux-v1.0.0.9.tar.gz' AR813X/ && cd AR813X
tar xvf '[459]AR813X-linux-v1.0.0.9.tar.gz'
cd src
BUILD_KERNEL='2.6.26-2-486' make
把目錄下產生的 atl1e.ko 複製到 usb 上,在 iso detect 的步驟做完以後(或是自己把usb mount 上以後),切到別的 tty 把 atl1e 加載到kernel 就可以了:
insmod atl1e.ko
接下來就可以順利安裝了(吧,至少可以用LAN 了,不然怎麼netinst)
---------------------------
不過呢.. 遺憾的是,我最後並沒有裝 Debian ... 為了這個 nic driver 我搞了好久才知道要這樣 compile (還是有高人指點我才會的,不然我到現在可能還在重編debian installer) 弄好以後已經好晚了,睡前我在想這樣到底是幹嘛,小筆電真的有需要灌 Linux 嗎?雖然我用Linux 當桌機好幾年了,我也認為這樣很美好,但是我目前實在想不出來NB 要裝 Linux 的理由。所以最後我還是沒有裝,搞不好我以後會改變心意 :p

ubuntu minimal

Ubuntu Minimal, 今天在網路上突然瞄到,我也算是個 Ubuntu 的愛好者,但近年來覺得Ubuntu 裡面真的有不少雜物,看了一下 Ubuntu Minimal 的一些教學,覺得大概跟 debian netinst 差不多吧,至少不會有雜七雜八的一堆東西(猜). 所以就抓來玩了,CD image 很小,x86 的才 9.9MB.

大致上也跟 debian netinst 很像,只不過我看了一下光碟的內容,似乎是沒有任何的 package 可以用,也難怪會這麼小,但這樣好像也沒辦法用 ppp 的方式來安裝了,不然就是要另外把套件塞進去,不過這樣好麻煩 :( ,那不如裝 ubuntu server !? 。(debian netinst 的話只要在boot line 加上 modules=ppp-udeb 就可以了)

星期三, 7月 29, 2009

Reverse Regular Expression

我一直都是 Perl 的愛好者,雖然,說實在,我寫perl 的"功力"不怎麼樣,不過 perl 給我寫程式的生涯添了不少色彩,立了不少待征的高山。每次寫perl 都有新的體悟,這也是讓我很喜歡它的原因。

今天因為需要,在找有沒有 regexp 可以從後面開始找第一個 match,換句話說,就是找到最後一個match。於是我 google 到了這篇 Reversing Regular Expressions 剛進去就發現好像是我以前瞄過的文章,今天好好的看一次,發現是很有趣的思維。

所謂的 Reverse Regexp 就是:
1. reverse string input
2. reverse regexp
3. reverse match
reverse 的代價遠比把整個字串都比對完小多了,如此一來對於"找到最後一個xxx" 的問題就有了快速又方便的解法。唯一的缺點就是你要把 regexp 倒過來寫,不過這通常不是什麼難事,或者說.. 對於喜歡寫 perl 的人來說件很有趣的事情。
---------------
下面又提到 variable length 的 zero-width look ahead assertion 實作方法,也是很好玩。

還是要說一句 I love PERL !!


延伸閱讀:
http://japhy.perlmonk.org/sexeger/sexeger.html

Readline & network programming

GNU Readline Library 真的是很不錯的一個東西,對於要做 console interface 的人來說可以說是福音吧!很多shell 也都是用readline 的。
Readline 主要是提供了一些輸入上與使用者的互動,包括一些常用(emacs)的編輯指令,也有我很喜歡的vi mode :p . 想要做到與shell 一樣強大的輸入介面,用readline 就對了!

最近在寫個網路應用程式需要用到 Readline,可是我們寫網路應用程式最討厭的就是會 block,當呼叫 readline 的時候因為他需要分開處理每個 key,並表現在 buffer 中,才能達成一些編輯的功能,當然 readline 也提供在需要 non-blocking IO 的環境使用的方法,配合 select,可以使用它的 Alternate Interface 也就是下面這幾個 function:
void rl_callback_handler_install (const char *prompt, rl_vcpfunc_t *lhandler)
void rl_callback_read_char (void)
void rl_callback_handler_remove (void)
使用方法還蠻簡單的,install 一個在輸入完成(return) 以後會執行的 handler 以後,使用在 select 裡,當 stdin 是active (readline 在 initialize 的時候就已經把stdin 設成 raw 了) 的時候 read_char,結束以後 remove handler 就可以了。

========= update 3 Aug ========
值得注意的是,bind key 似乎要在 rl_callback_handler_install 之前先做,或是bind 完要重新remove&install 一次,不然有些key binding 的時候一些Meta key 會讀不到.

星期四, 6月 18, 2009

xmonad 初體驗

最近awesome 這個window manager 很紅,學長很多都跳槽去玩。聽了學長大力推薦我也想說來試看看,可是Hardy 上的版本只有2.0 ,玩不到最新的就不好玩了!!所以只好自己來compile,但awesome 牽涉XCB,XCB 在系統上又很多應用,compile 以後發現不得了,影響太大,只好暫時放棄awesome,反正我的fluxbox 其實也很好用。

不過又聽到另一位玩haskell 的大大說 xmonad 也不錯,大致看了一下official site 發現同樣是tiling WM 可是config & extension 是用 haskell,想說那不如來試看看順便學一學haskell,於是就裝了 !
-------------

xmonad 本身就是用 haskell 寫的,根據我的瞭解,xmonad 在開始執行前還會先把你的config file (also haskell) compile 起來,也就是說你的config 會變成xmonad 程式碼的一部份,還蠻有趣的,其他C/C++ 的WM 大概很難做到這樣吧。

一些default 的 key binding 其實很夠用了,而且還有預設 dmenu 的快捷鍵 (Mod-p) 也就能應付所有程式了。 不過 panel 的設定讓我這個初學者實在弄了有點久,相對於awesome 一裝好就有的 panel 跟 trayer 比起來有點不太親切,但是因為 config 是直接compile 嵌進去的,所以還算靈活,在內部把panel info pipe 出來也不是什麼難事,這點讓我很喜歡。有時間再分享一下我的設定檔。

星期四, 6月 11, 2009

vim: diff between buffer and original file

上次看到學長用Emacs 可以把修改過的buffer 跟原檔案在編輯器裡面做diff,我就想vim 應該也可以。試了一下後來就成功了:
轉自: Vim Wiki
這個是我修改過的版本,做了toggle 的功能, map 到 \d (我的mapleader = \)
function! s:DiffWithSaved()
if exists("b:diffbuf")
unlet b:diffbuf
bdelete diffbuf
diffoff
else
let filetype=&ft
diffthis
vnew diffbuf| r # | normal! | ggdd
diffthis
exe "setlocal bt=nofile bh=wipe ro noswf ft=" . filetype
let b:diffbuf = 1
endif
endfunction
com! TDiffSaved call s:DiffWithSaved()
nmap <leader>d :TDiffSaved<CR>

-----------------------
另外我也在 vim online 找到一個 gitdiff.vim 用git 的時候也可以做出跟上面這樣一樣的效果,不過比對的對象是git repo 裡面的。而上面這個方法比對的對象是上一次存檔後的檔案跟現在的buffer

星期三, 6月 03, 2009

vim tip: when compiler gives you errors ....

vim 跟 gcc 還算蠻能合作的,對於gcc 的error/warning 都能直接找到對應的檔案行數,但有時候發生錯誤的檔案並不在現在的working buffer/tab/window,vim 跳過去的結果就是目前工作中的buffer 被換成該有錯誤的 buffer,造成原本tab/window 的配置都亂掉了。

老實說這個問題困擾我很久了,一直到今天在寫作業受不了,上網找了一下解法,結果在vim wiki 看到了解決的方案:
When I open an existing buffer from the buffer list... 這個section 寫到,可以把switchbuf 設成 useopen, 在做buffer switching 的時候會先看有沒有已經打開了。

之後去看了一下vim help,switching 還有其他模式可以選,最後我是選 opentab ,這個設定讓他不止看當前tab 的windows,而是看所有tabs 裡面的buffer,我想在vim7 以後應該都會用這個選項了吧。

設定方法很簡單.. 在 ~/.vimrc 加入以下這一行
set swb=opentab

就行了

星期一, 5月 25, 2009

recover deleted file while descriptor's still alive

偶而會有發生程式開啟某個檔案正在寫,結果我手滑刪掉了那個檔案的經驗。最近由於在維護一個mud 發生如此悲劇,log 檔就這樣被我刪了.. 於是上網找尋相關資料…

其實 Linux 上看到的的檔案是以inode 為根據表現出來的檔案,只要 inode 存在,檔案就還存在。(應該是這樣吧..) 。程式執行中開啟的檔案對程式本身來說是一個descriptor,也會在/proc/[pid]/fd/[fd number] 表現出來。而這個檔案也是對於inode 的一個連結。

若不小心把檔案刪掉的話,只要程式還開著,就可以到/proc/[pid]/fd/[fd number] 找到對 inode 的連結,然後把檔案copy 回來。

但是copy 回來的檔案內容只是copy 時當下的檔案,並不會對程式後來對檔案的操作有反應。若要真正復原成原本的狀態,需要把inode link 回來..這部分相關的資訊可以看這個網頁下半部的解法(我還沒試過..):
http://dag.wieers.com/blog/undeleting-an-open-file-by-inode

參考網頁:
http://dag.wieers.com/blog/undeleting-an-open-file-by-inode
http://prefetch.net/blog/index.php/2009/02/25/how-to-undelete-any-open-deleted-file-on-linux-solaris/
http://www.linux.com/archive/articles/58142

星期四, 5月 07, 2009

pulseaudio & x11 beep sound

以前都直接xset b off 把預設由主機發出的beep sound 直接停掉。今天看到使用pulseaudio 設定 beep sound 的方法:
在 ~/.pulse/default.pa:
加入指定音效
load-sample-lazy x11-bell [path-to-sound]
然後讀取 x11-bell module (也在default.pa):
load-module module-x11-bell sample=x11-bell
這兩行設定在預設的default.pa 的sample 中都可以找到,只要uncomment 來改就行了,當然自己寫上去也是可以的。

然後 beep 的音量由xset 設定(50%):
xset b 50
最後重開pulseaudio server 即可:
pulseaudio -k && pulseaudio -D


參考網頁:
http://jean-christophe.dubacq.fr/post/Parametrer-son-bip-systeme-avec-pulseaudio-comme-autrefois

星期日, 4月 05, 2009

mktemp

有時候shell script 會需要用一些暫存檔, 有些可以透過piping 完成. 像是這個:
elinks -dump 1 kill.html | perl -ne 'print "$1\n" if /\d+\. (http:\/\/.*)\b/'
這也可以寫成
elinks -dump 1 test.html > tmp
perl -ne 'print "$1\n" if /\d+\. (http:\/\/.*)\b/' tmp
rm -f tmp
前題是 tmp 沒有其他的用途,不然一直行這個script 以後 tmp 就不見了。
有時候沒辦法純粹用 piping 達成(或是不方便,寫起來很醜),這時候mktemp 就很有用了,他可以產生一個隨機的檔名,建立並把檔名輸出到stdout 供script 用。下面有個例子:
TMPFILE=`mktemp -t urltemp.XXXXXXXXXX` && {
echo $TMPFILE is created
elinks -dump 1 test.html > $TMPFILE
perl -ne 'print "$1\n" if /\d+\. (http:\/\/.*)\b/' $TMPFILE
rm -vf $TMPFILE
}
其中XXXXXXXXXX 是參數讓 mktemp 可以填入隨機檔名。

星期六, 2月 21, 2009

惱人的 Caps Lock!

今天看到學長在講HHKB 鍵盤,便上網看了看是怎麼樣子。雖然我沒有很喜歡,看起來好像太小了一點,不過我發現HHKB 的左邊Ctrl 鍵是長在我們正常鍵盤的Caps Lock 的位置,這真是太妙的設計了!老實說Caps Lock 對我來說根本是多餘的一個鍵。

找了一下網路上的教學,若要重新設計可以透過 XKB 或 xmodmap 來修改。XKB 的設置是要在xorg 的設定檔裡面更改,所以要有root 的權限才行,所以這裡我選則用xmodmap 來修改keyboard mapping 以下是我在一個網站找到的設定檔。
remove Lock = Caps_Lock
remove control = Control_L
keysym Caps_Lock = Control_L
add Lock = Caps_Lock
add Control = Control_L
存成檔案再用 xmodmap [filename] 就可以了!
------------------------

這個例子讓我有衝動想寫一個玩魔獸(爭霸) 用的keymap,把數字鍵改到鍵盤中間應該不錯,有時間再來試吧 :p

星期三, 2月 11, 2009

battlelan for Linux

雖然說Linux 本身不是設計用來玩遊戲的,但是有時候還是想玩一些遊戲。我最常玩的大概就是StarCraft(天阿,好老的遊戲,聽說快出2 了!!) 跟 WarCraft3 吧。但這些戰略遊戲自己玩單機一點也沒挑戰性,也不刺激,所以連線對戰可以說是這些戰略遊戲最重要的部分了。

除了上Battle.Net 以外,有時候我們想用區網連線,Windows 上透過 BattleLan 或是 LanCraft 都可以以 socket redirecting 達到與區網外連線的目的,但Linux 上我好像沒有看到類似的軟體。

那時候為了跟同學連線,上網找了相關的資料,後來看到有人自己寫了BattleLan,雖然是在Windows 上的,可是有了他的程式碼我可以改成在Linux 上用的BattleLan。搭配Qt,我做了我的'FreeLan',執行畫面如下。

目前是可以一次設定多個連線的ip/host,對於host game 很方便,做client 的時候通常只要設定一組就可以了。現在做的還不是很完全,所以暫時大概也不會開放下載,但如果很想要的人可以跟我要:p。

-----另解----------
由於是socket redirecting,理論上使用 iptables 也可以做到這種功能,但是我對iptables 實在不熟,試過幾種設定都不見功效,如果有高人請賜教 :)

不過以上這兩種都需要root的權限才行。

-----又 另解-------
就像Windows 上的 Garena (人稱 GGc),理論上也是可以hook 那些socket 的api (透過LD_PRELOAD, 應該可以) 修改過封包以後再送出,這種方法我還沒試過,不過就算是wine,最後也是調用系統的socket function 才是,所以我想這應該是沒問題的,而且這種方法也不需要root 的權限,應該是最方便的解決方法。

-------------------------------------------------------------------
02/13/09 更新

今天看了一下 wine 的 source, 看來WSASendTo 的地方是用 sendmsg 來實作。於是便寫了一個小 library 用 LD_PRELOAD 替換掉wine 會呼叫的 sendmsg,完全符合我預期的情況,看到War3 送了一堆broadcast 的 packet,redirecting 或修改封包也都不成問題了。想一想,這東西要是在Windows 下寫還真麻煩,不得不讚賞一下 Linux 完美的機制。

執行結果:

trap

今天在找 mplayer 相關的 dev 資訊,無意中翻到 mplayer 附的一些 code,裡面有個 mpconsole 的shell script挺有趣的。 裡面有用到一個指令叫作 `trap'。

找了一下資料,原來 trap 就是有點像 C 裡面的 signal(),可以設定在執行時的signal handler,沒想到 shell 也能做如此的設定,真是大開眼界 :p

使用範例:
http://steve-parker.org/sh/trap.shtml

所有的可以用的signal 在 signal(7) 有列表

星期四, 1月 15, 2009

stop autoplay with GreaseMonkey

Greasemonkey 是個firefox 的plugin, 非常有彈性所以很強大。使用者可以透過他將設計好的javascript 插入到網頁中,來達到任何目的。

我第一次聽到這個東西是在 2007 的 OSDC.tw,那時有個大大在介紹他寫的瀏覽無明相簿的 script。那時候就大概試了一下,後來沒什麼在用重灌後就也沒想到要加上。

今天聽到有人在討論firefox 的一個叫作 Stop Autoplay 的 plugin。突然想到這個功能應該也可以透過Greasemonkey 實現。Google 了一下果不然,有如此一個Disable Embed Autoplay 的script。馬上下載下來裝看看。可是發現現在無明很多都用yimg 的 flash music player,而剛剛那個script 只支援使用Embed 標籤的檔案。於是做了一點小hack,在script 後面加上:
var o = document.getElementById("automusic");
if(o != null)
{
o.style.display = "none";
}
由於無明好像提供的語法就是 span id="automusic",所以只要找到這個span,不顯示就可以了,這樣還蠻dirty 的可是可以work 啦 :p

星期日, 1月 11, 2009

Archlinux

用了Ubuntu 好幾年了(少說也有3, 4 年吧), 一直覺得Ubuntu 還蠻好用的, 雖然說有時候會被覺得是"新手" 用的 distro, 但好用嘛 :p

昨天看到學長在講 Archlinux, 小小新手的我就去找了一下這什麼. 看了官網的介紹, 似乎是給i686, x86-64 做過優化的distro, 心想我這 E6550 好像也是 i686, 不知道Archlinux 會不會快一些!? 雖然說我現在用Ubuntu, WM 是 fluxbox 速度還算不錯. urxvt 也讓我蠻滿意的, 但是想說學長推薦的distro 不試一下可惜, 便下載了 Arch 來試試.
-----------

Arch 安裝的速度真是蠻快的, 跟Ubuntu 比起來是輕便許多. 我在VirtualBox 裡裝的時間大概是 15 分鐘左右, base, bootloader 就都裝完可以開機了.

他用的package manager 是 pacman, 套件庫應該不算多但是還蠻夠的了.

試用了一天整個感覺就是:快!, 也是裝了才知道原來Ubuntu 裝了不少不必要的東西, 也難怪許多Ubuntu 老手後來都喜歡用 Debian. Anyway, 我也才試用這麼一天, 也實在沒資格說整個系統的優缺點, 等寒假再來玩個透撤.

更換游標主題

今天在試 Archlinux, 剛裝好X 的時候的cursor theme 是預設的xcursor theme, 對於用了Ubuntu 好幾年的我實在不習慣, 於是想換回DMZ 的theme.

通常裝好的 cursor theme 都會放在 /usr/share/icons 裡面, 如果沒有root 的話可以放在 ~/.icon/ 裡面, 更換 cursor theme 的話就只要在 ~/.icon/default/index.theme 放這些:
[Icon Theme]
Inherit=DMZ-White
然後重新啟動X 就行了.

這邊DMZ-White 是指 icon 的名字, 可以在icon theme 的資料夾裡, index.theme 中 Name= xxx 找到.