处理pc_lint结果文件

/*#############################################################
用法: 1. 修改pclint.cfg中的配置项
      2. 执行脚本,会在当前目录生成处理的文件: ret_原文件名.txt
         如果pclint.cfg中配置项为: MASK_INFOS="813 530",则生成
         的文件名为: ret_no530_no13_原文件名.txt
      3. 程序中使用第三方库: pcre进行正则处理
         该在linux/windows上安装pcre步骤如下:(以linux为例)
         a. 解压 b. 在解压后目录 执行: ./configure; make; makeinstall

      4. 编译此程序命令: cc deal_lint.c -lpcre   
         
##############################################################*/

#define PCRE_STATIC
#include 
#include 
#include 
#include 
#include 

/*#######################################
            全局变量
########################################*/
#define  TRUE 1
#define  FALSE 0

// 配置项
char LINT_FILES[20][100];
char MASK_INFOS[20][5];
char LINT_FILE_DIR[100];
char DIV_PATH[100];

// 是否删除"During Specfic Walk:"信息
int DEL_SPEC_FLAG = FALSE;

// 字符缓冲区
#define BUF_LEN 1024
char BUF[BUF_LEN];

// 字符串缓冲区
#define LEN 50
char STR_BUF[LEN][1024];

// 日志文件指针
FILE *LOGFILE;

// 空格, 用于分割字符串
const char *SPACES = " \t\f\r\v\n";


/*#######################################
打印日志
########################################*/
void Log(const char *pStr)
{
    if (LOGFILE && pStr)
    {
        fputs(pStr, LOGFILE);
    }
}

/*#######################################
删除前缀空格,修改源串
########################################*/
char * leftTrim(char *pStr)
{
    char buf[1024];
    char *pTmpStr;

    pTmpStr = pStr;
    while (*pTmpStr == ' ' 
        || *pTmpStr == '\t'
        || *pTmpStr == '\r'
        || *pTmpStr == '\n')
    {
        pTmpStr++;
    }

    strcpy(buf, pTmpStr);
    strcpy(pStr, buf);

    return pStr;
}

/*#######################################
删除后缀空格,修改源串
########################################*/
char * rightTrim(char *pStr)
{
    char buf[1024];
    char *pTmpStr;

    if (NULL == pStr || *pStr == 0)
    {
        return pStr;
    }
    
    pTmpStr = pStr + strlen(pStr) - 1;
    while (*pTmpStr == ' '
        || *pTmpStr == '\r'
        || *pTmpStr == '\n'
        || *pTmpStr == '\t')
    {
        pTmpStr--;
    }

    *(pTmpStr + 1) = 0;

    return pStr;
    
}


/*#######################################
删除首尾空格,修改源串
########################################*/
char * trim(char *pStr)
{
    return leftTrim(rightTrim(pStr));
}


/*#######################################
分割字符串
ret: 是否成功 
########################################*/
int split(const char *pStr, const char *pSplitChar)
{
    char *pToken;
    int i = 0;
    char buf[1024];

    strcpy(buf, pStr);

    pToken = strtok(buf, pSplitChar);
    if (!pToken)
    {
        return FALSE;
    }
    memset(STR_BUF, 0, sizeof(STR_BUF));
    while (pToken)
    {
        strcpy(STR_BUF[i++], pToken);
        pToken = strtok(NULL, pSplitChar);
    }

    return TRUE;
}


/*#######################################
对给定的字符串进行正则匹配,匹配的结果保存在全局数组中
arg1: 字符串
arg2: 正则表达式
ret:是否匹配
########################################*/
int match(const char *pStr, const char *pReg)
{
    pcre *re;
    const char *error;
    int erroffset;
    int ovector[30];
    int rc;
    int i;
    int j = 0;

    re = pcre_compile(
        pReg,           /* pattern */
        0,              /* default option */
        &error,         /* for error msg */
        &erroffset,     /* for error offset */
        NULL);          /* use default character tables */

    rc = pcre_exec(
        re,             /* the compiled pattern */
        NULL,           /* no extra data */
        pStr,           /* subject string */
        strlen(pStr),   /* subject string length */
        0,              /* start at offset 0 in the subject */
        0,              /* default option */
        ovector,        /* output of substr */
        30);             /* number of elemenets int the ouput ovector */

    pcre_free(re);

    // 将匹配的结果保存
    if (rc >= 0)
    {
        for (i = 1; i < rc; i++)
        {
            char *subStart = (char*)pStr + ovector[2*i];
            int subLen = ovector[2*i + 1] - ovector[2*i];
            memset(STR_BUF[j], 0, LEN);
            strncpy(STR_BUF[j++], subStart, subLen);
        }
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}

/*#######################################
对指定字符中进行替换操作
########################################*/
char * replace(char *pSrcStr, const char *pOldSubStr, const char *pNewSubStr, int isGlobal)
{
    int len;
    char buf[1024];

    char *pBegin;
    char *pEnd;

    len = strlen(pOldSubStr);
    do
    {
        pBegin = strstr(pSrcStr, pOldSubStr);
        pEnd = pBegin + len;

        // 源字串未找到时结束
        if (!pBegin)
        {
            break;
        }

        memset(buf, 0, 1024);
        strncpy(buf, pSrcStr, pBegin-pSrcStr);
        strcat(buf, pNewSubStr);
        strcat(buf, pEnd);

        // 修改源串
        strcpy(pSrcStr, buf);
        
    }while(isGlobal);

    return pSrcStr;
}

/*#######################################
打开文件,进行二次封装
########################################*/
FILE *openFile(const char *pFileName, const char *mode)
{
    char buf[200];
    FILE *pFile;
    sprintf(buf, "%s%s", LINT_FILE_DIR, pFileName);
    pFile = fopen(buf, mode);
    return pFile;
}

/*#######################################
检查LINT_FILES配置
########################################*/
int checkLintFiles(const char *pLintFiles)
{
    int i = 0;
    int j = 0;
    int ret = TRUE;
    FILE *pTmpFile;
    
    Log("##################### Check LINT_FILES ################\n");

    if (!split(pLintFiles, SPACES))
    {
        Log("    Error: LINT_FILES can't be NULL!\n\n");
        return FALSE;
    }

    // 判断配置的文件是否存在
    for (i = 0; i7)
    {
        return 0;
    }

    if (y == 1)
    {
        return x;
    }

    return myPow(x, y-1) * x;
}


/*#######################################
从"123"得到123整数
########################################*/
long getStrNumber(const char *pStr)
{
    int len = strlen(pStr);
    long num = 0;

    while (*pStr)
    {
        num += (*pStr - '0') * myPow(10, len--);
        pStr++;
    }
    return num;
}


/*#######################################
生成临时文件,其中每行代表一条lint信息
########################################*/
int createTmpFile(const char *pSrcFileName, const char *pRetFileName, int isDelSrcFile)
{
    char fileName[200] = {0};
    char lintInfo[15] = {0};
    char lineNum[10] = {0};
    char macroFlag[2] = "N";
    char macroValue[200] = {0};
    char details[1024] = {0};
    char content[100] = {0};

    char errNum[5] = {0};
    char okNum[5] = {0};

    char *pTmpStr;

    FILE *pInFile = openFile(pSrcFileName, "r");
    FILE *pOutFile = openFile(pRetFileName, "w");
    if (!pInFile || !pOutFile)
    {
        Log("createTmpFile: openFile failed!\n\n");
        return FALSE;
    }

    while (fgets(BUF, BUF_LEN, pInFile))
    {
        // 处理Warning 529: 和Info 715: Warning 550: Warning 530
        // pc_lint产生的出错行不准确, 需要从错误描述中提取
        if (match(BUF, "(Warning 529:)|(Info 715:)|(Waring 550:)|(Waring 530: .*[(])line \\d+[)])"))
        {
            match(BUF, "\\s+(\\d+)\\s+");
            strcpy(errNum, STR_BUF[0]);
            match(BUF, "[(]line\\s+(\\d+)[)]");
            strcpy(okNum, STR_BUF[0]);

            replace(BUF, errNum, okNum, FALSE);
        }

        // 宏
        if (match(BUF, "#\\.\\.\\."))
        {
            strcpy(macroFlag, "Y");
            pTmpStr = trim(BUF);
            // 去除开头的#... 
            pTmpStr += 5;
            pTmpStr = leftTrim(pTmpStr);
            sprintf(macroValue, " Macro valus is: %s", pTmpStr);
        }
        // 正常行信息
        else if (match(BUF, "[.][ch]\\s+\\d+\\s+[a-z]+\\s+\\d+:(.*)"))
        {
            sprintf(details, "%s%s", macroValue, rightTrim(STR_BUF[0]));
            // 分割行
            split(BUF, SPACES);
            strcpy(fileName, STR_BUF[0]);
            strcpy(lineNum, STR_BUF[1]);
            strcpy(lintInfo, STR_BUF[2]);
            strcat(lintInfo, " ");
            strncat(lintInfo, STR_BUF[3], strlen(STR_BUF[3]) - 1);

            // 行内容
            getFileContent(fileName, getStrNumber(lineNum), content);

            // 如果当前行内容为{,并且lint_info为Warning 578,则说明一定是函数
            // 参数问题, 那么lint的行号就是错误的,需要修正下
            if (strcmp(content, "{") == 0 && strcmp(lintInfo, "Warning 578") == 0)
            {
                getFileContent(fileName, getStrNumber(lineNum) -1 , content);
            }

            fprintf(pOutFile, "%s@%s@%s@%s@%s@%s\n", fileName, lintInfo, lineNum,
                macroFlag, details, content);

            // 清空宏信息
            strcpy(macroFlag, "N");
            strcpy(macroValue, "");
        }
        // 形如: During Specific Walk:的信息
        else if (match(BUF, "File .+ line \\d+(.*)"))
        {
            if (DEL_SPEC_FLAG)
            {
                continue;
            }
            sprintf(details, "During Specific Walk: %s", rightTrim(STR_BUF[0]));
            // 清空宏信息
            strcpy(macroFlag, "N");
            strcpy(macroValue, "");

            // 分割行
            split(BUF, SPACES);
            strcpy(fileName, STR_BUF[1]);
            strncpy(lineNum, STR_BUF[3], strlen(STR_BUF[3]) - 1);
            strcpy(lintInfo, "无");
            getFileContent(fileName, getStrNumber(lineNum), content);
            fprintf(pOutFile, "%s@%s@%s@%s@%s@%s\n", fileName, lintInfo, lineNum,
                macroFlag, details, content);

        }
    }

    fclose(pInFile);
    fclose(pOutFile);
    return TRUE;
}

/*#######################################
从文件中删除由正则表达式指定的行
########################################*/
int delLine(const char *pSrcFileName, const char *pRegStr)
{
    char delFileName[100] = {0};
    FILE *pInFile;
    FILE *pOutFile;

    strcpy(delFileName, "del_");
    strcat(delFileName, pSrcFileName);

    pInFile = openFile(pSrcFileName, "r");
    pOutFile = openFile(delFileName, "w");
    if (!pInFile || !pOutFile)
    {
        Log("delLine: open file failed\n");
        return FALSE;
    }


    while (fgets(BUF, BUF_LEN, pInFile))
    {
        if (match(BUF, pRegStr))
        {
            continue;

        }
        fputs(BUF, pOutFile);
    }
    fclose(pInFile);
    fclose(pOutFile);

    // 替换源文件内容为生成的新文件
    pInFile = openFile(delFileName, "r");
    pOutFile = openFile(pSrcFileName, "w");
    if (!pInFile || !pOutFile)
    {
        Log("delLine: open file failed\n");
        return FALSE;
    }

    while (fgets(BUF, BUF_LEN, pInFile))
    {
        fputs(BUF, pOutFile);
    }

    fclose(pInFile);
    fclose(pOutFile);

    return TRUE;
}


/*#######################################
生成最终结果文件
########################################*/
int createRetFile(const char *pSrcFileName, const char *pRetFileName, int isDelSrcFile)
{
    // 定义字段名
    char fileName[200] = {0};
    char lintInfo[15] = {0};
    char lineNum[5] = {0};
    char macroFlag[2] = {0};
    char details[1024] = {0};
    char content[100] = {0};
    char preName[200] = {0};
    int fileCount = 0 ;
    FILE *pInFile = openFile(pSrcFileName, "r");
    FILE *pOutFile = openFile(pRetFileName, "w");
    if (!pInFile || !pOutFile)
    {
        Log("createRetFile: open file failed!\n\n");
        return FALSE;
    }

    while (fgets(BUF, BUF_LEN, pInFile))
    {
        split(rightTrim(BUF), "@");
        strcpy(fileName, STR_BUF[0]);
        strcpy(lintInfo, STR_BUF[1]);
        strcpy(lineNum, STR_BUF[2]);
        strcpy(macroFlag, STR_BUF[3]);
        strcpy(details, STR_BUF[4]);
        strcpy(content, BUF + strlen(fileName) + strlen(lintInfo) 
            + strlen(lineNum) + strlen(macroFlag) + strlen(details) + 5);
        if (strcmp(preName, fileName) != 0 )
        {
            if (fileCount++ > 0)
            {
                fputs("\r\n\r\n", pOutFile);
            }

            fprintf(pOutFile, "%d.文件: %s\n", fileCount, fileName);
            fputs(" ----------------------------------------------------\n", pOutFile);
            fputs(" 行号    信息     当前行内容(前50字符) 含有宏    详细描述\n", pOutFile);
            fputs(" ----------------------------------------------------\n", pOutFile);
        }

        strcpy(preName, fileName);
        fprintf(pOutFile, "    %-8s%-15s%-55s %-5s%s\n", lineNum, lintInfo, content,
            macroFlag, details);
        
    }
    
    if (fileCount == 0)
    {
        fputs("Very good, no lint info.\n", pOutFile);
    }

    fclose(pInFile);
    fclose(pOutFile);
}


/*#######################################
根据MASK_INFOS生成结果文件
########################################*/
int createMaskRetFile(const char *pSrcFileName, const char *uniqFileName, int isDelSrcFile)
{
    char retMaskFileName[100] =  {0};
    char regBuf[100] = {0};
    int i = 0;

    // 未配置MASK_INFOS
    if (*MASK_INFOS[0]  == 0)
    {
        return FALSE;
    }

    // 生成结果文件名
    strcpy(retMaskFileName, "ret");
    for (i = 0; i<20;i++)
    {
        if (*MASK_INFOS[i] == 0)
        {   
            break;
        }

        strcat(retMaskFileName, "_no");
        strcat(retMaskFileName, MASK_INFOS[i]);

        strcpy(regBuf, "@[a-zA-Z]+ ");
        strcat(regBuf, MASK_INFOS[i]);
        strcat(regBuf, "@");
        delLine(uniqFileName, regBuf);
    }
    strcat(retMaskFileName, "_");
    strcat(retMaskFileName, pSrcFileName);

    createRetFile(uniqFileName, retMaskFileName, FALSE);

}


/*#######################################
处理lint_file文件
########################################*/
int dealLintFile(const char * pSrcFileName)
{
    char preFileName[100] = {0};
    char tmpFileName[100] = {0};
    char sortFileName[100] = {0};
    char uniqFileName[100] = {0};
    char retFileName[100] = {0};
    char regBuf[20] = {0};
    int i = 0;
    int ret = TRUE;

    sprintf(preFileName, "pre_%s", pSrcFileName);
    sprintf(tmpFileName, "%s.tmp", pSrcFileName);
    sprintf(sortFileName, "sort_%s", pSrcFileName);
    sprintf(uniqFileName, "uniq_%s", pSrcFileName);
    sprintf(retFileName, "ret_%s", pSrcFileName);

    // 预处理
    if (!preDeal(pSrcFileName, preFileName, FALSE))
    {
        return FALSE;
    }

    // 生成临时文件
    if (!createTmpFile(preFileName, tmpFileName, FALSE))
    {
        return FALSE;
    }

    // 排序
    if (!sortFile(tmpFileName, sortFileName, FALSE))
    {
        return FALSE;
    }

    // 去重
    if (!uniqFile(sortFileName, uniqFileName, FALSE))
    {
        return FALSE;
    }

    // 生成结果文件
    createRetFile(uniqFileName, retFileName, FALSE);
    // 根据MASK_INFOS生成另一结果文件
    createMaskRetFile(pSrcFileName, uniqFileName, FALSE);

    return TRUE;
}


//################################ 程序入口 ###########################
int main(void)
{
    int i = 0;

    // 生成日志文件
    createLogFileName(BUF);
    LOGFILE = openFile(BUF, "w");
    if (!LOGFILE)
    {
        printf("main: create log file failed\n");
    }

    // 配置项检查
    checkCfg();

    // 处理所有lint文件
    for (i = 0; i < 20; i++)
    {
        if (*LINT_FILES[i] == 0)
        {
            break;
        }
        dealLintFile(LINT_FILES[i]);
    }

    Log("\n####################### All Done ######################\n");

    return 0;
}
/// pc_lint.cfg 
# pc_lint文件所在的目录,如果是当前目录,填写为.
# LINT_FILE_DIR = .

# 要处理的lint_file,以空格分开,注意必须写在同一行
LINT_FILES = LintAll.txt

# 不需要处理的lint消息,如果Info 813. 只需要填数字,以空格分开,可为空
# 如MASK_INFOS="813 712" 代表不需要处理813 712信息
MASK_INFOS = 813

# 是否删除"During Specific Walk:" 信息,默认不删除
DEL_SPEC_FLAG = N



 

你可能感兴趣的:(C/C++)