//以十六进制方式显示指定数据区内容。 int dbg_bin_hex(char* pPrintBuffer, char* pBuffer, int nLength) { int i = 0; int j = 0; int nCount = 0; //一个比较复杂的打印循环,虽然很长,但还是很简单 for (i = 0; i < nLength; i++) { nCount += SafePrintf(pPrintBuffer + nCount, 256, "%02X ", (unsigned char) *(pBuffer + i)); j++; if (4 == j) { j = 0; nCount += SafePrintf(pPrintBuffer + nCount, 256, " "); } } if (16 > nLength) //每行 打印16字节 { for (; i < 16; i++) { nCount += SafePrintf(pPrintBuffer + nCount, 256, " "); j++; if (4 == j) { j = 0; nCount += SafePrintf(pPrintBuffer + nCount, 256, " "); } } } return nCount; }
int CTonyLowDebug::Debug2File(char *szFormat, ...) { //注意,这个类设计时,还没有内存池概念,因此,动态内存申请,原则上应该避免 //以免出现内存碎片。此处使用静态数组实现buffer,在浮动栈建立。 //这也是为什么这个类必须声明最大输出字符串长度的原因 char szBuf[DEBUG_BUFFER_LENGTH]; //准备输出buffer char szTemp[DEBUG_BUFFER_LENGTH]; //时间戳置换的中间buffer char szTime[DEBUG_BUFFER_LENGTH]; //时间戳的buffer FILE* fp = NULL; //文件指针,以C 模式工作 int nListCount = 0; va_list pArgList; time_t t; struct tm *pTM = NULL; int nLength = 0; //这是构建时间戳 time(&t); pTM = localtime(&t); nLength = SafePrintf(szTemp, DEBUG_BUFFER_LENGTH, "%s", asctime(pTM)); szTemp[nLength - 1] = '\0'; SafePrintf(szTime, DEBUG_BUFFER_LENGTH, "[%s] ", szTemp); //注意,此处开始进入加锁,以此保证跨线程调用安全 m_Lock.Lock(); { //习惯性写法,以大括号和缩进清晰界定加锁区域,醒目。 //下面这个段落是从SafePrintf 拷贝出来的,一个逻辑的可重用性, //也可以根据需要,直接拷贝代码段实现,不一定非要写成宏或函数。 va_start(pArgList, szFormat); nListCount += Linux_Win_vsnprintf(szBuf + nListCount, DEBUG_BUFFER_LENGTH - nListCount, szFormat, pArgList); va_end(pArgList); if (nListCount > (DEBUG_BUFFER_LENGTH - 1)) nListCount = DEBUG_BUFFER_LENGTH - 1; *(szBuf + nListCount) = '\0'; //开始真实的输出 fp = fopen(m_szFileName, "a+"); //请注意下面逻辑,由于本函数使用了锁,因此只能有一个退出点 //这里笔者没有使用goto,因此,必须使用if 嵌套,确保不会中间跳出 if (fp) { //输出到文件 nListCount = fprintf(fp, "%s%s", szTime, szBuf); if (m_bPrint2TTYFlag) { //根据需要输出至控制台 TONY_PRINTF("%s%s", szTime, szBuf); if (m_pInfoOutCallback) { //注意此处,回调输出给需要的上层调用 //注意,本段为后加,没有使用前文变量,目前是减少bug 率 char szInfoOut[APP_INFO_OIT_STRING_MAX]; SafePrintf(szInfoOut, APP_INFO_OIT_STRING_MAX, "%s%s", szTime, szBuf); m_pInfoOutCallback(szInfoOut, //注意把输出字符串传给回调 m_pInfoOutCallbackParam); //透传的指针 } } fclose(fp); } else { nListCount = 0; } } m_Lock.Unlock(); //解锁 return nListCount; //返回输出的字节数,所有字符串构造和输出函数的习惯 }
void CNEOLog::MakeFileName(void) { char szTemp[LOG_ITEM_LENGTH_MAX] = "\0"; MakeATimeString(szTemp,LOG_ITEM_LENGTH_MAX); //获得时间戳字符串 FixFileInfo(); //维护文件总个数(默认72个) int nLen=SafePrintf(m_szFileName,(FILENAME_STRING_LENGTH*2),"%s_%s.log",m_szFilePath,szTemp);//生成日志文件名 nLen++; //将新的文件名添加到队列 int nAddLastRet=m_pFileInfoQueue->AddLast(m_szFileName,nLen); if(0>=nAddLastRet) { //为防止队列满了,删除对头的三个名字 DeleteFirstFile(); DeleteFirstFile(); DeleteFirstFile(); //重新添加 nAddLastRet=m_pFileInfoQueue->AddLast(m_szFileName,nLen); } m_nFileSize=0; //新建文件,长度为0 //新建文件,在文件头打印一些信息 time(&m_tFileNameMake); { bool bPrintToScr=m_bPrintfToScrFlag; m_bPrintfToScrFlag=false; _Printf("NEO.base lib log file %s\n",m_szFileName); _Printf("____________________________________\n"); m_bPrintfToScrFlag=bPrintToScr;//输出完毕,恢复标志 } }
//申请一个token头 SNEOQueueTokenHead *CNEOMemQueue::GetAToken(void)//返回指针,不遵守谁申请谁释放的原则 { SNEOQueueTokenHead *pToken=NULL; char *pTokenBuffer=NULL; //临时指针 char szNameBuffer[NEO_APPLICATION_NAME_SIZE];//说明文字缓冲区 if(!ICanWork()) goto CNEOMemQueue_GetAToken_End; SafePrintf(szNameBuffer,256,"%s::Token_Head",m_szAppName); //开始申请Token头内存块 pTokenBuffer=(char *)m_pMemPool->Malloc(SNEOQueueTokenHeadSize,szNameBuffer); if(!pTokenBuffer) { m_pDebug->DebugToFile("%s::GetAToken:Malloc new Token fail!\n",m_szAppName); goto CNEOMemQueue_GetAToken_End; } //强制指针转换 pToken=(SNEOQueueTokenHead *)pTokenBuffer; pToken->m_nDataLen=0; pToken->m_pNext=NULL; pToken->m_pBuffer=NULL; m_nTokenCount++; CNEOMemQueue_GetAToken_End: return pToken; }
//****************这是主入口函数 //以16 字节为一行,格式化输出二进制数据内容。 void dbg_bin(char* pBuffer, int nLength) { int nAddr = 0; int nLineCount = 0; int nBufferCount = nLength; int n = 0; char szLine[256]; //行缓冲 if (0 < nLength) { while (1) { n = 0; n += SafePrintf(szLine + n, 256 - n, "%p - ", pBuffer + nAddr); nLineCount = 16; if (nBufferCount < nLineCount) nLineCount = nBufferCount; n += dbg_bin_hex(szLine + n, pBuffer + nAddr, nLineCount); n += dbg_bin_ascii(szLine + n, pBuffer + nAddr, nLineCount); CON_PRINTF("%s\n", szLine); nAddr += 16; nBufferCount -= 16; if (0 >= nBufferCount) break; } CON_PRINTF("\n"); } else CON_PRINTF("dbg_bin error length=%d\n", nLength); }
void CTonyXiaoLog::MakeFileName(void) //创造一个新文件名 { char szTemp[LOG_ITEM_LENGTH_MAX]; //临时缓冲区 MakeATimeString(szTemp, LOG_ITEM_LENGTH_MAX); //获得时间戳字符串 FixFileInfo(); //维护文件总个数不超标(默认72 个) int nLen = SafePrintf( //注意看这句,利用构造函数中的种子名字 m_szFileName, //加上时间戳,后面再加上“.log”后缀 FILENAME_STRING_LENGTH * 2, //生成日志文件名 "%s_%s.log", m_szFilePath, szTemp); nLen++; //习惯,长度+1,保留最后’\0’的位置 //将新的文件名添加到队列 int nAddLastRet = m_pFileInfoQueue->AddLast(m_szFileName, nLen); if (0 >= nAddLastRet) { //这是一个特殊的防护,如果队列满了(内存不够用),删除最开始三个文件名 //释放内存空间,这是预防服务器业务太繁忙,导致内存不够用,队列无法添加的 //规避措施,这也体现非关键模块为关键业务模块让路的思维 DeleteFirstFile(); DeleteFirstFile(); DeleteFirstFile(); //删除三个之后,重新尝试添加 nAddLastRet = m_pFileInfoQueue->AddLast(m_szFileName, nLen); //如果此时添加仍然失败,投降,日志发生一点错乱没有关系。 } m_nFileSize = 0; //新文件创建,文件长度为0 //下面逻辑,新创建一个文件,在文件头先打印一点文件名相关信息,帮助以后的跟踪查找 time (&m_tFileNameMake); { //由于这是非业务打印,因此不希望输出到屏幕,这里临时将屏幕开关关闭 bool bPrint2Scr = m_bPrintf2ScrFlag; m_bPrintf2ScrFlag = false; _Printf("Tony.Xiao. base libeary log file %s\n", m_szFileName); _Printf("-----------------------------------------------\n"); m_bPrintf2ScrFlag = bPrint2Scr; //输出完毕,屏幕开关恢复原值 } }
//输出格式 //0000 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 xxxxxxxxxxxxxxxx //以ASCII 方式显示数据内容 int dbg_bin_ascii(char* pPrintBuffer, char* pBuffer, int nLength) { //内部函数,只有笔者本人的函数调用的函数,一般不写防御性设计,保持简洁。 int i; int nCount = 0; for (i = 0; i < nLength; i++) //请关注for 的写法,笔者所有的for 都是这个模式 { //ASCII 字符表中,可显示字符代码>32 if (32 <= *(pBuffer + i)) //请关注常量写左边 nCount += SafePrintf(pPrintBuffer + nCount, 256, "%c", *(pBuffer + i)); else //不可显示字符以”.”代替占位,保持格式整齐,且避免出错 nCount += SafePrintf(pPrintBuffer + nCount, 256, "."); //如果指定的内容不是可以显示的ASCII 字符,显示’.’ } return nCount; }
int CTonyXiaoLog::_Printf(char *szFormat, ...) { char szTime[LOG_ITEM_LENGTH_MAX]; char szTemp[LOG_ITEM_LENGTH_MAX]; char szBuf[LOG_ITEM_LENGTH_MAX]; int nMaxLength = LOG_ITEM_LENGTH_MAX; int nListCount = 0; time_t t; struct tm *pTM = NULL; int nLength = 0; //获得当前时间戳,这在MakeATimeString 中已经有介绍 time(&t); pTM = localtime(&t); nLength = SafePrintf(szTemp, LOG_ITEM_LENGTH_MAX, "%s", asctime(pTM)); szTemp[nLength - 1] = '\0'; SafePrintf(szTime, LOG_ITEM_LENGTH_MAX, "[%s] ", szTemp); //这段比较经典,变参函数处理模块,不再赘述 va_list pArgList; va_start(pArgList, szFormat); nListCount += Linux_Win_vsnprintf(szBuf + nListCount, nMaxLength - nListCount, szFormat, pArgList); va_end(pArgList); if (nListCount > (nMaxLength - 1)) nListCount = nMaxLength - 1; *(szBuf + nListCount) = '\0'; //得到当前使用的文件名 GetFileName(); //调用debug 的功能函数,直接将信息输出到文件 nListCount = dbg2file(m_szFileName, "a+", "%s%s", szTime, szBuf); if (m_bPrintf2ScrFlag) //如果屏幕输出开关打来 { TONY_XIAO_PRINTF("%s%s", szTime, szBuf); //输出到屏幕 } if (m_pInfoOutCallback) //如果拦截函数存在 { //输出到拦截函数 char szInfoOut[APP_INFO_OIT_STRING_MAX]; SafePrintf(szInfoOut, APP_INFO_OIT_STRING_MAX, "%s%s", szTime, szBuf); m_pInfoOutCallback(szInfoOut, m_pInfoOutCallbackParam); } m_nFileSize += nListCount; //这里很重要,修订文件长度 //维护模块需要这个值判定文件大小 //是否超标 return nListCount; //返回输出的字节数 }
int CNEOLog::_Printf(const char *szFormat,...) { char szTime[LOG_ITEM_LENGTH_MAX] = {"\0"}; char szTemp[LOG_ITEM_LENGTH_MAX] = {"\0"}; char szBuf[LOG_ITEM_LENGTH_MAX] = {"\0"}; int nMaxLength=LOG_ITEM_LENGTH_MAX; int nListCount=0; time_t t; struct tm *pTM=NULL; int nLength=0; time(&t); pTM=localtime(&t); nLength=SafePrintf(szTemp,LOG_ITEM_LENGTH_MAX,"%s",asctime(pTM)); szTemp[nLength-1]='\0'; SafePrintf(szTime,LOG_ITEM_LENGTH_MAX,"[%s]",szTemp); va_list pArgList; va_start(pArgList,szFormat); nListCount+=WIN_LINUX_vsnprintf(szBuf+nListCount,nMaxLength-nListCount,szFormat,pArgList); va_end(pArgList); if(nListCount>(nMaxLength-1)) nListCount=nMaxLength-1; *(szBuf+nListCount)='\0'; //得到当前的文件名 GetFileName(); //将信息输出到文件 nListCount=OutputFileOrScreen(m_szFileName,"a+","%s%s",szTime,szBuf); if(m_bPrintfToScrFlag) { NEO_PRINTF("%s%s",szTime,szBuf); } if(m_pInfoOutCallback) { char szInfoOut[APP_INFO_OIT_STRING_MAX]; SafePrintf(szInfoOut,APP_INFO_OIT_STRING_MAX,"%s%s",szTime,szBuf); m_pInfoOutCallback(szInfoOut,m_pInfoOutCallbackParam); } m_nFileSize+=nListCount; return nListCount; }
//向指定的缓冲区输出一个时间戳字符串 //szBuf: 用户指定的输出缓冲区 //nMaxLength:用户指定的输出缓冲区尺寸 //返回输出的字符总数(strlen 的长度,不包括最后的’\0’) int GetATimeStamp(char* szBuf, int nMaxLength) { time_t t; struct tm *pTM = NULL; int nLength = 0; time(&t); pTM = localtime(&t); nLength = SafePrintf(szBuf, nMaxLength, "%s", asctime(pTM)); //这里是个重要的技巧,asctime(pTM)产生的字符串最后会自动带上回车符, //这给后面很多的格式化输出带来不便 //此处退格结束字符串,目的是过滤掉这个回车符。 szBuf[nLength - 1] = '\0'; return nLength; }
//带安全锁的类 CNEOMemQueueWithLock::CNEOMemQueueWithLock(CNEOLowDebug *pDebug, CNEOMemPoolWithLock *pMemPool, const char *szAppName, // 应用程序名,代表队列名 int nMaxToken ) { SafeStrcpy(m_szAppName,szAppName,NEO_APPLICATION_NAME_SIZE); m_pMemPool=pMemPool; m_pQueue=new CNEOMemQueue(pDebug,pMemPool,m_szAppName,nMaxToken); if(m_pQueue) { char szNameBuffer[256]; SafePrintf(szNameBuffer,256,"%s::m_pQueue",m_szAppName); m_pMemPool->Register(m_pQueue,szNameBuffer); } }
//申请用来存储数据的内存 int CNEOMemQueue::AddLastToThisToken(SNEOQueueTokenHead *pToken,const char *szData,int nDataLen) { int nRet=0; char szNameBuffer[256]; if(!ICanWork()) goto CNEOMemQueue_AddLastToThisToken_End; //指针不为空,说明存在数据,跳到next指针处 if(!pToken->m_pBuffer) { //如果本Token不包含有效数据,则保存到自己 SafePrintf(szNameBuffer,256,"%s::pToken->m_pBuffer",m_szAppName); //格式化说明文字 pToken->m_pBuffer=(char *)m_pMemPool->Malloc(nDataLen,szNameBuffer);//向内存池申请数据块 if(!pToken->m_pBuffer) { //申请失败 m_pDebug->DebugToFile("%s::AddLastToThisToken():Malloc new Token fail!\n",m_szAppName); goto CNEOMemQueue_AddLastToThisToken_End; } memcpy(pToken->m_pBuffer,szData,nDataLen); //拷贝业务数据到内存块 pToken->m_nDataLen=nDataLen; nRet=nDataLen; m_pLast=pToken; goto CNEOMemQueue_AddLastToThisToken_End; }//if else { //next为空,则在next下面插入 if(!pToken->m_pNext) { //如果下家的链指针为空,就利用GetAToken创建头 pToken->m_pNext=GetAToken(); if(!pToken->m_pNext) { //创建失败报警 m_pDebug->DebugToFile("%s::AddLastToThisToken():malloc pToken->m_pNext fail!!\n",m_szAppName); goto CNEOMemQueue_AddLastToThisToken_End; } } if(pToken->m_pNext)//递归调用 nRet=AddLastToThisToken(pToken->m_pNext,szData,nDataLen); } CNEOMemQueue_AddLastToThisToken_End: return nRet; }
int CNEOLog::MakeATimeString(char *szBuffer,int nBufferSize) { int i=0; time_t t; struct tm *pTM=NULL; int nLength=0; if(LOG_TIME_STRING_MAX>nBufferSize) goto CNEOLog_MakeATimeString_End; time(&t); pTM=localtime(&t);//生成时间自动带一个;;\0 nLength=SafePrintf(szBuffer,LOG_ITEM_LENGTH_MAX,"%s",asctime(pTM)); szBuffer[nLength-1]='\0'; //过滤空格 for(i=0;i<nLength;i++) { if(' '==szBuffer[i]) szBuffer[i]='_'; if(':'==szBuffer[i]) szBuffer[i]='_'; } CNEOLog_MakeATimeString_End: return nLength; }
//****************这是主入口函数 //以16 字节为一行,格式化输出二进制数据内容。 void dbg2file4bin(char* szFileName, char* szMode, char* pBuffer, int nLength) { int nAddr = 0; int nLineCount = 0; int nBufferCount = nLength; int n = 0; char szLine[256]; //行缓冲 FILE* fp; if (0 < nLength) { while (1) { n = 0; n += SafePrintf(szLine + n, 256 - n, "%p - ", pBuffer + nAddr); nLineCount = 16; if (nBufferCount < nLineCount) nLineCount = nBufferCount; n += dbg_bin_hex(szLine + n, pBuffer + nAddr, nLineCount); n += dbg_bin_ascii(szLine + n, pBuffer + nAddr, nLineCount); fp = fopen(szFileName, szMode); if (fp) { fprintf(fp, "%s\n", szLine); //文件打印 //CON_PRINTF("[%s] %s", szTime, szBuf); //屏幕打印 fclose(fp); } nAddr += 16; nBufferCount -= 16; if (0 >= nBufferCount) break; } fp = fopen(szFileName, szMode); if (fp) { fprintf(fp, "\n"); //文件打印 fclose(fp); } } else CON_PRINTF("dbg_bin error length=%d\n", nLength); }
int CTonyXiaoLog::MakeATimeString(char* szBuffer, int nBufferSize) { int i = 0; time_t t; struct tm *pTM = NULL; int nLength = 0; if (LOG_TIME_STRING_MAX > nBufferSize) //防御性设计 goto CTonyXiaoLog_MakeATimeString_End_Porcess; time(&t); //获得当前时间 pTM = localtime(&t); //或当当前时区的时间戳字符串 nLength = SafePrintf(szBuffer, LOG_ITEM_LENGTH_MAX, "%s", asctime(pTM)); //时间戳字符串入缓冲区 //localtime 生成的字符串最后自带一个’\n’,即回车符,这不利于后续的打印 //因此下面这行向前退一格,清除掉这个回车符。这是一个小经验。 szBuffer[nLength - 1] = '\0'; //文件名有一定限制,一般不要有空格,’:’字符,这里过滤一下, //将时间戳中的非法字符都改变成各系统都能接受的’_’下划线 for (i = 0; i < nLength; i++) { if (' ' == szBuffer[i]) szBuffer[i] = '_'; if (':' == szBuffer[i]) szBuffer[i] = '_'; } CTonyXiaoLog_MakeATimeString_End_Porcess: return nLength; //返回总长度 }
//队列数据从磁盘读出 int CNEOMemQueue::ReadFromFile(const char *szFileName) { FILE *fp=NULL; int n=0; int i=0; int nReadTokenCount=0; int nDataLen=0; char *pTempBuffer=NULL; char szNameBuffer[256]; if(!ICanWork()) goto CNEOMemQueue_ReadFromFile_End; SafePrintf(szNameBuffer,256,"%s::ReadFromFile::pTempBuffer",m_szAppName);////////////////////////////???? pTempBuffer=(char *)m_pMemPool->Malloc(1,szNameBuffer); fp=fopen(szFileName,"rb"); if(!fp) goto CNEOMemQueue_ReadFromFile_End; n=fread((void*)&nReadTokenCount,sizeof(int),1,fp); if(1>n) { m_pDebug->DebugToFile("%s::ReadFromFile():Read token count fail!\n",m_szAppName); goto CNEOMemQueue_ReadFromFile_End; } for(i=0;i<nReadTokenCount;i++) { n=fread((void *)&(nDataLen),sizeof(int),1,fp); if(1>n) { m_pDebug->DebugToFile("%s::ReadFromFile():%d/%d,read data len fail!\n",m_szAppName,i,nReadTokenCount); goto CNEOMemQueue_ReadFromFile_End; } if(0>nDataLen) { m_pDebug->DebugToFile("%s::ReadFromFile():%d/%d,nDataLen=%d<0!\n",m_szAppName,i,nReadTokenCount,nDataLen); goto CNEOMemQueue_ReadFromFile_End; } pTempBuffer=(char *)m_pMemPool->ReMalloc(pTempBuffer,nDataLen,false); if(!pTempBuffer) { m_pDebug->DebugToFile("%s::ReadFromFile():remalloc pTempBuffer fail!\n",m_szAppName); goto CNEOMemQueue_ReadFromFile_End; } //开始读入 token 数据 n=fread((void *)pTempBuffer,sizeof(char),nDataLen,fp); if(nDataLen>n) { m_pDebug->DebugToFile("%s::ReadFromFile():read data fail!\n",m_szAppName); goto CNEOMemQueue_ReadFromFile_End; } //读入成功 if(!AddLast(pTempBuffer,nDataLen)) break; } CNEOMemQueue_ReadFromFile_End: if(pTempBuffer) { m_pMemPool->Free(pTempBuffer); pTempBuffer=NULL; } if(fp) { fclose(fp); fp=NULL; } return nReadTokenCount; }
void VDVideoFilterInterlace::GetScriptString(char *buf, int maxlen) { SafePrintf(buf, maxlen, "Config(%d, %d)", mConfig.mbLaceFields, mConfig.mbOddFieldFirst); }
void VDVideoFilterGammaCorrect::GetSettingString(char *buf, int maxlen) { SafePrintf(buf, maxlen, " (%s)", mConfig.mbConvertToLinear ? "to linear" : "to sRGB"); }
void VDVideoFilterGammaCorrect::GetScriptString(char *buf, int maxlen) { SafePrintf(buf, maxlen, "Config(%d)", mConfig.mbConvertToLinear); }
void VDVideoFilterInterlace::GetSettingString(char *buf, int maxlen) { SafePrintf(buf, maxlen, " (%s, %s)", mConfig.mbLaceFields ? "fields" : "frames", mConfig.mbOddFieldFirst ? "BFF" : "TFF"); }