使用cygwin X server实现Linux远程桌面 (for windows)

在windows上访问linux有多种方法:

对于习惯使用命令行的人来说,可以使用终端的方式进行访问,也就是通过telnet, ssh等方法远程登录到linux主机,对其进行访问。至于登录软件,既可以使用windows自带的命令行界面,也可以使用专门的终端软件,例如putty, secureCRT等。其中putty是免费软件,而secureCRT并不是。

对于习惯使用图形界面的人来说,更希望以图形界面的方式来访问linux主机。主要有以下几种方法:

今天我主要介绍第二种方法。

有很多软件在windows上实现了X server的功能,例如XmanagerHummingbird Exceedcygwin X server,以及Xming X Server for Windows。前两个都是商业软件,需要付费使用;cygwin和Xming是免费软件。本文主要介绍如何使用cygwin X实现Linux的远程桌面。关于Xming X server的使用请参见其主页。

先调动一下大家的积极性,看看最终的效果图:

[ 背景知识 ]

网络上有很多关于X的背景知识,如果你想对X了解的深入一些,去网上搜索一下吧。

这里是王垠写的”理解 Xwindow“,介绍了X server, X client, 窗口管理器,桌面环境相关的知识,读一下对理解本文也有帮助。

好了,现在我们开始配置。

[ 安装cygwin ]

Cygwin项目的目的是在windows主机上提供一个类UNIX的环境,网络也有很多相关的资料。大家可以看一下这一篇:Cygwin使用指南,这篇文章在网络上流行比较广,作者未知,上面提供的仅是其中一个链接。

如果你的计算机上还没有cygwin,首先需要安装它。

这个过程很简单,先到cygwin的主页去下载setup.exe,然后使用setup.exe进行安装。在安装的过程中需要选择要安装的组件,此时需要把X server组件选上。

这里有一个安装指南,虽然是英文的,不过看抓图就可以了。

选择X server组件时,其实只需要选择xorg-x11-base,选中它之后,其它相关组件会自动被选中。

在安装cygwin时,记得把expect这个软件装上,它位于interpreters类别下面。我会在后面的章节中说明为什么要安装这个组件。

[ 运行cygwin X server]

在运行X server前,先假定一下我们的组网。

我们假设X server运行在一台windows XP计算机上,此机器的IP地址是192.168.190.91。

我们的Linux主机上将运行X client程序,它的IP地址是192.168.190.15。

在你的安装目录中找到c:\cygwin\usr\X11R6\bin\startxwin.bat (假设你把cygwin安装在c:\cygwin目录),双击它就会启动X server,同时会启动一个终端(这个终端运行在Windows本地),效果如下图:

现在,我们要允许远程的X client对X server进行访问,因此,在终端中输入下面的命令,

xhost + 192.168.190.15 

接下来,我们要到X client所在的计算机上进行配置,使用telnet或ssh登录Linux主机(192.168.190.15),然后运行下面的命令,

export DISPLAY=192.168.190.91:0.0 
xterm &
gvim &

上面第一条命令设置DISPLAY变量,它表示X客户端将使用192.168.190.91上的0.0来显示自己。192.168.190.91是运行cygwin X server的Windows计算机(它的防火墙要打开X server所监听的端口,通常为6000)。

后面两条命令则在Linux主机上(192.168.190.15)启动了两个程序,一个是xterm,另外一个是gvim,我们发现这两个程序启动后,并没有显示在Linux主机上,相反,它们显示在了windows主机上。下图是执行完上述命令的效果图,我使用putty远程登录到Linux主机上,然后执行上述命令:

用这种方法,你可以在Linux主机上运行任何图形程序,并把它显示到windows上。

如果你想把诸如KDE、GNOME这样的桌面环境也显示到windows上,就需要做些调整。

[ 运行桌面环境 ]

在此我以KDE桌面为例。要把KDE桌面环境显示到windows上的X server中,需要更改一下X server的启动批处理。

首先备份一下c:\cygwin\usr\X11R6\bin\startxwin.bat,然后使用文本编辑器打开此文件,找到下面这行:

%RUN% XWin -multiwindow -clipboard -silent-dup-error 

去掉”-multiwindow“参数:

%RUN% XWin -clipboard -silent-dup-error 

我们通常不需要启动一个xterm窗口,因此找到下面这行:

%RUN% xterm -e /usr/bin/bash –l 

把它注释掉:

REM %RUN% xterm -e /usr/bin/bash –l 

好了,批处理文件改完了。

回想一下上面的操作,在启动了X server后,我们执行了xhost命令来设置允许哪些计算机连接到X server,现在我们可以在配置文件中设置它。打开一个cygwin窗口,输入下面的命令:

echo "192.168.190.15" >> /etc/X0.hosts 

上面的命令会在/etc/X0.hosts文件中加入你想允许的X client,你可以在此文件中加入你的X客户端。因为我们使用的DISPLAY是0,所以在文件/etc/X0.hosts中增加;如果使用DISPLAY 1,则需要修改文件/etc/X1.hosts文件。现在启动X server后,192.168.190.15就被自动允许接入了。

现在我们再次双击startxwin.bat批处理,执行后就会出现一个丑陋的空白窗口,这就是所谓的根窗口。之所以是空白的,是因为现在还没有运行任何窗口管理器。别急,我们使用telnet或ssh远程登录Linux主机,执行命令:

startkde & 

哈哈~~~本文开头所展示的KDE窗口出来了!!!现在你在KDE中运行任何程序,它们都运行在Linux主机上,却把结果显示在Windows主机上。

[ 创建快捷方式 ]

在上面的操作中,启动X server后,需要使用telnet或ssh登录到Linux主机,才能启动自己想要的X client程序,有没有更简单的方法?

现在我们就需要用到expect软件了。这是一个如此有用的软件,以至于我忍不住要在这里插一段广告。

Expect为用户提供一种机制,使用户能够自动执行一些交互式的任务。例如,通常我们在使用telnet的时候,都需要手动输入用户名、密码才能登录。而使用Expect,我们就可以实现全自动的telnet交互,不需用户干预。Expect由Don Libes开发,基于TCL内核,它的主页在http://expect.nist.gov/

广告时间结束,我们继续。我使用expect编写了如下的TCL/EXPECT脚本,它可以使用ssh自动登录到指定Linux主机,然后启动我们需要的程序。程序如下:

#! /bin/expect -f

# Change these variable to yours
set user {easwy}
set host {192.168.190.15}
set xserver {192.168.190.91}
set password {123456}
set program {startkde}

set timeout 5
set done 0

spawn ssh "$user@$host"

while {!$done} {
    expect {
        "*(yes/no)?*" {
            # If the 1st time run ssh, it will prompt continue or not
            # answer yes
            exp_send "yes\n"
        }
        "assword*" {
            # Answer password
            exp_send "$password\n"
        }
        "\$*" {
            # Exit the loop
            incr done
        }
        "#*" {
            # Exit the loop
            incr done
        }
        timeout {
            # Timeout
            exp_send_user "Login timeout, please check!"
        }
    }
}

# Set DISPLAY environment variable
exp_send "export DISPLAY=$xserver:0\n"

# Start your program
exp_send "nohup $program &\n"
expect -regexp {\[[0-9]*\] [0-9]*}
exp_send "\n"

# Finished 

把上面的内容保存为一个文件,例如,保存为cygwin的~/login.exp。注意:把脚本起始处的5个变量替换成你自己的,只需要替换大括号中间的内容。使用telnet的朋友请自行修改此脚本。

下面我们再改一下c:\cygwin\usr\X11R6\bin\startxwin.bat文件,在此文件的最后增加:

REM Start your X client program
%CYGWIN_ROOT%\bin\run -p /bin expect -f ~/login.exp 

我们使用expect来执行刚才保存的~/login.exp。

现在,我们右击startxwin.bat文件,选择“发送到桌面快捷方式”。以后,只要你双击此快捷方式,就能立刻在Windows上使用Linux主机上的程序了。

我们再来看一个有趣的例子。

在上图中共开了三个终端,它们分别运行在不同的主机上,却都在Windows主机上进行输入输出。这就是X window的魅力了,如果你愿意,你还可以把其它Windows及Linux主机上的程序显示到这个X server中,正所谓一”桥”飞架南北,天堑变通途。

在本文完成后,经网友jiachunyu介绍,才知道有一个名为XWinLogon的软件,它也是使用cygwin的X server实现Linux的远程桌面。相比之下,它的安装和使用都简单了很多。这个软件的主页在:http://sourceforge.net/projects/xwinlogon/

或者

http://www.calcmaster.net/visual-c++/xwinlogon/

有兴趣可以试一下。

需要说明的是,XWinLogon中包含了部分cygwin的软件包,如果你安装了cygwin,则不能安装此软件(我没有试过,在作者主页这样说明)。

[参考文档]

原创文章,请阅读页脚的许可方式,转载请注明:转载自易水博客 [ http://easwy.com/blog/ ]

本文链接地址: http://easwy.com/blog/archives/linux-remote-desktop-via-cygwin-x-server/

文章的脚注信息由WordPress的wp-posturl插件自动生成

用VNC实现远程桌面共享(支持Windows, Linux, …)

VNC,全称为Virtual Network Computing,它是一个桌面共享系统。它的功能,类似于windows中的远程桌面功能。VNC使用了RFB(Remote FrameBuffer,远程帧缓冲)协议来实现远程控制另外一台计算机。它把键盘、鼠标动作发送到远程计算机,并把远程计算机的屏幕发回到本地。
VNC技术与平台无关,VNC Viewer可以和VNC Server在不同的操作系统上。VNC几乎支持所有的操作系统,也支持Java,甚至可以通过支持Java的浏览器来访问VNC Server。多个VNC客户端可以同时连接到一个VNC Server上。
VNC最初由AT&T开发的,它的源代码是开源的。

在CentOs 4.3上配置VNC服务很简单(这里假定你的计算机上已经安装了VNC软件)

首先需要配置VNC密码,密码在使用客户端连接服务器时使用。
注意:VNC密码保存在用户的主目录中,每个用户都可以设置自己的密码。因此,请使用你的用户名(尽量不要使用root)运行下列命令:

vncpasswd 


然后输入密码。

接下来就可以启动VNC server了。在启动VNC server时,需要为你的server指定一个display参数。你可以把display理解为一个桌面,每个用户都可以有自己的桌面。VNC客户端在连接时,可以指定连接到哪个桌面上。在系统中,display号不能重复,也就是说,如果有用户已经建立了名为“:1”的display,另外一个用户就不能再使用“:1”了,他可以使用“:2”。
启动VNC server的命令是:

vncserver <display>


例如,

vncserver :1


最后,需要配置一下防火墙,允许VNC客户端连接VNC server。VNC server监听的端口从5900开始,display :1的监听5901,display :2监听5902,以此类推。CentOs的防火墙缺省是不允许连接这些端口的,所以需要使用下面的步骤打开防火墙(需要root权限):

vi /etc/sysconfig/iptables


找到下面的语句:

-A RH-Firewall-1-INPUT -j REJECT –reject-with icmp-host-prohibited


在此行之前,加上下面的内容:

-A RH-Firewall-1-INPUT -m state –state NEW -m tcp -p tcp –dport 5900:5903 -j ACCEPT


这句话的含义是,允许其它机器访问本机的5900到5903端口,这样,display:1, display:2, display:3的用户就可以连接到本机。

然后使用root身份重新启动防火墙:

/sbin/service iptables restart

好了,现在就可以运行客户端软件,连接到VNC server上了。
VNC客户端软件很多,在linux下有vncviewer,KDE还提供了一个krdc(它的菜单项就是”Remote Desktop Connection”,远程桌面连接)。
在window也有不少vnc客户端,你可以到http://www.realvnc.com/去下载一个,安装就可以用了。

假设VNC server的IP地址是192.168.1.1,display是:1。在VNC viewer的server栏中输入:“192.168.1.1:1”,然后连接。OK,你可以看到自己的桌面了。以后不管你什么时候关闭自己的本地PC机都不怕了,只要server不关机,你只要连接到VNC server,你就可以看到你前一天关闭本地PC机时的桌面还保持着原样。

不过…这个桌面怎么这么丑?!
原来vncserver默认使用的窗口管理器是twm,这是一个很简陋的窗口管理器,你可以把你的桌面改成GNOME或KDE。
方法是,进入你自己的home目录,然后编辑这个文件:.vnc/xstartup,下面是这个文件的内容:

#!/bin/sh

# Uncomment the following two lines for normal desktop:
#unset SESSION_MANAGER
#exec 
/etc/X11/xinit/xinitrc

/etc/vnc/xstartup ] && exec /etc/vnc/xstartup
r $HOME/.Xresources ] && xrdb $HOME/.Xresources
xsetroot 
solid grey
vncconfig 
iconic &
xterm 
geometry 80x24+10+10 ls title $VNCDESKTOP Desktop &
#twm 
&
gnome
session &


你可以把像上面这样把”twm &”这一行注释掉,然后在下面加入一行”gnome-session &”,或者是”startkde &”,分别启动GNOME桌面和KDE桌面。

如果server重启了,那你就需要重新运行一次vncserver命令来启动VNC server,这很麻烦。有没有更好的方法呢?

有!我们可以把VNC server启动成后台服务。执行如下步骤:

首先要允许VNC server在系统启动过程中被启动。这可以通过“系统设置–>服务器设置–>服务”菜单来配置,把vncserver一项选上就可以了。
如果使用命令行的话,以root身份运行以下两条命令:

cd /etc/rc5.d
mv K35vncserver S35vncserver


然后编辑/etc/sysconfig/vncservers,以下是文件内容:

# The VNCSERVERS variable is a list of display:user pairs.
#
# Uncomment the line below to start a VNC server on display :
1
# as my ‘myusername’ (adjust this to your own).  You will also
# need to set a VNC password
; run ‘man vncpasswd’ to see how
# to do that.
#
# DO NOT RUN THIS SERVICE if your local area network is
# untrusted!  For a secure way of using VNC
, see
# <URL:http://www.uk.research.att.com/vnc/sshvnc.html>.

VNCSERVERS=1:user1 2:user2 3:user3
VNCSERVERARGS
[1]=-geometry 1024×768
VNCSERVERARGS
[2]=-geometry 1024×768
VNCSERVERARGS
[3]=-geometry 800×600


解释一下这个文件:
VNCSERVERS这一行是配置在系统启动时启动几个VNC server,上面的例子里运行了三个VNC server,其中user1在display :1,user2在display :2,user3在display :3。
VNCSERVERARGS这三行,分别为VNC server 1, 2, 3配置启动参数,上面的例子里对user1和user2使用屏幕分辨率1024×768,对user3使用800×600。
其它支持的参数请使用“man vncserver”命令查询。

编辑好这个文件后,保存,然后以root身份运行:

/sbin/service vncserver start


这样user1, user2, user3的vncserver就启动了。
以后每次系统重启时,都会自动启动这三个用户的vncserver。

注意:上面三个用户必须已经使用vncpasswd命令设置过vnc密码,不然他的vncserver启动会失败!

另外,还可以使用cygwin中的X server来实现远程桌面共享,参见我的文章:
使用cygwin X server实现Linux远程桌面 (for windows)  

 参考资料:
[1] Taking your desktop virtual with VNC
[2] Virtual Network Computing

原创文章,请阅读页脚的许可方式,转载请注明:转载自易水博客 [ http://easwy.com/blog/ ]

本文链接地址: http://easwy.com/blog/archives/linux-remote-desktop-by-vnc/

文章的脚注信息由WordPress的wp-posturl插件自动生成

使用rxvt做为cygwin终端

昨天配置cygwin下的X server,在网上搜集资料时看到有人使用rxvt做为cygwin的终端,于是也试了一下。最终配置如下:

首先编辑文件~/.Xdefaults,内容如下:

! ~/.Xdefaults - X default resource settings
Rxvt*geometry: 120x40
Rxvt*background: #000020
Rxvt*foreground: #ffffbf
!Rxvt*borderColor: Blue
!Rxvt*scrollColor: Blue
!Rxvt*troughColor: Gray
Rxvt*scrollBar: True
Rxvt*scrollBar_right: True
Rxvt*font: Fixedsys
Rxvt*mfont: Terminal
Rxvt*SaveLines: 2000
Rxvt*loginShell: True
! VIM-like colors
Rxvt*color0: #000000
Rxvt*color1: #FFFFFF
Rxvt*color2: #00A800
Rxvt*color3: #FFFF00
Rxvt*color4: #0000A8
Rxvt*color5: #A800A8
Rxvt*color6: #00A8A8
Rxvt*color7: #D8D8D8
Rxvt*color8: #000000
Rxvt*color9: #FFFFFF
Rxvt*color10: #00A800
Rxvt*color11: #FFFF00
Rxvt*color12: #0000A8
Rxvt*color13: #A800A8
Rxvt*color14: #00A8A8
Rxvt*color15: #D8D8D8
! eof 

然后修改你的c:\cygwin\cygwin.bat文件,使用rxvt来替代cmd.exe:

@echo off
C:
chdir C:\cygwin\bin
set EDITOR=vi
set VISUAL=vi
set CYGWIN=codepage:oem tty binmode title
rxvt -e bash --login -i 

我在Xdefault中已经设置了中文字体,不过要想正常的显示和输入中文,还需要更改几个文件。在文件~/.bashrc中增加如下内容:

# Chinese locale
export LANG=zh_CN.GBK
export OUTPUT_CHARSET="GBK"

# Display Chinese
alias ls='ls --show-control-chars --color'
alias dir='ls --show-control-chars'
alias less='less --raw-control-chars' 

如果~/.bash_profile还未存在,那么创建它,并添加如下内容:

# Exec .bashrc
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi

另外再创建一个~/.inputrc文件,内容如下:

# Chinese input/output in bash
set meta-flag on
set input-meta on
set output-meta on
set convert-meta off
set completion-ignore-case on

好了,现在可以使用rxvt做为cygwin的终端了。

[ 参考文档 ]

Cygwin + Rxvt

原创文章,请阅读页脚的许可方式,转载请注明:转载自易水博客 [ http://easwy.com/blog/ ]

本文链接地址: http://easwy.com/blog/archives/use-rxvt-in-cygwin/

文章的脚注信息由WordPress的wp-posturl插件自动生成

在debian etch中配置subversion版本管理

以下操作如无特殊注明,均为root执行的操作。

安装软件包

首先,需要下载安装下列软件包:

  • apache2
  • apache2-common
  • apache2-utils
  • libapache2-svn
  • openssl
  • ssl-cert
  • subversion
  • subversion-tools

使用apt-get install命令安装上列软件包。

生成SSL自认证证书

如果要加密对版本服务器的访问,需要启用SSL。你可以到商业证书颁发机构去申请一个合法的证书,也可以采用自认证的方式。我们用下面的命令生成SSL自认证证书,并把它放在/etc/apache2/ssl/目录中。

mkdir /etc/apache2/ssl
/usr/sbin/make-ssl-cert /usr/share/ssl-cert/ssleay.cnf /etc/apache2/ssl/apache.pem 

根据提示回答相应的信息,最后就会生成所需的证书了。

配置apache2

在apache2中启用ssl模块,使用下面的命令:

a2enmod ssl 

接下来,配置虚拟主机来使能ssl,我的apache2服务器只提供版本库的加密访问,不提供基本的http web服务,所以关闭了80端口,只开启443端口。

修改/etc/apache2/sites-available/default文件,将前两行改为:

NameVirtualHost *:443
<VirtualHost *:443> 

然后在文件中加入下面的内容:

      SSLEngine On
      SSLCertificateFile /etc/apache2/ssl/apache.pem 

上面的语句打开了SSL引擎,使用我们刚刚生成的证书文件进行认证。

default虚拟主机应该缺省已经使能了,也就是在/etc/apache2/sites-enabled/目录中已经存在一个符号链接,指向/etc/apache2/sites-available/default。如果没有的话,可以使用下面的命令使能这个虚拟主机:

a2ensite default 

现在修改文件/etc/apache2/ports.conf,把文件的内容改为:

Listen 443 

也就是我们的apache2只监听443端口。

好了,现在启动apache2:

/etc/init.d/apache2 start 

如果你没有使用ServerName配置主机名的话,会提示下面的错误,忽略即可:

Starting web server (apache2)...apache2: Could not reliably determine the server's fully qualified domain name, using 127.0.1.1 for ServerName 

在浏览器中输入如下URL,看是否能够访问:

https://127.0.0.1/
    

如果正常的话,你会看到一个缺省的页面,上面显示”It works!“。如果没有出现此页面,可能你的apache2配置有问题,查看一下错误日志和访问日志,以定位问题。这两个日志的缺省位置在 /var/log/apache2/。

配置subversion

首先新建一个用户svnadmin来管理版本库,使用下面的命令:

addgroup svn
adduser svnadmin –ingroup svn
adduser www-data svn 

上面的命令首先创建一个svn用户组,然后创建用户svnadmin,并把这个用户放在svn组中。第三个命令则是把www-data用户也加入到svn组,因为web server是以www-data用户在运行的,要从web server读写版本库,www-data用户必须有版本库的读写权限。

现在用su – svnadmin命令切换到svnadmin用户,我们要保证svn用户组的所有用户都具备版本库的读写权限,所以修改svnadmin的umask,修改svnadmin用户的~/.bashrc,在文件中加入下面这行:

umask 002 

退出再重新登录。这样,由svnadmin创建的版本库,就可以被所有属于svn组的用户读写了。

现在创建版本库(由用户svnadmin执行下面的命令):

svnadmin create ~/repos/svntest 

我们创建了一个名为svntest的版本库。如果你已经有cvs的版本库,想把它转到subversion上,可以安装cvs2svn软件包,用里面的工具进行转换。

配置apache2/SVN

首先,使能apache2的dav_svn模块:

a2enmod dav_svn 

我们使用基本的http认证对访问版本库的所有用户进行认证,只有认证用户才有版本库的访问权。

首先为版本库的用户生成密码文件:

htpasswd -cm /etc/svnusers xxxxx
htpasswd -m /etc/svnusers yyyyy 

上面的命令创建了密码文件/etc/svnusers,并增加两个用户xxxxx和yyyyy。

然后在/etc/apache2/sites-available/default文件中加入如下语句:

<Location /svn>
DAV svn
SVNParentPath /home/svnadmin/repos
AuthType Basic
AuthName "Subversion Auth"
AuthUserFile /etc/svnusers
require valid-user
</Location> 

这段话,对URL中指向/svn目录的访问请求,使用DAV进行访问。我们把/home/svnadmin/repos做为所有版本库的父目录,在该目录下可以增加多个版本库。另外,使用/etc/svnusers密码文件对用户进行认证。

现在,重启apache2服务:

/etc/init.d/apache2 restart 

在浏览器中输入:

https://127.0.0.1/svn/svntest 

这时,会询问你是否接受服务器的证书,选择接受,然后输入你的用户名和密码,验证通过后,在浏览器中就可以看到版本库了。

测试通过后,你就可以使用其它的subversion客户端对版本库进行访问了。

[参考文档]

原创文章,请阅读页脚的许可方式,转载请注明:转载自易水博客 [ http://easwy.com/blog/ ]

本文链接地址: http://easwy.com/blog/archives/subversion-configuration-in-debian-etch/

文章的脚注信息由WordPress的wp-posturl插件自动生成

vi/vim使用进阶: 程序员的利器 – cscope

<< 返回vim使用进阶: 目录

本节所用命令的帮助入口:

:help cscope 

在前面的文章中介绍了利用tag文件,跳转到标签定义的地方。但如果想查找函数在哪里被调用,或者标签在哪些地方出现过,ctags就无能为力了,这时需要使用更为强大的cscope。

Cscope具有纯正的Unix血统,它最早是由贝尔实验室为PDP-11计算机开发的,后来成为商用的AT&T Unix发行版的组成部分。直到2000年4月,这个工具才由SCO公司以BSD license开源发行。

Cscope的主页在http://cscope.sourceforge.net/,如果你的计算机上没有cscope,你可以在此处下载它,在写本文时,它的最新版本是15.6。安装它非常简单,你只需要在cscope的源代码目录中执行下面三条命令:

./configure
make
make install 

在windows上也可以使用cscope,在cscope的主页上可以下载到由DJGPP编译器编译的cscope for windows,不过这个版本不能和vi一起工作。或者你可以下载cygwin工具包(http://www.cygwin.com/),这个工具包中也包含了cscope。

http://iamphet.nm.ru/cscope/有Sergey Khorev预编译的一个Win32版本的cscope,这个版本的cscope可以很好的与windows版本的vim搭配使用。

cscope的用法很简单,首先需要为你的代码生成一个cscope数据库。在你的项目根目录运行下面的命令:

cscope -Rbq 

这些选项的含义见后面。这个命令会生成三个文件:cscope.out, cscope.in.out, cscope.po.out。其中cscope.out是基本的符号索引,后两个文件是使用”-q“选项生成的,可以加快cscope的索引速度。在windows上使用cscope时,你可能会遇到-q选项被忽略的提示,解决办法请看这篇文章:Windows下cscope -q选项出错的解决

在缺省情况下,cscope在生成数据库后就会进入它自己的查询界面,我们一般不用这个界面,所以使用了”-b“选项。如果你已经进入了这个界面,按CTRL-D退出。

Cscope在生成数据库中,在你的项目目录中未找到的头文件,会自动到/usr/include目录中查找。如果你想阻止它这样做,使用”-k“选项。

Cscope缺省只解析C文件(.c和.h)、lex文件(.l)和yacc文件(.y),虽然它也可以支持C++以及Java,但它在扫描目录时会跳过C++及Java后缀的文件。如果你希望cscope解析C++或Java文件,需要把这些文件的名字和路径保存在一个名为cscope.files的文件。当cscope发现在当前目录中存在cscope.files时,就会为cscope.files中列出的所有文件生成索引数据库。通常我们使用find来生成cscope.files文件,仍以vim 7.0的源代码为例:

cd ~/src/vim70 
find . –type f > cscope.files
cscope -bq 

这条命令把~src/vim70目录下的所有普通文件都加入了cscope.files,这样,cscope会解析该目录下的每一个文件。上面的cscope命令并没有使用”-R“参数递归查找子目录,因为在cscope.files中已经包含了子目录中的文件。

注意:find命令输出的文件以相对路径表示,所以cscope.out的索引也相对于当前路径。如果你要在其它路径中使用当前的cscope.out,需要使用下面介绍的-P选项。

Cscope只在第一次解析时扫描全部文件,以后再调用cscope,它只扫描那些改动过的文件,这大大提高了cscope生成索引的速度。

下表中列出了cscope的常用选项:

  • -R: 在生成索引文件时,搜索子目录树中的代码
  • -b: 只生成索引文件,不进入cscope的界面
  • -q: 生成cscope.in.out和cscope.po.out文件,加快cscope的索引速度
  • -k: 在生成索引文件时,不搜索/usr/include目录
  • -i: 如果保存文件列表的文件名不是cscope.files时,需要加此选项告诉cscope到哪儿去找源文件列表。可以使用”“,表示由标准输入获得文件列表。
  • -Idir: 在-I选项指出的目录中查找头文件
  • -u: 扫描所有文件,重新生成交叉索引文件
  • -C: 在搜索时忽略大小写
  • -Ppath: 在以相对路径表示的文件前加上的path,这样,你不用切换到你数据库文件所在的目录也可以使用它了。

要在vim中使用cscope的功能,需要在编译vim时选择”+cscope“。vim的cscope接口先会调用cscope的命令行接口,然后分析其输出结果找到匹配处显示给用户。

在vim中使用cscope非常简单,首先调用”cscope add“命令添加一个cscope数据库,然后就可以调用”cscope find“命令进行查找了。vim支持8种cscope的查询功能,如下:

  • s: 查找C语言符号,即查找函数名、宏、枚举值等出现的地方
  • g: 查找函数、宏、枚举等定义的位置,类似ctags所提供的功能
  • d: 查找本函数调用的函数
  • c: 查找调用本函数的函数
  • t: 查找指定的字符串
  • e: 查找egrep模式,相当于egrep功能,但查找速度快多了
  • f: 查找并打开文件,类似vim的find功能
  • i: 查找包含本文件的文件

例如,我们想在vim 7.0的源代码中查找调用do_cscope()函数的函数,我们可以输入:”:cs find c do_cscope“,回车后发现没有找到匹配的功能,可能并没有函数调用do_cscope()。我们再输入”:cs find s do_cscope“,查找这个C符号出现的位置,现在vim列出了这个符号出现的所有位置。

我们还可以进行字符串查找,它会双引号或单引号括起来的内容中查找。还可以输入一个正则表达式,这类似于egrep程序的功能,但它是在交叉索引数据库中查找,速度要快得多。

vim提供了一些选项可以调整它的cscope功能:

  • cscopecscopeprg选项用于设置cscope程序的位置。
  • cscopecscopequickfix设定是否使用quickfix窗口来显示cscope的结果,详情请”:help cscopequickfix“;
  • 如果你想vim同时搜索tag文件以及cscope数据库,设置cscopecscopetag选项;
  • cscopecscopetagorder选项决定是先查找tag文件还是先查找cscope数据库。设置为0则先查找cscope数据库,设置为1先查找tag文件。我通常设置为1,因为在tag文件中查找到的结果,会把最佳匹配列在第一位。

vim的手册中给出了使用cscope的建议方法,使用命令”:help cscope-suggestions“查看。

下面是我的vimrc中关于cscope接口的设置:

    
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" cscope setting
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
if has("cscope")
  set csprg=/usr/bin/cscope
  set csto=1
  set cst
  set nocsverb
  " add any database in current directory
  if filereadable("cscope.out")
      cs add cscope.out
  endif
  set csverb
endif

nmap <C-@>s :cs find s <C-R>=expand("<cword>")<CR><CR>
nmap <C-@>g :cs find g <C-R>=expand("<cword>")<CR><CR>
nmap <C-@>c :cs find c <C-R>=expand("<cword>")<CR><CR>
nmap <C-@>t :cs find t <C-R>=expand("<cword>")<CR><CR>
nmap <C-@>e :cs find e <C-R>=expand("<cword>")<CR><CR>
nmap <C-@>f :cs find f <C-R>=expand("<cfile>")<CR><CR>
nmap <C-@>i :cs find i ^<C-R>=expand("<cfile>")<CR>$<CR>
nmap <C-@>d :cs find d <C-R>=expand("<cword>")<CR><CR>
 

下面的两个链接是cscope主页提供的cscope使用方法,也可以作为参考:

vim/cscope指导:http://cscope.sourceforge.net/cscope_vim_tutorial.html

在大项目中使用cscope:http://cscope.sourceforge.net/large_projects.html

在vim的网站上有很多与cscope相关的插件,有兴趣可以去看一下。

我以前写的Vim + Cscope/Ctags

[参考文档]

<< 返回vim使用进阶: 目录

原创文章,请阅读页脚的许可方式,转载请注明:转载自易水博客 [ http://easwy.com/blog/ ]

本文链接地址: http://easwy.com/blog/archives/advanced-vim-skills-cscope/

文章的脚注信息由WordPress的wp-posturl插件自动生成

使用awk去掉重复的单词

在水木社区的VIM版看到这样一个帖子,要求去掉文本中的重复单词。这个工作用VIM来完成有不太容易,但用awk来做就很简单。

发信人: lars (蓝天白云), 信区: VIM
标  题: 怎么去掉重复的单词?
发信站: 水木社区 (Thu Mar 22 13:44:01 2007), 站内

一段文字,包含很多单词,每两个单词之间有空格,怎么让所有重复的单词只剩下一个?
比如
ABC fff ddd ABC
eee ABC
替换后只剩下第一个ABC
thanks

发信人: Easwy (Easwy), 信区: VIM
标  题: Re: 怎么去掉重复的单词?
发信站: 水木社区 (Thu Mar 22 15:58:59 2007), 站内

awk could match your requirement.
save the following code as t.sh:

#! /bin/awk -f

{
    for (i = 1; i <= NF; i++)
    {
        ++word[$i]

        if (word[$i] == 1)
            printf(“%s “, $i)
    }
    printf(“\n”)
}


and exec:
chmod u+x t.sh
./t.sh <your_file_name_here>

简单介绍一下上面的awk脚本:
awk处理文本的方式是逐行处理,因此,对于文件的每一行,都会执行上面的for循环。在执行for循环时,awk已经把这一行中所有以空格间隔的单词都分隔开了,并保存在诸如$1,$2这样的变量中。NF则是这一行中所包含的字段的数目,也就是单词的个数。
for循环的工作就是以该单词做为下标,计算文件中每个单词出现的次数。如果单词出现的次数为1,则输出此单词,否则不输出。这里用到了awk的关系数组。awk的数组与C语言不同,数组的下标不仅可以是数字,也可以是一个字符串,也就是说,诸如word[“hello”]这样的数组元素是允许的。上面的代码就是使用关系数组的一个例子。
在日常处理文本时,虽然VIM是最主要的文件编辑工具,但它并不是唯一可以高效完成工作的工具。在适当的时候,使用适当的工具,才是高效完成工作的最好方式。
生活不同于学校中的考试,所有的事情并不是仅有一个正确答案!

原创文章,请阅读页脚的许可方式,转载请注明:转载自易水博客 [ http://easwy.com/blog/ ]

本文链接地址: http://easwy.com/blog/archives/remove-duplicate-word-with-awk/

文章的脚注信息由WordPress的wp-posturl插件自动生成

Exuberant Ctags中文手册

[译序]

(Easwy) First of all, I would like to thank the author of Exuberate Ctags, Darren Hiebert,
without his help, I cannot finish the work.

翻译这个手册的想法,最初源于我在写“使用VIM开发软件项目”系列文章(现在改名为”vim使用进阶“时。当时看到大家在使用 ctags 时,
基本都是用 "ctags -R"。其实 ctags 所拥有的能力并不止这些。它的众多选项可以让你方便的控制标签文件的
内容,甚至你可以自己定义一种语言,由 ctags 为它生成标签文件 (这方面的例子,可见下面的链接:
http://ctags.sourceforge.net/EXTENDING.html)

你可以在我的BLOG上找到最新版本的译文: http://easwy.com/blog/
译文可自由使用,转载请保留译序部分。
======

NAME
ctags – 为源代码产生标签文件

SYNOPSIS
ctags [options] [file(s)]

etags [options] [file(s)]

DESCRIPTION
ctags 和 etags 程序 (下文中统称为 ctags,除非特别指明) 为文件中的各种语言对象生成一个索引
(或称为标签) 文件。标签文件允许这些项目能够被一个文本编辑器或其它工具简捷迅速的定位。一个
“标签”是指一个语言对象,它对应着一个有效的索引项 (或者换言之,这个索引项为这个对象而创建)。

可选的,ctags 能够为多种程序语言文件的语言对象信息生成可读格式的交叉索引列表。

标签索引文件被多种编辑器支持。这些编辑器允许用户通过出现在源文件中的名字定位对象,并且跳转到
定义这个名字的文件和行。在这个版本发布时,我们所知的编辑器包括:

Vi(1)及其变种(例如,Elvis, Vim, Vile, Lemmy), CRiSP, Emacs, FTE (Folding Text Editor),
JED, jEdit, Mined, NEdit (Nirvana Edit), TSE (The SemWare Editor), UltraEdit, WorkSpace,
X2, Zeus

Ctags可以为许多种不同的程序语言产生不同类型的标签。要获得完整的程序语言支持列表、它们被识别
的名字、为它们所产生的标签的的类型,请见 –list-languages 和 –list-kinds 选项。

SOURCE FILES
除非定义了 –language-force 选项,每个源文件的语言类型将根据文件名到程序语言名的映射自动选择。
每种程序语言的映射可以通过 –list-maps 选项查看,并且可以通过 –langmap 选项修改。在支持的平
台上,如果文件的名字没有映射到一种程序语言并且这个文件是可执行的,将检查文件的第一行,看该文
件是不是一种可识别编程语言的 "#!" 脚本。
缺省的,所有其它文件都被忽略。这允许在一个目录的所有文件上执行 ctags (例如,"ctags *" ),或
在整个源代码目录树的所有文件上执行 ctags (例如,"ctags -R")。因为只有那些文件名被映射到一种
程序语言的文件才会被扫描。

[ .h 扩展名的文件被映射为 C++ 文件而不是 C 文件的原因是 .h 扩展名也应用于 C++ 语言,并且把它
当做 C++ 文件对待并没有害处]

OPTIONS
尽管拥有大量的选项,ctags 设置了缺省值 (适合多数情况),因此通常不带任何选项来执行 ctags (例
如,ctags *,或ctags -R),这将为当前目录下所有可识别的源文件生成一个标签文件。下面提供的选项
仅仅为了在有特殊需要时允许用户自定义。

需注意,用来分隔单字母选项和它们参数的空格是可选的。

同样需注意,长格式选项的布尔型参数 (那些以 "–" 开头并且带 "[=yes|no]" 参数的选项) 可以被省
略,在这种情况下隐含为 "=yes" ,而 "=0" 和 "=off" 被认为是 "=no" 。

某些选项在以 etags 模式运行时或被忽略,或会起作用 (见 -e 选项)。这样的选项会特殊注明。

绝大多数选项可以出现在命令行的任意位置,只影响在该选项后面的文件。然而,少数选项必须出现在第
一个文件名之前,这样的选项也会特殊注明。
带程序语言名字的选项允许名字是大写或小写。见 –list-languages 选项,以获得内建程序语言名的完
整列表。

-a 等同于 –append

-B 使用向上查找的模式 (例如 ?pattern?)。 [在 etags 模式中忽略]

-e 使能 etags 模式,这将创建 Emacs 编辑器使用的标签文件。可选的,如果包含 "etags" 调用
ctags 时 (通过重命名,或者创建符号链接到可执行文件的方式),会使能 etags 模式。这个选项
必须出现在第一个文件名之前。

-f tagfile
使用所指定的 tagfile 做为标签文件的名字 (缺省是 "tags",或 "TAGS" 当以etags模式运行时)。
如果 tagfile 被定义成 "-",那么标签文件被输出到标准输出。如果 tagfile 存在并且它的第一
行不是有效的标签行时,ctags 将拒绝执行。如果你错误的输入了 "ctags -f *.c",这会救你一命,
不然它会把其它文件所产生的标签覆盖到你的第一个 C 文件! ctags 也会拒绝接受以一个 "-" (减
号)开头的文件名,因为这很可能是你忘记输入标签文件的名字,而本选项试图把它后面的选项做为
文件名。如果你真的想把你的输出标签文件名命名为 "-ugly",把它定义成 "./-ugly"。这个选项
必须出现在第一个文件名之前。如果这个选项出现多次,只有最后一个生效。

-F 使用向下查找的模式 (例如 /pattern/) (缺省)。 [在 etags 模式中忽略]

-h list
定义一个文件扩展名列表,以句号分隔,这些文件将做为包含文件(或头文件)被解析。要指定没有
扩展名的文件,用一个句号,后面不跟句号以外的字符 (例如,".","..x",".x.")。这个选项只
影响如何解析一种特定类型的标签的作用域 (也就是说,这些标签是全局可见,还是这些标签只在
定义它们的文件中可见);它并不把这些扩展名映射到任何特定的程序语言。任何位于非头文件中的
标签,如果不能被另外一个文件可见 (例如,链接到另外一个文件),那么它的作用域被认为局限于
该文件 (例如,static)。在头文件中的所有类型的标签,它的作用域都不会被认为局限于该文件。
如果列表中的第一个字符是加号,那么该列表中的扩展名将被加到现有列表之后;否则,该列表将
替换现有列表。另外,参见 –file-scope 选项。缺省的列表是 ".h.H.hh.hpp.hxx.h++.inc.def"。
要恢复缺省列表,使用 -h default。注意,如果此选项指定的一个扩展名还没有被映射到一种特定
的程序语言 (见上面的 SOURCE FILES),你也需要使用 –langmap 或 –language-force 选项。

-I identifier-list
定义一个标识符列表,在解析 C 和 C++ 源文件时会对这些标识符进行特殊的处理。这个选项主要
用来处理由于编译预处理宏的使用而引发的特殊情况。当列出的标识符是简单的标识符时,这些标
识符在解析源文件时会被忽略。如果一个标识符以 "+" 字符做为结尾,ctags 将忽略源文件中紧跟
在此标识符后的被括号括起来的参数列表。如果两个标识符以 "=" 字符分隔,在解析时,第一个标
识符将被第二个标识符所替代。标识符列表可以直接在命令行上提供,也可以从一个单独的文件中
读出。如果 identifier-list 的第一个字符是 "@",".",或目录分隔符 ("/" 或 ""), 或前两个
字符是驱动器的盘符 (例如,"C:"),identifier-list 参数将被解释为一个文件名,从这个文件中
读取标识符列表,每行一个标识符。否则,identifier-list 是需要被特殊处理的标识符的列表
(或一组标识符对的列表),每一个标识符被逗号或空格分开,(如果以空格分隔,需要用引号把整个
列表括起来,以使整个列表做为一个命令行参数)。可以使用多个 -I 选项。要清除已定义的标识符
列表,以 "-" 做为 identifier-list 参数。

这个特性在编译预处理宏的出现会导致句法混淆的时候非常有用。实际上,这是解决源文件中干扰
语法的宏所引发的问题的最好办法 (见下面的 CAVEATS)。下面的例子详细描述这点。

int foo ARGDECL4(void *, ptr, long int, nbytes)

在上面的例子中,宏 "ARGDECL4" 将被错误的解释为函数的名字,而不是正确的名字 "foo"。定义
-I ARGDECL4 会获得正确的结果。

/* creates an RCS version string in module */
MODULE_VERSION("$Revision: 1.41 $")

在上面的例子,宏定义看起来非常像一个函数的定义,因为它没有以分号结尾 (实际上,它后面甚
至还可以跟一个全局变量定义,这样看起来更像一个 K&R 风格的函数参数定义)。实际上,在试图
完成这个看起来像函数的定义时,可能会导致文件的其它部分被跳过。定义 -I MODULE_VERSION+
可以避免这样的问题。

CLASS Example {
// your content here
};

上面的例子使用了 "CLASS" 做为预处理宏,它在不同的平台上被扩展为不同的东西。例如,在
Win32 平台上它可能被定义为 "class __declspec(dllexport)",而在 UNIX 上简单的被定义为
"class"。通常,没有 C++ 的 "class" 关键字将导致源文件被错误的解析。定义 -I CLASS=class
能够得到正确的结果。

-L file
在文件 file 中读取需要产生标签文件的文件列表。如果 file 被指定为 "-",那么文件列表由标
准输入上读取。通过这个选项读到的文件将在命令行上给出的文件之后被处理。输入中的选项也会
被接受 (*1)。如果此选项被定义多次,只使用最后一个。注意:file 以行的方式被读取,只以换
行符做为分隔符,空格被认为是有意义的,这是为了支持文件名中包含空格的情况;如果输入中包
含选项,这会影响选项如何被解析 (*2)。

-n 同 –excmd=number。

-N 同 –excmd=pattern。

-o tagfile
同 -f tagfile。

-R 同 –recurse。

-u 同 –sort=no (也就是 "unsorted",不排序)。

-V 同 –verbose。

-w 此选项被悄悄忽略。仅为兼容 SVR4 Unix 的 ctags。

-x 打印一个表格形式的、可读的交叉索引 (xref) 文件到标准输出,而不是产生一个标签文件。输出
的信息包括:标签名字;标签类型;行号,文件名和标签所定义行的内容 (多余的空格被压缩)。不
会写标签文件,并且所有影响标签文件输出的选项都被忽略。这个特性的一个应用实例是为源文件
中定义的函数生成一个列表 (例如,ctags -x –c-kinds=f file),或为源文件中所有外部可见全
局变量生成一个列表 (例如,ctags -x –c-kinds=v –file-scope=no file)。这个选项必须出现
在第一个文件名之前。

–append[=yes|no]
指明为指定文件生成的标签是增加到标签文件已存在内容的后面,还是替换它们。此选项缺省关闭。
这个选项必须出现在第一个文件名之前。

–etags-include=file
在标签文件中包含一个到 file 的引用。此选项可以被指定任意多次。这个选项支持 Emacs 在一个
标签文件中包含另外一个标签文件的功能。[只在 etags 模式中有效]

–exclude=[pattern]
将 pattern 加到排除文件/目录列表中。这个选项可以被指定任意多次。对每一个 ctags 处理的文
件名,都会把该文件的完整路径 (例如,some/path/base.ext) 以及文件名 (例如,base.ext) 与
此选项定义的每个 pattern 进行比较,这允许 pattern 只匹配一个给定的文件名而不管其路径,
或者只匹配一个指定的路径。如果你所用的 C 编译器的运行库支持,那么 pattern 中可以包含
Unix 上通用的 shell 通配符 (不是正则表达式) (确保把这个选项的参数用引号括起来,以保证通
配符在传给 ctags 之前不会被 shell 扩展;另外,要知道通配符可以匹配 "/" 字符)。 你可以通
过检查 –version 选项的输出来确定在你的平台上 shell 通配符是否可用,(如果可用,) 在编译
的特性表中将包含 "+wildcards";否则将通过简单的文本比较来检查 pattern 与文件名的匹配。

如果 pattern 以字符 "@" 开始,那么剩余的字符串将被解释成一个文件的名字,由此文件中读取
排除模式字串,每行一个。如果 pattern 为空,排除列表将被清空。注意,在程序启动时,缺省的
排除列表包含"EIFGEN","SCCS","RCS",和"CVS",这些是在处理 –recurse 选项时不想意外进入
的目录名。

–excmd=type
定义在源文件中定位标签时所用的 EX 命令的类型。[在 etags 模式中忽略]

type 的有效值为 (用整个单词或用第一个字母都可以):

number 在标签文件中只使用行号来定位标签。这有4个优点:
1. 明显减小最终标签文件的大小。
2. 消除因为定义标签的行被修改而导致使用 pattern 查找标签失败的情况,导致模式
匹配失败 (注意,有些编辑器,例如vim, 够在很多这样的情况中恢复)。
3. 消除在查找雷同的匹配时,找到不正确的源码行的情况 (见下面的 BUGS)。
4. 在标签文件中为内容相同的行保留多个不同的表项。在 pattern 模式,重复的表项
被丢弃,因为它们产生的查找字串是相同的,保存重复的表项没有意义。

但是,这个选项有一个显著的缺点:对源文件的更改会导致标签文件中的行号记录不再对
应源文件的行号,导致跳转到某些标签时偏离标签定义位置一行或多行。大体上讲,这个
选项最好用在那些不打算更改的源文件上。选择这个选项导致下面的选项被忽略:-BF。

pattern 对所有标签只使用搜索字串,与行号不同,行号通常用于宏定义。优点是标签文件产生后,
增加或删除行不会引用 到旧的行号。

mixed 在这个模式,除少数例外,通常都使用搜索字串。对 C 语言,行号用于宏定义标签。这
是原始的 ctags 生成的缺省格式,因此,保留这个选项的缺省值。对 Fortran,common
块使用行号,因为它们的源码行通常都相同,使搜索模式在查找所有匹配时没有用处。

–extra=[+|-]flags
指定是否为特定类型的信息增加额外的标签条目。flags 参数是一组单字母标记,每个代表标签文
件中的一种额外的标签条目。如果 flags 前带 "+" 或 "-" 字符,会向当前生效的标记中加入,或
删除这些标记。否则 flags 替代当前的设置。每个标记的含义如下:

f 为每个源文件的文件名包含一个条目 (例如,"example.c"),它定位到文件的第一行。

q 为每个类成员包含一个额外的类修饰符条目 (为那些支持这类信息的编程语言;当前包括
C++, Eiffel 和 Java)。修饰符标签的实际格式取决于定义该标签的语言 (使用这种语言中
修饰符被定义的那种格式)。对 C++来说,格式为 "class::member";对 Eiffel 和 Java,
格式为 "class.member"。当标签文件中一个标签的名字出现多次时,这将更容易的定位到
特定的标签。然而需注意,这有可能使标签文件的大小不止增加一倍。

–fields=[+|-]flags
定义标签文件表项中的有效扩展字段 (见下面的 TAG FILE FORMAT,以获得更多信息)。flags 参数
是一组单个字母标记, 每一个代表一种类型的扩展字段,具有如下含义 (缺省为禁用,除非下面有
注明):

a 类成员的访问控制信息
f 作用域局部于文件 [使能]
i (关于)继承的信息
k 使用一个字符表示的标签类型 [使能]
K 标签类型的完整名称
l 包含该标签的源文件的编程语言类型
m (关于)实现的信息
n 标签出现的行号
s 标签的范围 [使能]
S 函数的指纹 (例如,原型或参数列表)
z 在 kind 字段中包含 "kind:" 关键字
t 把变量或 typedef 的类型和名字做为 "typeref:" 字段 [使能] (*3)

每个字母或字母组合的前面可以为 "+" ,表示将它加到缺省集合,或者为 "-",表示排除它。如果
既没有 "+" 前缀也没有 "-"前缀,只有在 flags 中明确列出的类型被包含在输出中 (也就是说,
覆盖缺省集合)。如果 –format=1 选项定义了,此选项被忽略。此选项缺省值为 "fkst"。

–file-scope[=yes|no]
指明作用域只在一个文件的标签 (即只在定义它们的文件中可见,不能被其它文件见到的标签,例
如 "static" 的标签) 是否被包含在输出中。又见 -h 选项。这个选项缺省使能。

–filter[=yes|no]
使 ctags 表现的像一个过滤器,由标准输入读取文件的名字,并一个文件接一个文件的输出它们的
标签。如果 –sorted 选项使能,只对文件内定义的标签排序。文件由标准输入上按行读入 (见 -L
选项的备注 ),并且这些文件在命令行及 -L 选项指定的文件之后处理。本选项使能时, -f,-o
和 –totals 选项被忽略。这个选项太过高深,缺省为禁用。这个选项必须出现在第一个文件名之前。

–filter-terminator=string
在 –filter 选项使能时,定义一个字符串,在一个文件的标签解析完后,会打印这个字符串到标
准输出。这允许读取 ctags 输出的应用程序能够确定一个文件的输出在什么时候结束。注意,如果
读入文件名是一个目录,并且 –recurse 选项使能,这个字符串只在该目录中的所有标签之后输出
一次。这个字符串总是被文件的最后一个标签的换行符隔开。这个选项太过高深,缺省为空。这个
选项必须出现在第一个文件名之前。

–format=level
改变输出标签文件的格式。当前有效的 level 只有 1 或 2。级别1指定原始的标签文件格式,级别2
指定一种新的扩展格式,里面包含扩展字段 (但使用了一种手段,使之仍后向兼容原始的 vi(1)
现)。缺省的级别为 2。这个选项必须出现在第一个文件名之前。 [在 etags 模式中忽略]

–help
向标准输出打印一个详细用法描述,然后退出。

–if0[=yes|no]
指定是否对于 "#if 0" 编译预处理分支中的非宏标签进行检查 (宏标签总被包含)。因为这种构造
是为了禁用代码,所以此选项的缺省值为 no。注意,这只是指明一种偏好,并不能保证在 "#if 0"
分支中的代码真的被跳过,因为产生标签的算法会在编译预处理条件太复杂时会解析条件编译的每
一个分支。

–<LANG>-kinds=[+|-]kinds
为特定的编程语言指定一个与语言相关的标签种类 (或类型) 的列表,这些内容会被包含在输出文
件中,在这里 <LANG> 不区分大小写,并且是内建语言名的一种 (见 –list-languages 选项以获
得完整列表)。kinds 参数是一组单字母标记,用来指明 (特定于这种语言的) 标签类型是包含在输
出中,还是不包含。这些特定标记集基于每种程序语言被识别,它们的含义以及缺省值可以由
–list-kinds 选项列出。每个字母或组合可以以 "+" 做前缀,表示在缺省值中加入它,或者以 "-"
做前缀,表示在缺省值中排除它。如果不以 "+" 或 "-" 为前缀,只有在 kinds 中明确列出的类型
被包含在输出中 (就是说,覆盖这种编程语言的缺省值)。

做为 C 语言的一个例子,要想在缺省标签类型中加入函数原型和外部变量定义,但是排除宏定义,
使用 –c-kinds=+px-d;要想只包含函数的标签,使用 –c-kinds=f。

–langdef=name
定义一种新的用户自定义语言,name,使用正则表达式进行解析。一旦被定义,name 可以在其它使
用程序语言名字的选项中被使用。这个选项的典型用法是,先定义这种语言,然后使用 –langmap
把文件名映射到它,最后使用 –regex-<LANG> 定义它的标签如何被解析。

–langmap=map[,map[…]]
控制文件名如何被映射到程序语言 (见 –list-maps 选项)。每个以逗号分隔的映射中,包含语言
的名字 (内建语言或用户自定义语言),一个冒号,以及一个文件扩展名和/或文件名模式的列表。
要定义一个文件扩展名,在此扩展名前加上句号 (例如,".c")。要定义一个文件名模式,把这个模
式用括号括起来 (例如,"([Mm]ake-file)")。如果你的 C 编译器的运行库支持,那么文件名模式
中可以包含 Unix 中通用的 shell 通配符 (确保用引号把参数括起来,以保护通配符在传给 ctags
之前不会被 shell 扩展)。 你可以通过检查 –version 选项的输出来确定在你的平台上 shell 通
配符是否可用,(如果可用,) 在编译的特性表中将包含 "+wildcards";否则将通过简单的文本比
较来检查文件名模式与文件名的匹配。要映射一个 (已经使用的) 文件扩展名,首先要取消它与其
它语言的映射关系。

如果映射的第一个字符是一个 "+",那么这个映射中的扩展名和文件名模式将加到这种语言的当前
映射中;否则,这个映射将替换当前映射。例如,为了指定只有扩展名为 .c 和 .x 的文件被当做
C 语言文件,使用 "–langmap=c:.c.x";想同时把扩展名为 .j 的文件加到 Java 语言文件,定义
"–langmap=c:.c.x,java:+.j"。为了把 makefiles (例如,文件名为 "Makefile","makefile",
或具有扩展名 ".mak") 映射到一种称为 "make" 的语言,定义 "–langmap=make:([Mm]akefile).mak"。
想映射没有扩展名的文件,定义一个句号,后面不包含句号以外字符 (例如,".","..x",".x.")。
想要为一种特定的语言清除映射 (这会防止自动为这个语言生成标签),定义一个空的扩展名列表
(例如, "–langmap=fortran:")。想为特定的语言恢复缺省的映射,将映射定义为default。想为
所有的语言恢复缺省的映射,定义 "–langmap=default"。
注意,在判别文件的程序语言时,文件扩展名先于文件名模式被判断。

–language-force=language
缺省的,ctags 自动为一个源文件选择语言,忽略那些不能确定程序语言的文件 (见上面的 SOURCE
FILES)。这个选项强制把每个文件做为指定程序语言 (不区分大小写;内建或用户自定义) 的文件,
而不是根据它们的扩展名自动为其选择语言类型。另外,特殊值 auto 表示语言类型应该被自动选
择 (这否决的本选项的有效方法)。

–languages=[+|-]list
定义一个语言列表,将为这些语言产生标签,list 包含一个逗号分隔的语言名列表 (不区分大小写;
内建或用户自定义)。如果列表的第一个语言前面不是 "+" 或 "-" 字符,在向列表增加或从列表删
除语言前,会先清空当前列表。列表的每个语言都将加入列表,直到遇到一个 "-"。因为 "+" 或
"-" 都可以在列表中出现,在这两个符号后面的语言就相应被加到列表,或从列表中去掉。这样,
使用一个新的列表替换当前列表,或者从当前列表中增加或删除语言都变得很简单。实际会生成标
签的文件列表取决于生效的语言扩展名映射 (见 –langmap 选项)。注意,所有的语言,包括用户
自定义的语言,(缺省)都是使能的,除非使用本选项禁止。列表中的语言名可以是任何内建语言或
一个先前被 –langdef 选项定义的语言。缺省值为 "all",这也是一个可被接受的参数。见
–list-languages 选项以获得一个完整的内建语言名称。

–license
向标准输出打印软件许可证信息,然后退出。

–line-directives[=yes|no]
定义 "#line" 操作符是否应该被识别。它们存在于预处理器的输出中,包括行号,可能还包括生成
这个预处理输出的源文件的名字。当选项使能时,ctags 会生成标签项目,将使用源文件的文件名
和行号,而不是它们在预处理器输出中的位置。标签文件中的实际文件名将和预处理器输出文件具
有同样的路径,这是因为它假设原始文件的位置相对于预处理器输出文件 (当然,除非 #line 操作
符定义的是绝对路径)。这个选项缺省关闭。注意:这个选项通常在和 –excmd-number (-n) 选项
一起使用才比较有用。你也需要使用 –langmap 或 –language-force 选项,如果 ctags 不能识
别预处理器输出文件的扩展名的话。

–links[=yes|no]
指示是否跟踪符号链接 (如果系统支持符号链接的话)。在禁止时,符号链接被忽略。这个选项缺省
打开。

–list-kinds[=language|all]
列出指定语言或全部语言所能够识别的标签种类,然后退出。在标签文件中,每个种类的标签都用
一个单字母的标记来表示,它也用于 –<LANG>-kinds 选项,用以过滤在输出中所包含的标签种类。
注意,有些语言和/或标签种类可能用正则表达式来实现,如果正则表达式支持没有编译到 ctags
中,可能无法支持 (见 –regex-<LANG> 选项)。列出的每个种类都是使能的,除非后面跟有 "[off]"。

–list-maps[=language|all]
列出指定的语言或全部语言的文件扩展名和文件名模式,然后退出。这些扩展名以及文件名模式把
一个文件与特定程序语言相关联。见上面的 –langmap 选项,以及 SOURCE FILES。

–list-languages
列出 ctags 能够识别的程序语言名,然后退出。这些程序语言名称不区分大小写,可以用在
–language-force,–languages,–<LANG>-kinds 和–regex-<LANG> 选项。

–options=file
从 file 中读取附加选项。做为一种特殊情形,如果 –options=NONE 做为命令行的第一个选项,
它将禁止自动从文件或环境变量 (见 FILES) 中读取任何配置选项。

–recurse[=yes|no]
递归进入文件列表中所遇到的目录。如果给出的文件列表为空,并且没有使用 -L 指定文件列表,
那么当前目录被使用 (也就是 ".")。符号链接将被跟踪。如果你不喜欢这样的处理,或者显式的指
定文件列表,或者通过管道将 find(1) 的输出传给 "ctags -L-"。注意,这个选项当前并不能支持
所有的平台。如果 –help 选项的输出中包含本选项,说明它可用。又见 –exclude 选项,以限制
递归行为。

–regex-<LANG>=/regexp/replacement/[kind-spec/][flags]
/regexp/replacement/ 定义一个正则表达式的替换串,与 sed 的 substitution 命令风格类似,
使用它为映射到 <LANG> 语言 (不区分大小写;内建程序语言,或用户自定义程序语言) 的源文件
产生标签。正则表达式 regexp 定义一个扩展正则表达式 (主要为 egrep(1) 所用),它用来定位包
含标签的一个源码行,使用 t 来定义 tab 字符。当一个匹配行被发现,将会生成一个名为
replacement 的标签,replacement 通常会包含特殊的前向引用 1 到 9,以引用 regexp 中的子
表达式。选项参数中的 "/" 分隔字符实际上可以换成任何字符。注意,不管使用哪个分隔符,如果
它在参数中不做分隔用,必须使用 "" 字符对其进行转义。
本选项定义的正则表达式会被添加到这种语言当前的正则表达式列表中,除非省略选项参数,这种
情况当前列表会被清空。
除非由 flags 做出更改,否则 regexp 被作为 Posix 扩展正则表达式解析。对于每个匹配行,
replacement 应该被扩展为一个非空字符串,不然的话会产生一条告警信息。一个可选的标签类型
定义可以跟在 replacement 后面,它用来指定在标签的 "kind" 扩展字段里写入的类型 (见下面的
TAG FILE FORMAT)。kind-spec 的完整格式是一个单个字母,一个逗号,一个名字 (不包含空格),
一个逗号,一个描述,后面跟分隔符,这个格式定义了类型及其文本描述的长、短形式 (使用
–list-kinds 可以显示出来)。类型的名字和/或类型的描述可以被省略。如果 kind-spec 被省略,
它的缺省值为 "r,regex"。最后,flags 是一个或多个单字母字符,对 regexp 的解析有下列影响:

b 此模式被解析为 Posix 的基本正则表达式

e 此模式被解析为 Posix 的扩展正则表达式 (缺省)

i 此模式以忽略大小写的方式被应用

注意,这个选项只在 ctags 编译时加入正则表达式支持时才有效,这取决于你所用的平台。你可通
过检查 –version 选项的输出,以确定编译时是否加入正则表达式支持,(如果支持),输出的编译
特性列表中将包含 "+regex"。

欲获得 ctags 使用的正则表达式的详细信息,见 regex(5,7) 的手册页,或见 regex 的 GUU info
文档 (例如,"info regex")。

–sort[=yes|no|foldcase]
指明标签文件是否按标签名排序 (缺省为排序)。注意,原始的 vi(1) 要求排序标签。foldcase 指
定不区分大小写排序 (或大小写合并排序)。
对大小写合并排序进行快速二叉树查找需要由使用标签文件的工具提供特殊支持,例如 ctags 的
readtags 库,或 Vim 6.2 以上版本 (使用 "set ignorecase")。这个选项必须出现在第一个文件
名之前。[在 etags 模式中忽略]

–tag-relative[=yes|no]
指明标签文件中记录的名字路径应该相对于标签文件所在的目录,而不是相对于当前目录,除非命
令行所指定的文件名使用绝对路径。这个选项必须出现在第一个文件名之前。当运行在 etags 模式
时,缺省为 yes (见 -e 选项),否则缺省值为 no。

–totals[=yes|no]
打印在本次 ctags 运行期间所读入源文件以及所写标签的统计信息。这个选项缺省关闭。这个选项
必须出现在第一个文件名之前。

–verbose[=yes|no]
使能详细模式。打印处理选项的信息,以及在 ctags 处理每个文件时打印一条简洁的消息,描述采
取什么样的动作。通常,ctags 在配置文件中的选项 (见下面的 FILES) 以及 CTAGS 环境变量被读
入前,不会读取命令行参数。然而,如果本选项是命令行的第一个选项,它将在配置文件、CTAGS
环境变量,以及命令行上的每个选项被读入前生效。缺省值为 no。

–version
打印 ctags 的版本信息,然后退出。信息中始终包含字符串 "Exuberant Ctags"。

OPERATIONAL DETAILS
在 ctags 依次处理每个文件时,它试图挨顺序进行以下三步测试来确定文件的程序语言类型:是否文件
的扩展名被映射到一种程序语言,是否文件名匹配一个映射到程序语言的 shell 模式,最后判断是否该
文件可执行并且它的第一行使用 Unix 风格的 "#!" 定义了一个解释器 (如果平台支持的话)。如果程序
语言确定了,这个文件会被打开,接下来相应的语言解析器被调用,以解析当前打开的文件。解析器解析
整个文件,并且在标签文件中为每个语言对象增加一个条目。见下面的 TAG FILE FORMAT,以获得这些条
目的详细信息。

这个 ctags 实现不像旧有的实现那样,对 C 代码的格式有要求。旧的实现往往依赖特殊的预定格式来帮
助它解决编译预处理条件引发的困难。

通常,ctags 试图更巧妙的处理翻译预处理操作符。如果在一条定义了标签的语句中遇到一个编译预处理
条件,ctags 只跟随此条件的第一个分支 (除非第一分支是 "#if 0" ,在这种情况下,只跟随剩下的唯
一一条分支)。这样做的原因是 (如果) 跟随不只一条分支会导致语法不明确,就像下面例子:

#ifdef TWO_ALTERNATIVES
struct {
#else
union {
#endif
short a;
long b;
}

不能同时跟随两个分支,否则括号会不匹配,ctags 将不能识别语法。

由于这些条件很复杂,并且 (分支) 相互排斥,如果这种办法不能正确的解析一个文件,ctags 将重新尝
试另一种不同的方法,这种方法不并选择性的跟随条件预处理分支,而是在 #if 条件分支导致大括号不
匹配时,通过位于第 1 列的大括号 ("}") 来做为一个代码块结束的指示。

Ctags 也尝试对括在两个圆括号中的参数列表进行特殊处理,以接受下面这样的条件结构:

extern void foo __ARGS((int one, char two));

任何紧挨着 "((" 的名字都被自动忽略,而使用在它之前的名字。

C++ 的运算符定义会被特殊处理。为了对所有种类的运算符 (重载或转换) 保持一致,在标签文件中,所
有运算符的名字总是以 "operator " 为前缀 (也就是说,即使实际的运算符定义被写成 "operator<<")。

在创建标签文件,或向标签文件中添加标签后,将根据标签的名字进行排序,删除相同的标签行。

TAG FILE FORMAT
在不以 etags 模式运行时,标签文件中的每个表项占单独的一行,通常每个看起来都如同这样:

tag_name<TAB>file_name<TAB>ex_cmd;"<TAB>extension_fields

字段以及分隔符定义如下:

1. 标签名
2. 单个 tab 字符
3. 文件名,这个标签对应的对象在此文件中定义
4. 单个 tab 字符
5. 在文件中定位此标签的 EX 命令;通常是一个搜索模式 (/pattern/ 或 ?pattern?) 或行号 (见
–excmd)。标签文件格式 2 (见 –format)
在某些情况下扩展了这个 EX 命令,在紧挨着此 EX 命令后面的 EX 命令注释里嵌入了一套扩展
字段 (在下面描述),这样使它仍能向下兼容原始的 vi(1) 实现。

基于内部使用的目的,会向标签文件中写入一些特殊的标签。这些标签的构成使它们始终被排序到文件的
最前面。因此,这些标签的前两个字符被用做标签文件的幻数,以确定正在写入的是一个有效的标签文件,
而不是一个源文件。

注意,记录在标签文件的每个源文件名,和命令行上定义的完全相同。因此,如果你在命令行上指定的是
相对于当前目录的路径的话,它们在标签文件中以同样的方式被记录。然而,见 –tag-relative 选项,
以更改此设置。

如上所说,扩展字段作为注释增加在 EX 命令之后,是以 tab 字符分隔的 "关键字-值" 组合。这些 "关
键字-值" 组合一般为 "key:value" 的格式。它们是否在标签文件中出现,由 –fields 选项控制。可能
的关键字以及它们值的含义见下:

access 指明类成员的可见范围,它的值特定于程序语言。

file 指明此标签只在文件中可见。这个关键字没有相应的值。

kind 指明标签的类型,或种类。它的值要么是上面 –<LANG>-kinds 选项所描述的相应单字母标
志,要么是全名。此字段的关键字部分允许被省略 (实际上,这是缺省设置)。由 –fields
选项控制它的表现。

implementation
如果存在,它指明一个函数或类具有实现的限制 (抽象与具体),它的值特定于程序语言
(对 C++ 而言是 "virtual" 或 "pure virtual";对 Java 而言是 "abstract").

inherits 如果存在,值为一个逗号分隔的类列表,这个类源于列表中的类 (也就是说,它由列表中的
类继承而来)。

signature 如果存在,它的值是函数指纹,表示方法与程序语言相关。完整的函数指纹定义了此函数的
返回类型及它的参数列表格式。这个扩展字段当前只支持基于 C 的程序语言,并且不包括
返回类型。

另外,标签作用域有关的信息也 (在标签文件中) 可用,它的关键字部分是程序语言中的构造名称,它的
值是程序中此构造的名字。作用域表项指明定义此标签的范围。例如,C 语言的结构成员所生成的标签,
会包含一个作用域,看起来像这样 "struct:myStruct"。

HOW TO USE WITH VI
Vi 缺省的期望当前工作目录中有一个名为 "tags" 的标签文件。一旦生成了标签文件,下面的命令执行
按标签索引的特性:

vi -t tag 启动 vi 并且把光标定位在 "tag" 定义所在的文件和行上。

:ta tag 查找一个标签。

Ctrl-] 查找光标下的标签

Ctrl-T 返回跳转到标签前的前一次位置 (不是所有实现都支持)。

HOW TO USE WITH GNU EMACS
Emacs 缺省的期望当前工作目录中有一个名为 "TAGS" 的标签文件。一旦生成了标签文件,下面的命令执
行按标签索引的特性:

M-x visit-tags-table <RET> FILE <RET>
选择所使用的标签文件 "FILE"。

M-. [TAG] <RET>
查找第一个 TAG 定义。缺省的标签是光标下的标识符。

M-* 跳回你先前调用 "M-." 的位置

C-u M-. 查找前一次所查找的标签的下一个定义

阅读 Emacs info 文档的 Tags 主题,以了解更多命令。

HOW TO USE WITH NEDIT
NEdit 的 5.1 及以后版本可以处理新的扩展标签文件格式 (见 –format)。要使 NEdit 使用标签文件,
选择 "File->Load Tags File"。要跳转到一个标签的定义,高亮这个标签,然后按 Ctrl-D。NEdit 5.1
可以从不同的目录读取多个标签文件。设置 X 资源中的 nedit.tagFile 为标签文件的名字,可以使
NEdit 在启动时自动加载这个标签文件。

CAVEATS
由于 ctags 既不是一个预处理器也不是一个编译器,使用预处理宏会使 ctags 漏掉标签或者错误的生成
不正确的标签。虽然 ctags 已经被设计成处理一些的通用情况,但这依旧是提交最多的问题。特别是使
用预处理构造改变 C 的语法结构时,会欺骗 ctags。你可以通过使用 -I 选项避开很多这样的问题。

(*4)
White space is treated as a separator for file names and options read from list files,
specified using the -L option, and in filter mode (specified using the –filter option).
Therefore, it is not currently possible to supply file names or other options contain-ing
embedded white space (spaces, etc.) through these options.

注意,当 ctags 使用模式字串来定位标签时 (见 –excmd 选项),如果另外一个源码行和包含这个标签
的行完全相同,你的编辑器完全有可以跳到错误的行上。下面的例子说明这种情况:

int variable;

/* … */
void foo(variable)
int variable;
{
/* … */
}

取决于你所使用的编辑器,以及你在代码中位置,搜索模式可能会在查找到真正的全局变量定义之前,查
找到 foo() 的局部参数声明,因为这两行完全相同 (因此它们的搜索模式也相同)。这可以通过使用
–excmd=n 来避免。

BUGS
Ctags 具有比 ls(1) 更多的选项.

当解析一个 C++ 成员函数定义时 (例如,"className::function"),ctags 不能确定域分隔符是一个类
名分隔符还是一个 namespace 分隔符,总是把它做一个类名放在扩展字段的作用域部分。另外,如果一
个 C++ 函数定义在类定义外面 (通常都是这样),函数定义中包含的访问限定符 (即 public,protected
或 private) 以及实现信息 (例如 virtual,pure virtual) 在为这个函数生成标签时无法知道。然而,
对于原型,这些信息可用 (例如,–c++-kinds+=p)。

没有为继承自一个类的语言对象产生标签。

ENVIRONMENT VARIABLES
CTAGS 如果这个环境变量存在,在 ctags 启动时会从此环境变量中读取缺省选项,读取发生在下面
FILES 一节中列出的配置文件之后,但在命令行选项之前。命令行中出现的选项会覆盖此环境变
量中的选项。只从这个环境变量中读取选项值。注意,环境变量中的所有空格都被认为是分隔符,
这样传递一个包含空格的选项参数是不可能的。如果这会导致问题,改用配置文件。

ETAGS 与上面的 CTAGS 类似,如果存在,它会在 etags 启动时读取。如果这个环境变量未找到,etags
将尝试改用 CTAGS 环境变量。

TMPDIR 在支持 mkstemp() 的类 Unix 主机上,这个环境变量的值定义了存放临时文件的目录。这在临
时文件太大导致缺省临时文件目录所在的分区无法装下它时比较有用。ctags 只在下列情况时创
建临时文件: (1) 生成一个 emacs 格式的标签文件, (2) 标签文件被输出到标准输出,
(3) 它被编译成使用内部的排序算法来排序标签文件,而不是使用操作系统的 sort 工具。如果
使用系统的 sort 工具,它通常也会使用这个变量。如果 ctags 是 setuid 的,TMPDIR 的值将
被忽略。

FILES
/ctags.cnf (只在 MSDOS,MSWindows)
/etc/ctags.conf
/usr/local/etc/ctags.conf
$HOME/.ctags (在 MSDOS, MSWindows 上是 $HOME/ctags.cnf)
.ctags (在 MSDOS,MSWindows上是 ctags.cnf)
如果这些配置文件中任一个存在,每个都应该包含一个缺省的选项集合,在 ctags 启动时会按列
出的顺序读入这些选项,读入的时刻发生在读取 CTAGS 环境变量以及命令行选项之前。这使得设
置适用于整个系统、每个人或基于项目的缺省选项值成为可能。在编译 ctags 时为它指定一个额
外的配置文件是可能的,它会在上面列出文件被读入之前读取,在 –version 选项输出中的
"custom-conf" 指示这个特性可用。CTAGS 环境变量及命令行中选项会覆盖这些文件中定义的选
项。只从这些文件中读入选项值。注意,选项文件按行读入,行内的空格有效 (因为不能像 shell
那样使用引号)。文件的每行被当做一个命令行参数 (就像它们被单引号括起来一样)。因此,使
用换行符做为命令行参数的分隔标志。

tags ctags 生成的缺省标签文件。

TAGS etags 生成的缺省标签文件。

SEE ALSO
Exuberant Ctags 的官方网站在:

http://ctags.sourceforge.net

参阅 ex(1),vi(1),elvis,或更好的,vim,ctags 的正式编辑器。欲获得 vim 的更多信息,请到
VIM 的 web 网站:

http://www.vim.org/

AUTHOR
Darren Hiebert <dhiebert at users.sourceforge.net>
http://DarrenHiebert.com/

MOTIVATION
"Think ye at all times of rendering some service to every member of the human race."

"All effort and exertion put forth by man from the fullness of his heart is worship, if it
is prompted by the highest motives and the will to do service to humanity."

— From the Baha’i Writings

CREDITS
这个版本的 ctags 最初继承了 Steve Kirkendall <kirkenda@cs.pdx.edu> 的 ctags 并从中获取灵感,
他的 ctags 伴随 Elvis vi 变种发行 (虽然事实上没有使用一行原来的代码)。

荣誉也要归于 Bram Moolenaar <Bram@vim.org>,vim 的作者,他花费如此多的时间和精力开发这个编辑
器 (服务于他人) 以及帮助乌干达的孤儿。

名为 "HOW TO USE WITH GNU EMACS" 的一节是从 GNU etags 的 info 文档中 "偷来" 的。

Darren Hiebert Version 5.6 CTAGS(1)

译者注:

(*1) 原文为 "Options all also accepted in this input" 。经过与作者沟通,本句应为 "Options also
accepted in this input"。意思是“在输入中的选项也会被接受”,也就是说,可以在 file 中加入选项,
这些选项将会应用在其后出现的文件上。这提供了一种非常便捷的方式,允许用户为不同的文件指定不同的
选项。

(*2) 这句话意思是,因为行内的空格被视为有意义的,所以不能再以空格来分隔各个选项,而应该以换行符来分
隔多个选项。

(*3) 按译者的理解,在使用类如 struct,union 这样的复杂数据类型进行类型定义 (typedef) 或直接定义变量
时,会为之增加 "typeref:" 字段。下面两个例子中的代码生成的标签文件就包含此字段:
/* 定义类型 */
typedef struct abc
{
int a;
char b;
} abc;

/* 直接定义变量 */
union {
TEST1,
TEST2
} test;

(*4) 这段话与前面的选项解释相抵触,正在与作者沟通。

[译文版本]
27Apr07, easwy, initial version
28Apr07, easwy, reformat it

原创文章,请阅读页脚的许可方式,转载请注明:转载自易水博客 [ http://easwy.com/blog/ ]

本文链接地址: http://easwy.com/blog/archives/exuberant-ctags-chinese-manual/

文章的脚注信息由WordPress的wp-posturl插件自动生成