2010年11月26日 星期五

忽然想要列印 man page 怎麼辦?

老 Unix 玩家應該覺得很簡單,但對於新手的我還是要紀錄一下:
1. 先由命令查閱要列印的 man page 再哪裡? 例如 :
tom@glest:~/temp$ man -w groff
/usr/share/man/man1/groff.1.gz
2. 原來是有壓縮的,知道後就可以印了:
tom@glest:~/temp$ zcat `man -w groff` | groff -m man -T ps - | lpr

這裡 groff 是排版用的指令,輸入格式為 man page ,輸出格式為 ps 。
That's it !

p.s. 當然你的 lpr 要正確才行,如果有裝好 cups,下列命令就可以看到系統印表機狀態:
tom@glest:~/temp$ iceweasel http://localhost:631/admin



2010年11月19日 星期五

一些 C preprocessor 的用法

在 wireshark source 裡面,看到有些奇怪的 C 語言寫法 : 查不到定義的 _U_。在這裡當備忘錄記一下:
hostname$ cat foo.c
int  foo(int a _U_, int b _U_, int c)
{
    return c + 17;
}
#hostname$ gcc -D_U_=  -c -O2 -Wall -W foo.c
  foo.c: In function `foo':
  foo.c:2: warning: unused parameter `a'
  foo.c:2: warning: unused parameter `b'

上面定義 _U_  為"什麼東東都沒有" ,結果出現 compiler warning.

#hostname$ gcc -D_U_="__attribute((unused))" -c -O2 -Wall -W foo.c
#hostname$ gcc --version
2.95.1f

這裡 _U_ 被定義為 attribute of "suppress unused variable warning",所以就沒有 compiler warning 了!
那為何不使用的參數不拿掉呢? 不知道耶! 猜想是為了將來需要時不用動到很多 callers 就可以修改 function code 吧!







2010年8月26日 星期四

emacsclient font configurations

This text applies to version after Emacs 23.1
首先,我們可以把下列一行加入 ~/.bashrc
  alias ex='emacsclient -a "" -c "$@"'

解釋一下:
當我們使用 emacsclient 時,必須有一個 emacs server 啟動才可以用。
emacsclient 的參數有一個 -a "" 表示萬一 emacs server 沒有啟動,
就使用 `alternate editor' ,它可以是 vi, pico ... ,若是空字串 ("") ,表示 `那就叫一個 emacs server 起來好了'.
另外 參數 -c 表示 `create a new frame' 而不是用 server 的 frame.
至於後面要打開的檔案(可以一次指定開多個檔案來編輯),就用 bash 提供的 $@ 來代入即可。

第二,設定字型,因為 emacs server 可以在 X 之前就啟動了,因此,
很合理的,它不理會你指定在 X 環境下的字型。
現在的 X 環境下有兩種字體系統:核心字體系統與 Xft 字體系統。Xft 有許多優良的特性(向量,反鋸齒等),
所以 Emacs 23.1 開始支援 Xft as its font base. (see XftGnuEmacs).
只要在你的  ~/.Xresources 指定就好,例如,我們打算用 DejaVu Sans Mono 字型 :
    Emacs.FontBackend: xft
    Emacs.font: DejaVu Sans Mono-14

(謎:怎樣查出這個字型呢? M-x describe-font 然後給個 mono 讓它 match 出完整的字型敘述)

第三,設定 frame 的特性,我們希望打開 frame 時,是黑底白字,不要 tool bar, 不要 scroll bar ...
這些都與預設值不同,該怎麼設定呢?
emacs 的 default-frame-alist 裡面紀錄了 `新開一個 frame 所需的參數',設定這個就對了!
在你的 ~/.emacs 內這樣指定
(let ((frame '((left . 0)
               (top . 0)
               (width . 110)
               (height . 30)
               (tool-bar-lines . nil)
               (vertical-scroll-bars . nil)
               (background-color . "black")
               (foreground-color . "white")          
)))
  (setq default-frame-alist frame)
  (setq initial-frame-alist frame)

)

說明一下,[ GNU Emacs 手冊 ]查得到所有的 frame parameters。
第一次開啟的 frame(應該是 server frame)  參數會參考 `initial-frame-alist' ,往後開啟 frames(emacsclient frame)都會參考 `default-frame-alist' .

完工了!記得重新開啟 X 讓 .Xresources 生效啊啊~

2010年8月17日 星期二

lpr and cups troubleshooting

Bad situation encountered :
系統是 Debian/Testing.
透過 browser 瀏覽 http://localhost:631 可以透過 CUPS 管理印表機,目前我系統是安裝 CUPS 1.4.4。
使用其中的 Administration | Maintenance -> Print Self Test Page 可以順利印出測試頁面。
但是 emacs 裡面要列印時,就出問題了: 使用 print buffer 命令根本沒反應!

Troubleshooting :
因為 emacs 使用 `lpr' 指令作列印動作 --- 改用 `lpr' 指令試著列印一個文字檔 --- 也失效。
用 `lpq' 觀察 printing jobs 發現都在 spool 上,卻沒有送到 printer 。
觀察 debian 套件關係,原因是 cups-bsd-1.4.4-2 沒有裝,反倒是 lpr-2008.05 套件有裝上,這兩個是 conflict 的套件,因為都有提供 `lpr' 等指令。
但是前者提供 printing commands (i.e. `lpr') interactive with the CUPS. 必須裝這個套件而不是 `lpr-2008.05' 套件
這次裝錯套件的現象,可能是以前 upgrade 時沒有仔細看就同意用 lpr 套件來取代。
移除 `lpr-2008-05' 並裝上 `cups-bsd-1.4.4-2' ,重新啟動 cupsd 還不夠;可能是我還有 daemon 沒有重起,或是 debian 套件系統沒有正確的 post processing,就沒有去追究了。
試著重新開機, work !






2010年7月13日 星期二

如何賠掉時間和錢

轉錄好文章:[ 如何賠掉時間和錢 ]
從今以後,要常常審視有效的工作時間,減少其他雜事----
尤其現在的工作電腦,都能上網,很容易分心!常常體醒自己,正在有效率的工作嗎?

ASN.1 的 TYPE-IDENTIFIER.&Type 語法

遇到一個 ASN.1 語法敘述,查到在討論群有人問一樣的問題:[ASN.1] TYPE-IDENTIFIER.&Type是甚麼意思
例如:
X ::= SEQUENCE
{
  a INTEGER, -- stuff...
  b BOOLEAN
}
Z ::= SEQUENCE
y TYPE-IDENTIFIER.&Type (X)
}
則表示 "y" MUST be of type "X" only. 意思同於
Z ::= SEQUENCE
{
    y OCTET STRING (CONTAINING X)
}
這種表示法適用表示於當資料 y 以 PER Encode 後的狀態。舉例說明:
T.38 Annex A ---ASN.1 Notation 可見到
UDPTLPacket ::= SEQUENCE
{
seq-number  INTEGER (0..65535),
primary-ifp-packet   TYPE-IDENTIFIER.&Type(IFPPacket),
error-recovery CHOICE
{
      secondary-ifp-packets SEQUENCE OF TYPE-IDENTIFIER.&Type(IFPPacket),
      fec-info   SEQUENCE
{
         fec-npackets  INTEGER,
         fec-data   SEQUENCE OF OCTET STRING
      }
}
}
我們限定 primary-ifp-packet 必須是經過 PER Encode 之後的 IFPPacket, 還有
secondary-ifp-packets 也是連續的 PER Encode 過的 octets stream. 唯有用
"TYPE-IDENTIFIER.&Type" 語法,才能表示出來。
更多的說明,可參考:
"Communications Between Heterogenus Systems" by Oliver Dubuisson, or
"ASN.1 Complete" by John Larmouth
#



2010年5月26日 星期三

[轉貼]用gcc 自製 Library

By kaineshu

轉自 PTT LinuxDev

作者: cole945 (躂躂..) 看板: LinuxDev

標題: [心得] 用gcc 自製Library

時間: Sun Nov 5 04:15:45 2006

Library可分成三種,static、shared與dynamically loaded。

1. Static libraries

Static 程式庫用於靜態連結,簡單講是把一堆object檔用ar(archiver)包裝集合起來,檔名以`.a’ 結尾。優點是執行效能通常會比後兩者快,而且因為是靜態連結,所以不易發生執行時找不到library或版本錯置而無法執行的問題。缺點則是檔案較大,維護度較低;例如library如果發現bug需要更新,那麼就必須重新連結執行檔。

1.1 編譯

編譯方式很簡單,先例用`-c’ 編出object 檔,再用ar 包起來即可。

____ hello.c ____

#include

void hello(){ printf(“Hello “); }

____ world.c ____

#include

void world(){ printf(“world.”); }

____ mylib.h ____

void hello();

void world();

$ gcc -c hello.c world.c /* 編出hello.o 與world.o */

$ ar rcs libmylib.a hello.o world.o /* 包成limylib.a */

這樣就可以建出一個檔名為libmylib.a 的檔。輸出的檔名其實沒有硬性規定,但如果想要配合gcc 的’-l’ 參數來連結,一定要以`lib’ 開頭,中間是你要的library名稱,然後緊接著`.a’ 結尾。

1.2 使用

____ main.c ____

#include “mylib.h”

int main() {

hello();

world();

}

使用上就像與一般的object 檔連結沒有差別。

$ gcc main.c libmylib.a

也可以配合gcc 的`-l’ 參數使用

$ gcc main.c -L. -lmylib

-L 參數用來指定要搜尋程式庫的目錄,`.' 表示搜尋現在所在的目錄。通常預設會搜/usr/lib 或/lib 等目錄。

-l  參數用來指定要連結的程式庫,'mylib' 表示要與mylib進行連結

,他會搜尋library名稱前加`lib'後接`.a'的檔案來連結。

$ ./a.out

Hello world.

2. Shared libraries

Shared library 會在程式執行起始時才被自動載入。因為程式庫與執行檔是分離的,所以維護彈性較好。有兩點要注意,shared library是在程式起始時就要被載入,而不是執行中用到才載入,而且在連結階段需要有該程式庫才能進行連結。

首先有一些名詞要弄懂,soname、real name與linker name。

soname 用來表示是一個特定library 的名稱,像是libmylib.so.1 。前面以`lib' 開頭,接著是該library 的名稱,然後是`.so' ,接著是版號,用來表名他的介面;如果介面改變時,就會增加版號來維護相容度。

real name 是實際放有library程式的檔案名稱,後面會再加上minor 版號與release 版號,像是libmylib.so.1.0.0 。

一般來說,版號的改變規則是(印象中在APress-Difinitive Guide to GCC中有提到,但目前手邊沒這本書),最尾碼的release版號用於程式內容的修正,介面完全沒有改變。中間的minor用於有新增加介面,但相舊介面沒改變,所以與舊版本相容。最前面的version版號用於原介面有移除或改變,與舊版不相容時。

linker name是用於連結時的名稱,是不含版號的soname ,如: libmylib.so。

通常linker name與real name是用ln 指到對應的real name ,用來提供彈性與維護性。

2.1 編譯

shared library的製作過程較複雜。

$ gcc -c -fPIC hello.c world.c

編譯時要加上-fPIC 用來產生position-independent code。也可以用-fpic參數。(不太清楚差異,只知道-fPIC 較通用於不同平台,但產生的code較大,而且編譯速度較慢)。

$ gcc -shared -Wl,-soname,libmylib.so.1 -o libmylib.so.1.0.0 \

hello.o world.o

-shared 表示要編譯成shared library

-Wl 用於參遞參數給linker,因此-soname與libmylib.so.1會被傳給linker處理。

-soname用來指名soname 為limylib.so.1

library會被輸出成libmylib.so.1.0.0 (也就是real name)

若不指定soname 的話,在編譯結連後的執行檔會以連時的library檔名為soname,並載入他。否則是載入soname指定的library檔案。

可以利用objdump 來看library 的soname。

$ objdump -p libmylib.so | grep SONAME

SONAME libmylib.so.1

若不指名-soname參數的話,則library不會有這個欄位資料。

在編譯後再用ln 來建立soname 與linker name 兩個檔案。

$ ln -s libmylib.so.1.0.0 libmylib.so

$ ln -s libmylib.so.1.0.0 libmylib.so.1

2.2 使用

與使用static library 同。

$ gcc main.c libmylib.so

以上直接指定與libmylib.so 連結。

或用

$ gcc main.c -L. -lmylib

linker會搜尋libmylib.so 來進行連結。

如果目錄下同時有static與shared library的話,會以shared為主。使用-static 參數可以避免使用shared連結。

$ gcc main.c -static -L. -lmylib

此時可以用ldd 看編譯出的執行檔與shared程式庫的相依性

$ldd a.out

linux-gate.so.1 => (0xffffe000)

[1;33mlibmylib.so.1 => not found[m

libc.so.6 => /lib/libc.so.6 (0xb7dd6000)

/lib/ld-linux.so.2 (0xb7f07000)

輸出結果顯示出該執行檔需要libmylib.so.1 這個shared library。會顯示not found 因為沒指定該library所在的目錄,所找不到該library。因為編譯時有指定-soname參數為libmylib.so.1 的關係,所以該執行檔會

載入libmylib.so.1。否則以libmylib.so連結,執行檔則會變成要求載入libmylib.so

$ ./a.out

./a.out: error while loading shared libraries: [1;33mlibmylib.so.1[m:

cannot open shared object file: No such file or directory

因為找不到libmylib.so.1 所以無法執行程式。

有幾個方式可以處理。

a. 把libmylib.so.1 安裝到系統的library目錄,如/usr/lib下

b. 設定/etc/ld.so.conf ,加入一個新的library搜尋目錄,並執行ldconfig

更新快取

c. 設定LD_LIBRARY_PATH 環境變數來搜尋library

這個例子是加入目前的目錄來搜尋要載作的library

$ LD_LIBRARY_PATH=. ./a.out

Hello world.

3. Dynamically loaded libraries

Dynamicaaly loaded libraries 才是像windows 所用的DLL ,在使用到

時才載入,編譯連結時不需要相關的library。動態載入庫常被用於像plug-ins的應用。

3.1 使用方式

動態載入是透過一套dl function來處理。

#include

void *dlopen(const char *filename, int flag);

開啟載入filename 指定的library。

void *dlsym(void *handle, const char *symbol);

取得symbol 指定的symbol name在library被載入的記憶體位址。

int dlclose(void *handle);

關閉dlopen開啟的handle。

char *dlerror(void);

傳回最近所發生的錯誤訊息。

____ dltest.c ____

#include

#include

#include

int main() {

void *handle;

void (*f)();

char *error;

/* 開啟之前所撰寫的libmylib.so 程式庫*/

handle = dlopen("./libmylib.so", RTLD_LAZY);

if( !handle ) {

fputs( dlerror(), stderr);

exit(1);

}

/* 取得hello function 的address */

f = dlsym(handle, "hello");

if(( error=dlerror())!=NULL) {

fputs(error, stderr);

exit(1);

}

/* 呼叫該function */

f();

dlclose(handle);

}

編譯時要加上-ldl 參數來與dl library 連結

$ gcc dltest.c -ldl

結果會印出Hello 字串

$ ./a.out

Hello

關於dl的詳細內容請參閱man dlopen

--

參考資料:

Creating a shared and static library with the gnu compiler [gcc]

http://www.adp-gmbh.ch/cpp/gcc/create_lib.html

Program Library HOWTO

http://tldp.org/HOWTO/Program-Library-HOWTO/index.html

APress – Definitive Guide to GCC

※發信站: 批踢踢實業坊(ptt.cc)




2010年5月20日 星期四

emacs and program tracing

使用 emacs tracing pogram 之時,陸續發現幾個方便的按鍵,因為沒什麼系統性,又怕忘記,只好開個 blog 來紀錄:

C-M-p
C-M-n

   如同 Visual C++ 的括號追蹤,游標可以來回跳至成對的括號位置。
   小技巧,遇到 { 時,游標要放在括號的位置上
                 遇到 } 時,游標要放在括號的右邊一格

C-c C-p
C-c C-n
   從游標處往上找,移至最近的 #ifdef  
   從游標處往下找,移至最近的 #endif 後面一格

C-c C-u
   移至上一層的 #ifdef
[ Note ] C-c 是 mode specific command 之意,在此例就是 C mode


C-x C-b
   列出 buffers list

C-x C-→
C-x C-←

   跳至前後一個 buffer

C-x C-q
   toggle buffer read only

M-% string RET new-string RET
   Replace string with new-string

C-M-% gregexp RET new-string RET
   Replace some matches for regexp with newstring.

C-h a [RET] apropos-key
   可以用某些 key word 找出命令。例如讓 apropos-key`window` 就會找出含有 `window` 字串的命令。

C-x {
  buffer window 水平變大

C-x }
   buffer window 水平變小

C-x z
   重複上一個指令動作,緊接著直接按 z 就可再重複

C-h i
   可以在 emacs 裡面看 info pages, 進去後,按 [m]emacs [RET] 可以跳進 emacs info 閱讀。(其實就是在emacs里邊閱讀 info pages)
例如:在
(emacs)Top:: > *Note Keyboard Macros:: > Save Keyboard Macro 一節,
可以找到有關設定 macro 的方法。

M-n 餵給命令所需參數
   以 C-v (往上捲動,內容往下)這命令為例,內定的參數是捲動一整頁,若給它前面加參數1,像這樣:
     M-1 C-v
 就只會往上捲一行了。參數也可以是負數喔!例如這樣按:
    按住 "Alt" 然後按 "-" "1" 然後放開 "Alt" 就是輸入參數 -1 的意思,mini-buffer 表示為
     M- M-1
  用在剛剛的命令就成了 :M- M-1 C-v "往下捲動一行" 了。
  OK, 亂玩一下,恰好有個命令是往下捲動一頁 M-v
 所以 M- M-1 C-v 效果等於 M-1 M-v,都會往下捲動一行
 
另外 C-u 是輸入參數 4 的意思
 C-u C-v 往上捲 4 行,C-u C-u C-v 表示會捲 16 行喔

C-s C-w ... C-s
  尋找 String, 中間的 C-w 可以從游標處往後選字,直到你要尋找的字整個進來為止,接著按 C-s 就可以望下開始找了!超好用!

M-x set-buffer-file-coding-system RET unix
or
C-x  <RET>  f  unix  <RET>
    把 Dos 文字格式(\r\n)轉為 Unix文字格式(\n)

M-x delete-trailing-whitespace <RET>
    移除多餘的行尾空白,符合 Linux Coding Style

下面是我的 .emacs 內容:

; auto complete
(add-to-list 'load-path "~/.emacs.d/")
(require 'auto-complete-config)
(add-to-list 'ac-dictionary-directories "~/.emacs.d/ac-dict")
(ac-config-default)

; edit properties
(modify-frame-parameters nil '((wait-for-wm . nil)))
(setq scroll-margin 0 scroll-conservatively 10000 )
(global-font-lock-mode "t")
;(require 'hl-line)
;(global-hl-line-mode t)
(transient-mark-mode t)
(setq ring-bell-function 'ignore)
;(require 'paren)
;(show-paren-mode 1)
(setq c-default-style "linux")
;(setq c-basic-offset 4)

(which-function-mode "t")

(require 'color-theme)
(color-theme-initialize)
(color-theme-hober)

(load-file "/usr/share/emacs/site-lisp/xcscope.el")
(require 'xcscope)

(setq cscope-do-not-update-database "t")
(setq cscope-set-initial-directory "./")
(autoload 'gtags-mode "gtags" "" t)

(setq ecb-tip-of-the-day nil)

; key bindings
;bind C-> to 'M-x enlarge-window'
(global-set-key (kbd "C-.") (quote enlarge-window))
;bind C-< to 'M-x shrink-window'
(global-set-key (kbd "C-,") (quote shrink-window))
;set <M-f11> as 'scroll-other-window-up-one-line'
(fset 'scroll-other-window-up-one-line "\2551\226")
;set <f11> as 'scroll-other-window-down-one-line'
(fset 'scroll-other-window-down-one-line "\261\226")

;(global-set-key [f5] 'cscope-find-this-file)
;(global-set-key [f6] 'cscope-find-this-symbol)
;(global-set-key [f7] 'cscope-pop-mark)
;(global-set-key [f8] 'cscope-find-global-definition)
;(global-set-key [f9] 'cscope-find-global-definition-no-prompting)
;(global-set-key [M-up] 'cscope-prev-symbol)'gtags-find-rtag)
;(global-set-key [M-down] 'cscope-next-symbol)

(global-set-key "\C-cgA" 'gtags-visit-rootdir)
(global-set-key "\C-cgr" 'gtags-find-rtag)
(global-set-key "\C-cgs" 'gtags-find-symbol)

(global-set-key [f5] 'gtags-find-file)
(global-set-key [f6] 'gtags-find-with-grep)
(global-set-key [f7] 'gtags-pop-stack)
(global-set-key [f8] 'gtags-find-tag)
(global-set-key [f9] 'gtags-find-tag-from-here)


(global-set-key [M-f11] 'scroll-other-window-up-one-line)
(global-set-key [f11] 'scroll-other-window-down-one-line)
(global-set-key [C-f12] 'ecb-activate)
(global-set-key [f12] 'ecb-toggle-ecb-windows)
(global-set-key [C-f1] 'color-theme-select)

(setq c-mode-hook '(lambda () (gtags-mode 1) (auto-complete-mode 1)))

(let ((frame '((left . 0)
           (top . 0)
           (width . 110)
           (height . 28)
           (tool-bar-lines . nil)
           (vertical-scroll-bars . nil)
           (background-color . "black")
           (foreground-color . "white")         
)))
  (setq default-frame-alist frame)
  (setq initial-frame-alist frame)
)

;(defun my-font-face ()
;  (custom-set-faces
;   '(default ((t (:inherit nil :stipple nil :background "black" :foreground "white" :inverse-video nil :box nil :strike-through nil :overline nil :underline nil :slant normal :weight normal :height 138 :width normal :foundry "unknown" :family "DejaVu Sans Mono"))))
;   '(ecb-tag-header-face ((t (:background "midnight blue"))))
;   '(ecb-default-highlight-face ((((class color) (background dark)) (:background "#28FF46FF66FF"))))
;))

(custom-set-variables
  ;; custom-set-variables was added by Custom.
  ;; If you edit it by hand, you could mess it up, so be careful.
  ;; Your init file should contain only one such instance.
  ;; If there is more than one, they won't work right.
 '(display-time-mode t)
 '(ecb-options-version "2.32")
 '(show-paren-mode t))


#





2010年3月13日 星期六

find 配合 regex

在目錄下想要找所有的 .cxx  與 .h 檔 ,然後餵給 cscope.files 怎麼打呢?
[這篇]解說得很好,在 find 下配合 -regex 應該這樣找 cxx 與 h 檔 :
find ./ -regex ".*\.\(cxx\|h\)" -print > cscope.files

其中 -regex 表示之後用 regex pattern 來尋找, `find` 是用與 `emacs` 相同的 regex 規則
所以後面這麼多反斜線 `\'  都是因為 emacs regex specifiers 需要用反斜線當 Escape 字元。
#