使用 cscope 编写脚本
cscope(及cscope-fast)工具为我们在 Solaris 源代码内部搜索短语等特定实例提供了出色的方法。惟一的缺点在于,该工具是交互式的:它需要用户输入才能显示输出。那么,如何才能在脚本中利用这款工具呢?
正确的解决方案是对 cscope 和 cscope-fast 进行修改,让它支持 Non-Curses 类型的输出格式。但与此同时,我们可以采用一种更加简便的方法,即定义一个特殊的 "tty" 来确保输出中不包含任何转义序列(或其他不需要的内容)。
- 1. 创建两个目录,分别为 $HOME/.terminfo 和 $HOME/.terminfo/c
- 2. 创建一个 termcap 定义文件 $HOME/.terminfo/c/cscope.termcap。在第一次创建的 termcap 定义文件时,我复制了 vt100 中的内容并将所有转义序列转换为制表符。该文件的内容应如下所示:
cscope:\ :do=^J:co#9999999:li#9999999:cl=^I:sf=^I:\ :le=^H:bs:am:cm=^I:nd=^I:up=^I:\ :ce=^I:cd=^I:so=^I:se=^I:us=^I:ue=^I:\ :md=^I:mr=^I:mb=^I:me=^I:is=^I:\ :rs=^I:ks=^I=:ke=^I:\ :ku=^I:kd=^I:kr=^I:kl=^I:kb=^H:\ :ho=^I:k1=^I:k2=^I:k3=^I:k4=^I:pt:sr=^I:vt#3:xn:\ :sc=^I:rc=^I:cs=^I: - 3. 将 termcap 转换为 Curses 可以使用的 terminfo 文件,这需要借助 captoinfo 和 tic 工具。为此,我使用了下面这个脚本:
#!/bin/sh cd $HOME/.terminfo/c setenv TERMINFO $HOME/.terminfo captoinfo cscope.termcap > cscope.terminfo tic cscope.terminfo
- 4. 在 cscope-fast 中编写一个前台。
#!/bin/sh TERMINFO=$HOME/.terminfo export TERMINFO TERM=cscope export TERM cat /dev/null | cscope-fast -d -0 $1 | egrep '^[1-9]'
最后,结果如下所示:
$ ~/bin/cscope-grep ip_input 1 ip.c <global> 15017 ip_input(ill_t *ill, ill_rx_ring_t *ip_ring, mblk_t *mp_chain, 2 ip.h <global> 3225 extern void ip_input(ill_t *, ill_rx_ring_t *, mblk_t *, 3 ip_if.c ill_capability_dls_capabl 2925 dls.dls_rx = (uintptr_t)ip_input; 4 ip.c ip_rput 14993 ip_input(ill, NULL, mp, NULL); 5 ip_netinfo.c ip_ni_queue_func_impl 1293 ip_input(ill, NULL, packet->ni_packet, 0); 6 ip_squeue.c ip_soft_ring_assignment 754 ip_input(ill, NULL, mp_chain, mhip);
更新
正如 Alan Burlinson 所说,cscope-fast 提供了一个命令行选项 "-l",可以生成不面向屏幕的输出。使用方法如下所示:
$ cscope-fast -l -d -0 ip_input uts/common/inet/ip/ip.c <global> 15017 ip_input(ill_t *ill, ill_rx_ring_t *ip_ring, mblk_t *mp_chain, uts/common/inet/ip.h <global> 3225 extern void ip_input(ill_t *, ill_rx_ring_t *, mblk_t *, uts/common/inet/ip/ip_if.c ill_capability_dls_capable 2925 dls.dls_rx = (uintptr_t)ip_input; uts/common/inet/ip/ip.c ip_rput 14993 ip_input(ill, NULL, mp, NULL); uts/common/inet/ip/ip_netinfo.c ip_ni_queue_func_impl 1293 ip_input(ill, NULL, packet->ni_packet, 0); uts/common/inet/ip/ip_squeue.c ip_soft_ring_assignment 754 ip_input(ill, NULL, mp_chain, mhip); >>
虽然这为我们提供了便利,但仍然存在两个问题:
- 1. 由于仍然需要用户输出信息,因此我们将执行 "cat /dev/null | cscope-fast -l..." 终止它。
- 2. 其他输出中并没有 TAB 等明确的字段界限符。只要前 4 个字段包含转义字符,就不会产生很大的问题。
最后,我选择使用比较熟悉的 perl 脚本来实现,并且它支持拆分数组并打印输出。
#!/bin/perl
$args = join(' ',@ARGV);
open(I, "cat /dev/null | cscope-fast -l -d $args|") || die $!;
while (<I>) {
last if (/^>>/);
@F = split(/ /);
@B = splice(@F,3,$#F);
@A = splice(@F,0,3);
print join("\t",@A)."\t".join(' ',@B)."\n";
}
close(I);
exit(0);
感谢 Alan 的建议和提醒。
本文翻译自:http://blogs.sun.com/avalon/date/20070717
发表于 jerry [JDS] ( 四月 30, 2008 12:29 上午 ) Permalink | 评论[0]
评论:
