/*************************************************************************** * * * _____ ____ * * | __ \ / __ \ _ _ _____ * * | | \ \ / / \_\ | | | | _ \ * * | | \ \| | | | | | |_| | * * | | | || | | | | | ___/ * * | | / /| | __ | | | | _ \ * * | |__/ / \ \__/ / | |___| | |_| | * * |_____/ \____/ |_____|_|_____/ * * * * Wiimms source code library * * * *************************************************************************** * * * Copyright (c) 2012-2023 by Dirk Clemens * * * *************************************************************************** * * * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * See file gpl-2.0.txt or http://www.gnu.org/licenses/gpl-2.0.txt * * * ***************************************************************************/ #define DCLIB_DEBUG_C 1 #include "dclib-debug.h" #include #include #include #include #include #include #include #include "dclib-basics.h" #include "dclib-file.h" #include "dclib-xdump.h" // /////////////////////////////////////////////////////////////////////////////// /////////////// error messages /////////////// /////////////////////////////////////////////////////////////////////////////// ccp TRACE_PREFIX = ""; FILE *TRACE_FILE = 0; FILE *MEM_LOG_FILE = 0; ccp (*GetErrorNameHook)( int stat, ccp ret_not_found ) = 0; ccp (*GetErrorTextHook)( int stat, ccp ret_not_found ) = 0; ccp GENERIC_ERROR_MESSAGE = "generic err"; /////////////////////////////////////////////////////////////////////////////// ccp GetErrorName ( int stat, // error status, err := abs(stat) ccp ret_not_found // not NULL: return this, if no message is found // GENERIC_ERROR_MESSAGE: return a generic message ) { if (GetErrorNameHook) { ccp res = GetErrorNameHook(stat,0); if ( res && *res ) return res; } if ( stat < 0 ) stat = -stat; switch(stat) { case ERR_OK: return "OK"; case ERR_DIFFER: return "DIFFER"; case ERR_NOTHING_TO_DO: return "NOTHING TO DO"; case ERR_SOURCE_FOUND: return "SOURCE FOUND"; case ERR_NO_SOURCE_FOUND: return "NO SOURCE"; case ERR_JOB_IGNORED: return "JOB IGNORED"; case ERR_SUBJOB_WARNING: return "SUB JOB WARNINGS"; case ERR_NOT_EXISTS: return "NOT EXISTS"; case ERR_WARNING: return "WARNING"; case ERR_WRONG_FILE_TYPE: return "WRONG FILE TYPE"; case ERR_INVALID_FILE: return "INVALID FILE"; case ERR_INVALID_VERSION: return "INVALID VERSION"; case ERR_INVALID_DATA: return "INVALID DATA"; case ERR_ENCODING: return "ENCODING FAILED"; case ERR_DECODING: return "DECODING FAILED"; case ERR_ALREADY_EXISTS: return "FILE ALREADY EXISTS"; case ERR_SUBJOB_FAILED: return "SUB JOB FAILED"; case ERR_CANT_REMOVE: return "CAN'T REMOVE FILE"; case ERR_CANT_RENAME: return "CAN'T RENAME FILE"; case ERR_CANT_CLOSE: return "CAN'T CLOSE FILE"; case ERR_CANT_CONNECT: return "CAN'T CONNECT"; case ERR_FILE_TOO_BIG: return "FILE TOO BIG"; case ERR_CANT_OPEN: return "CAN'T OPEN FILE"; case ERR_CANT_APPEND: return "CAN'T APPEND FILE"; case ERR_CANT_CREATE: return "CAN'T CREATE FILE"; case ERR_CANT_CREATE_DIR: return "CAN'T CREATE DIRECTORY"; case ERR_READ_FAILED: return "READ FILE FAILED"; case ERR_REMOVE_FAILED: return "REMOVE FILE FAILED"; case ERR_WRITE_FAILED: return "WRITE FILE FAILED"; case ERR_DATABASE: return "DATABASE ACCESS FAILED"; case ERR_MISSING_PARAM: return "MISSING PARAMETERS"; case ERR_SEMANTIC: return "SEMANTIC ERROR"; case ERR_SYNTAX: return "SYNTAX ERROR"; case ERR_INTERRUPT: return "INTERRUPT"; case ERR_ERROR: return "ERROR"; case ERR_NOT_IMPLEMENTED: return "NOT IMPLEMENTED YET"; case ERR_INTERNAL: return "INTERNAL ERROR"; case ERR_OUT_OF_MEMORY: return "OUT OF MEMORY"; case ERR_FATAL: return "FATAL ERROR"; } if ( ret_not_found != GENERIC_ERROR_MESSAGE ) return ret_not_found; //--- generic messages if (GetErrorNameHook) { ccp res = GetErrorNameHook(stat,GENERIC_ERROR_MESSAGE); if ( res && *res ) return res; } if ( stat >= ERU_WARN_00 & stat <= ERU_WARN_XX ) { const uint buf_size = 20; char *buf = GetCircBuf(buf_size); snprintf(buf,buf_size,"USER WARNING #%02u", stat - ERU_WARN_00 ); return buf; } if ( stat >= ERU_ERROR1_00 & stat <= ERU_ERROR1_XX ) { const uint buf_size = 20; char *buf = GetCircBuf(buf_size); snprintf(buf,buf_size,"USER ERROR #%02u", stat - ERU_ERROR1_00 ); return buf; } if ( stat >= ERU_ERROR2_00 & stat <= ERU_ERROR2_XX ) { const uint buf_size = 20; char *buf = GetCircBuf(buf_size); snprintf(buf,buf_size,"USER ERROR #%02u", stat - ERU_ERROR2_00 + ERU_ERROR1_XX+1 - ERU_ERROR1_00 ); return buf; } if ( stat >= ERU_FATAL_00 & stat <= ERU_FATAL_XX ) { const uint buf_size = 24; char *buf = GetCircBuf(buf_size); snprintf(buf,buf_size,"USER FATAL ERROR #%02u", stat - ERU_FATAL_00 ); return buf; } ccp res = GetErrorName(stat+1,""); return res && *res ? res : "?"; } /////////////////////////////////////////////////////////////////////////////// ccp GetErrorText ( int stat, // error status, err := abs(stat) ccp ret_not_found // not NULL: return this, if no message is found // GENERIC_ERROR_MESSAGE: return a generic message ) { if (GetErrorTextHook) { ccp res = GetErrorTextHook(stat,0); if (res) return res; } if ( stat < 0 ) stat = -stat; switch(stat) { case ERR_OK: return "Ok"; case ERR_DIFFER: return "Files differ"; case ERR_NOTHING_TO_DO: return "Nothing to do"; case ERR_SOURCE_FOUND: return "Source found"; case ERR_NO_SOURCE_FOUND: return "No source found"; case ERR_JOB_IGNORED: return "Job ignored"; case ERR_SUBJOB_WARNING: return "Sub job had warnings"; case ERR_NOT_EXISTS: return "File does not exists"; case ERR_WARNING: return "Unspecific warning"; case ERR_WRONG_FILE_TYPE: return "Wrong type of file"; case ERR_INVALID_FILE: return "Invalid file"; case ERR_INVALID_VERSION: return "Invalid file version"; case ERR_INVALID_DATA: return "Invalid data"; case ERR_ENCODING: return "Encoding data failed"; case ERR_DECODING: return "Decoding data failed"; case ERR_ALREADY_EXISTS: return "File already exists"; case ERR_SUBJOB_FAILED: return "Sub job failed"; case ERR_CANT_REMOVE: return "Can't remove file"; case ERR_CANT_RENAME: return "Can't rename file"; case ERR_CANT_CLOSE: return "Can't close file"; case ERR_CANT_CONNECT: return "Can't connect"; case ERR_FILE_TOO_BIG: return "Can't open, because file is too big"; case ERR_CANT_OPEN: return "Can't open file"; case ERR_CANT_APPEND: return "Can't open file for appending"; case ERR_CANT_CREATE: return "Can't create file"; case ERR_CANT_CREATE_DIR: return "Can't create directory"; case ERR_READ_FAILED: return "Reading from file failed"; case ERR_REMOVE_FAILED: return "Removing a file failed"; case ERR_WRITE_FAILED: return "Writing to file failed"; case ERR_DATABASE: return "Access to database failed"; case ERR_MISSING_PARAM: return "Missing at least one parameter"; case ERR_SEMANTIC: return "Semantic error"; case ERR_SYNTAX: return "Syntax error"; case ERR_INTERRUPT: return "Program interrupted by user"; case ERR_ERROR: return "Unspecific error"; case ERR_NOT_IMPLEMENTED: return "Not implemented yet"; case ERR_INTERNAL: return "Internal error"; case ERR_OUT_OF_MEMORY: return "Allocation of dynamic memory failed"; case ERR_FATAL: return "Unspecific fatal error"; } if ( ret_not_found != GENERIC_ERROR_MESSAGE ) return ret_not_found; //--- generic messages if (GetErrorTextHook) { ccp res = GetErrorTextHook(stat,GENERIC_ERROR_MESSAGE); if ( res && *res ) return res; } if ( stat >= ERU_WARN_00 & stat <= ERU_WARN_XX ) { const uint buf_size = 20; char *buf = GetCircBuf(buf_size); snprintf(buf,buf_size,"USER WARNING #%02u", stat - ERU_WARN_00 ); return buf; } if ( stat >= ERU_ERROR1_00 & stat <= ERU_ERROR1_XX ) { const uint buf_size = 20; char *buf = GetCircBuf(buf_size); snprintf(buf,buf_size,"USER ERROR #%02u", stat - ERU_ERROR1_00 ); return buf; } if ( stat >= ERU_ERROR2_00 & stat <= ERU_ERROR2_XX ) { const uint buf_size = 20; char *buf = GetCircBuf(buf_size); snprintf(buf,buf_size,"USER ERROR #%02u", stat - ERU_ERROR2_00 + ERU_ERROR1_XX+1 - ERU_ERROR1_00 ); return buf; } if ( stat >= ERU_FATAL_00 & stat <= ERU_FATAL_XX ) { const uint buf_size = 24; char *buf = GetCircBuf(buf_size); snprintf(buf,buf_size,"USER FATAL ERROR #%02u", stat - ERU_FATAL_00 ); return buf; } ccp res = GetErrorText(stat+1,0); return res && *res ? res : "?"; } /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// void ListErrorCodes ( FILE * f, // valid output stream int indent, // indent of output bool all // true: print all user reserved messages too. ) { if (!f) return; indent = NormalizeIndent(indent); fprintf(f,"\n%*sList of error messages:\n\n",indent,""); ccp p2 = all ? 0 : ""; uint i, fw_name = 4, fw_text = 7; for ( i = 0; i < ERR__N; i++ ) { ccp name = GetErrorName(i,p2); if (name) { const uint len = strlen(name); if ( fw_name < len ) fw_name = len; } ccp text = GetErrorText(i,p2); { const uint len = strlen(text); if ( fw_text < len ) fw_text = len; } } fprintf(f, "%*s err | %-*s | %-*s\n" "%*s-----+%.*s+%.*s\n", indent, "", fw_name, "name", fw_text, "message", indent, "", fw_name+2, Minus300, fw_text+2, Minus300 ); for ( i = 0; i < ERR__N; i++ ) { ccp name = GetErrorName(i,p2); ccp text = GetErrorText(i,p2); if ( name && *name || text && *text ) fprintf(f,"%*s%4u | %-*s | %-*s\n", indent, "", i, fw_name, name ? name : "-", fw_text, text ? text : "-" ); if ( i == ERR_OK || i == ERR_WARNING || i == ERR_ERROR ) fprintf(f,"%*s-----+%.*s+%.*s\n", indent, "", fw_name+2, Minus300, fw_text+2, Minus300 ); } fprintf(f,"%*s-----+%.*s+%.*s\n\n", indent, "", fw_name+2, Minus300, fw_text+2, Minus300 ); } // /////////////////////////////////////////////////////////////////////////////// /////////////// error handling /////////////// /////////////////////////////////////////////////////////////////////////////// #ifdef EXTENDED_ERRORS ProgInfo_t ProgInfo = { .error_level = ERRLEV_EXTENDED }; #else ProgInfo_t ProgInfo = { .error_level = ERRLEV_MINIMAL }; #endif /////////////////////////////////////////////////////////////////////////////// enumError PrintError ( ccp func, ccp file, uint line, int syserr, enumError err_code, ccp format, ... ) { va_list arg; va_start(arg,format); const int stat = PrintErrorArg(func,file,line,syserr,err_code,format,arg); va_end(arg); return stat; } /////////////////////////////////////////////////////////////////////////////// enumError PrintErrorFile ( ccp func, ccp file, uint line, struct File_t *F, int syserr, enumError err_code, ccp format, ... ) { va_list arg; va_start(arg,format); const int stat = PrintErrorArg(func,file,line,syserr,err_code,format,arg); va_end(arg); return F ? RegisterFileError(F,stat) : stat; } /////////////////////////////////////////////////////////////////////////////// enumError PrintErrorArg ( ccp func, ccp file, unsigned int line, int syserr, enumError err_code, ccp format, va_list arg ) { if ( err_code > ERR_OK ) { ProgInfo.error_count++; ProgInfo.last_error = err_code; if ( ProgInfo.max_error < err_code ) ProgInfo.max_error = err_code; } fflush(stdout); if (!stdwrn) { SetupStdMsg(); if (!stdwrn) { stdwrn = stderr; if (!stdwrn) return err_code; } } char msg[1000]; if (!ProgInfo.progname) ProgInfo.progname = "?"; const int plen = strlen(ProgInfo.progname)+2; if ( !format && err_code > ERR_NOT_IMPLEMENTED ) format = "Program is aborted immediately!"; if (format) { vsnprintf(msg,sizeof(msg),format,arg); msg[sizeof(msg)-2] = 0; const int mlen = strlen(msg); if ( mlen > 0 && msg[mlen-1] != '\n' ) { msg[mlen] = '\n'; msg[mlen+1] = 0; } } else StringCat2S(msg,sizeof(msg),GetErrorText(err_code,0),"\n"); ccp prefix = err_code == ERR_OK ? "" : err_code <= ERR_WARNING ? "! " : "!! "; const int fw = GetTermWidth(80,40) - 1; #ifdef DEBUG TRACE("%s%s #%d [%s] in %s() @ %s#%d\n", prefix, err_code <= ERR_WARNING ? "WARNING" : "ERROR", err_code, GetErrorName(err_code,0), func, file, line ); TRACE("%s%*s%s",prefix,plen,"",msg); if (syserr) TRACE("!! %s(), ERRNO=%d: %s\n",__FUNCTION__,syserr,strerror(syserr)); fflush(TRACE_FILE); #endif ccp coln, col1, col0; if (IsFileColorized(stdwrn)) { coln = GetTextMode(1,TTM_COL_INFO); col1 = GetTextMode(1, err_code > ERR_WARNING ? TTM_COL_WARN : TTM_COL_HINT ); col0 = TermTextModeReset; } else coln = col1 = col0 = EmptyString; if ( err_code >= ERR_NOT_IMPLEMENTED || ProgInfo.error_level >= ERRLEV_HEADING && err_code > ERR_WARNING ) { if ( err_code >= ERR_NOT_IMPLEMENTED || ProgInfo.error_level >= ERRLEV_EXTENDED ) { if ( err_code > ERR_WARNING ) fprintf(stdwrn,"%s%s%s:%s ERROR #%d [%s] in %s() @ %s#%d%s\n", prefix, coln, ProgInfo.progname, col1, err_code, GetErrorName(err_code,0), func, file, line, col0 ); else fprintf(stdwrn,"%s%s%s:%s WARNING in %s() @ %s#%d%s\n", prefix, coln, ProgInfo.progname, col1, func, file, line, col0 ); } else { if ( err_code > ERR_WARNING ) fprintf(stdwrn,"%s%s%s:%s ERROR #%d [%s]%s\n", prefix, coln, ProgInfo.progname, col1, err_code, GetErrorName(err_code,0), col0 ); else fprintf(stdwrn,"%s%s%s:%s WARNING%s\n", prefix, coln, ProgInfo.progname, col1, col0 ); } if ( ProgInfo.error_level >= ERRLEV_ANNOTATE ) { #ifdef SVN_NEXT fprintf(stdwrn,"%s -> %s/%s?annotate=%d#l%d\n", prefix, URI_VIEWVC, file, SVN_NEXT, line ); #elif defined(REVISION_NEXT) fprintf(stdwrn,"%s -> %s/%s?annotate=%d#l%d\n", prefix, URI_VIEWVC, file, REVISION_NEXT, line ); #endif } fputs(prefix,stdwrn); PutLines(stdwrn,plen,fw,0,prefix,msg,0); } else { fprintf(stdwrn,"%s%s%s:%s",prefix,coln,ProgInfo.progname,col0); PutLines(stdwrn,plen,fw,strlen(ProgInfo.progname)+1,prefix,msg,0); } if (syserr) { fprintf(stdwrn,"%s%*s-> ",prefix,plen,""); snprintf(msg,sizeof(msg),"%s [%d]",strerror(syserr),syserr); PutLines(stdwrn,plen+3,fw,plen+3,prefix,msg,0); } fflush(stdwrn); if ( err_code > ERR_NOT_IMPLEMENTED ) exit(err_code); return err_code; } /////////////////////////////////////////////////////////////////////////////// enumError PrintErrorStat ( enumError err, int verbose, ccp cmdname ) { if ( verbose > 0 && err >= ERR_WARNING || verbose > 1 && err || err == ERR_NOT_IMPLEMENTED ) { if (!stdwrn) { SetupStdMsg(); if (!stdwrn) { stdwrn = stderr; if (!stdwrn) return err; } } fprintf(stdwrn,"%s: Command '%s' returns with status #%d [%s]\n", ProgInfo.progname, cmdname, err, GetErrorName(err,0) ); } return err; } /////////////////////////////////////////////////////////////////////////////// bool mark_used ( ccp name, ... ) { return true; } /////////////////////////////////////////////////////////////////////////////// #if HAVE_PRINT #undef PRINT_TIME void PRINT_TIME ( time_t time, ccp title ) { struct tm utc, loc; gmtime_r(&time,&utc); localtime_r(&time,&loc); PRINT( "%s: UTC= %4u-%02u-%02u %2u:%02u:%02u dst=%d" " LOCAL= %4u-%02u-%02u %2u:%02u:%02u dst=%d\n", title ? title : "TIME", utc.tm_year+1900, utc.tm_mon+1, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec, utc.tm_isdst, loc.tm_year+1900, loc.tm_mon+1, loc.tm_mday, loc.tm_hour, loc.tm_min, loc.tm_sec, loc.tm_isdst ); } #endif // /////////////////////////////////////////////////////////////////////////////// /////////////// hexdump /////////////// /////////////////////////////////////////////////////////////////////////////// uint HexDump ( FILE * f, int indent, u64 addr, int addr_fw, int row_len, const void * p_data, size_t count ) { // return the number of printed lines if ( !f || !p_data || !count ) return 0; XDump_t xd; InitializeXDumpEx(&xd,f,indent,addr,addr_fw,row_len); const int stat = XDump(&xd,p_data,count,true); return stat < 0 ? 0 : stat; } //----------------------------------------------------------------------------- uint HexDump16 ( FILE * f, int indent, u64 addr, const void * data, size_t count ) { // return the number of printed lines return HexDump(f,indent,addr,4,16,data,count); } //----------------------------------------------------------------------------- uint HexDump20 ( FILE * f, int indent, u64 addr, const void * data, size_t count ) { // return the number of printed lines return HexDump(f,indent,addr,4,20,data,count); } /////////////////////////////////////////////////////////////////////////////// uint HexDumpCRLF ( FILE * f, int indent, u64 addr, int addr_fw, int row_len, const void * p_data, size_t count ) { const typeof(hexdump_eol)saved_eol = hexdump_eol; hexdump_eol = "\r\n"; const uint stat = HexDump(f,indent,addr,addr_fw,row_len,p_data,count); hexdump_eol = saved_eol; return stat; } //----------------------------------------------------------------------------- uint HexDump16CRLF ( FILE * f, int indent, u64 addr, const void * data, size_t count ) { // return the number of printed lines return HexDumpCRLF(f,indent,addr,4,16,data,count); } //----------------------------------------------------------------------------- uint HexDump20CRLF ( FILE * f, int indent, u64 addr, const void * data, size_t count ) { // return the number of printed lines return HexDumpCRLF(f,indent,addr,4,20,data,count); } /////////////////////////////////////////////////////////////////////////////// uint HexDump16BE2 ( FILE * f, int indent, u64 addr, const void * data, size_t count ) { // return the number of printed lines return HexDumpBE2(f,indent,addr,4,16,data,count); } //----------------------------------------------------------------------------- uint HexDump20BE2 ( FILE * f, int indent, u64 addr, const void * data, size_t count ) { // return the number of printed lines return HexDumpBE2(f,indent,addr,4,20,data,count); } //----------------------------------------------------------------------------- uint HexDumpBE2 ( FILE * f, int indent, u64 addr, int addr_fw, int row_len, const void * p_data, size_t count ) { // return the number of printed lines if ( !f || !p_data || !count ) return 0; XDump_t xd; InitializeXDumpEx(&xd,f,indent,addr,addr_fw,row_len); xd.format = XDUMPF_INT_2; xd.endian = DC_BIG_ENDIAN; const int stat = XDump(&xd,p_data,count,true); return stat < 0 ? 0 : stat; } /////////////////////////////////////////////////////////////////////////////// uint HexDump16LE2 ( FILE * f, int indent, u64 addr, const void * data, size_t count ) { // return the number of printed lines return HexDumpLE2(f,indent,addr,4,16,data,count); } //----------------------------------------------------------------------------- uint HexDump20LE2 ( FILE * f, int indent, u64 addr, const void * data, size_t count ) { // return the number of printed lines return HexDumpLE2(f,indent,addr,4,20,data,count); } //----------------------------------------------------------------------------- uint HexDumpLE2 ( FILE * f, int indent, u64 addr, int addr_fw, int row_len, const void * p_data, size_t count ) { // return the number of printed lines if ( !f || !p_data || !count ) return 0; XDump_t xd; InitializeXDumpEx(&xd,f,indent,addr,addr_fw,row_len); xd.format = XDUMPF_INT_2; xd.endian = DC_LITTLE_ENDIAN; const int stat = XDump(&xd,p_data,count,true); return stat < 0 ? 0 : stat; } /////////////////////////////////////////////////////////////////////////////// uint HexDump16BE4 ( FILE * f, int indent, u64 addr, const void * data, size_t count ) { // return the number of printed lines return HexDumpBE4(f,indent,addr,4,16,data,count); } //----------------------------------------------------------------------------- uint HexDump20BE4 ( FILE * f, int indent, u64 addr, const void * data, size_t count ) { // return the number of printed lines return HexDumpBE4(f,indent,addr,4,20,data,count); } //----------------------------------------------------------------------------- uint HexDumpBE4 ( FILE * f, int indent, u64 addr, int addr_fw, int row_len, const void * p_data, size_t count ) { // return the number of printed lines if ( !f || !p_data || !count ) return 0; XDump_t xd; InitializeXDumpEx(&xd,f,indent,addr,addr_fw,row_len); xd.format = XDUMPF_INT_4; xd.endian = DC_BIG_ENDIAN; const int stat = XDump(&xd,p_data,count,true); return stat < 0 ? 0 : stat; } /////////////////////////////////////////////////////////////////////////////// uint HexDump16LE4 ( FILE * f, int indent, u64 addr, const void * data, size_t count ) { // return the number of printed lines return HexDumpLE4(f,indent,addr,4,16,data,count); } //----------------------------------------------------------------------------- uint HexDump20LE4 ( FILE * f, int indent, u64 addr, const void * data, size_t count ) { // return the number of printed lines return HexDumpLE4(f,indent,addr,4,20,data,count); } //----------------------------------------------------------------------------- uint HexDumpLE4 ( FILE * f, int indent, u64 addr, int addr_fw, int row_len, const void * p_data, size_t count ) { // return the number of printed lines if ( !f || !p_data || !count ) return 0; XDump_t xd; InitializeXDumpEx(&xd,f,indent,addr,addr_fw,row_len); xd.format = XDUMPF_INT_4; xd.endian = DC_LITTLE_ENDIAN; const int stat = XDump(&xd,p_data,count,true); return stat < 0 ? 0 : stat; } /////////////////////////////////////////////////////////////////////////////// uint HexDump016 ( FILE * f, int indent, u64 addr, const void * data, size_t count ) { // return the number of printed lines return HexDump0(f,indent,addr,4,16,data,count); } //----------------------------------------------------------------------------- uint HexDump0 ( FILE * f, int indent, u64 addr, int addr_fw, int row_len, const void * p_data, size_t count ) { // return the number of printed lines if ( !f || !p_data || !count ) return 0; XDump_t xd; InitializeXDumpEx(&xd,f,indent,addr,addr_fw,row_len); xd.mode_ignore = true; const int stat = XDump(&xd,p_data,count,true); return stat < 0 ? 0 : stat; } /////////////////////////////////////////////////////////////////////////////// void HexDiff16 ( FILE * f, int indent, u64 addr, const void * data1, size_t count1, const void * data2, size_t count2 ) { HexDiff(f,indent,addr,4,16,data1,count1,data2,count2); } //----------------------------------------------------------------------------- void HexDiff ( FILE * f, int indent, u64 addr, int addr_fw, int row_len, const void * p_data1, size_t count1, const void * p_data2, size_t count2 ) { if (!f) return; XDump_t xd; InitializeXDumpEx(&xd,f,indent,addr,addr_fw,row_len); XDiff(&xd, p_data1,count1,true, p_data2,count2,true, 0,false ); return; } // /////////////////////////////////////////////////////////////////////////////// /////////////// trace functions /////////////// /////////////////////////////////////////////////////////////////////////////// static void trace_helper ( int print_stderr, ccp format, va_list arg ) { static uint last_day = 0; DayTime_t dt = GetDayTime(false); if (!TRACE_FILE) { char extend[16]; if (ProgInfo.multi_processing) snprintf(extend,sizeof(extend),"-%u",getpid()); else *extend = 0; char fname[1000]; if ( ProgInfo.progname && *ProgInfo.progname && *ProgInfo.progname != '?' ) snprintf( fname, sizeof(fname), "_trace-%s%s.tmp", ProgInfo.progname, extend ); else snprintf( fname, sizeof(fname), "_trace-%s.tmp", extend ); TRACE_FILE = fopen(fname,"wb"); if (TRACE_FILE) { fcntl(fileno(TRACE_FILE),F_SETFD,FD_CLOEXEC); fprintf(TRACE_FILE,"\n#\f\n#OPEN %s, pid=%d\n\n", PrintTimeByFormat("%F %T %z",dt.time), getpid() ); } else TRACE_FILE = stderr; last_day = dt.day; } char pre[200]; if ( last_day != dt.day ) { SetupTimezone(true); dt = GetDayTime(false); last_day = dt.day; snprintf(pre,sizeof(pre), "\n#DAY: %s, pid=%d\n%02u:%02u:%02u.%03u ", PrintTimeByFormat("%F %T %z",dt.time), getpid(), dt.hour, dt.min, dt.sec, dt.usec/1000 ); } else snprintf(pre,sizeof(pre),"%02u:%02u:%02u.%03u ", dt.hour, dt.min, dt.sec, dt.usec/1000 ); if ( print_stderr || TRACE_FILE == stderr ) { fflush(stdout); fputs(pre,stderr); fputs(TRACE_PREFIX,stderr); va_list arg2; va_copy(arg2,arg); vfprintf(stderr,format,arg2); va_end(arg2); fflush(stderr); } if ( TRACE_FILE && TRACE_FILE != stderr ) { fputs(pre,TRACE_FILE); fputs(TRACE_PREFIX,TRACE_FILE); vfprintf(TRACE_FILE,format,arg); fflush(TRACE_FILE); } } /////////////////////////////////////////////////////////////////////////////// #undef TRACE_ARG_FUNC void TRACE_ARG_FUNC ( ccp format, va_list arg ) { trace_helper(0,format,arg); } /////////////////////////////////////////////////////////////////////////////// #undef TRACE_FUNC void TRACE_FUNC ( ccp format, ... ) { va_list arg; va_start(arg,format); trace_helper(0,format,arg); va_end(arg); } /////////////////////////////////////////////////////////////////////////////// #undef PRINT_ARG_FUNC void PRINT_ARG_FUNC ( ccp format, va_list arg ) { trace_helper(1,format,arg); } /////////////////////////////////////////////////////////////////////////////// #undef PRINT_FUNC void PRINT_FUNC ( ccp format, ... ) { va_list arg; va_start(arg,format); trace_helper(1,format,arg); va_end(arg); } /////////////////////////////////////////////////////////////////////////////// #undef BINGO_FUNC void BINGO_FUNC ( ccp func, int line, ccp src ) { #if defined(DEBUG) && defined(TEST) if (colerr) PRINT_FUNC("%sBINGO!%s %s() #%d @ %s\n", colerr->magenta, colerr->reset, func, line, src ); else PRINT_FUNC("BINGO! %s() #%d @ %s\n", func, line, src ); #else if (colerr) fprintf(stderr,"%sBINGO!%s %s() #%d @ %s\n", colerr->magenta, colerr->reset, func, line, src ); else fprintf(stderr,"BINGO! %s() #%d @ %s\n", func, line, src ); #endif } /////////////////////////////////////////////////////////////////////////////// #undef WAIT_ARG_FUNC void WAIT_ARG_FUNC ( ccp format, va_list arg ) { if ( format && *format ) trace_helper(1,format,arg); PRINT_FUNC(">>>>>> PRESS RETURN: "); getchar(); } /////////////////////////////////////////////////////////////////////////////// #undef WAIT_FUNC void WAIT_FUNC ( ccp format, ... ) { va_list arg; va_start(arg,format); WAIT_ARG_FUNC(format,arg); va_end(arg); } // /////////////////////////////////////////////////////////////////////////////// /////////////// alloc/free system /////////////// /////////////////////////////////////////////////////////////////////////////// #if TRACE_ALLOC_MODE > 2 #define MEM_FILLER_SIZE 8 static u8 mem_filler[MEM_FILLER_SIZE]; #else #define MEM_FILLER_SIZE 0 #endif #if TRACE_ALLOC_MODE > 1 #define MPARAM ccp func, ccp file, uint line, #define MCALL func,file,line, #define PRINT_OOM(...) \ PrintError(func,file,line,0,ERR_OUT_OF_MEMORY,__VA_ARGS__) #else #define MPARAM #define MCALL #define PRINT_OOM(...) \ PrintError(__FUNCTION__,__FILE__,__LINE__,0,ERR_OUT_OF_MEMORY,__VA_ARGS__) #endif /////////////////////////////////////////////////////////////////////////////// void dclib_free ( void * ptr ) { free(ptr); } /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// void * dclib_xcalloc ( size_t nmemb, size_t size ) { void * res = calloc(nmemb,size); if (!res) PrintError(__FUNCTION__,__FILE__,__LINE__,0,ERR_OUT_OF_MEMORY, "Out of memory while calloc() %zu bytes (%zu*%zu=0x%zx)\n", nmemb*size, nmemb, size, nmemb*size ); return res; } /////////////////////////////////////////////////////////////////////////////// void * dclib_xmalloc ( size_t size ) { void * res = malloc(size); if (!res) PrintError(__FUNCTION__,__FILE__,__LINE__,0,ERR_OUT_OF_MEMORY, "Out of memory while malloc() %zu bytes (0x%zx)\n", size, size ); return res; } /////////////////////////////////////////////////////////////////////////////// void * dclib_xrealloc ( void * ptr, size_t size ) { void * res = realloc(ptr,size); if ( !res && size ) PrintError(__FUNCTION__,__FILE__,__LINE__,0,ERR_OUT_OF_MEMORY, "Out of memory while realloc() %zu bytes (0x%zx)\n", size, size ); return res; } /////////////////////////////////////////////////////////////////////////////// char * dclib_xstrdup ( ccp src ) { char * res = strdup(src?src:""); if (!res) { const uint size = src ? strlen(src)+1 : 0; PrintError(__FUNCTION__,__FILE__,__LINE__,0,ERR_OUT_OF_MEMORY, "Out of memory while strdup() %u bytes (0x%x)\n", size, size ); } return res; } /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// void * dclib_calloc ( MPARAM size_t nmemb, size_t size ) { void * res = calloc(nmemb,size); if (!res) PRINT_OOM("Out of memory while calloc() %zu bytes (%zu*%zu=0x%zx)\n", nmemb*size, nmemb, size, nmemb*size ); return res; } /////////////////////////////////////////////////////////////////////////////// void * dclib_malloc ( MPARAM size_t size ) { void * res = malloc(size); if (!res) PRINT_OOM("Out of memory while malloc() %zu bytes (0x%zx)\n", size, size ); return res; } /////////////////////////////////////////////////////////////////////////////// void * dclib_realloc ( MPARAM void * ptr, size_t size ) { void * res = realloc(ptr,size); if ( !res && size ) PRINT_OOM("Out of memory while realloc() %zu bytes (0x%zx)\n", size, size ); return res; } /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// char * dclib_strdup ( MPARAM ccp src ) { char * res = strdup(src?src:""); if (!res) { const uint size = src ? strlen(src)+1 : 0; PRINT_OOM("Out of memory while strdup() %u bytes (0x%x)\n", size, size ); } return res; } /////////////////////////////////////////////////////////////////////////////// char * dclib_strdup2 ( MPARAM ccp src1, ccp src2 ) { const uint len1 = src1 ? strlen(src1) : 0; const uint len2 = src2 ? strlen(src2) : 0; char * res = dclib_malloc( MCALL len1+len2+1 ); if (len1) memcpy(res,src1,len1); if (len2) memcpy(res+len1,src2,len2); res[len1+len2] = 0; return res; } /////////////////////////////////////////////////////////////////////////////// char * dclib_strdup3 ( MPARAM ccp src1, ccp src2, ccp src3 ) { const uint len1 = src1 ? strlen(src1) : 0; const uint len2 = src2 ? strlen(src2) : 0; const uint len3 = src3 ? strlen(src3) : 0; char * res = dclib_malloc( MCALL len1+len2+len3+1 ); char * dest = res; if (len1) { memcpy(dest,src1,len1); dest += len1; } if (len2) { memcpy(dest,src2,len2); dest += len2; } if (len3) { memcpy(dest,src3,len3); dest += len3; } *dest = 0; return res; } /////////////////////////////////////////////////////////////////////////////// void * dclib_memdup ( MPARAM const void * src, size_t copylen ) { char * dest = dclib_malloc( MCALL copylen+1); memcpy(dest,src,copylen); dest[copylen] = 0; return dest; } /////////////////////////////////////////////////////////////////////////////// void * dclib_memdup2 ( MPARAM cvp src1, size_t len1, cvp src2, size_t len2 ) { char *res = dclib_malloc( MCALL len1+len2+1); char *dest = res; if (len1) { memcpy(dest,src1,len1); dest += len1; } if (len2) { memcpy(dest,src2,len2); dest += len2; } *dest = 0; return res; } /////////////////////////////////////////////////////////////////////////////// void * dclib_memdup3 ( MPARAM cvp src1, size_t len1, cvp src2, size_t len2, cvp src3, size_t len3 ) { char *res = dclib_malloc( MCALL len1+len2+len3+1); char *dest = res; if (len1) { memcpy(dest,src1,len1); dest += len1; } if (len2) { memcpy(dest,src2,len2); dest += len2; } if (len3) { memcpy(dest,src3,len3); dest += len3; } *dest = 0; return res; } /////////////////////////////////////////////////////////////////////////////// void * dclib_allocdup ( MPARAM const void * src, size_t copylen ) { char * dest = dclib_malloc( MCALL copylen); memcpy(dest,src,copylen); return dest; } /////////////////////////////////////////////////////////////////////////////// char * dclib_printdup ( MPARAM ccp format, ... ) { char buf[2000]; va_list arg; va_start(arg,format); const int stat = vsnprintf(buf,sizeof(buf),format,arg) + 1; va_end(arg); char * dest = dclib_malloc( MCALL stat ); if ( stat <= sizeof(buf) ) memcpy(dest,buf,stat); else { va_start(arg,format); vsnprintf(dest,stat,format,arg); va_end(arg); } return dest; } // /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// #if TRACE_ALLOC_MODE > 2 /////////////////////////////////////////////////////////////////////////////// // [[mem_info_t]] typedef struct mem_info_t { ccp func; ccp file; uint line; u8 * data; uint size; bool filler; uint seqnum; } mem_info_t; //----------------------------------------------------------------------------- static mem_info_t * mem_list = 0; static uint mem_used = 0; static uint mem_size = 0; static uint mem_seqnum = 0; /////////////////////////////////////////////////////////////////////////////// static FILE * OpenMemLog() { static bool done = false; if (!done) { done = true; char fname[500]; if ( ProgInfo.progname && *ProgInfo.progname && *ProgInfo.progname != '?' ) snprintf(fname,sizeof(fname),"_trace_alloc-%s-%u.tmp",ProgInfo.progname,getpid()); else snprintf(fname,sizeof(fname),"_trace_alloc-%u.tmp",getpid()); MEM_LOG_FILE = fopen(fname,"ab"); if (MEM_LOG_FILE) { fcntl(fileno(MEM_LOG_FILE),F_SETFD,FD_CLOEXEC); fprintf(MEM_LOG_FILE,"#\f\n# OPEN FILE %s\n", PrintTimeByFormat("%F %T %z",time(0))); fflush(MEM_LOG_FILE); } } return MEM_LOG_FILE; } /////////////////////////////////////////////////////////////////////////////// static void MemLog ( ccp func, ccp file, uint line, ccp info, const u8 * ptr, bool no_stderr ) { static uint line_no = 0; if (!no_stderr) { fprintf(stderr,"MEM-ERR[%s,%p] %s() @ %s#%u\n", info, ptr, func, file, line ); fflush(stderr); } if (OpenMemLog()) { if (!line_no) fputs("#index addr type function line file\n",MEM_LOG_FILE); fprintf(MEM_LOG_FILE,"%07u %p %s %s %u %s\n", line_no, ptr, info, func, line, file ); fflush(MEM_LOG_FILE); } line_no++; } /////////////////////////////////////////////////////////////////////////////// static void MemLogItem ( ccp func, ccp file, uint line, ccp info, const mem_info_t * mi ) { if (func) fprintf(stderr,"MEM-ERR[%s] %s() @ %s#%u\n", info, func, file, line ); fprintf(stderr,"MEM-ERR[%s,%07u] %s() @ %s#%u\n", info, mi->seqnum, mi->func, mi->file, mi->line ); fflush(stderr); if (OpenMemLog()) { if (func) fprintf(MEM_LOG_FILE,"[%s] %s() @ %s#%u\n", info, func, file, line ); fprintf(MEM_LOG_FILE,"[%s,%07u] %s() @ %s#%u\n", info, mi->seqnum, mi->func, mi->file, mi->line ); if (mi->filler) { HexDump( MEM_LOG_FILE, 8, 0, 7, 16, mi->data - MEM_FILLER_SIZE, 2*MEM_FILLER_SIZE ); HexDump( MEM_LOG_FILE, 8, mi->size + MEM_FILLER_SIZE, 7, 16, mi->data + mi->size - MEM_FILLER_SIZE, 2 * MEM_FILLER_SIZE ); } fputc('\n',MEM_LOG_FILE); fflush(MEM_LOG_FILE); } } /////////////////////////////////////////////////////////////////////////////// uint FindMemInfoHelper ( u8 * data, uint size ) { int beg = 0; int end = mem_used - 1; while ( beg <= end ) { uint idx = (beg+end)/2; mem_info_t * mi = mem_list + idx; if ( data < mi->data ) end = idx - 1 ; else if ( data > mi->data ) beg = idx + 1; else if ( size < mi->size ) end = idx - 1 ; else if ( size > mi->size ) beg = idx + 1; else { noTRACE("FindMemInfoHelper(%llx,%llx) FOUND=%d/%d/%d\n", (u64)off, (u64)size, idx, mem_used, mem_size ); return idx; } } noTRACE("FindStringFieldHelper(%llx,%llx) failed=%d/%d/%d\n", (u64)off, (u64)size, beg, mem_used, mem_size ); return beg; } /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// void InitializeTraceAlloc() { static bool done = false; if (done) return; done = true; OpenMemLog(); memset(mem_filler,0xdc,sizeof(mem_filler)); mem_filler[MEM_FILLER_SIZE/2] = 0xcd; mem_filler[MEM_FILLER_SIZE/3] = 0xcd; } /////////////////////////////////////////////////////////////////////////////// int CheckTraceAlloc ( ccp func, ccp file, uint line ) { int count = 0; mem_info_t *ptr, *end = mem_list + mem_used; for ( ptr = mem_list; ptr < end; ptr++ ) { if (!ptr->filler) continue; if (memcmp(ptr->data-MEM_FILLER_SIZE,mem_filler,sizeof(mem_filler))) { MemLogItem(0,0,0,"BEG",ptr); memcpy(ptr->data-MEM_FILLER_SIZE,mem_filler,sizeof(mem_filler)); count++; } if (memcmp(ptr->data+ptr->size,mem_filler,sizeof(mem_filler))) { MemLogItem(0,0,0,"END",ptr); memcpy(ptr->data+ptr->size,mem_filler,sizeof(mem_filler)); count++; } } if (count) { fprintf(stderr,"MEM-ERR: %u error%s found -> %s() @ %s#%u\n", count, count == 1 ? "" : "s", func, file, line ); fflush(stderr); if (OpenMemLog()) { fprintf(MEM_LOG_FILE,"--- %u errors found -> %s() @ %s#%u\n\n", count, func, file, line ); fflush(MEM_LOG_FILE); } } return count; } /////////////////////////////////////////////////////////////////////////////// void DumpTraceAlloc ( ccp func, ccp file, uint line, FILE * f ) { CheckTraceAlloc(func,file,line); if (!f) return; fprintf(f,"---- MEM-DUMP [N=%u] -----\n",mem_used); mem_info_t *ptr, *end = mem_list + mem_used; for ( ptr = mem_list; ptr < end; ptr++ ) { ccp file = strrchr(ptr->file,'/'); file = file ? file+1 : ptr->file; fprintf(f,"%6u %p %6u %-20.20s %5u %-.25s\n", ptr->seqnum, ptr->data, ptr->size, ptr->func, ptr->line, file ); } fflush(stderr); } /////////////////////////////////////////////////////////////////////////////// mem_info_t * RegisterAlloc ( ccp func, ccp file, uint line, cvp data, uint size, bool filler ) { if (!mem_seqnum) InitializeTraceAlloc(); if (filler) { memcpy((u8*)data-MEM_FILLER_SIZE,mem_filler,MEM_FILLER_SIZE); memcpy((u8*)data+size,mem_filler,MEM_FILLER_SIZE); } uint idx = FindMemInfoHelper((u8*)data,size); ASSERT( mem_used <= mem_size ); if ( mem_used == mem_size ) { mem_size += 1000 + mem_size/2; const uint alloc_size = mem_size * sizeof(*mem_list); mem_list = realloc(mem_list,alloc_size); if (!mem_list) PRINT_OOM("Out of memory while RegisterAlloc() %u bytes (0x%x)\n", alloc_size, alloc_size ); } DASSERT( idx <= mem_used ); mem_info_t * mi = mem_list + idx; memmove(mi+1,mi,(mem_used-idx)*sizeof(*mi)); mem_used++; mi->func = func; mi->file = file; mi->line = line; mi->data = (u8*)data; mi->size = size; mi->filler = filler; mi->seqnum = mem_seqnum++; #if TRACE_ALLOC_MODE > 3 MemLog(func,file,line,"ALLOC",data,true); #endif return mi; } // /////////////////////////////////////////////////////////////////////////////// #endif // TRACE_ALLOC_MODE > 2 /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// uint trace_test_alloc ( ccp func, ccp file, uint line, const void *p_data, bool hexdump ) { #if TRACE_ALLOC_MODE > 2 if (!p_data) return 0; const u8 *data = p_data; int beg = 0; int end = mem_used - 1; while ( beg <= end ) { uint idx = (beg+end)/2; mem_info_t * mi = mem_list + idx; if ( data < mi->data ) end = idx - 1 ; else if ( data > mi->data ) beg = idx + 1; else { #if TRACE_ALLOC_MODE > 3 MemLog(func,file,line,"TEST",data,true); #endif uint stat = 0; if (memcmp(data-MEM_FILLER_SIZE,mem_filler,MEM_FILLER_SIZE)) { MemLogItem(func,file,line,"BEG",mi); stat = 1; HexDump16(stderr,0,0,data-MEM_FILLER_SIZE,16); } if (memcmp(data+mi->size,mem_filler,MEM_FILLER_SIZE)) { MemLogItem(func,file,line,"END",mi); stat |= 2; HexDump16(stderr,0,mi->size+sizeof(mem_filler),data+mi->size,16); } return stat; } } MemLog(func,file,line,"NOT FOUND",data,false); return 4; #else return 0; #endif } /////////////////////////////////////////////////////////////////////////////// static void * UnregisterAlloc ( ccp func, ccp file, uint line, u8 * data ) { #if TRACE_ALLOC_MODE > 2 if (!data) return 0; int beg = 0; int end = mem_used - 1; while ( beg <= end ) { uint idx = (beg+end)/2; mem_info_t * mi = mem_list + idx; if ( data < mi->data ) end = idx - 1 ; else if ( data > mi->data ) beg = idx + 1; else { #if TRACE_ALLOC_MODE > 3 MemLog(func,file,line,"FREE",data,true); #endif if (mi->filler) { if (memcmp(data-MEM_FILLER_SIZE,mem_filler,MEM_FILLER_SIZE)) MemLogItem(func,file,line,"BEG",mi); if (memcmp(data+mi->size,mem_filler,MEM_FILLER_SIZE)) MemLogItem(func,file,line,"END",mi); data -= MEM_FILLER_SIZE; } memmove(mi,mi+1,(--mem_used-idx)*sizeof(*mi)); return data; } } MemLog(func,file,line,"NOT FOUND",data,false); #endif return data; } /////////////////////////////////////////////////////////////////////////////// void trace_free ( ccp func, ccp file, uint line, void * ptr ) { free(UnregisterAlloc(func,file,line,ptr)); } /////////////////////////////////////////////////////////////////////////////// void * trace_malloc ( ccp func, ccp file, uint line, size_t size ) { u8 * res = malloc( size + 2 * MEM_FILLER_SIZE ); if (!res) PRINT_OOM("Out of memory while allocate %zu+%u bytes (0x%zx)\n", size, 2 * MEM_FILLER_SIZE, size + 2 * MEM_FILLER_SIZE ); res += MEM_FILLER_SIZE; #if TRACE_ALLOC_MODE > 2 RegisterAlloc(func,file,line,res,size,true); #endif return res; } /////////////////////////////////////////////////////////////////////////////// void * trace_calloc ( ccp func, ccp file, uint line, size_t nmemb, size_t size ) { uint total_size = nmemb * size; void * res = trace_malloc(func,file,line,total_size); memset(res,0,total_size); return res; } /////////////////////////////////////////////////////////////////////////////// void * trace_realloc ( ccp func, ccp file, uint line, void *ptr, size_t size ) { ptr = UnregisterAlloc(func,file,line,ptr); u8 * res = realloc( ptr, size + 2 * MEM_FILLER_SIZE ); if (!res) PRINT_OOM("Out of memory while re allocate %zu+%u bytes (0x%zx)\n", size, 2 * MEM_FILLER_SIZE, size + 2 * MEM_FILLER_SIZE ); res += MEM_FILLER_SIZE; #if TRACE_ALLOC_MODE > 2 RegisterAlloc(func,file,line,res,size,true); #endif return res; } /////////////////////////////////////////////////////////////////////////////// char * trace_strdup ( ccp func, ccp file, uint line, ccp src ) { const uint len = src ? strlen(src)+1 : 0; char * res = trace_malloc(func,file,line,len); memcpy(res,src,len); return res; } /////////////////////////////////////////////////////////////////////////////// char * trace_strdup2 ( ccp func, ccp file, uint line, ccp src1, ccp src2 ) { const uint len1 = src1 ? strlen(src1) : 0; const uint len2 = src2 ? strlen(src2) : 0; char * res = trace_malloc(func,file,line,len1+len2+1); if (len1) memcpy(res,src1,len1); if (len2) memcpy(res+len1,src2,len2); res[len1+len2] = 0; return res; } /////////////////////////////////////////////////////////////////////////////// char * trace_strdup3 ( ccp func, ccp file, uint line, ccp src1, ccp src2, ccp src3 ) { const uint len1 = src1 ? strlen(src1) : 0; const uint len2 = src2 ? strlen(src2) : 0; const uint len3 = src3 ? strlen(src3) : 0; char * res = trace_malloc(func,file,line,len1+len2+len3+1); char * dest = res; if (len1) { memcpy(dest,src1,len1); dest += len1; } if (len2) { memcpy(dest,src2,len2); dest += len2; } if (len3) { memcpy(dest,src3,len3); dest += len3; } *dest = 0; return res; } /////////////////////////////////////////////////////////////////////////////// void * trace_memdup ( ccp func, ccp file, uint line, const void * src, size_t copylen ) { char * dest = trace_malloc(func,file,line,copylen+1); memcpy(dest,src,copylen); dest[copylen] = 0; return dest; } /////////////////////////////////////////////////////////////////////////////// void * trace_memdup2 ( ccp func, ccp file, uint line, cvp src1, size_t len1, cvp src2, size_t len2 ) { char *res = trace_malloc(func,file,line,len1+len2+1); char *dest = res; if (len1) { memcpy(dest,src1,len1); dest += len1; } if (len2) { memcpy(dest,src2,len2); dest += len2; } *dest = 0; return res; } /////////////////////////////////////////////////////////////////////////////// void * trace_memdup3 ( ccp func, ccp file, uint line, cvp src1, size_t len1, cvp src2, size_t len2, cvp src3, size_t len3 ) { char *res = trace_malloc(func,file,line,len1+len2+len3+1); char *dest = res; if (len1) { memcpy(dest,src1,len1); dest += len1; } if (len2) { memcpy(dest,src2,len2); dest += len2; } if (len3) { memcpy(dest,src3,len3); dest += len3; } *dest = 0; return res; } /////////////////////////////////////////////////////////////////////////////// void * trace_allocdup ( ccp func, ccp file, uint line, const void * src, size_t copylen ) { char * dest = trace_malloc(func,file,line,copylen); memcpy(dest,src,copylen); return dest; } /////////////////////////////////////////////////////////////////////////////// char * trace_printdup ( ccp func, ccp file, uint line, ccp format, ... ) { char buf[2000]; va_list arg; va_start(arg,format); const int stat = vsnprintf(buf,sizeof(buf),format,arg) + 1; va_end(arg); char * dest = trace_malloc(func,file,line,stat); if ( stat <= sizeof(buf) ) memcpy(dest,buf,stat); else { va_start(arg,format); vsnprintf(dest,stat,format,arg); va_end(arg); } return dest; } // /////////////////////////////////////////////////////////////////////////////// /////////////// mem check /////////////// /////////////////////////////////////////////////////////////////////////////// static u8 mem_check_buf[0x100]; static const void * mem_check_ptr = 0; static uint mem_check_size = 0; /////////////////////////////////////////////////////////////////////////////// void MemCheckSetup ( const void * ptr, uint size ) { if ( ptr && size > 0 ) { mem_check_ptr = ptr; if ( size > sizeof(mem_check_buf) ) { ERROR0(ERR_WARNING, "MemCheckSetup(), max watch size = %zx (<%x)", sizeof(mem_check_buf), size ); size = sizeof(mem_check_buf); } mem_check_size = size; memcpy(mem_check_buf,ptr,size); } else mem_check_size = 0; } /////////////////////////////////////////////////////////////////////////////// void MemCheck ( ccp func, ccp file, uint line ) { if (!mem_check_size) return; if ( memcmp(mem_check_buf,mem_check_ptr,mem_check_size) ) { fprintf(stderr,"--- MemCheck: %p should be:\n",mem_check_ptr); HexDump16(stderr,0,0,mem_check_buf,mem_check_size); fprintf(stderr,"--- MemCheck: ... but is:\n"); HexDump16(stderr,0,0,mem_check_ptr,mem_check_size); TRACE("--- MemCheck: %p should be:\n",mem_check_ptr); TRACE_HEXDUMP16(0,0,mem_check_buf,mem_check_size); TRACE("--- MemCheck: ... but is:\n"); TRACE_HEXDUMP16(0,0,mem_check_ptr,mem_check_size); PrintError(func,file,line,0,ERR_FATAL,"MemCheck() failed!\n"); } else TRACE("MemCheck OK: %s @ %s#%u\n",func,file,line); } // /////////////////////////////////////////////////////////////////////////////// /////////////// END /////////////// ///////////////////////////////////////////////////////////////////////////////