文档章节

cTags源码分析(1) - 概要

htfy96
 htfy96
发布于 2015/02/26 15:26
字数 882
阅读 86
收藏 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
Linux 平台下阅读源码的工具链

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

伯乐在线
2016/05/23
0
0

没有更多内容

加载失败,请刷新页面

加载更多

码云项目100,水一发

简单回顾一下: 早期构想最多的,是希望能将PHP一些类和编码分区做得更细,所以很多尝试。但不得不说,PHP的功能过于单一,是的,也许写C/C++扩展,可以解决问题,那我为什么不用C#或者Golan...

曾建凯
今天
3
0
Spring应用学习——AOP

1. AOP 1. AOP:即面向切面编程,采用横向抽取机制,取代了传统的继承体系的重复代码问题,如下图所示,性能监控、日志记录等代码围绕业务逻辑代码,而这部分代码是一个高度重复的代码,也就...

江左煤郎
今天
4
0
eclipse的版本

Eclipse各版本代号一览表 Eclipse的设计思想是:一切皆插件。Eclipse核心很小,其它所有功能都以插件的形式附加于Eclipse核心之上。 Eclipse基本内核包括:图形API(SWT/Jface),Java开发环...

mdoo
今天
3
0
SpringBoot源码:启动过程分析(一)

本文主要分析 SpringBoot 的启动过程。 SpringBoot的版本为:2.1.0 release,最新版本。 一.时序图 还是老套路,先把分析过程的时序图摆出来:时序图-SpringBoot2.10启动分析 二.源码分析 首...

Jacktanger
今天
6
0
小白带你认识netty(二)之netty服务端启动(上)

上一章 中的标准netty启动代码中,ServerBootstrap到底是如何启动的呢?这一章我们来瞅下。 server.group(bossGroup, workGroup);server.channel(NioServerSocketChannel.class).optio...

天空小小
今天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部