TAG

首都機能移轉 (2) 歌詞 (2) 靠北文 (40) 戲言 (30) 糟糕 (7) ACG (23) Assembly (2) Boost (2) C (31) C++ (69) CMake (4) CSIE (67) Debian (34) Design_Pattern (2) Django (1) Eclipse (1) en_US (13) FFmpeg (3) FoolproofProject (26) FreeBSD (2) Git (4) GNU_Linux (65) IDE (5) Java (11) JavaScript (19) KDE (15) Khopper (16) KomiX (3) Kubuntu (18) Life (1) Lighttpd (2) Mac_OS_X (2) Opera (1) PHP (2) PicKing (2) Programing (21) Prolog (1) Python (7) QSnapshot (2) Qt (30) Qt_Jambi (1) Regular_Expression (1) Shell_Script (7) Talk (98) VirtualBox (7) Visual_Studio (13) Windows (18) zh_TW (36)

2008年1月31日 星期四

防火牆修復

在遠端登入時如果不小心把防火牆搞爛了,可是非常麻煩的事,因為你很有可能無法再次遠端登入來修復防火牆;所以前幾天用python寫了個程式,在伺服器完全斷線時可以先讓防火牆恢復正常。
#! /usr/bin/env python
# -*- encoding: utf-8 -*-

import os, time, sys

def connect_test( *sites ):
        for site in sites :
                if os.system( "wget --tries=2 --timeout=120 -O - %s >/dev/null 2>&1" % site ) == 0 :
                        return True
        return False

flog = open( '/var/log/firewall_fix.log', 'a' )
timestamp = time.strftime( '%Y/%m/%d %H:%M' )

if connect_test( 'http://www.google.com/' ):
        print >> flog, "%s\tSuccess and do nothing.\n" % timestamp
else:
        try:
                if os.system( 'iptables-restore <%s >/dev/null 2>&1' % sys.args[1] ) != 0 :
                        raise OSError
                else:
                        print >> flog, "%s\tFirewall fixed. ( Use `%s'. )\n" % ( timestamp, sys.args[1] )
        except ( IndexError, OSError ):
                os.system( 'iptables -F' )
                for chain in [ 'INPUT', 'OUTPUT', 'FORWARD' ] :
                        os.system( "iptables -P %s ACCEPT" % chain )
                print >> flog, "%s\tFirewall fixed. ( Flush all. )\n" % timestamp

flog.close()

中間的連線測試其實滿dirty的[?],不過目前想不到其他更好的辦法。
噢,對了,Linux only。
2008/2/08 edited. Few code changed.

2008年1月30日 星期三

/dev/null的用處

在一個程式裡呼叫其他程式時,難免會有一些訊息跑出來,而當你不希望它出現時,可以利用I/O redirect導向到/dev/null裡。簡單地形容就是....垃圾筒。

2008年1月28日 星期一

getch()的POSIX實作

#include <stdio.h>
#include <termios.h>

char getch(void) {
        char buf = 0;
        struct termios old = {0};
        if (tcgetattr(0, &old) < 0)
                perror("tcsetattr()");
        old.c_lflag &= ~ICANON;
        old.c_lflag &= ~ECHO;
        old.c_cc[VMIN] = 1;
        old.c_cc[VTIME] = 0;
        if (tcsetattr(0, TCSANOW, &old) < 0)
                perror("tcsetattr ICANON");
        if (read(0, &buf, 1) < 0)
                perror ("read()");
        old.c_lflag |= ICANON;
        old.c_lflag |= ECHO;
        if (tcsetattr(0, TCSADRAIN, &old) < 0)
                perror ("tcsetattr ~ICANON");
        return (buf);
}

int main() {
        char key;
        printf("Press 'x' to exit...\n");
        while((key=getch()) && (key != 'x'))
                printf ("you pressed %c\n", key);
        return(0);
}

Reference

直接觀看封裝/壓縮過的檔案

Unix-like的紀錄檔通常在經過一定時間後就會壓縮為gz檔,為此可以使用如下的指令直接閱讀,不需要真正解開成一個檔案:
gzip -cd file.gz | less
如果壓縮過之前還被封裝過,就要換個程式:
tar -ztf file.tar.gz | less
於是,再一次地我們要發揮程式設計員的美德之一:懶惰。
每次都要打那些指令太煩了,所以我寫了一個bash shell,名叫xless[?],自己根據檔案類型展開。
#! /bin/bash

if [ $# -eq 1 ] ; then                          # 只接受一個參數
        if [[ $1 =~ '\.tar\.gz$' ]] ; then      # 以regex過濾*.tar.gz
                exec tar -ztf $1 | less
        elif [[ $1 =~ '\.gz$' ]] ; then         # 再過濾*.gz
                exec gzip -cd $1 | less
        else
                echo 'Invalid filename.'
        fi
else
        echo 'Must takes one argument.'
fi
然後再把這個檔案改成可執行檔,export到PATH裡,就可以隨時取用了。

Copy Right真絕....

剛才為了要寫一個能在Windows[?]下控制防火牆的程式,但是測試用的code竟然不能用,因為它需要netfw.h,而之前下載的Windows® Server 2003 SP1 Platform SDK裡沒有包含;仔細看一下文件才發現這已經不是最新的Platform SDK,而且也不會再更新了,目前最新的是Windows® Server 2003 R2 Platform SDK,無奈的是它要通過WGA認證才能下載。
其實我也不是在說微軟怎樣,只是這樣會讓我的compile-time需求又多上一筆....

2008年1月27日 星期日

詭異的execv

昨天在寫Linux的系統程式時發現了一件很詭異的事....
那就是execv的prototype竟然是int execv( const char *path, char *const argv[]);
根據這篇的描述,char * const的意思是char的const指標,也就是說雖然有保護到指標,但是沒有保護到pointee的字元
而且雖然非const轉型到const是合法的,但是反向操作很危險。
真想知道它這麼定的理由= =

2008年1月18日 星期五

如何讓你的程式更難理解(2)

#include <iostream>
#include <algorithm>
#include <vector>
#include <iterator>

#include <boost/lambda/lambda.hpp>

using namespace std;
using namespace boost::lambda;

int main( int argc, char * argv[] ) {
    vector< size_t > v;

    copy( istream_iterator< size_t >( cin ), istream_iterator< size_t >(), back_inserter( v ) );

    sort( v.begin(), v.end(), _1 > _2 );

    for_each( v.begin(), v.end(), cout << _1 << '\n' );

    return 0;
}
以上和以下同義:
#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;

template< typename T > inline bool gt( T a, T b ) { return a > b; }

int main( int argc, char * argv[] ) {
    size_t temp;
    vector< size_t > v;

    while( cin >> temp ) {
        v.push_back( temp );
    }

    sort( v.begin(), v.end(), gt< size_t > );

    for( size_t i = 0; i < v.size(); ++i ) {
        cout << v[i] << '\n';
    }

    return 0;
}
簡單地說,先從輸入串流讀入一串數字存入陣列,再反序排序,最後全部印出來。
首先仔細地檢視我們要什麼。事實上輸入的動作只要從串流複製一份資料到陣列裡即可,因此使用algorithm的copy和iterator的功能就可以達成目的。
至於排序,預設是遞減排序,其他排法必須要另外再寫一個比較函式。因此這裡使用Boost的lambda函式來減少多餘的宣告。lambda function就是一個臨時的匿名函式,不少高階語言都有,但是C++目前的標準函式庫沒有;Boost是C++標準委員會所擴充的函式庫,基本上很有希望加入為新的標準。
最後是輸出;其實這裡用copy也可以,只是這樣就很難在項目之間插入空白或換行,因此使用algorithm的for_each加上lambda functor。
不要問我為什麼使用using namespace...這只是示範....
 

2008年1月16日 星期三

為什麼學程式語言要從C開始學?

因為指標可以刷掉不適合寫程式的人
By 學弟
Well, 這當然是玩笑話一句。

2008年1月14日 星期一

La Fonera花轟了

不知道為啥只要La fonera想移植就會卡到陰,昨天reset鍵按了五秒左右,就回到出廠值了。
詭異的是default gateway變成192.168.182.1,而且沒辦法由這個位址連線回去更改設定....
我應該找誰呢?(攤手)

2008年1月10日 星期四

災難啊....

我已經不知道從何說起了....在FreeBSD上搞了快十個小時的東西,在Debian上三秒解決;只能說我對FreeBSD不熟吧....寒假再去玩它。
總之感謝Zeroplex的友情贊助。

pkgdb rebuild

在FreeBSD上用
# pkgdb -F
時出現了要我重新整理的提示,google了一下發現這似乎是主幹的bug,在某個分支有修復的樣子。
# setenv PORTS_DBDRIVER bdb1_hash
# setenv PKG_DBDRIVER bdb1_hash
設定以上的環境變數就可以解決,問題似乎是出在btree的結構上,換成hash就解決了。
接下來就是愉快的portupgrade...不過還真他XX的久。

2008年1月7日 星期一

蠢事

星期六有人要我調整防火牆,但是新的規則一直加不進去,於是我想乾脆重來算了,下了指令:# iptables -F....然後才想起來我是用ssh登入....
這種蠢事跟學弟ssh回去下# ifdown eth0一樣白爛,但是更慘,因為小組專案的Subversion檔案庫在那台伺服器上....
因為過了下午五點,然後星期日沒人進得了機房,專案驗證停擺,連我的blog也受到影響= =[?]
這個故事告訴我們,永遠不要用ssh玩網路!= =

2008年1月4日 星期五

pointer和cv修飾詞

大家可能都很習慣用類似const char *這種東西了,在傳遞C-style字串時經常會用到,用意是不要更改到字串內容。不過其實在多層指標時,因應const的位置,狀況還可以更複雜。
首先必需要有的概念是,const TYPETYPE const等義的。
舉例:
const int a = 1;       // a的值永遠為1
int const b = 2;       // b的值永遠為2
const int const c = 3; // 編譯期錯誤,冗餘的cv修飾飼
第二個觀念是,cv修飾詞修飾的是它左邊的型別。
如果它本來就在最左邊,可以用上面的規則代換成TYPE const
舉例:
int x = 4;
int y = 5;
const int * cip = &x;    // 指向const的指標
int const * icp = &x;    // 如前段所述,icp和cip其實是同一種型別
int * const ipc = &x;    // 因為const的左邊是pointer,故它其實是const指標

*cip += y;               // 失敗,因為指向的空間被修飾為const
*icp += y;               // 失敗,理由同上
*ipc += y;               // 正確,指向的空間並沒有被修飾為const

cip = &y;                // 正確,指標本身並不是const
icp = &y;                // 正確,理由同上
ipc = &y;                // 失敗,指標本身是const
當然也可以合起來宣告成int const * const icpc,這樣指標本身不能更改,其指向的空間也不能更動。
最後一個,在指標有多層的時候,解析是由右往左展開。這個比較複雜一點,一樣還是舉例比較快:
const char * const * argv;
const char * test = "Hello, world!";
const char * const temp[] = { "abc", NULL };

argv = temp;         // 正確,最右邊的*沒有cv修飾,因此最上層的argv可以更改為其他指標
argv[0] = test;      // 失敗,右邊第二個*有cv修飾,所以*argv的取值是不能更改的
argv[0][0] = 'd';    // 失敗,最後的char也加了const,是故陣列中的字元不能更改
以下是小應用:
int EXECVP_POSIX( const std::vector< std::string > & args ) {
    const char * * argv = new const char * [ args.size() + 1 ];
    for( size_t i = 0; i < args.size(); ++i ) {
        argv[i] = args[i].c_str();
    }
    argv[args.size()] = NULL;

    return execvp( argv[0], argv );
}
用意是把vector<string>轉為系統函式通用的const char * const *。
Edited: 2008/07/22
修正code。
事實上如這篇所述,POSIX的prototype是怪怪的。