搜索

Google
 

星期五, 三月 30, 2007

星期四, 三月 29, 2007

生死边缘的轮回 - reiserfs文件系统的数据恢复

昨天晚上给客户一个应用定制裁减linux系统的时候,发生了一件非常不幸的事,我的data目录被我无意给rm -rf删除掉了,那里面存放着我的所有项目的代码和文档,还有很多其它重要的东西。看见那个目录突然什么都没有的时候那种感觉简直无法形容,由于长期出差一直没有机会给公司保留备份,还好今天恢复了大部分重要的文档和代码。希望跟我一样倒霉的朋友能以此为鉴,删除文件时一定要小心,并且经常备份重要的代码和文档。

网上有两篇文章对reiserfs文件系统的数据恢复做了详细的介绍,ReiserFS undelete/data recovery HOWTOReiserfs filesystem recovery,另外提供几点建议:
  1. 在误删除之后切记不要再进行任何操作,立即关机,做好准备再来做数据恢复!
  2. 准备好一块大硬盘或移动硬盘(最好使用usb 2.0的硬盘盒子),第一时间用dd把误删除数据的分区完整备份一份。恢复也最好针对这个image文件,直到重要的数据完全找到再处理该分区,如果失败了还可以借助专业数据恢复公司来进行数据恢复。
  3. 您在恢复时一定记得给reiserfsck加上-l参数,生成日志文件是非常重要的,如果文件太多reiserfsck并不能100%地恢复您的数据,日志文件里会告诉您哪些文件没有被正确地恢复。再次提醒您经常备份自己重要的数据!!!
顺便赞叹一下reiserfs作者,reiserfs确实是一个非常优秀的文件系统,我54G容量的分区dd到移动硬盘时间不超过1小时,数据恢复时间不超过30分钟,并且最终重要的数据基本上都得以恢复!

星期六, 三月 17, 2007

beryl/compiz的ontop补丁

用beryl/compiz的时候有个比较遗憾的地方,那就是窗口没有了ontop功能,也就是窗口置顶,不过给libwnck打上补丁就可以解决这个问题了。

补丁地址:libwnck补丁

星期一, 三月 12, 2007

GtkScrolledWindow滚动条问题

在使用GtkTreeView时,用GtkScrolledWindow来添加滚动条,但列表(或树)中的数据行在不断得更新(增加),而垂直滚动条默认情况下不能自动往下滚动,以显示最新的数据行,而是始终停在top的位置,针对此问题有什么方法可以解决呢?

每次增加数据行之后,得到最后一行的path,需要手动调用gtk_tree_view_scroll_to_cell,滚动到最后的地方。如果不想手动 调用,可以监听 model 的 row-inserted,在该signal callback中gtk_tree_view_scroll_to_cell,如果大量迅速的增加新行的话,速度会受影响,可以跟延时结合减少scroll的频率。

星期日, 三月 11, 2007

强悍的回复帖

从CSDN主页上偶尔看到了一篇帖子,于是进去看了一下,十年MFC经历认识的Microsoft技术,楼主的行文风格不错,于是耐心地看了下去,一来觉得楼主知识系统全面值得学习,二来楼主的文字功底也颇为深厚,这种散文式的技术帖即使用来消遣也不错。不过没想到的是后来的一个回复帖真的让我捧腹大笑久久不能平静^_^。。。

逐句地看完这个帖子以后,我的心久久不能平静,震撼啊!为什么会有如此好的帖子!我纵横网络bbs多年,自以为再也不会有任何帖子能打动我,没想到今天看到了如此精妙绝伦的这样一篇帖子。楼主,是你让我深深地理解了‘人外有人,天外有天’这句话。谢谢侬!在看完这帖子以后,我没有立即回复,因为我生怕我庸俗不堪的回复会玷污了这网上少有的帖子。但是我还是回复了,因为觉得如果不能在如此精彩的帖子后面留下自己的网名,那我死也不会瞑目的!能够在如此精彩的帖子后面留下自己的网名是多么骄傲的一件事啊!

楼主,请原谅我的自私!我知道无论用多么华丽的辞藻来形容楼主您帖子的精彩程度都是不够的,都是虚伪的,所以我只想说一句:您的帖子太好看了!我愿意一辈子的看下去!这篇帖子构思新颖,题材独具匠心,段落清晰,情节诡异,跌宕起伏,主线分明,引人入胜,平淡中显示出不凡的文学功底,可谓是字字珠玑,句句经典,是我辈应当学习之典范。就小说艺术的角度而言,这篇帖子不算太成功,但它的实验意义却远远大于成功本身。正所谓:“一马奔腾,射雕引弓,天地都在我心中!”楼主真不愧为无厘界新一代的开山怪!

星期五, 三月 09, 2007

如何方便控制笔记本触摸板

笔记本的鼠标触摸板我基本上很少用,比起外接鼠标还是没那么方便灵活,何况写程序的时候基本上很少用鼠标,但是笔记本的触摸板却在写程序的时候经常搞得鼠标指针胡乱飘移,非常影响键盘输入的准确性。

在linux下控制触摸板必须得使用2.6.x内核,大致有几件事要做:正确配置内核、安装synaptics驱动、正确配置xorg.conf。

1、配置内核




Linux Kernel Configuration: Enable synaptics support
Device Drivers --->
   Input Device Support --->
<*> Event Interface
[*] Mouse --->

<*> PS/2 mouse


2、安装synaptics,在gentoo下直接emerge synaptics即可。

3、配置xorg.conf,首先看看你的输入设备信息,我机器上的输出信息如下:

/home/debianl $ cat /proc/bus/input/devices
I: Bus=0011 Vendor=0001 Product=0001 Version=ab41
N: Name="AT Translated Set 2 keyboard"
P: Phys=isa0060/serio0/input0
S: Sysfs=/class/input/input0
H: Handlers=kbd event0
B: EV=120013
B: KEY=4 2000000 3802078 f840d001 feffffdf ffefffff ffffffff fffffffe
B: MSC=10
B: LED=7

I: Bus=0011 Vendor=0002 Product=0007 Version=0000
N: Name="SynPS/2 Synaptics TouchPad"
P: Phys=isa0060/serio4/input0
S: Sysfs=/class/input/input1
H: Handlers=mouse0 event1
B: EV=b
B: KEY=6420 0 70000 0 0 0 0 0 0 0 0
B: ABS=11000003

I: Bus=0003 Vendor=046d Product=c016 Version=0340
N: Name="Logitech Optical USB Mouse"
P: Phys=usb-0000:00:1d.1-1/input0
S: Sysfs=/class/input/input2
H: Handlers=mouse1 event2
B: EV=7
B: KEY=70000 0 0 0 0 0 0 0 0
B: REL=103

然后配置xorg.conf,加入TouchPad的Section内容,并在ServerLayout中加入InputDevice "TouchPad" "AlwaysCore",以下是我的xorg.conf配置:

Section "ServerLayout"
Identifier "X.org Configured"
Screen 0 "Screen0" 0 0
InputDevice "Mouse0" "CorePointer"
InputDevice "Keyboard0" "CoreKeyboard"
InputDevice "TouchPad" "AlwaysCore"
EndSection

Section "Files"
RgbPath "/usr/share/X11/rgb"
ModulePath "/usr/lib/xorg/modules"
FontPath "/data/fonts/"
FontPath "/usr/share/fonts/misc/"
FontPath "/usr/share/fonts/TTF/"
FontPath "/usr/share/fonts/OTF"
FontPath "/usr/share/fonts/Type1/"
FontPath "/usr/share/fonts/CID/"
FontPath "/usr/share/fonts/100dpi/"
FontPath "/usr/share/fonts/75dpi/"
EndSection

Section "Module"
Load "glx"
Load "extmod"
Load "xtrap"
Load "record"
Load "dbe"
Load "dri"
Load "freetype"
Load "type1"
EndSection

Section "InputDevice"
Identifier "Keyboard0"
Driver "kbd"
EndSection

Section "InputDevice"
Identifier "Mouse0"
Driver "mouse"
Option "Protocol" "auto"
Option "Device" "/dev/input/mice"
Option "ZAxisMapping" "4 5 6 7"
EndSection

Section "InputDevice"
Identifier "TouchPad"
Driver "synaptics"
Option "Device" "/dev/input/mouse0"
Option "Protocol" "auto"
Option "SHMConfig" "on"
EndSection

Section "Monitor"
Identifier "Monitor0"
VendorName "Monitor Vendor"
ModelName "Monitor Model"
EndSection

Section "Device"
Identifier "Card0"
Driver "nvidia"
VendorName "nVidia Corporation"
BoardName "Unknown Board"
BusID "PCI:1:0:0"
Option "Accel" "True"
Option "RenderAccel" "True"
EndSection

Section "Screen"
Identifier "Screen0"
Device "Card0"
Monitor "Monitor0"
Option "AddARGBGLXVisuals" "true"
SubSection "Display"
Viewport 0 0
Depth 1
EndSubSection
SubSection "Display"
Viewport 0 0
Depth 4
EndSubSection
SubSection "Display"
Viewport 0 0
Depth 8
EndSubSection
SubSection "Display"
Viewport 0 0
Depth 15
EndSubSection
SubSection "Display"
Viewport 0 0
Depth 16
EndSubSection
SubSection "Display"
Viewport 0 0
Depth 24
EndSubSection
EndSection

Section "Extensions"
Option "Composite" "enable"
EndSection

现在你应该就可以使用synclient来配置各项参数了,也可以禁用触摸板,如果你用gnome的话可以安装一个gsynaptics,图形化的配置界面更易用点。

linux视频转换: mencoder

在网上发现一篇讲解利用mplayer的mencoder转换视频的文章,刚好适用我简陋的mp4转贴一下^_^,原文网址:Linux下的视频转换

制作适合在智能手机和PDA上观看的mpeg4视频。
Linux上有一个很强大的视频音频转换软件,就是Mplayer自带的mencoder (MPlayer's Movie Encoder)。mencoder就象是一台全手动的照相机,可调整的选项非常多,不过这儿只是把最常见的情况说一下。

转换avi文件,并把字幕内嵌到视频中。首先假设一下下列的条件:
文件名:video.avi
字幕文件名:video.srt
目标文件:new.avi
目标文件格式:mpeg4
目标文件视频码率:200
目标文件音频码率:64
目标文件分辨率: 320:240
制作内嵌字幕所需的字体:simsun.ttf
(上面各项都可以根据实际情况进行调整)
转换命令如下:

mencoder -oac mp3lame -lameopts vbr=3:br=64 -ovc lavc -lavcopts vcodec=mpeg4:mbd=1:vbitrate=200 -sub video.srt -o new.avi -font simsun.ttf video.avi -subcp cp936 -subfont-text-scale 4 -vf scale=320:240
各选项的含义:
-oac 编码文件的音频部分。这儿是用lame将音频encode成mp3,即mp3lame。其他可用的选项可以调用mencoder的man page查看。
-lameopts 顾名思义,即lame选项,这儿只需定义一下码率就可以了。
vbr 设定音频码率的方法,格式为vbr=<0-4>

0 cbr average bitrate
1 mt
2 rh constant bitrate Also forces CBR mode encoding on subsequent ABR presets modes.
3 abr
4 mtrh

在这儿用的是3,abr。
br 就是设定我们所需要的码率值,格式为br=<0-1024>,只能在vbr为0和3的情况下才能使用该选项。
-ovc 编码文件的视频部分。主要有以下几个选项

-ovc copy
不进行编码,只是复制视频流
-ovc divx4
编码成DivX4/DivX5
-ovc raw
编码成任意不压缩的格式(用‘-vf format’设定具体的格式)
-ovc lavc
使用libavcodec进行编码

-lavcopts 就是libavcodec的选项。
vcodec=使用指定的视频编码,下面列一下几个主要的值

h264
H.264
h263
H.263
h263p
H.263+
mpeg4
MPEG-4 (DivX 4/5)
msmpeg4
DivX 3
msmpeg4v2
MS MPEG4v2
wmv1
Windows Media Video, version 1 (又称 WMV7)
wmv2
Windows Media Video, version 2 (又称 WMV8)
rv10
旧的RealVideo格式
mpeg1video
MPEG-1 video
mpeg2video
MPEG-2 video

mbd 决定视频宏块的算法,这儿只需要mbd=1即可。其余的可以查看man page。
vbitrate 设定视频的码率(默认为800)。
-sub 设定字幕文件
-o 目标视频文件
-font 制作内嵌字幕所需字体的路径
-subcp 字幕的编码,简体中文就是cp936
-subfont-text-scale 字幕字体的大小
-vf scale 视频的分辨率
如果不需要将字幕内嵌入视频文件,只需要去掉-sub、-font、-subcp、-subfont-text-scale这几个选项。将rmvb转换成mpeg4也是如此。

python扩展与嵌入的入门级FAQ

以下是我在开发一个应用中集成python脚本引擎的过程中所遇到的一些入门级问题,稍后再整理一些比较完整的关于python扩展与嵌入的日志。

1、如何在宿主应用中注册module?可在Py_Initialize之前调用PyImport_AppendInittab来注册,也可在Py_Initialize之后直接调用注册函数。

2、如何添加宿主应用脚本的路径到python搜索路径?在Py_Initialize之后通过PySys_GetObject("path")得到sys.path,然后再通过PyList_Insert加入宿主应用的脚本路径。

3、如何调用python模块中的函数?通过PyImport_ImportModule得到module,然后再通过PyModule_GetDict从module中得到dict,再通过PyDict_GetItemString得到函数对象,最后通过PyObject_CallObject或其它PyObject_Call系列函数调用,当然调用之前最好用PyCallable_Check检查,另外就是dict、func都属于Borrowed reference,因此不需要Py_DECREF或Py_XDECREF。

4、所有的wrapper函数都应该返回PyObject实例指针,即使在python中调用的时候并不需要返回值,但仍需要返回Py_None,相当于C/C++中的void,Py_INCREF(Py_None); return Py_None;当然也可以用宏Py_RETURN_NONE来代替。

星期四, 三月 08, 2007

gtk+开发中的几个小经验

1、在gtk+开发过程中,我们经常需要在event handler中来访问该窗口中的某些控件的信息,通常习惯于整一大堆全局变量,其实还有更好的方式,在glib的实现中我们可以通过g_object_set_data和g_object_get_data给一个GObject对象绑定自定义的数据及属性,g_object_set_data_full还可以在对象释放资源时通知你的回调函数来做资源释放处理,这样我们就可以给event handler传递一个窗口对象指针就行了,其它的数据及控件信息可以通过窗口对象得到我们想要的东西。

2、某些对象并未提供所有属性的存取方法,但只要是通过GObject继承下来的对象均可采用g_object_set、g_object_set_property及g_object_get、g_object_get_property来存取这些属性,如给TreeView中某一列的值要求居右则可以对gtk_cell_renderer_text_new()产生的GtkCellRenderer对象调用g_object_set(renderer, "xalign", 1.0, NULL)来达到居右的效果。

3、使用g_idle_add及g_timeout_add等函数中的时候一定要小心,由于代码延后执行,因此一定要保证其数据的生命周期,如下面的例子是我在开发一个项目应用中遇到的问题(注释掉的代码即为出现问题之后的修正代码),传递的Python对象到代码执行的时候已经被释放掉了,因此出现了比较奇怪的现象:如果连续调用这个函数两次,结果加进去的两行信息全部都是最后一次的数据,当然可能还会有更奇特的现象发生。

static gboolean
_etc_main_win_add_trans(gpointer data)
{
PyObject *args = data;
if (PyTuple_Size(args) != lv_columns)
return FALSE;

GtkWidget *listview;
GtkTreeModel *model;
GtkTreeIter iter;
int i;
GValue value;
PyObject *obj;

listview = GTK_WIDGET(g_object_get_data(G_OBJECT(main_window), "trans_list"));
model = gtk_tree_view_get_model(GTK_TREE_VIEW(listview));
gtk_list_store_append(GTK_LIST_STORE(model), &iter);
for (i = 0; i < lv_columns; ++i) {
memset(&value, 0, sizeof(value));
g_value_init(&value, lv_types[i]);
obj = PyTuple_GetItem(args, i);
switch(lv_types[i]) {
case G_TYPE_INT:
if (PyInt_Check(obj))
g_value_set_int(&value, PyInt_AsLong(obj));
break;

case G_TYPE_LONG:
if (PyLong_Check(obj))
g_value_set_long(&value, PyLong_AsLong(obj));
break;

case G_TYPE_UINT:
if (PyLong_Check(obj))
g_value_set_uint(&value, PyLong_AsUnsignedLong(obj));
break;

case G_TYPE_ULONG:
if (PyLong_Check(obj))
g_value_set_ulong(&value, PyLong_AsUnsignedLong(obj));
break;

case G_TYPE_FLOAT:
if (PyFloat_Check(obj))
g_value_set_float(&value, PyFloat_AsDouble(obj));
break;

case G_TYPE_DOUBLE:
if (PyFloat_Check(obj))
g_value_set_double(&value, PyFloat_AsDouble(obj));
break;

default:
if (PyString_Check(obj))
g_value_set_string(&value, PyString_AsString(obj));
break;
}
gtk_list_store_set_value(GTK_LIST_STORE(model), &iter, i, &value);
}

//Py_XDECREF(args);
return FALSE;
}

void
etc_main_win_add_trans(PyObject *args)
{
//Py_INCREF(args);
g_idle_add(_etc_main_win_add_trans, args);
}

我的mlterm配置

~/.mlterm/main

use_transbg = true
wall_picture =
scrollbar_mode = none
brightness = 100
contrast = 100
gamma = 100
scrollbar_view_name = mozmodern
use_anti_alias = true
use_variable_column_width = false

~/.mlterm/aafont

ISO10646_UCS2_1=Bitstream Vera Sans Mono-iso10646-1;
ISO10646_UCS2_1_BIWIDTH=SimSun-iso10646-1;

~/.mlterm/termcap

xterm|mlterm:kD=\E[3~:kb=^?

程序库的autotools脚本

1、configure.ac的不同

AC_INIT()
AM_INIT_AUTOMAKE(lclibs, 0.1)
AM_CONFIG_HEADER([config.h])

# Checks for programs.
AC_PROG_CC

# 库与应用程序不一样,需要libtool支持
# 一般不用intltool,所以没有AC_PROG_INTLTOOL
AC_PROG_LIBTOOL

# Checks for libraries.

# Checks for header files.
AC_HEADER_STDC
AC_CHECK_HEADERS([arpa/inet.h netdb.h netinet/in.h stdlib.h string.h strings.h sys/socket.h unistd.h])

# Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
AC_C_INLINE
AC_TYPE_SIZE_T

# Checks for library functions.
AC_FUNC_MALLOC
AC_FUNC_REALLOC
AC_CHECK_FUNCS([atexit bzero gethostbyname inet_ntoa memset socket strcasecmp strchr strdup strpbrk strspn strstr])

AC_OUTPUT([
Makefile
src/Makefile
])


2、src/Makefile.am的不同

lib_LTLIBRARIES = liblclibs.la
liblclibs_la_SOURCES = \
utils.c\
stack.c\
sockets_wrapper.c\
queue.c\
packages.c\
inifiles.c\
hash.c

lclibsincludedir = $(includedir)/lclibs
lclibsinclude_HEADERS = \
lclibs.h\
utils.h\
threads_wrapper.h\
stack.h\
sockets_wrapper.h\
queue.h\
packages.h\
inifiles.h\
hash.h

autotools实践

1、准备好目录树(一般情况下请将源码扔/src目录)

2、运行autoscan && mv configure.scan configure.ac && rm -f autoscan*

修改configure.ac,去掉AC_INIT后面括号里的东西,增加AM_INIT_AUTOMAKE(你的包名, 包版本号),并将AC_CONFIG_HEADER改为AM_CONFIG_HEADER,删除掉AC_CONFIG_FILES,改AC_OUTPUT为AC_OUTPUT(Makefile src/Makefile po/Makefile.in),用AC_CONFIG_FILES在automake时会报错。

3、注意加上你程序中用到的库和头文件检测语句,看起来应如下所示:

AC_INIT()
AM_INIT_AUTOMAKE(dsrc, 0.1)
AM_CONFIG_HEADER(config.h)

# Checks for programs.
AC_PROG_CC
AC_PROG_INTLTOOL

# Checks for libraries.
# PKG_CHECK_MODULES可直接在Makefile.am中引用$(xxx_CFLAGS)和$(xxx_LIBS)
PKG_CHECK_MODULES(xml2, [xml2])
PKG_CHECK_MODULES(openssl, [openssl])

AC_CHECK_LIB([pthread], [main])

# Checks for header files.
AC_HEADER_STDC
AC_CHECK_HEADERS([arpa/inet.h libintl.h locale.h netinet/in.h stdlib.h string.h sys/socket.h unistd.h])

# Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
AC_TYPE_SIZE_T

# Checks for library functions.
AC_FUNC_FORK
AC_FUNC_MALLOC
AC_FUNC_REALLOC
AC_CHECK_FUNCS([inet_ntoa memset setlocale socket strcasecmp strncasecmp])

# gettext
GETTEXT_PACKAGE=dsrc
AC_SUBST(GETTEXT_PACKAGE)

ALL_LINGUAS="zh_CN"
AM_GLIB_GNU_GETTEXT

AC_OUTPUT([
Makefile
src/Makefile
po/Makefile.in
])

4、准备/Makefile.am

SUBDIRS = src po

dsrcdocdir = ${prefix}/doc/dsrc
dsrcdoc_DATA = \
README\
COPYING\
AUTHORS\
ChangeLog\
INSTALL\
NEWS

EXTRA_DIST = $(dsrcdoc_DATA)

其实这个内容非常简单,一看就明白了,上面所列的EXTRA_DIST为需要安装到/usr/share/doc下的东西,如果你还有其它文档可以加到这个列表中

5、准备src/Makefile.am

INCLUDES = -DLOCALEDIR=\""$(prefix)/share/locale"\"
AM_CFLAGS = -DDEBUG -g $(xml2_CFLAGS)
LIBS = $(xml2_LIBS) $(openssl_LIBS) -lpthread
# AM_LDFLAGS =

bin_PROGRAMS = dsrc
dsrc_SOURCES = main.c security.c XML_utils.c DSRC_handler.c DSRC_builder.c
# dsrc_CFLAGS =
# dsrc_LDFLAGS =

如果会生成多个执行文件可为bin_PROGRAMS增加文件名即可,以空格隔开,下面对每个执行文件需要的源文件定义为xxx_SOURCES即可,如果某执行文件编译参数以及链接参数也可以单独设置:xxx_CFLAGS、xxx_LDFLAGS,不过我建议库文件链接参数直接在configure.ac里AC_CHECK_LIB了事,来得方便点

6、创建automake需要的一些文件

touch AUTHORS NEWS README INSTALL ChangeLog

7、心动从现在开始

aclocal
autoconf
intltoolize
autoheader
automake --add-missing --gnu

8、正事要紧

给自己的程序添加gettext支持,关于gettext的详细介绍可参考其它文章,一般就是以下套路

#include <libintl.h>
#include <locale.h>

#define _(string) gettext(string)
#define N_(string) string

void
i18n_init(void)
{
bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
textdomain(GETTEXT_PACKAGE);
}

通常程序在入口处就调用i18n_init(),在显示常量字符串的时候一般如fprintf(stdout, _("Hello World\n"));

9、创建po文件

创建并进入/po目录,创建POTFILES.in,内容为你需要提取源码中有需要翻译的字符串的源文件列表,每行一个文件,然后执行intltool-update --pot产生pot文件,如果将来你在维护代码中代码有变化或者在POTFILES.in中新增了源文件,可用intltool-update --maintain更新。

有了pot文件,现在需要产生各种语言的po文件,如msginit --locale=zh_CN产生中文po文件,如将来源文件有变化可以intltool-update zh_CN更新zh_CN.po,接下来翻译的工作就是你自己来做了。

要生成特定语言的mo文件,需要维护configure.ac中的ALL_LINGUAS,以空格分隔就可以了

10、测试

./configure --prefix=/usr
make
sudo make install
LANG="zh_CN.UTF-8" xxx

libxml2尝试

etc项目中实现一个http server,刚好用到大量的XML,每次处理的数据包XML数据相对较小,先尝试了expat,SAX解析方式确实痛苦,需要自己维护状态树。libxml2相对功能比较全,SAX、DOM解析方式都有实现,而且还有XPath、XLink等实现,甚至连HTMLparser都有了,下面是我这次用到的一些API:

1、解析XML文档DOM树(参考parser.h)

xmlDocPtr doc = xmlParseDoc((const xmlChar *)xml_data);
xmlNodePtr node = xmlDocGetRootElement(doc);
然后node就可以在DOM树里面漫游了,当然xmlParseDoc之后理所当然应该检查doc是否为空意即解析是否成功,结束之后记得xmlFreeDoc(doc);如果需要解析xml文件,则使用xmlParseFile(const xmlChar *)"test.xml")。

2、常见操作(参考tree.h)

得到一个节点的名称:node->name^_^
得到一个节点的内容:xmlChar *value = xmlNodeGetContent(node)返回值value应该使用xmlFree(value)释放内存
设置一个节点的内容:xmlNodeSetContent(node, (const xmlChar *)"test")
得到一个节点的某属性值:xmlChar *value = xmlGetProp(node, (const xmlChar *)"prop1"),返回值需要xmlFree(value)释放内存
设置一个节点的某属性值:xmlSetProp(node, (const xmlChar *)"prop1", (const xmlChar *)"v1")

3、新建XML文档(参考tree.h)

xmlDocPtr doc = xmlNewDoc("1.0"),其中1.0是版本号
doc->children = xmlNewDocNode(doc, NULL, (const xmlChar *)"stream", NULL)创建根节点,具体函数原型可参考其API-Manual
xmlNodePtr node = xmlNewChild(doc->children, NULL, (const xmlChar *)"dsrc_frame", NULL),用xmlNewChild可生成某节点的子节点
xmlDocDumpFormatMemory(doc, buf, &result, 1),用来保存生成的xml文档到内存中,此系列函数还包括:xmlDocDump、xmlDocDumpFormatMemoryEnc、xmlDocDumpMemory、xmlDocDumpMemoryEnc、xmlDocFormatDump

4、XPath操作(参考xpath.h)(XPath可参考w3c文档http://www.w3.org/TR/xpath)

有时候对一个XML文档我们可能只关心其中某一个或某几个特定的Element的值或其属性,如果漫游DOM树将是很痛苦也很无聊的事,XPath可以非常方便地得到你想的Element。下面是一个自定义函数:

xmlXPathObjectPtr
get_nodeset(xmlDocPtr doc, const xmlChar *xpath)
{
xmlXPathContextPtr context;
xmlXPathObjectPtr result;

context = xmlXPathNewContext(doc);
if (context == NULL)
return NULL;

result = xmlXPathEvalExpression(xpath, context);
xmlXPathFreeContext(context);
if (result == NULL)
return NULL;
if (xmlXPathNodeSetIsEmpty(result->nodesetval)) {
xmlXPathFreeObject(result);
return NULL;
}

return result;
}

下面是调用代码:

xmlXPathObjectPtr app_result = get_nodeset(doc, (const xmlChar *)"/stream/dsrc_frame/tapdu/application[1]/param");
if (app_result == NULL)
return 0;

xmlNodeSetPtr nodeset = app_result->nodesetval;
xmlChar *value = xmlNodeGetContent(nodeset->nodeTab[0]);
if (value == NULL)
goto ret;

printf("%s\n", value);

xmlXPathFreeObject(app_result);
xmlFree(value);

查看导出符号

用nm即可,共享库.so加一个-D参数,其它参数可参考help

wget整站下载

wget -r -p -np -k http://www.gtk.org/tutorial/

-r, --recursive specify recursive download.
-k, --convert-links make links in downloaded HTML point to local files.
-p, --page-requisites get all images, etc. needed to display HTML page.
-np, --no-parent don't ascend to the parent directory.

一个简单的awk应用

有两个文件:
一个文件是两列,第一列是ID,第二列是ID对应的经验植。
第2个文件是等级,3列,第一列是等级,第2列是经验值开始值,第3列是经验值结束值,就是2,3列是等级经验范围。
现在要求查出第一个文件每行对应等级,并输出。

#!/bin/awk -f

BEGIN {
i = 1
while((getline < "level.txt") > 0) {
level[i] = $1
min[i] = $2
max[i] = $3
i++
}
line = i
}

{
for(j = 1; j <= line; j++) {
if($2 >= min[j] && $2 < max[j]) printf "%s,%s\n",$1,level[j]
}
}

linux裁减实践

1、编译busybox,我通常会选择Busybox Settings/General Configuration中的前面6项,Installation Options中的Don't use /usr,下面的Applets我基本上都选,反正也不大,Init Utilities中我去掉了两个与debugging有关的选项,其它也没什么了,看着选择自己需要的就行了。

2、如果你的busybox编译得没什么问题不需要再调整接下来的工作你可以在_install目录里面做,否则我觉得最好还是挂载好你将要使用的设备,将_install下的所有文件和目录复制到设备上去。mkdir -p boot/grub root dev etc/init.d lib proc tmp var/lib/misc var/lock var/log var/tmp usr/bin usr/lib && chmod 1777 tmp var/tmp。

3、裁减kernel,通常裁减主要用于一个特定的应用,设备都是指定的,可以针对相应的硬件配置只选择自己需要的驱动,裁减的linux应用通常也比较单一,因此很多功能都可以不选择。复制kernel文件vmlinuz到boot目录,如果用grub的话可将grub的stage1和stage2两个文件复制boot/grub中,编辑好grub.conf安装grub即可。

4、要复制的/dev下的一些设备文件:console、core、fd0、null、ptmx、pts、ram*、random、stderr、stdin、stdout、rd、fd、tty、tty0~tty9、urandom、vcs、zero、hda*(如果用的是ide接口硬盘)、pty*,如果要使用X还要复制agppart、misc、log、mem、input。复制方法用cp -avp /dev/xxx

5、复制母系统的/etc/group、passwd、shadow到etc目录,删除掉不需要的组和用户即可。

6、配置/etc/fstab,至少有类似以下这样的项:
/dev/hda11 / reiserfs defaults 0 0
proc /proc proc defaults 0 0
none /dev/pts devpts gid=5,mode=620 0 0

7、配置/etc/inittab:
::sysinit:/etc/init.d/rcS

::respawn:/sbin/getty 38400 tty1
tty2::respawn:/sbin/getty 38400 tty2
tty3::respawn:/sbin/getty 38400 tty3
tty4::respawn:/sbin/getty 38400 tty4

::restart:/sbin/init

::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r
::shutdown:/sbin/swapoff -a

8、编辑/etc/issue,如Welcome to MyLinux release 0.1 on \l

9、编辑/etc/init.d/rcS:
#!/bin/sh

/bin/mount -a
/bin/mount -o remount,rw /

echo
echo
echo
echo -en "\t\t\tWelcome to \\033[0;32mMyLinux\\033[0;39m release 0.1\n"

hostname MyLinux
ifconfig lo up
ifconfig eth0 192.168.4.240 netmask 255.255.255.0 up
route add default gw 192.168.4.1
syslogd

10、复制必要的库文件,当然在这儿busybox也可以静态编译链接,但你的应用应该也要用到库文件的,都静态编译链接还是挺浪费空间的,所以我一般并不使用静态编译链接。现在复制必要的库文件到lib目录,可以使用ldd查看某个elf文件需要使用哪些共享库。

基本上就这些步骤,X的配置也很简单,推荐使用gentoo,用gentoo裁减linux非常方便,可以简单地用quickpkg打包你想要的,然后解压到目标设备上,然后删掉不需要的东西即可。现在可以启动一下试试了。。。

kernel的LXR页面

1.0以下版本代码:http://www.oldlinux.org/lxr/http_cn/source/

1.0以上版本代码:http://lxr.linux.no/source/

常用的firefox扩展

Fasterfox - 据说可以提速,我倒没有感觉出来。
Tab Mix Plus - 给标签页上加上了关闭按扭,这是我最喜欢的,其它功能对我似乎没用。
Wizz RSS News Reader - 这个也不错,省去了我安装Liferea。
FireFTP - 感觉这个插件比gftp还好用。
JSView - 可以直接从它这儿得到你喜欢的网页的js和css,对web开发挺有用的。
Gmail Manager - 管理gmail邮箱方便,有了它我几乎不用evolution。
Greasemonkey - 一个强大的脚本管理工具,不过我用它几乎只是为了上btchina.net。
Google Browser Sync - 将Firefox中的浏览历史、收藏夹之类的东西同步到你的google帐号去,这个功能很有用,尤其是重装系统把/home下的东西删掉了。
IGoogle Sidebar - 以侧栏方式查看你的google自定义主页上的个性化内容。

Noia - 不算是扩展,是Firefox里我最喜欢用的一个主题。

以link方式管理eclipse扩展

以link方式管理eclipse扩展非常方便,可将安装的第三方插件统一放一个目录,在eclipse目录中创建一个links目录,创建一个.link文件加入path=/your/extensions/path即可,如我的eclipse第三方插件全在/data/soft/eclipse,/usr/lib/eclipse-3.2/links/myeclipse.link内容为:path=/data/soft,eclipse目录在我的gentoo中是/usr/lib/eclipse-3.2,其它发行版可能不一样。

串口设置

给一个应用裁减了4M左右的linux,对于串口的内核配置很简单,内核启动时明明发现了四个串口但是只正确映射了串口一和串口二的设备文件/dev/ttyS0和/dev/ttyS1,琢磨了很久怀疑是因为主板的设计问题,COM3和COM4的地址不是标准的0x2f8和0x2e8,而是0x2f0和0x2e0,最后手动设置了一下大功告成:

setserial /dev/ttyS2 port 0x2f0 irq 7 uart 8250
setserial /dev/ttyS3 port 0x2e0 irq 9 uart 8250

修改MAC地址

ifconfig eth0 down
ifconfig eth0 hw ether 00:0A:EB:2A:88:2D
ifconfig eth0 up

善用backtrace

程序在得到一个Segmentation fault这样的错误信息毫无保留地就跳出来了,遇到这样的问题让人很痛苦,查找问题不亚于你N多天辛苦劳累编写代码的难度。那么有没有更好的方法可以在产生SIGSEGV信号的时候得到调试可用的信息呢?看看下面的例程吧!

sigsegv.h

#ifndef __sigsegv_h__
#define __sigsegv_h__

#ifdef __cplusplus
extern "C" {
#endif

int setup_sigsegv();

#ifdef __cplusplus
}
#endif

#endif /* __sigsegv_h__ */

sigsegv.c

#define _GNU_SOURCE
#include <memory.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <ucontext.h>
#include <dlfcn.h>
#include <execinfo.h>
#ifndef NO_CPP_DEMANGLE
#include <cxxabi.h>
#endif

#if defined(REG_RIP)
# define SIGSEGV_STACK_IA64
# define REGFORMAT "%016lx"
#elif defined(REG_EIP)
# define SIGSEGV_STACK_X86
# define REGFORMAT "%08x"
#else
# define SIGSEGV_STACK_GENERIC
# define REGFORMAT "%x"
#endif

static void signal_segv(int signum, siginfo_t* info, void*ptr) {
static const char *si_codes[3] = {"", "SEGV_MAPERR", "SEGV_ACCERR"};

size_t i;
ucontext_t *ucontext = (ucontext_t*)ptr;

#if defined(SIGSEGV_STACK_X86) || defined(SIGSEGV_STACK_IA64)
int f = 0;
Dl_info dlinfo;
void **bp = 0;
void *ip = 0;
#else
void *bt[20];
char **strings;
size_t sz;
#endif

fprintf(stderr, "Segmentation Fault!\n");
fprintf(stderr, "info.si_signo = %d\n", signum);
fprintf(stderr, "info.si_errno = %d\n", info->si_errno);
fprintf(stderr, "info.si_code = %d (%s)\n", info->si_code, si_codes[info->si_code]);
fprintf(stderr, "info.si_addr = %p\n", info->si_addr);
for(i = 0; i < NGREG; i++)
fprintf(stderr, "reg[%02d] = 0x" REGFORMAT "\n", i, ucontext->uc_mcontext.gregs[i]);

#if defined(SIGSEGV_STACK_X86) || defined(SIGSEGV_STACK_IA64)
# if defined(SIGSEGV_STACK_IA64)
ip = (void*)ucontext->uc_mcontext.gregs[REG_RIP];
bp = (void**)ucontext->uc_mcontext.gregs[REG_RBP];
# elif defined(SIGSEGV_STACK_X86)
ip = (void*)ucontext->uc_mcontext.gregs[REG_EIP];
bp = (void**)ucontext->uc_mcontext.gregs[REG_EBP];
# endif

fprintf(stderr, "Stack trace:\n");
while(bp && ip) {
if(!dladdr(ip, &dlinfo))
break;

const char *symname = dlinfo.dli_sname;
#ifndef NO_CPP_DEMANGLE
int status;
char *tmp = __cxa_demangle(symname, NULL, 0, &status);

if(status == 0 && tmp)
symname = tmp;
#endif

fprintf(stderr, "% 2d: %p <%s+%u> (%s)\n",
++f,
ip,
symname,
(unsigned)(ip - dlinfo.dli_saddr),
dlinfo.dli_fname);

#ifndef NO_CPP_DEMANGLE
if(tmp)
free(tmp);
#endif

if(dlinfo.dli_sname && !strcmp(dlinfo.dli_sname, "main"))
break;

ip = bp[1];
bp = (void**)bp[0];
}
#else
fprintf(stderr, "Stack trace (non-dedicated):\n");
sz = backtrace(bt, 20);
strings = backtrace_symbols(bt, sz);

for(i = 0; i < sz; ++i)
fprintf(stderr, "%s\n", strings[i]);
#endif
fprintf(stderr, "End of stack trace\n");
exit (-1);
}

int setup_sigsegv() {
struct sigaction action;
memset(&action, 0, sizeof(action));
action.sa_sigaction = signal_segv;
action.sa_flags = SA_SIGINFO;
if(sigaction(SIGSEGV, &action, NULL) < 0) {
perror("sigaction");
return 0;
}

return 1;
}

#ifndef SIGSEGV_NO_AUTO_INIT
static void __attribute((constructor)) init(void) {
setup_sigsegv();
}
#endif

main.c

#include "sigsegv.h"
#include <string.h>

int die() {
char *err = NULL;
strcpy(err, "gonner");
return 0;
}

int main() {
return die();
}

下面来编译上面的main.c程序看看将会产生什么样的信息呢,不过要注意的就是如果要在你的程序里引用sigsegv.h、sigsegv.c得到堆栈信息的话记得加上-rdynamic -ldl参数。

/data/codes/c/test/backtraces $ gcc -o test -rdynamic -ldl -ggdb -g sigsegv.c main.c
/data/codes/c/test/backtraces $ ./test
Segmentation Fault!
info.si_signo = 11
info.si_errno = 0
info.si_code = 1 (SEGV_MAPERR)
info.si_addr = (nil)
reg[00] = 0x00000033
reg[01] = 0x00000000
reg[02] = 0xc010007b
reg[03] = 0x0000007b
reg[04] = 0x00000000
reg[05] = 0xb7fc8ca0
reg[06] = 0xbff04c2c
reg[07] = 0xbff04c1c
reg[08] = 0xb7f8cff4
reg[09] = 0x00000001
reg[10] = 0xbff04c50
reg[11] = 0x00000000
reg[12] = 0x0000000e
reg[13] = 0x00000006
reg[14] = 0x080489ec
reg[15] = 0x00000073
reg[16] = 0x00010282
reg[17] = 0xbff04c1c
reg[18] = 0x0000007b
Stack trace:
1: 0x80489ec <die+16> (/data/codes/c/test/backtraces/test)
2: 0x8048a16 <main+19> (/data/codes/c/test/backtraces/test)
End of stack trace
/data/codes/c/test/backtraces $

下面用gdb来看看出错的地方左右的代码:

/data/codes/c/test/backtraces $ gdb ./test
gdb> disassemble die+16
Dump of assembler code for function die:
0x080489dc <die+0>: push %ebp
0x080489dd <die+1>: mov %esp,%ebp
0x080489df <die+3>: sub $0x10,%esp
0x080489e2 <die+6>: movl $0x0,0xfffffffc(%ebp)
0x080489e9 <die+13>: mov 0xfffffffc(%ebp),%eax
0x080489ec <die+16>: movl $0x6e6e6f67,(%eax)
0x080489f2 <die+22>: movw $0x7265,0x4(%eax)
0x080489f8 <die+28>: movb $0x0,0x6(%eax)
0x080489fc <die+32>: mov $0x0,%eax
0x08048a01 <die+37>: leave
0x08048a02 <die+38>: ret
End of assembler dump.
gdb>

也可以直接break *die+16进行调试,看看在出错之前的堆栈情况,那么下面我们再来看看代码问题到底出在什么地方了。

/data/codes/c/test/backtraces $ gdb ./test
gdb> break *die+16
Breakpoint 1 at 0x80489f2: file main.c, line 6.
gdb> list *die+16
0x80489f2 is in die (main.c:6).
1 #include "sigsegv.h"
2 #include <string.h>
3
4 int die() {
5 char *err = NULL;
6 strcpy(err, "gonner");
7 return 0;
8 }
9
10 int main() {
gdb>

现在看看定位错误将会多么方便,上面的调试指令中list之前break不是必须的,只是让你可以看到break其实就已经指出了哪一行代码导致Segmentation fault了。如果你要发布你的程序你一般会为了减少体积不会附带调试信息的(也就是不加-ggdb -g参数),不过没关系,你一样可以得到上面stack-trace信息,然后你调试之前只要加上调试信息即可。

how to hack gentoo livecd

下午花了半个多小时hack了一把gentoo livecd 2006.1,给一个项目裁减好的linux系统制作安装光盘,省了不少时间,gentoo的livecd里关键的就两个文件:image.squashfs和isolinux/gentoo.igz,前者基本上就是一个完整的gentoo base system,后者是一个initramfs,临时的根文件系统,用于加载光盘并让前者正确地接管系统,下面开始说正题吧。。。

1、挂载光盘文件mount -o loop /data/soft/livecd/livecd.iso /mnt/cdrom,/mnt/cdrom下现在就是livecd光盘的完整内容。另外建立一个目录/mnt/mycd把光盘里的文件全部复制过来用于制作光盘。

2、挂载image.squashfs:mount -o loop /mnt/cdrom/image.squashfs /mnt/gentoo(需要你的内核支持squashfs文件系统),全部复制到另一个目录进行hack吧,复制的时候记得加上-pr参数。这个是重头戏,进去好好研究研究,放手去修改配置添加东西吧,你甚至可以把你的开发环境、portage等等全搞进去。搞好了直接mksquashfs * /mnt/mycd/image.squashfs就可以了,不过在mksquashfs之前你得把原文件删掉。

3、复制isolinux/gentoo.igz到你另外一个目录,mv gentoo.igz gentoo.gz && gunzip gentoo.gz,然后正确地解压gentoo文件,得到一个简单的临时用根文件系统,下面这个脚本可以很方便地进行解压,用下面的脚本./unigz.sh gentoo就生成了gentoo.dir目录,执行脚本之前确认一下你的系统里有没有安装File-Slurp包:

#!/usr/bin/perl -w
#

use strict;

use File::Slurp qw(slurp);

my $ifile = slurp($ARGV[0], binmode=> ':raw');
my $newfile;
my $i=1;
my @newfiles = split(/TRAILER!!!/,$ifile);
`mkdir $ARGV[0].dir`;

foreach $newfile (@newfiles)
{
open F, "> ./$ARGV[0].dir/$i";
print F $newfile;
print F "TRAILER!!!\0";
close F;
`cd $ARGV[0].dir; cpio -i -H newc < $i; rm $i; cd ..`;
$i++;
}

进入gentoo.dir目录主要看看init和etc下两个脚本文件initrd.defaults和initrd.scripts,加上自己想要执行的东西即可,当然如果你想大刀阔斧地hack也可以,完了之后在gentoo.dir目录下执行find . -print | cpio --quiet -o -H newc | gzip -9 > ../gentoo.igz。

4、一切就绪之后制作iso文件:
cd /mnt/mycd
mkisofs -v -R -J -P "cd" -p "cd" -V "xxx_installer" -A "xxx-install-cd" -b isolinux/isolinux.bin -c isolinux/boot.cat -no-emul-boot -boot-load-size 4 -boot-info-table -o /data/download/etc.iso .

mysql字符集问题

以前一个web项目采用mysql 4.0.28,公司大部分开发人员用的是windows,java程序里存取数据采用的是GBK编码,当时建库的时候也没有指定字符集编码,因此升级到4.1之后原来的程序取出来的数据中文全成了乱码,mysql 4.1变化比较大,要兼容原来的程序及数据库服务器端设置/etc/mysql/my.cnf须做以下修改:

[mysqld]
default-character-set = gbk
skip-character-set-client-handshake

Makefile奇技淫巧

自从用了autotools很久不曾有过编写Makefile的经历了,这两天维护客户以前让别的公司给做的一个项目中的代码,写了个Makefile感觉挺不错。。。

CC = g++

GTK_CFLAGS = $(shell gdk-pixbuf-config --cflags)
GTK_LIBS = $(shell gdk-pixbuf-config --libs) $(shell pkg-config --libs gthread)

MYSQL_CFLAGS = $(shell mysql_config --cflags)
MYSQL_LIBS = $(shell mysql_config --libmysqld-libs)

CFLAGS = $(GTK_CFLAGS) $(MYSQL_CFLAGS) -I/usr/include/lclibs -DMYSQL_EMBED -DETC_THREAD
LIBS = $(GTK_LIBS) $(MYSQL_LIBS) -L./libs -ldl -rdynamic -llclibs -ldsrc -lgts

SRC_PATH = src
OBJ_PATH = obj

SOURCES = $(wildcard $(SRC_PATH)/*.c)
OBJECTS = $(patsubst $(SRC_PATH)/%.c, $(OBJ_PATH)/%.o, $(SOURCES))
DEPENDS = $(patsubst $(SRC_PATH)/%.c, $(OBJ_PATH)/%.d, $(SOURCES))

all: hwetc

$(DEPENDS): $(OBJ_PATH)/%.d: $(SRC_PATH)/%.c
$(CC) -MM $(CFLAGS) $< > $@; \
sed -i 's,\($*\)\.o[ :]*,$(OBJ_PATH)/\1.o $@ : ,g' $@

include $(DEPENDS)

hwetc: $(OBJECTS)
$(CC) $(OBJECTS) $(LIBS) -o $@

$(OBJECTS):
$(CC) -c $(CFLAGS) $< -o $@

.PHONY: clean
clean:
rm -f hwetc $(OBJECTS) $(DEPENDS)

mplayer使用技巧

在Linux下视频文件我一般都关联使用mplayer打开,~/.mplayer/config配置就显得非常重要了,先看看我的config文件内容吧:

# Write your default config options here!

ao=alsa
vo=xv
stop-xscreensaver=yes
monitoraspect=1280:800
font=/usr/share/fonts/zh_CN/simsun.ttf
subcp=GB18030
subfont-autoscale=2
subfont-text-scale=4
sub-fuzziness=1
cache=8192
ontop=yes

常见的ao和vo参考man pages即可。

如果你在使用宽屏如1280x800、1280x768之类的分辨率时,你会发现按默认配置播放时图像变形了(不过mplayer的GUI版本 gmplayer好象能自适应这个,但我不喜欢gmplayer另外再打开着一个控制窗口且非常难用,因此纯洁的mplayer就成了我的首选), monitoraspect参数配置方法就使用你的分辨率做比率就可以了。

字幕问题又来了,在播放带字幕文件的DVDRip格式的电影时按默认配置是不是又乱码了,那么接下来的几个参数就可以让你舒服地看到汉字,font配置字体文件的路径,字幕文件一般是由国人在windows下制作的,所以一般文件内容编码都是GBK(CP936),所以你可以设置成GBK或CP936,关于字符集编码的名称你可以使用iconv -l看看你的系统都支持些什么

到此为止你应该可以看到汉字了,不过字体有点太大,多行字体可能有点影响你看电影了,subfont-autoscale参数用来设置按什么方法来进行自动缩放(0-不自动缩放,1 -按电影高度缩放,2-按电影宽度缩放,3-按电影对角线缩放(默认值)),subfont-text-scale参数用来设置字幕文本的自动缩放系数 (屏幕尺寸的百分比),值范围为0~100,默认值为5。

mplayer是可以自动加载字幕文件的,但是这只是在字幕文件名跟媒体文件名相同时才起作用(后缀不同)例如这样的:

单刀直入
单刀直入-CD1.avi
单刀直入-CD1.srt
单刀直入-CD2.avi
单刀直入-CD2.srt

这样的就能自动加载字幕,通过j键切换。但像这种的就不行了:

单刀直入
单刀直入-CD1.avi
单刀直入-CD1.Chs.srt
单刀直入-CD1.Eng.srt
单刀直入-CD2.avi
单刀直入-CD2.Chs.srt
单刀直入-CD2.Eng.srt

这种情况下要使用参数具体指定一个字幕文件,其实mplayer还有一个聪明的参数可以使用的,就是
-sub-fuzziness
Adjust matching fuzziness when searching for subtitles:
0 exact match
1 load all subs containing movie name
2 load all subs in the current directory
可以使用-sub-fuzziness 1来让mplayer加载目录下的所有与电影文件相关的字幕文件,播放时可以通过j键切换。

最后这个cache主要是设置播放流媒体文件时使用的缓存大小,可以根据你机器的配置进行调整。

wine简单配置过程

1、先运行winecfg让它自己去创建~/.wine,Windows Version选择windows xp,Audio选择ALSA取消默认的OSS。

2、进入~/.wine/drive_c/windows/fonts目录,复制一个simsun.ttf或创建一个符号链接都可以。

3、运行regedit,找到HKEY_LOCALE_MACHINE\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes,修改MS Shell Dlg和MS Shell Dlg 2,改成你喜欢的中文字体,不过这儿如果你用simsun的话或导致英文字体过小,你可以使用别的字体来代替,如微软雅黑或Vera YuanTi Sans。

4、如果你用SimSun又想将字体改大可修改HKEY_LOCALE_MACHINE\\System\\CurrentControlSet\\Handware Profiles\\Current\\Software\\Fonts中的LogPixels,这个值也就是我们在X下常说的DPI,默认是标准的96,根据经验发现LogPixels设置为104用SimSun字体就刚刚好。

5、当然如果你改了LogPixels那么某些地方如菜单等字体就变大了,你可以修改~/.wine/drive_c/windows/win.ini,加上以下语句:
[Desktop]
IconTitleFaceName=SimSun
MenuFontSize=12
MessageFontSize=12
StatusFontSize=12
IconTitleSize=12
其它的项目可到网上找找,其实看看windows的属性里外观设置就知道这个作用了。

6、最后一步就是如何让wine外观变得漂亮点,按windows主题目录结构创建主题目录,mkdir -p ~/.wine/drive_c/windows/Resources/Themes。然后复制windows主题到此目录,cp -R /mnt/win_c/WINDOWS/Resources/Themes/LE4* (/mnt/win_c是我linux下windows系统盘挂载目录,我喜欢LE4主题)。最后运行winecfg,选择"Desktop Integration"标签,从Theme下面的下拉框里选择即可。

7、不过你应该已经发现使用了主题之后运行windows程序会非常慢,不过别着急,你可以使用一部分主题的配置而又不使用主题,具体方法可这样做,直接修改~/.wine/user.reg,删除[Software\\Microsoft\\Windows\\CurrentVersion\\ThemeManager]里关于主题名的一行,忘了关键字是什么了,这样你的菜单看起来也是平面的了,而且窗口颜色看起来更顺眼一些。如果发现中文字体模糊的话可以给HKEY_CURRENT_USER\\Software\\Wine\\X11 Driver里创建一个字符串型键值ClientSideAntiAliasWithRender设置为N即取消AntiAlias。

emacs23字体配置

1、编辑~/.Xresources文件,将其内容设置如下:
Xft.antialias: 1
Xft.hinting: 1
Xft.hintstyle: hintfull
Xft.rgba: rgb

Emacs.FontBackend: xft

之所以要在此设置Xft选项,是因为Emacs不像一般的gtk程序从系统环境中读取Xft配置,也不理睬fontconfig配置,这也就是为什么我们无法通过fontconfig来控制中文字体顺序的原因。

2、配置字体。如果现在以Xft为字体渲染引擎后端进入emacs会发现emacs中中文非常难看,可以通过给~/.emacs中加入以下配置:
;设置字体
(set-default-font "Bitstream Vera Sans Mono-10")
(set-fontset-font (frame-parameter nil 'font)
'han '("Microsoft YaHei" . "unicode-bmp"))

3、启动Emacs加-enable-font-backend打开Xft字体渲染引擎后端。