2005年11月04日

.一些有用的文档
PIXIL/src/microwin/src/INSTLL PIXIL/src/microwin/docs PIXIL/src/microwin/src/config http://www.fltk.org http://www.microwindow.org

2.nano-X app/server 机制
可以参加omap/ddpv2/pixil_oe-1.00/src/nxapps/nxtest.sh,和在X11环境中不同,在microwindow环境中 server为nano-x和nanowm,在运行任何其他程序以前,要确保这两个程序已经起动. 要修改omap/ddpv2/pixil_oe-1.00/src/nxapps/TOP程序所在的路径

3.交叉编译hello.cxx所用的脚本
#!/bin/bash
arm-linux-g++ -o helloarm hello.cxx -O2 -Wall \
-DNANXFOLDER=’”/root/omap/ddpv2/pixil_oe-1.00/src/microwin/src”‘ \
-I$PIXIL/src/microwin/src/include -I$PIXIL/include \
-L$PIXIL/src/microwin/src/lib $PIXIL/src/flnx-pda/lib/libfltk.a -lnano-X

4.mmc上的动态库
cp libnano-X.so /mmc/wd ln -s /mmc/wd/libnano-X.so /lib/libnano-X.so

5.一些工具的使用
arm-linux-readelf 可以使用-d选项来查看二进制可执行文件所链接的动态库
arm-linux-strip 可以去掉可执行文件中的符号,使文件变小
arm-linux-nm可以查看可执行文件的符号(使用arm-linux-strip之前)

2005年03月09日

tcpdump采用命令行方式,它的命令格式为:
  tcpdump [ -adeflnNOpqStvx ] [ -c 数量 ] [ -F 文件名 ]
          [ -i 网络接口 ] [ -r 文件名] [ -s snaplen ]
          [ -T 类型 ] [ -w 文件名 ] [表达式 ]

  1. tcpdump的选项介绍
   -a    将网络地址和广播地址转变成名字;
   -d    将匹配信息包的代码以人们能够理解的汇编格式给出;
   -dd    将匹配信息包的代码以c语言程序段的格式给出;
   -ddd    将匹配信息包的代码以十进制的形式给出;
   -e    在输出行打印出数据链路层的头部信息;
   -f    将外部的Internet地址以数字的形式打印出来;
   -l    使标准输出变为缓冲行形式;
   -n    不把网络地址转换成名字;
   -t    在输出的每一行不打印时间戳;
   -v    输出一个稍微详细的信息,例如在ip包中可以包括ttl和服务类型的信息;
   -vv    输出详细的报文信息;
   -c    在收到指定的包的数目后,tcpdump就会停止;
   -F    从指定的文件中读取表达式,忽略其它的表达式;
   -i    指定监听的网络接口;
   -r    从指定的文件中读取包(这些包一般通过-w选项产生);
   -w    直接将包写入文件中,并不分析和打印出来;
   -T    将监听到的包直接解释为指定的类型的报文,常见的类型有rpc (远程过程
调用)和snmp(简单       网络管理协议;)

  2. tcpdump的表达式介绍
   表达式是一个正则表达式,tcpdump利用它作为过滤报文的条件,如果一个报文满足表
达式的条件,则这个报文将会被捕获。如果没有给出任何条件,则网络上所有的信息包将会
被截获。
   在表达式中一般如下几种类型的关键字,一种是关于类型的关键字,主要包括host,
net,port, 例如 host 210.27.48.2,指明 210.27.48.2是一台主机,net 202.0.0.0 指明
202.0.0.0是一个网络地址,port 23 指明端口号是23。如果没有指定类型,缺省的类型是
host.
   第二种是确定传输方向的关键字,主要包括src , dst ,dst or src, dst and src ,
这些关键字指明了传输的方向。举例说明,src 210.27.48.2 ,指明ip包中源地址是210.27.
48.2 , dst net 202.0.0.0 指明目的网络地址是202.0.0.0 。如果没有指明方向关键字,则
缺省是src or dst关键字。
   第三种是协议的关键字,主要包括fddi,ip ,arp,rarp,tcp,udp等类型。Fddi指明是在
FDDI(分布式光纤数据接口网络)上的特定的网络协议,实际上它是”ether”的别名,fddi和e
ther具有类似的源地址和目的地址,所以可以将fddi协议包当作ether的包进行处理和分析。
其他的几个关键字就是指明了监听的包的协议内容。如果没有指定任何协议,则tcpdump将会
监听所有协议的信息包。
   除了这三种类型的关键字之外,其他重要的关键字如下:gateway, broadcast,less,
greater,还有三种逻辑运算,取非运算是 ‘not ‘ ‘! ‘, 与运算是’and’,'&&’;或运算 是’o
r’ ,’||’;
   这些关键字可以组合起来构成强大的组合条件来满足人们的需要,下面举几个例子来
说明。
   (1)想要截获所有210.27.48.1 的主机收到的和发出的所有的数据包:
    #tcpdump host 210.27.48.1
   (2) 想要截获主机210.27.48.1 和主机210.27.48.2 或210.27.48.3的通信,使用命令
:(在命令行中适用   括号时,一定要
    #tcpdump host 210.27.48.1 and \ (210.27.48.2 or 210.27.48.3 \)
   (3) 如果想要获取主机210.27.48.1除了和主机210.27.48.2之外所有主机通信的ip包
,使用命令:
    #tcpdump ip host 210.27.48.1 and ! 210.27.48.2
   (4)如果想要获取主机210.27.48.1接收或发出的telnet包,使用如下命令:
    #tcpdump tcp port 23 host 210.27.48.1

  3. tcpdump 的输出结果介绍
   下面我们介绍几种典型的tcpdump命令的输出信息
   (1) 数据链路层头信息
   使用命令#tcpdump –e host ice
   ice 是一台装有linux的主机,她的MAC地址是0:90:27:58:AF:1A
   H219是一台装有SOLARIC的SUN工作站,它的MAC地址是8:0:20:79:5B:46;上一条
命令的输出结果如下所示:
21:50:12.847509 eth0 < 8:0:20:79:5b:46 0:90:27:58:af:1a ip 60: h219.33357 > ice.
telne
t 0:0(0) ack 22535 win 8760 (DF)
  分析:21:50:12是显示的时间, 847509是ID号,eth0 <表示从网络接口eth0 接受该
数据包,eth0 >表示从网络接口设备发送数据包, 8:0:20:79:5b:46是主机H219的MAC地址,它
表明是从源地址H219发来的数据包. 0:90:27:58:af:1a是主机ICE的MAC地址,表示该数据包的
目的地址是ICE . ip 是表明该数据包是IP数据包,60 是数据包的长度, h219.33357 > ice.
telnet 表明该数据包是从主机H219的33357端口发往主机ICE的TELNET(23)端口. ack 22535
表明对序列号是222535的包进行响应. win 8760表明发送窗口的大小是8760.

  (2) ARP包的TCPDUMP输出信息
   使用命令#tcpdump arp
   得到的输出结果是:
  22:32:42.802509 eth0 > arp who-has route tell ice (0:90:27:58:af:1a)
  22:32:42.802902 eth0 < arp reply route is-at 0:90:27:12:10:66 (0:90:27:58:af
:1a)
  分析: 22:32:42是时间戳, 802509是ID号, eth0 >表明从主机发出该数据包, arp表明是
ARP请求包, who-has route tell ice表明是主机ICE请求主机ROUTE的MAC地址。 0:90:27:5
8:af:1a是主机ICE的MAC地址。

  (3) TCP包的输出信息
   用TCPDUMP捕获的TCP包的一般输出信息是:
  src > dst: flags data-seqno ack window urgent options
  src > dst:表明从源地址到目的地址, flags是TCP包中的标志信息,S 是SYN标志, F (F
IN), P (PUSH) , R (RST) “.” (没有标记); data-seqno是数据包中的数据的顺序号, ack是
下次期望的顺序号, window是接收缓存的窗口大小, urgent表明数据包中是否有紧急指针.
Options是选项.

  (4) UDP包的输出信息
   用TCPDUMP捕获的UDP包的一般输出信息是:
  route.port1 > ice.port2: udp lenth
  UDP十分简单,上面的输出行表明从主机ROUTE的port1端口发出的一个UDP数据包到主机
ICE的port2端口,类型是UDP, 包的长度是lenth

2005年02月28日

#define EPFNOSUPPORT 96 /* Protocol family not supported */
#define ECONNRESET 104 /* Connection reset by peer */
#define ENOBUFS 105 /* No buffer space available */
-#define EAFNOSUPPORT 106
-#define EPROTOTYPE 107
-#define ENOTSOCK 108
-#define ENOPROTOOPT 109
-#define ESHUTDOWN 110
+#define EAFNOSUPPORT 106 /* Address family not supported by protocol family */
+#define EPROTOTYPE 107 /* Protocol wrong type for socket */
+#define ENOTSOCK 108 /* Socket operation on non-socket */
+#define ENOPROTOOPT 109 /* Protocol not available */
+#define ESHUTDOWN 110 /* Can’t send after socket shutdown */
#define ECONNREFUSED 111 /* Connection refused */
#define EADDRINUSE 112 /* Address already in use */
#define ECONNABORTED 113 /* Connection aborted */
-#define ENETUNREACH 114
-#define ENETDOWN 115
-#define ETIMEDOUT 116
-#define EHOSTDOWN 117
-#define EHOSTUNREACH 118
-#define EINPROGRESS 119
-#define EALREADY 120
-#define EDESTADDRREQ 121
-#define EMSGSIZE 122
-#define EPROTONOSUPPORT 123
-#define ESOCKTNOSUPPORT 124
-#define EADDRNOTAVAIL 125
+#define ENETUNREACH 114 /* Network is unreachable */
+#define ENETDOWN 115 /* Network interface is not configured */
+#define ETIMEDOUT 116 /* Connection timed out */
+#define EHOSTDOWN 117 /* Host is down */
+#define EHOSTUNREACH 118 /* Host is unreachable */
+#define EINPROGRESS 119 /* Connection already in progress */
+#define EALREADY 120 /* Socket already connected */
+#define EDESTADDRREQ 121 /* Destination address required */
+#define EMSGSIZE 122 /* Message too long */
+#define EPROTONOSUPPORT 123 /* Unknown protocol */
+#define ESOCKTNOSUPPORT 124 /* Socket type not supported */
+#define EADDRNOTAVAIL 125 /* Address not available */
#define ENETRESET 126
-#define EISCONN 127
-#define ENOTCONN 128
+#define EISCONN 127 /* Socket is already connected */
+#define ENOTCONN 128 /* Socket is not connected */
#define ETOOMANYREFS 129
#define EPROCLIM 130
#define EUSERS 131
#define EDQUOT 132
#define ESTALE 133
-#define ENOTSUP 134
+#define ENOTSUP 134 /* Not supported */
#define ENOMEDIUM 135 /* No medium (in tape drive) */
#define ENOSHARE 136 /* No such host or network path */

2005年02月23日

者:hoyt

这一章我们学习Linux的时间表示和计算函数

1.时间的表示
2.时间的测量
3.计时器的使用
——————————————————————————–

1。时间表示 在程序当中,我们经常要输出系统当前的时间,比如我们使用date命令的输出结果.这个时候我们可以使用下面两个函数

#include

time_t time(time_t *tloc);
char *ctime(const time_t *clock);

time函数返回从1970年1月1日0点以来的秒数.存储在time_t结构之中.不过这个函数的返回值对于我们来说没有什么实际意义.这个时候我们使用第二个函数将秒数转化为字符串. 这个函数的返回类型是固定的:一个可能值为. Thu Dec 7 14:58:59 2000 这个字符串的长度是固定的为26.

2。时间的测量 有时候我们要计算程序执行的时间.比如我们要对算法进行时间分析.这个时候可以使用下面这个函数.

#include

int gettimeofday(struct timeval *tv,struct timezone *tz);

strut timeval {
long tv_sec; /* 秒数 */
long tv_usec; /* 微秒数 */
};

gettimeofday将时间保存在结构tv之中.tz一般我们使用NULL来代替.

#include #include #include
void function()
{
unsigned int i,j;
double y;
for(i=0;i<1000;i++)
for(j=0;j<1000;j++)
y=sin((double)i);
}

main()
{
struct timeval tpstart,tpend;
float timeuse;

gettimeofday(&tpstart,NULL);
function();
gettimeofday(&tpend,NULL);
timeuse=1000000*(tpend.tv_sec-tpstart.tv_sec)+
tpend.tv_usec-tpstart.tv_usec;
timeuse/=1000000;
printf(“Used Time:%f\n”,timeuse);
exit(0);
}

这个程序输出函数的执行时间,我们可以使用这个来进行系统性能的测试,或者是函数算法的效率分析.在我机器上的一个输出结果是: Used Time:0.556070

3。计时器的使用 Linux操作系统为每一个进程提供了3个内部间隔计时器.
ITIMER_REAL:减少实际时间.到时的时候发出SIGALRM信号.
ITIMER_VIRTUAL:减少有效时间(进程执行的时间).产生SIGVTALRM信号.
ITIMER_PROF:减少进程的有效时间和系统时间(为进程调度用的时间).这个经常和上面一个使用用来计算系统内核时间和用户时间.产生SIGPROF信号.
具体的操作函数是:

#include
int getitimer(int which,struct itimerval *value);
int setitimer(int which,struct itimerval *newval,
struct itimerval *oldval);

struct itimerval {
struct timeval it_interval;
struct timeval it_value;
}

getitimer函数得到间隔计时器的时间值.保存在value中 setitimer函数设置间隔计时器的时间值为newval.并将旧值保存在oldval中. which表示使用三个计时器中的哪一个. itimerval结构中的it_value是减少的时间,当这个值为0的时候就发出相应的信号了. 然后设置为it_interval值.

#include
#include
#include
#include
#include

#define PROMPT “时间已经过去了两秒钟\n\a”

char *prompt=PROMPT;
unsigned int len;

void prompt_info(int signo)
{
write(STDERR_FILENO,prompt,len);
}

void init_sigaction(void)
{
struct sigaction act;
act.sa_handler=prompt_info;
act.sa_flags=0;
sigemptyset(&act.sa_mask);
sigaction(SIGPROF,&act,NULL);
}

void init_time()
{
struct itimerval value;
value.it_value.tv_sec=2;
value.it_value.tv_usec=0;
value.it_interval=value.it_value;
setitimer(ITIMER_PROF,&value,NULL);
}

int main()
{
len=strlen(prompt);
init_sigaction();
init_time();
while(1);
exit(0);
}

这个程序每执行两秒中之后会输出一个提示.

来自: http://www.linuxfans.org/nuke/modul…ewtopic&t=25521

2005年02月02日

1、常吃宵夜.会得胃癌. 因为胃得不到休息
2、一个星期只能吃四颗蛋.吃太多.对身体不好
3、.鸡屁股含有致癌物, 不要吃较好
4、饭后吃水果是错误的观念. 应是饭前吃水果
5、女生月经来时.不要喝绿茶. 反正茶类不要喝就对了.多吃可以补血的东西
6、喝豆浆时不要加鸡蛋及糖. 也不要喝太多
7、空腹时不要吃蕃茄, 最好饭后吃
8、早上醒来.先喝一杯水. 预防结石
9、睡前三小时不要吃东西. 会胖
10、少喝奶茶. 因为高热量.高油.没有营养价值可言.长期饮用.易罹患高血压.糖尿病.等
疾病
11、刚出炉的面包 不宜马上食用
12、远离充电座. 人体应远离30公分以上.切忌放在床边
13、天天喝水 八大杯
14、每天十杯水. 膀胱癌不会来
15、白天多喝水. 晚上少喝水
16、一天不要喝两杯以上的咖啡. 喝太多易导致失眠,胃痛
17、多油脂的食物少吃.因 为得花5~7小时去消化,并使脑中血液集中到肠胃.易昏
昏欲睡
18、下午五点后.大餐少少吃, 因为五点后身体不需那么多能量
19、10种吃了会快乐的食物: 深海鱼,香蕉,葡萄柚,全麦面包,菠菜,大蒜,南瓜,低
脂牛奶,鸡肉,樱桃
20、睡眠不足会变笨, 一天须八小时睡眠,有午睡习惯较不会老
21、最佳睡眠时间是在 晚上10点~清晨6点
22、每天喝酒不要超过一杯, 因为酒精会抑制制造抗体的B细胞,增加细菌感染的机会
23、服用胶囊应以冷水吞服(可以第一个吃), 睡前30分先服药.忌立即躺下
24、酸梅具防止老化作用, 青春永驻;肝火有毛病者宜多食用
25、掉发因素: 熬夜,压力,烟酒,香鸡排.麻辣锅.油腻食物.调味过重的料理
26、帮助头发生长:多 食用包心菜,蛋.豆类;少吃甜食(尤其是果糖)
27、每天一杯柠檬汁,柳橙汁. 不但可以美白还可以淡化黑斑
28、苹果是机车族、瘾君子、家庭主妇的常备良药, 一天一颗,才能让自己有个
干干净净的肺
29、抽烟又吃维他命(B胡萝卜素-A维他命的一种), 会致癌,尽早戒烟.才是最健康
的做法
30、女性不宜喝茶的五个时期: 月经来时,孕妇,临产前.生产完后,更年期
31、抽烟,关系最大的是 肺癌,唇癌,舌癌,喉癌,食道癌,也与膀胱癌有关
32、饮酒导致肝硬化 .引发肝癌
33、吃槟榔会导致口腔纤维化, 口腔癌
34、食物过于精细,缺乏纤维; 含大量脂肪,尤其是胆固醇会引发胃癌
35、食物过于粗糙, 营养不足时导致食道癌,胃癌
36、食品中的黄曲毒素. 亚硝酸类物皆具有致癌性
37、不抽烟. 拒吸二手烟
38、适量饮酒, 不拚久.不醉酒
39、减少食用 盐腌.烟熏,烧烤的食物
40、每天摄取新鲜的 蔬菜与水果
41、每天摄取富含高纤维的 五谷类及豆类
42、每天摄取均衡的饮食, 不过量
43、维持理想体重. 不过胖
44、保持规律的 生活与运动
45、保持 轻松愉快的心情
46、正确饮食习惯: 早上吃的像皇帝,中午吃的像平民,晚上吃的像乞

2005年01月28日

看到身边好几个人用这个,很好奇
找到它的tutorial看了一下

http://home.worldonline.co.za/~jctrembath/mctutorial.html

Midnight Commander is a file manager and directory browser, apparently similar to Norton Commander. For those of us to whom it is new, there are many tips and tricks to make it a friendly system for certain tasks. The man page of the Commander runs to over 2000 lines, so this article will be quicker to read, but the man page would naturally be more character-building…!

Once in mc, you can switch back to the console quickly with ctl – o, and back to mc the same way, with ctl – o.
The top is the menu bar, which you can access by the F9 key. Move across with the sideways arrow keys and enter on the menu you want to view.

Copying files is accomplished using the F5 key. Deleting using F8.

If you wish to create a directory, use F7.
For text editing, hit key F4. This opens the file in mcedit. My favourite editor, because it is reasonably simple. When you are finished, F2 to save and F10 to quit. If it won’t save your file, that means you forgot to edit it as root and now you’re going to have to su and do it all over again! And how do I know…? hehe.

Even if you’re not in mc, you can invoke mcedit directly from the command line – mcedit – and it will open it in the editor.

SuSe 9.2自带的amarok版本是1.0.2,使用的是arts引擎,可以播放mp3,cd,ogg没试过,
修改源代码中的metahundle.cpp,
MetaBundle&
MetaBundle::readTags( bool audioProperties )
添加了
QTextCodec *gp_codec;
gp_codec = QTextCodec::codecForName(“GB2312″);
m_title = gp_codec->toUnicode(m_title.latin1());
m_artist = gp_codec->toUnicode(m_artist.latin1());//added by ryan
m_album = gp_codec->toUnicode(m_album.latin1());
m_comment = gp_codec->toUnicode(m_comment.latin1());
m_genre = gp_codec->toUnicode(m_genre.latin1());

可以正确显示中文的歌曲名
音效的配置窗口bug较多,容易崩溃

今天编译了amarok-1.2-Beta,音效还是不能用,
去amarok的论坛看了一下,
from http://amarok.kde.org/component/option,com_simpleboard/Itemid,/func,view/catid,8/id,1506/#1506
The aRts-effects were disabled for stability reasons mainly. We got many bug reports about broken effects that made amaroK crash, and we got fed up with reports on stuff we can’t influence. Adding to that, most of the effects are not very well done, so the whole feature appeared rather useless.

I think the number one effect people want to use is an Equalizer. In amaroK CVS we have implemented an internal Equalizer plugin for GStreamer, which will probably also be ported to xine-engine. Check it out, it works quite nicely.

aRts-engine is currently almost unmaintained; if we do not find a new maintainer for it we might disabled it entirely in 1.2.

看来要是想升级amarok只好放弃arts了,
Gstreamer也不错,有均衡器

Gstreamer 播放有一些歌曲时如Change the world 64kbps 22khz 音质很差
arts相比较而言音质好多了

2005年01月21日

当第N次vi编辑器跳出来让我填写注释,我按了N次键盘才挪动到想要的位置,终于下决心好好学习一下vi的使用,上一次学vi命令是为了应付考试,但很快忘记了,现在只记得 i, l ,k ,j, :q, :x 和查找等几个命令了~~~

http://www.forecast.com.cn/network/jishuzhichi-xt-9.htm

Vi 输入模式

要如何输入资料呢?有好几个指令可以进入输入模式:

新增 (append)
a 从游标所在位置後面开始新增资料,游标後的资料随新增资料向後移动。
A 从游标所在列最後面的地方开始新增资料。

插入 (insert)
i 从游标所在位置前面开始插入资料,游标後的资料随新增资料向後移动。
I 从游标所在列的第一个非空白字元前面开始插入资料。

开始 (open)
o 在游标所在列下新增一列并进入输入模式。
O 在游标所在列上方新增一列并进入输入模式。

也许文字叙述看起来有点繁杂,但是只要实际操作一下马上可以了解这些操作方式。实务很重要,尤其是电脑方面的东西随时可以尝试及验证结果。极力建议实际去使用它而不要只是猛K文件,才有事半功倍的效用。(注:此段为废话。
删除与修改

何谓编辑?在这里我们认为是文字的新增修改以及删除,甚至包括文字区块的搬移、复制等等。这里先介绍vi的如何做删除与修改。(注意:在vi的原始观念里,输入跟编辑是两码子事。编辑是在指令模式下操作的,先利用指令移动游标来定位要进行编辑的地方,然後才下指令做编辑。)

x 删除游标所在字元。

dd 删除游标所在的列。

r 修改游标所在字元,r 後接著要修正的字元。

R 进入取代状态,新增资料会覆盖原先资料,直到按[ESC]回到指令模式下为止。

s 删除游标所在字元,并进入输入模式。

S 删除游标所在的列,并进入输入模式。

其实呢,在PC上根本没有这麽麻烦!输入跟编辑都可以在输入模式下完成。例如要删除字元,直接按[Delete]不就得了。而插入状态与取代状态可以直接用[Insert]切换,犯不著用什麽指令模式的编辑指令。不过就如前面所提到的,这些指令几乎是每台终端机都能用,而不是仅仅在PC上。

在指令模式下移动游标的基本指令是h,j,k,l 。想来各位现在也应该能猜到只要直接用PC的方向键就可以了,而且无论在指令模式或输入模式下都可以。多容易不是。

当然PC键盘也有不足之处。有个很好用的指令u可以恢复被删除的资料,而U指令则可以恢复游标所在列的所有改变。这与某些电脑上的[Undo]按键功能相同。
—————————————————————————-
Vi 进阶应用

相信现在对於vi应该已经有相当的认识。处理文字也不会有什麽麻烦才对。如果有兴趣善用vi的其它功能进一步简化操作过程,不妨继续看下去。

移动游标

由於许多编辑工作是藉由游标来定位,所以vi提供许多移动游标的方式,这个我们列几张简表来说明(这些当然是指令模式下的指令):

┌—————┬—————————————┬—————┐
│指令 │说明 │功能键 │
├—————┼—————————————┼—————┤
│0 │移动到游标所在列的最前面 │[Home] │
├—————┼—————————————┼—————┤
│$ │移动到游标所在列的最後面 │[End] │
├—————┼—————————————┼—————┤
│[CTRL][d] │向下半页 │ │
├—————┼—————————————┼—————┤
│[CTRL][f] │向下一页 │[PageDown]│
├—————┼—————————————┼—————┤
│[CTRL][u] │向上半页 │ │
├—————┼—————————————┼—————┤
│[CTRL][b] │向上一页 │[PageUp] │
└—————┴—————————————┴—————┘
┌——┬—————————————————┐
│指令│说明 │
├——┼—————————————————┤
│H │移动到视窗的第一列 │
├——┼—————————————————┤
│M │移动到视窗的中间列 │
├——┼—————————————————┤
│L │移动到视窗的最後列 │
├——┼—————————————————┤
│b │移动到下个字的第一个字母 │
├——┼—————————————————┤
│w │移动到上个字的第一个字母 │
├——┼—————————————————┤
│e │移动到下个字的最後一个字母 │
├——┼—————————————————┤
│^ │移动到游标所在列的第一个非空白字元│
└——┴—————————————————┘
┌——┬———————————————————┐
│指令│说明 │
├——┼———————————————————┤
│n- │减号移动到上一列的第一个非空白字元 │
│ │前面加上数字可以指定移动到以上 n 列 │
├——┼———————————————————┤
│n+ │加号移动到下一列的第一个非空白字元 │
│ │前面加上数字可以指定移动到以下 n 列 │
├——┼———————————————————┤
│nG │直接用数字 n 加上大写 G 移动到第 n 列 │
└——┴———————————————————┘
┌————┬———————————————┐
│指令 │说明 │
├————┼———————————————┤
│fx │往右移动到 x 字元上 │
│Fx │往左移动到 x 字元上 │
├————┼———————————————┤
│tx │往右移动到 x 字元前 │
│Tx │往左移动到 x 字元前 │
├————┼———————————————┤
│; │配合 f&t 使用,重复一次 │
│, │配合 f&t 使用,反方向重复一次 │
├————┼———————————————┤
│/string │往右移动到有 string 的地方 │
│?string │往左移动到有 string 的地方 │
├————┼———————————————┤
│n │配合 /&? 使用,重复一次 │
│N │配合 /&? 使用,反方向重复一次 │
└————┴———————————————┘
┌————┬———————————————————┬—————————
—┐
│指令 │说明 │备注

├————┼———————————————————┼—————————
—┤
│n( │左括号移动到句子的最前面 │句子是以

│ │前面加上数字可以指定往前移动 n 个句子 │! . ? 三种符号来界
定│
│n) │右括号移动到下个句子的最前面 │

│ │前面加上数字可以指定往後移动 n 个句子 │

├————┼———————————————————┼—————————
—┤
│n{ │左括弧移动到段落的最前面 │段落是以

│ │前面加上数字可以指定往前移动 n 个段落 │段落间的空白列界定

│n} │右括弧移动到下个段落的最前面 │

│ │前面加上数字可以指定往後移动 n 个段落 │

└————┴———————————————————┴—————————
—┘

不要尝试背诵这些指令,否则後果自行负责。它们看起来又多又杂乱,事实上这叙述本身的障碍。再强调一次,实际去使用它只要几次就可以不经大脑直接下达奇怪怪的指令,远比死记活背搞得模模糊糊强多了。(注:若真的不经大脑而误与我无关。另,此段为废话。)

进阶编辑指令这些编辑指令非常有弹性,基本上可以说是由指令与范围所构成。例如dw是由删除指指令列表如下:

d 删除(delete)

y 复制(yank)

p 放置(put)

c 修改(change)

范围可以是下列几个:

e 游标所在位置到该字的最後一个字母

w 游标所在位置到下个字的第一个字母

b 游标所在位置到上个字的第一个字母

$ 游标所在位置到该列的最後一个字母

0 游标所在位置到该列的第一个字母

) 游标所在位置到下个句子的第一个字母

( 游标所在位置到该句子的第一个字母

} 游标所在位置到该段落的最後一个字母

{ 游标所在位置到该段落的第一个字母

说实在的,组合这些指令来编辑文件有一点点艺术气息。不管怎麽样,它们提供更多编辑文字的能力。值得注意的一点是删除与复制都会将指定范围的内容放到暂存区里,然後就可以用指令p贴到其它地方去,这是vi用来处理区段拷贝与搬移的办法。

某些vi版本,例如Linux所用的elvis可以大幅简化这一坨指令。如果稍微观察一下这些编辑指令就会发现问题其实是定范围的方式有点杂,实际上只有四个指令罢了。

指令v非常好用,只要按下v键,游标所在的位置就会反白,然後就可以移动设定范围,接著再直接下指令进行编辑即可。

对於整列操作,vi另外提供了更方便的编辑指令。前面曾经提到过删除整列文字的指令dd就是其中一个;cc可以修改整列文字;而yy则是复制整列文字;指令以删除游标到该列结束为止所有的文字。

档案指令

档案指令多以:开头,跟编辑指令有点区别。例如前面提到结束编辑的指令就是:q。现在就简单说明一下作为本篇故事的结尾:

q 结束编辑(quit)

如果不想存档而要放弃编辑过的档案则用 :q! 强制离开。

w 存档(write)

其後可加所要存档的档名。可以将档案指令合在一起,例如 :wq 即存档後离开。

zz 功能与 :wq 相同。
另外值得一提的是vi的部份存档功能。可以用:n,mw filename将第n行到第m行的文字存放的所指定的 filename里去哩。时代在变,世界在变,vi也在变,不过大致上就这样。

2005年01月19日

今天开始使用CVS服务器
首先要设置环境变量(添加到/etc/profile),
export CVSROOT=:pserver:ryan@192.168.10.20:/cvs
cvs login
第一次导入工程:
$cvs import -m “this is a cvstest project” cvstest v_0_0_1 start
说明:import 是cvs的命令之一,表示向cvs仓库输入项目文件.
-m参数后面的字串是描述文本,随便写些有意义的东西,如果不加 -m 参
数,那么cvs会自动运行一个编辑器(一般是vi,但是可以通过修改环境变量
EDITOR来改成你喜欢用的编辑器.)让你输入信息,
cvstest 是项目名称(实际上是仓库名,在CVS服务器上会存储在以这个名字
命名的仓库里.)
v_0_0_1是这个分支的总标记.没啥用(或曰不常用.)
start 是每次 import 标识文件的输入层次的标记

首先在本地建立工作目录,然后cvs checkout cvstest
以后对代码做完修改后,cvs commit cvstest就可以了
现在这个project还是我一个人左,应该不会遇到冲突。

摘抄自《OOD 启思录》–Arthur J.Riel 著 鲍志云 译

“你不必严格遵守这些原则,违背它们也不会被处以宗教刑罚。但你应当把这些原则看成警铃,若违背了其中的一条,那么警铃就会响起。”

———-Arthur J.Riel

(1)所有数据都应该隐藏在所在的类的内部。p13

(2)类的使用者必须依赖类的共有接口,但类不能依赖它的使用者。p15

(3)尽量减少类的协议中的消息。p16

(4)实现所有类都理解的最基本公有接口[例如,拷贝操作(深拷贝和浅拷贝)、相等性判断、正确输出内容、从ASCII描述解析等等]。 p16

(5)不要把实现细节(例如放置共用代码的私有函数)放到类的公有接口中。p17
如果类的两个方法有一段公共代码,那么就可以创建一个防止这些公共代码的私有函数。

(6)不要以用户无法使用或不感兴趣的东西扰乱类的公有接口。p17

(7)类之间应该零耦合,或者只有导出耦合关系。也即,一个类要么同另一个类毫无关系,要么只使用另一个类的公有接口中的操作。 p18

(8)类应该只表示一个关键抽象。p19
包中的所有类对于同一类性质的变化应该是共同封闭的。一个变化若对一个包影响,则将对包中的所有类产生影响,而对其他的包不造成任何影响 .

(9)把相关的数据和行为集中放置。p19
设计者应当留意那些通过get之类操作从别的对象中获取数据的对象。这种类型的行为暗示着这条经验原则被违反了。

(10)把不相关的信息放在另一个类中(也即:互不沟通的行为)。p19
朝着稳定的方向进行依赖.

(11)确保你为之建模的抽象概念是类,而不只是对象扮演的角色。p23

(12)在水平方向上尽可能统一地分布系统功能,也即:按照设计,顶层类应当统一地共享工作。p30

(13)在你的系统中不要创建全能类/对象。对名字包含Driver、Manager、System、Susystem的类要特别多加小心。p30
规划一个接口而不是实现一个接口。

(14)对公共接口中定义了大量访问方法的类多加小心。大量访问方法意味着相关数据和行为没有集中存放。p30

(15)对包含太多互不沟通的行为的类多加小心。p31
这个问题的另一表现是在你的应用程序中的类的公有接口中创建了很多的get和set函数。

(16)在由同用户界面交互的面向对象模型构成的应用程序中,模型不应该依赖于界面,界面则应当依赖于模型。p33

(17)尽可能地按照现实世界建模(我们常常为了遵守系统功能分布原则、避免全能类原则以及集中放置相关数据和行为的原则而违背这条原则) 。p36

(18)从你的设计中去除不需要的类。p38
一般来说,我们会把这个类降级成一个属性。

(19)去除系统外的类。p39
系统外的类的特点是,抽象地看它们只往系统领域发送消息但并不接受系统领域内其他类发出的消息。

(20)不要把操作变成类。质疑任何名字是动词或者派生自动词的类,特别是只有一个有意义行为的类。考虑一下那个有意义的行为是否应当迁移到已经存在或者尚未发现的某个类中。p40

(21)我们在创建应用程序的分析模型时常常引入代理类。在设计阶段,我们常会发现很多代理没有用的,应当去除。p43

(22)尽量减少类的协作者的数量。p52
一个类用到的其他类的数目应当尽量少。

(23)尽量减少类和协作者之间传递的消息的数量。p55

(24)尽量减少类和协作者之间的协作量,也即:减少类和协作者之间传递的不同消息的数量。p55

(25)尽量减少类的扇出,也即:减少类定义的消息数和发送的消息数的乘积。p55

(26)如果类包含另一个类的对象,那么包含类应当给被包含的对象发送消息。也即:包含关系总是意味着使用关系。p55

(27)类中定义的大多数方法都应当在大多数时间里使用大多数数据成员。p57

(28)类包含的对象数目不应当超过开发者短期记忆的容量。这个数目常常是6。p57
当类包含多于6个数据成员时,可以把逻辑相关的数据成员划分为一组,然后用一个新的包含类去包含这一组成员。

(29)让系统功能在窄而深的继承体系中垂直分布。p58

(30)在实现语义约束时,最好根据类定义来实现。这常常会导致类泛滥成灾,在这种情况下,约束应当在类的行为中实现,通常是在构造函数中实现,但不是必须如此。p60

(31)在类的构造函数中实现语义约束时,把约束测试放在构造函数领域所允许的尽量深的包含层次中。p60

(32)约束所依赖的语义信息如果经常改变,那么最好放在一个集中式的第3方对象中。p60

(33)约束所依赖的语义信息如果很少改变,那么最好分布在约束所涉及的各个类中。p60

(34)类必须知道它包含什么,但是不能知道谁包含它。p61

(35)共享字面范围(也就是被同一个类所包含)的对象相互之间不应当有使用关系。p61

(36)继承只应被用来为特化层次结构建模。p74

(37)派生类必须知道基类,基类不应该知道关于它们的派生类的任何信息。p74

(38)基类中的所有数据都应当是私有的,不要使用保护数据。p75
类的设计者永远都不应该把类的使用者不需要的东西放在公有接口中。

(39)在理论上,继承层次体系应当深一点,越深越好。p77

(40)在实践中,继承层次体系的深度不应当超出一个普通人的短期记忆能力。一个广为接受的深度值是6。p77

(41)所有的抽象类都应当是基类。p81

(42)所有的基类都应当是抽象类。p82

(43)把数据、行为和/或接口的共性尽可能地放到继承层次体系的高端。p85

(44)如果两个或更多个类共享公共数据(但没有公共行为),那么应当把公共数据放在一个类中,每个共享这个数据的类都包含这个类。 p88

(45)如果两个或更多个类有共同的数据和行为(就是方法),那么这些类的每一个都应当从一个表示了这些数据和方法的公共基类继承。 p89

(46)如果两个或更多个类共享公共接口(指的是消息,而不是方法),那么只有他们需要被多态地使用时,他们才应当从一个公共基类继承。 p89

(47)对对象类型的显示的分情况分析一般是错误的。在大多数这样的情况下,设计者应当使用多态。p89

(48)对属性值的显示的分情况分析常常是错误的。类应当解耦合成一个继承层次结构,每个属性值都被变换成一个派生类。 p96

(49)不要通过继承关系来为类的动态语义建模。试图用静态语义关系来为动态语义建模会导致在运行时切换类型。p97

(50)不要把类的对象变成派生类。对任何只有一个实例的派生类都要多加小心。p99

(51)如果你觉得需要在运行时刻创建新的类,那么退后一步以认清你要创建的是对象。现在,把这些对象概括成一个类。 p103

(52)在派生类中用空方法(也就是什么也不做的方法)来覆写基类中的方法应当是非法的。p103

(53)不要把可选包含同对继承的需要相混淆。把可选包含建模成继承会带来泛滥成灾的类。p108

(54)在创建继承层次时,试着创建可复用的框架,而不是可复用的组件。p112

(55)如果你在设计中使用了多重继承,先假设你犯了错误。如果没犯错误,你需要设法证明。p120

(56)只要在面向对象设计中用到了继承,问自己两个问题:(1)派生类是否是它继承的那个东西的一个特殊类型?(2)基类是不是派生类的一部分?p121

(57)如果你在一个面向对象设计中发现了多重继承关系,确保没有哪个基类实际上是另一个基类的派生类。p122

(58)在面向对象设计中如果你需要在包含关系和关联关系间作出选择,请选择包含关系。p135

(59)不要把全局数据或全局函数用于类的对象的薄记工作。应当使用类变量或类方法。p140

(60)面向对象设计者不应当让物理设计准则来破坏他们的逻辑设计。但是,在对逻辑设计作出决策的过程中我们经常用到物理设计准则。 p149

(61)不要绕开公共接口去修改对象的状态。p164