Chinaunix首页 | 论坛 | 博客
  • 博客访问: 455918
  • 博文数量: 45
  • 博客积分: 2526
  • 博客等级: 少校
  • 技术积分: 478
  • 用 户 组: 普通用户
  • 注册时间: 2008-05-12 21:04
文章分类

全部博文(45)

文章存档

2014年(1)

2011年(1)

2010年(3)

2009年(22)

2008年(18)

我的朋友

分类: C/C++

2008-05-30 12:33:33

最近在研究ctags的实现代码,代码太复杂,于是自己动手写了个简单的实现。差不多可以

实现这样的功能--打印源程序的函数列表,包括函数名和该函数在文件中的行数。核心思想

就是用正则表达式匹配文件的每一行,如果匹配,则保存在一个链表中。

 

在C程序可以运行正则表达式,其库函数头文件为regex.h。具体的用法可以参见man regex

主要涉及三个函数:

int regcomp(regex_t *preg, const char *pattern, int cflags);

int regexec(const regex_t *preg, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags);

size_t regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size);

void regfree(regex_t *preg);

在使用之前,要把匹配的正则表达式用regcomp函数进行编译,接着用regexec函数执行。

运行的结果保存在pmatch这个数组中。用完之后记得调用regfree函数释放内存。regerror

函数主要用来打印错误信息。

 

下面就是具体的程序:

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <regex.h>
#include <assert.h>

#define MAX_LINE_NUMBER 256
#define EBUFLEN 128
#define BUFLEN 1024
#define SUBSLEN 5

typedef struct _taginfo {
    char* func_name; // Function name
    char* file_name; // which file the tag is
    unsigned int line_num; // line number where the function is in the file

    char reserverd[4];
} taginfo;

typedef struct _taglist {
    taginfo tag;
    struct _taglist *tag_next;
    unsigned int tag_num;
} taglist;

// list head

static taglist *local_taglist;

void usage(char* program)
{
    printf("Usage: %s filename pattren\n", program);
}

/*
 * Function: create a list head node.
 * Output: a list
 */

taglist* create_list(void)
{
    taglist *list;
    list = (taglist*)malloc(sizeof(taglist));
    if(list == NULL)
    {
        printf("malloc memory failed!\n");
        return NULL;
    }

    list->tag.func_name = NULL;
    list->tag.file_name = NULL;
    list->tag_next = NULL;
    list->tag_num = 0;

    return list;
}

/*
 * Function: Insert a new node with taginfo to a list
 * Input: list -- head node pointer of the list
 * tag -- a new list node
 */

int insert_list(taginfo *tag, taglist** list)
{
    assert(tag != NULL);
    assert(list != NULL);
    taglist *temp, *local_list;
    int len;

    local_list = *list;
    temp = local_list->tag_next;
    local_list->tag_next = (taglist*)malloc(sizeof(taglist));

    // set tag info

    local_list->tag_next->tag.func_name = tag->func_name;
    local_list->tag_next->tag.file_name = tag->file_name;
    local_list->tag_next->tag.line_num = tag->line_num;
    local_list->tag_next->tag_next = temp;
    local_list->tag_next->tag_num = local_list->tag_num + 1;

    local_list->tag_num++;
    local_list = temp = NULL;
    return 0;
}

/*
 * Function: Print a list.
 */

void output_taglist(taglist *list)
{
    taglist *loop;
    int i;

    printf("Function Name\tFile Name\tLine number\n");
    for(i = 0,loop = list->tag_next; i < list->tag_num; i++)
    {
        printf("%s\t", loop->tag.func_name);
        printf("%s\t", loop->tag.file_name);
        printf("%d\n", loop->tag.line_num);
        loop = loop->tag_next;
    }

    loop = NULL;
}

/*
 * Function: free memory
 */

int cleanup_taglist(taglist **list)
{
    taglist *loop = *list;
    taglist *temp;

    while(loop != NULL)
    {
        if (loop->tag.func_name != NULL) free(loop->tag.func_name);
        if (loop->tag.file_name != NULL) free(loop->tag.file_name);
        temp = loop->tag_next;
        loop->tag_next = NULL;
        free(loop);
        loop = temp;
    }

    loop = NULL;
    return 0;
}

/*
 * Function: Check a string whether matched certain pattern. If matched, fill
 * with store_tag, otherwise leave store_tag NULL.
 * Input: str -- a string
 * pattern -- regular-expression pattern
 * Output: store_tag -- where the matched string are stored to
 */

int check_matched(const char *str, taginfo *store_tag, const char* pattern)
{
    regex_t re;
    int i, err, len;
    char errbuf[EBUFLEN];
    char matched[BUFLEN];
    regmatch_t subs[SUBSLEN];

    assert(str != NULL);
    assert(store_tag != NULL);

    store_tag->func_name = NULL;
    err = regcomp(&re, pattern, REG_EXTENDED);
    if(err)
    {
        len = regerror(err, &re, errbuf, sizeof(errbuf));
        printf("error: regcomp: %s\n", errbuf);
        return 1;
    }

    err = regexec(&re, str, (size_t)SUBSLEN, subs, 0);
    if (err == REG_OKAY)
    {
        len = subs[0].rm_eo - subs[0].rm_so + 1;
        store_tag->func_name = (char*)malloc(len * sizeof(char));
        memcpy(store_tag->func_name, str+subs[0].rm_so, len);
        store_tag->func_name[len-1] = '\0';
    }

    regfree(&re);

    return 0;
}

/*
 * Function: Setup a tag list based on certain regular-expression pattern.
 * Input: filename -- input file name
 * pattern -- regular-expression pattern
 * Output: taglist -- a tag list
 */

taglist* setup_taglist(char *filename, const char* pattern)
{
    char line[MAX_LINE_NUMBER];
    unsigned int row, len;
    FILE *fp;
    taginfo tag;
    taglist *list = NULL;

    fp = fopen(filename, "r");
    if (fp == NULL)
    {
        printf("Open %s failed!\n", filename);
        return NULL;
    }

    list = create_list();
    if (list == NULL)
    {
        printf("Create list failed!\n");
        return NULL;
    }

    rewind(fp);
    row = 1;
    fgets(line, MAX_LINE_NUMBER, fp);
    while(!feof(fp))
    {
        //printf("%d %s", row, line);

        //tag = (taginfo*)malloc(sizeof(taginfo));

        check_matched(line, &tag, pattern);
        if (tag.func_name != NULL)
        {
            // insert new taginf to taglist

            tag.line_num = row;
            len = strlen(filename) + 1;
            tag.file_name = (char*) malloc(len * sizeof(char));
            memcpy(tag.file_name, filename, len);
            tag.file_name[len-1] = '\0';
            insert_list(&tag, &list);
            tag.file_name = NULL;
            tag.func_name = NULL;
        }

        //output_taglist(list);

        fgets(line, MAX_LINE_NUMBER, fp);
        ++row;
    }

    fclose(fp);
    return list;
}

int main (int argc, char** argv)
{
    char *filename, *pattern;
    int result;

    if(argc != 3)
    {
        usage(argv[0]);
        exit(1);
    }

    filename = argv[1];
    pattern = argv[2];
    local_taglist = setup_taglist(filename, pattern);
    if (local_taglist == NULL)
    {
        printf("Setup taglist failed! Try again\n");
        exit(1);
    }

    output_taglist(local_taglist);

    cleanup_taglist(&local_taglist);

    return 0;
}

 

编译,运行:

 

$gcc -o my_ctags my_ctags.c

$./my_ctags my_ctags.c "[a-zA-Z_][0-9a-zA-Z_&*]* +[a-zA-Z_][0-9a-zA-Z_ ]*\([^<>=.]*\)"

Function Name File Name Line number

int main (int argc, char** argv) my_ctags.c 225

taglist* setup_taglist(char *filename, const char* pattern) my_ctags.c 173

int check_matched(const char *str, taginfo *store_tag, const char* pattern) my_ctags.c 133

int cleanup_taglist(taglist **list) my_ctags.c 107

void output_taglist(taglist *list) my_ctags.c 87

int insert_list(taginfo *tag, taglist** list) my_ctags.c 61

taglist* create_list(void) my_ctags.c 38 void usage(char* program) my_ctags.c 28

 

这个结果跟grep命令的结果一样:

 

$grep -E -n "[a-zA-Z_][0-9a-zA-Z_&*]* +[a-zA-Z_][0-9a-zA-Z_ ]*\([^<>=.]*\)" my_ctags.c

28:void usage(char* program)

38:taglist* create_list(void) 61:int insert_list(taginfo *tag, taglist** list)

87:void output_taglist(taglist *list)

107:int cleanup_taglist(taglist **list)

133:int check_matched(const char *str, taginfo *store_tag, const char* pattern)

173:taglist* setup_taglist(char *filename, const char* pattern)

225:int main (int argc, char** argv)

阅读(2384) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~