/*############################################################# 用法: 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; i 7) { 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