【题目】
开发一个简单错误记录功能小模块,能够记录出错的代码所在的文件名称和行号。
处理:
1、 记录最多8条错误记录,循环记录,对相同的错误记录(净文件名称和行号完全匹配)只记录一条,错误计数增加;
2、 超过16个字符的文件名称,只记录文件的最后有效16个字符;
3、 输入的文件可能带路径,记录文件名称不能带路径。
Input:
一行或多行字符串。每行包括带路径文件名称,行号,以空格隔开。
如:E:\V1R2\product\fpgadrive.c 1325
Output:
将所有的记录统计并将结果输出,格式:文件名 代码行数 数目,一个空格隔开。
如:fpgadrive.c 1325 1
【实现】
以下给出作者的解法(思路类似《一则表驱动法的应用实例》):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ERR_NUM 8 //允许共存的错误数目
#define ERR_NAME_LEN sizeof("123456789ABCDE.c 4294967295 4294967295")
#define FILE_NAME_LEN 256 //假定文件路径最大长度为256字节
#define TRIM_FILENAME_LEN 16
typedef struct {
char szFileName[FILE_NAME_LEN];
unsigned int dwLineNo;
unsigned int dwOccurs;
}T_ERR_REC;
//gErrorMap按新旧次序环形记录ERR_NUM条错误记录
static char gErrorMap[ERR_NUM][ERR_NAME_LEN] = {{0}};
//gLatestErrIndex记录gErrorMap第一维最新错误记录的下标,
//该下标+1并对ERR_NUM取余后对应的元素为最旧的错误记录,即
//Oldest = (Latest + 1) mod ERR_NUM.
static unsigned int gLatestErrIndex = ERR_NUM-1;
static char *GetFileBasename(char *pszFileName) {
return strrchr(pszFileName, '\\') + 1; //也可考虑兼容Unix斜杠
}
static char *GetTrimmedFileName(char *pszFileName) {
unsigned int dwNameLen = strlen(pszFileName);
if(dwNameLen > TRIM_FILENAME_LEN)
return &pszFileName[dwNameLen-TRIM_FILENAME_LEN];
else
return &pszFileName[0];
}
static void InsertErrorRecord(char *pszMapEntry, T_ERR_REC *ptErrRec) {
memset(pszMapEntry, 0, ERR_NAME_LEN); //为求通用,对新增条目也先清零
sprintf(pszMapEntry, "%s %u %u",
GetTrimmedFileName(GetFileBasename(ptErrRec->szFileName)),
ptErrRec->dwLineNo, ptErrRec->dwOccurs);
}
void ShowErrorRecord(void) {
printf("Current Error Record:\n");
unsigned int dwRecIdx = 0;
for(; dwRecIdx < ERR_NUM && '\0' != gErrorMap[dwRecIdx][0]; dwRecIdx++) {
printf(" [%u]: %s\n", dwRecIdx, gErrorMap[dwRecIdx]);
}
}
int CreateErrorRecord(char *pszErrorInfo){
if(NULL == pszErrorInfo || '\0' == *pszErrorInfo)
return -1;
//解析错误信息里的文件名和行号
T_ERR_REC tErrRec = {/*.szFileName=*/{0}, /*.dwLineNo=*/0, /*.dwOccurs=*/1};
if(sscanf(pszErrorInfo, "%s %u", tErrRec.szFileName, &tErrRec.dwLineNo) != 2)
return -1;
unsigned int dwRecIdx = 0, bIsInErrorRecord = 0;
char *pszBaseName = GetFileBasename(tErrRec.szFileName);
for(; dwRecIdx < ERR_NUM && '\0' != gErrorMap[dwRecIdx][0]; dwRecIdx++) {
//相同的错误记录
if(!strncmp(pszBaseName, gErrorMap[dwRecIdx], strlen(pszBaseName))) {
unsigned int dwSavedOccurs = strtol((strrchr(gErrorMap[dwRecIdx], ' ')+1), NULL, 10);
tErrRec.dwOccurs += dwSavedOccurs;
bIsInErrorRecord = 1;
break;
}
}
if(bIsInErrorRecord) {
InsertErrorRecord(gErrorMap[dwRecIdx], &tErrRec);
} else {
gLatestErrIndex = (gLatestErrIndex+1)%ERR_NUM;
InsertErrorRecord(gErrorMap[gLatestErrIndex], &tErrRec);
}
return 0;
}
int main(void) {
CreateErrorRecord("E:\\V1R2\\product\\fpgadrive.c 1"); CreateErrorRecord("E:\\V1R2\\fpgadrive_bak.c 2");
CreateErrorRecord("E:\\V1R2\\fpgadrive_pdt.c 3"); CreateErrorRecord("E:\\fpgadrive_fpgpdt.c 4");
CreateErrorRecord("E:\\fpga.c 5"); CreateErrorRecord("E:\\V1R2\\123456789ABCDEFG.c 6");
CreateErrorRecord("E:\\V1R2\\product\\fpgadrive2.c 7"); CreateErrorRecord("E:\\V1R2\\fpgadrive_bak2.c 8");
CreateErrorRecord("E:\\fpga.c 1"); ShowErrorRecord(); //相同错误记录
CreateErrorRecord("E:\\fpga123456789AB.c 10"); ShowErrorRecord(); //文件名超过16个字符
//while(1);
return 0;
}
运行效果如下:
Current Error Record:
[0]: fpgadrive.c 1 1
[1]: fpgadrive_bak.c 2 1
[2]: fpgadrive_pdt.c 3 1
[3]: gadrive_fpgpdt.c 4 1
[4]: fpga.c 1 2
[5]: 3456789ABCDEFG.c 6 1
[6]: fpgadrive2.c 7 1
[7]: fpgadrive_bak2.c 8 1
Current Error Record:
[0]: pga123456789AB.c 10 1
[1]: fpgadrive_bak.c 2 1
[2]: fpgadrive_pdt.c 3 1
[3]: gadrive_fpgpdt.c 4 1
[4]: fpga.c 1 2
[5]: 3456789ABCDEFG.c 6 1
[6]: fpgadrive2.c 7 1
[7]: fpgadrive_bak2.c 8 1