文档章节

cTags源码分析(1) - 概要

htfy96
 htfy96
发布于 2015/02/26 15:26
字数 882
阅读 77
收藏 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

没有更多内容

加载失败,请刷新页面

加载更多

分布式锁的那点事

在多线程并发的情况下,要保证一个代码块在同一时间只能由一个线程访问,可以用锁来保证,比如java的synchronized语法以及ReentrantLock类等等。这样子可以保证JVM进程内的多个线程同步执行。...

无语年华
21分钟前
2
0
apahce启用http2

需要前置条件传送门 其实前置做完了,h2是很简单的事 1.apache启用http2_module 2.打开apche的配置文件,写上 Protocols h2 http/1.1 3.重启apache,打开浏览器看看吧...

gcudwork
37分钟前
1
0
redis-string

set key value 设置值 set命令有以下选项: ex senconds :为健设置秒级过期时间 px millisencondes :为健设置毫秒级过期时间 nx :健不存在时候,可以设置成功,用于添加 xx : 与nx相反,不...

拐美人
42分钟前
2
0
正弦 余弦 角度 用于画时钟

<html> <head> <title>时钟</title> </head> <style> #canvas{ background: #1977ca } </style>......

一箭落旄头
59分钟前
4
0
驰狼课堂

http://www.chilangedu.com/

求是科技
今天
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部