文档章节

cTags源码分析(1) - 概要

htfy96
 htfy96
发布于 2015/02/26 15:26
字数 882
阅读 72
收藏 0
点赞 0
评论 0

main.c开始。

extern int main (int __unused__ argc, char **argv)
{
    cookedArgs *args;
#ifdef VMS
    extern int getredirection (int *ac, char ***av);

    /* do wildcard expansion and I/O redirection */
    getredirection (&argc, &argv);
#endif

#ifdef AMIGA
    /* This program doesn't work when started from the Workbench */
    if (argc == 0)
        exit (1);
#endif

#ifdef __EMX__
    _wildcard (&argc, &argv);  /* expand wildcards in argument list */
#endif

#if defined (macintosh) && BUILD_MPW_TOOL == 0
    argc = ccommand (&argv);
#endif

    setCurrentDirectory ();
    setExecutableName (*argv++);
    checkRegex ();

    args = cArgNewFromArgv (argv);
    previewFirstOption (args);
    testEtagsInvocation ();
    initializeParsing ();
    initOptions ();
    readOptionConfiguration ();
    verbose ("Reading initial options from command line
");
    parseOptions (args);
    checkOptions ();
    makeTags (args);

    /*  Clean up.
     */
    cArgDelete (args);
    freeKeywordTable ();
    freeRoutineResources ();
    freeSourceFileResources ();
    freeTagFileResources ();
    freeOptionResources ();
    freeParserResources ();
    freeRegexResources ();

    exit (0);
    return 0;
}

一开始cTags维护了一个自己的cookedArgs类型的参数列表,args。之后根据不同系统的情况,重新定义了argcargv

第一个函数setCurrentDirectory()定义在routines.c中,根据系统不同,定义了CurrentDirectory一个全局变量(使用getcwd()),并在最后增加了OUTPUT_PATH_SEPARATOR

第二个函数setExecutableName (*argv++)定义了ExecutableProgram(主文件路径)和ExecutableName(主文件名)两个全局变量。

第三个函数checkRegex()regex库的内部函数,检查regex能否正常工作.

之后,args = cArgNewFromArgv (argv)将默认的选项格式加以处理转换到args中.

previewFirstOption (args)处理-v和没有选项的情况(直接退出)。

testEtagsInvocation ()检测是否有-e选项,若有,则初始化etags

initializeParsing()是重要的一步,它检查每一个内建的语言,它们的名称是否合法,它们的regex是否存在,如果是,则将它们插入LanguageTable[]数组中。这个数组的成员类型是parserDefinition*,而parserDefinition的定义如下:

typedef struct {
    /* defined by parser */
    char* name;                    /* name of language */
    kindOption* kinds;             /* tag kinds handled by parser */
    unsigned int kindCount;        /* size of `kinds' list */
    const char *const *extensions; /* list of default extensions */
    const char *const *patterns;   /* list of default file name patterns */
    parserInitialize initialize;   /* initialization routine, if needed (初始化的函数指针) */
    simpleParser parser;           /* simple parser (common case) */
    rescanParser parser2;          /* rescanning parser (unusual case) */
    boolean regex;                 /* is this a regex parser? */

    /* used internally */
    unsigned int id;               /* id assigned to language */
    boolean enabled;               /* currently enabled? */
    stringList* currentPatterns;   /* current list of file name patterns */
    stringList* currentExtensions; /* current list of extensions */
} parserDefinition;

之后initializeParsing调用initializeParsers (),即循环调用每个LanguageTable[]中语言的LanguageTable[i]->initialize(),进行语言初始化工作(建立hash表等)。

接下来的一大步是initOptions(),设置默认选项,建立默认语言映射,自动添加.git等控制文件到--exclude选项中。

readOptionConfiguration ()读取目录下的.ctags配置文件与环境变量。

parseOptions (args)把之前简单分拆的选项细分成longOptionsshortOptions,并设置Options结构的相应位。

checkOptions()是对选项的静态检查。

makeTags(args),是最重要的部分,代码如下:

static void makeTags (cookedArgs *args)
{
    clock_t timeStamps [3];
    boolean resize = FALSE;
    boolean files = (boolean)(! cArgOff (args) || Option.fileList != NULL
                              || Option.filter);

    if (! files)
    {
        if (filesRequired ())
            error (FATAL, "No files specified. Try "%s --help".",
                getExecutableName ());
        else if (! Option.recurse && ! etagsInclude ())
            return;
    }

#define timeStamp(n) timeStamps[(n)]=(Option.printTotals ? clock():(clock_t)0)
    if (! Option.filter)
        openTagFile ();

    timeStamp (0);

    if (! cArgOff (args))
    {
        verbose ("Reading command line arguments
");
        resize = createTagsForArgs (args);
    }
    if (Option.fileList != NULL)
    {
        verbose ("Reading list file
");
        resize = (boolean) (createTagsFromListFile (Option.fileList) || resize);
    }
    if (Option.filter)
    {
        verbose ("Reading filter input
");
        resize = (boolean) (createTagsFromFileInput (stdin, TRUE) || resize);
    }
    if (! files  &&  Option.recurse)
        resize = recurseIntoDirectory (".");

    timeStamp (1);

    if (! Option.filter)
        closeTagFile (resize);

    timeStamp (2);

    if (Option.printTotals)
        printTotals (timeStamps);
#undef timeStamp
}

简而言之,就是以下几步:

  1. openTagFile (resize)打开Tag文件;

  2. 根据选项不同,分别调用createTagsForArgs (args)createTagsFromListFile (Option.fileList)createTagsFromFileInput (stdin, TRUE)recurseIntoDirectory ("."),而它们都调用了createTagsForEntry(filename),经过检查后,最终调用了parse.c中的parseFile(filename);

  3. closeTagFile (resize)关闭Tag文件。

最终,通过如下几步,free掉前几步申请的动态内存,防止内存泄漏:

    cArgDelete (args);  //释放args[]
    freeKeywordTable ();  //释放KeywordTable[]
    freeRoutineResources ();  //释放CurrentDirectory
    freeSourceFileResources ();  //释放File(一个用于读取文件的变量)
    freeTagFileResources ();  //释放TagFile变量
    freeOptionResources ();  //释放Options变量
    freeParserResources ();  //释放LanguageTable[]
    freeRegexResources ();  //释放Regex库内存

© 著作权归作者所有

共有 人打赏支持
htfy96
粉丝 8
博文 5
码字总数 10027
作品 0
闵行
程序员
Linux源代码分析工具链

vim+ctags+cscope 源码阅读三剑客.vim配合ctags和cscope,足以在源代码里面自由翱翔,在函数和变量间自由跳转. 安装 1 sudo apt-get install vim ctags cscope 使用 vim vim的使用就略过了,网上...

CasparLi
2015/09/06
197
0
Vim编程之:tags,cscope,taglist

最近VIM用得比较多,所以在学了不少。在这里对收获到的东西做一个总结。 1.编程四要素vim,ctags,cscope,taglist vim配合这3件东西之后,极为强大。与SourceInsight有一拼。 1.1 ctags ctags叫...

临峰不畏
2013/06/20
0
0
使用 vim + ctags + cscope + taglist 阅读源码

阅读源码的工具有很多,而且如今的集成开发环境(IDE)也很强大,但对于经常使用vim编辑器的程序员来说,对vim的强大绝对是“不抛弃,不放弃”的,况且我们只要安装一些插件配合vim的工作一样...

Julian_Wu
2013/06/27
0
4
使用 vim + ctags + cscope + taglist 阅读源码

最近,准备跟学长一起往 linux kernel 的门里瞧瞧里面的世界,虽然我们知道门就在那,但我们还得找到合适的角度才会看得更舒服,对吧^_^ 。 阅读源码的工具有很多,而且如今的集成开发环境(...

bo博
2012/05/28
0
1
ubuntu搭建C/C++环境附VIM的常用命令表

ubuntu搭建C/C++环境附VIM的常用命令表 发布于: January 25, 2012, 9:21 pm 分类: linux,web服务器 作者: Cyrec 1,配置gcc 刚装好的的gcc什么文件都不能编译,因为没有一些必须的头文件,所...

Start-up
2012/04/27
0
0
Linux 平台下阅读源码的工具链

本文作者:伯乐在线 -肖汉松 。未经作者许可,禁止转载! 欢迎加入伯乐在线专栏作者。 前言 看源代码是一个程序员必须经历的事情,也是可以提升能力的一个捷径.个人认为: 要完全掌握一个软件的...

伯乐在线
2016/05/23
0
0
vim ctags请指点

使用vim,可以在源码文件上,直接点击右键-〉使用vim编辑。而且都有高亮,还是挺方便的。但是ctags每次都需要手动更新,感觉很麻烦 。请问如何让它自动更新? 例如这个代码 ,第一次打开鼠标...

Helloall
2014/08/27
35
0
用vim-NERDTree-Taglist写Scala

1.用pathogen管理插件,全部使用pathogen默认的设置方式。手动下载vim-scala、NERDTree、Taglist、easytags(支持Taglist自动更新的插件)丢到~/.vim/bundle下,或者也可以配置updat_bundles...

garbageaa
2015/11/22
157
0
vim配置文件集成版本--kenvim

色色的vim配置文件集成版本,你是不是总纠结于vim的高大尚,你是不是总被vim粉讥笑成小鸟,下定决心来试着使用下vim,但是不是又被坑爹的配置吓到了,国内的文档层次参差不齐,互相抄袭,也不...

vb2005xu
2014/09/24
1K
1
鸟人的Android揭秘(8)——搭建Android SDK开发环境(四)

到目前为止,我们已经完整讲解完Android源代码的编译,以及基于Android Studio的开发环境搭建和调试,读者按照前文所述即可开始自己的Android探索之旅。 虽然Android Studio用来开发和调试J...

鸟人部落
2016/12/23
15
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

about git flow

  昨天元芳做了git分支管理规范的分享,为了拓展大家关于git分支的认知,这里我特意再分享这两个关于git flow的链接,大家可以看一下。 Git 工作流程 Git分支管理策略   git flow本质上是...

qwfys
今天
1
0
Linux系统日志文件

/var/log/messages linux系统总日志 /etc/logrotate.conf 日志切割配置文件 参考https://my.oschina.net/u/2000675/blog/908189 dmesg命令 dmesg’命令显示linux内核的环形缓冲区信息,我们可...

chencheng-linux
今天
1
0
MacOS下给树莓派安装Raspbian系统

下载镜像 前往 树莓派官网 下载镜像。 点击 最新版Raspbian 下载最新版镜像。 下载后请,通过 访达 双击解压,或通过 unzip 命令解压。 检查下载的文件 ls -lh -rw-r--r-- 1 dingdayu s...

dingdayu
今天
0
0
spring boot使用通用mapper(tk.mapper) ,id自增和回显等问题

最近项目使用到tk.mapper设置id自增,数据库是mysql。在使用通用mapper主键生成过程中有一些问题,在总结一下。 1、UUID生成方式-字符串主键 在主键上增加注解 @Id @GeneratedValue...

北岩
今天
2
0
告警系统邮件引擎、运行告警系统

告警系统邮件引擎 cd mail vim mail.py #!/usr/bin/env python#-*- coding: UTF-8 -*-import os,sysreload(sys)sys.setdefaultencoding('utf8')import getoptimport smtplibfr......

Zhouliang6
今天
0
0
Java工具类—随机数

Java中常用的生成随机数有Math.random()方法及java.util.Random类.但他们生成的随机数都是伪随机的. Math.radom()方法 在jdk1.8的Math类中可以看到,Math.random()方法实际上就是调用Random类...

PrivateO2
今天
2
0
关于java内存模型、并发编程的好文

Java并发编程:volatile关键字解析    volatile这个关键字可能很多朋友都听说过,或许也都用过。在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果。在...

DannyCoder
昨天
0
0
dubbo @Reference retries 重试次数 一个坑

在代码一中设置 成retries=0,也就是调用超时不用重试,结果DEBUG的时候总是重试,不是0吗,0就不用重试啊。为什么还是调用了多次呢? 结果在网上看到 这篇文章才明白 https://www.cnblogs....

奋斗的小牛
昨天
2
0
数据结构与算法3

要抓紧喽~~~~~~~放羊的孩纸回来喽 LowArray类和LowArrayApp类 程序将一个普通的Java数组封装在LowArray类中。类中的数组隐藏了起来,它是私有的,所以只有类自己的方法才能访问他。 LowArray...

沉迷于编程的小菜菜
昨天
0
0
spring boot应用测试框架介绍

一、spring boot应用测试存在的问题 官方提供的测试框架spring-boot-test-starter,虽然提供了很多功能(junit、spring test、assertj、hamcrest、mockito、jsonassert、jsonpath),但是在数...

yangjianzhou
昨天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部