/* $Id: ncbi_util.c,v 6.102 2016/07/21 21:29:14 fukanchi Exp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE * National Center for Biotechnology Information * * This software/database is a "United States Government Work" under the * terms of the United States Copyright Act. It was written as part of * the author's official duties as a United States Government employee and * thus cannot be copyrighted. This software/database is freely available * to the public for use. The National Library of Medicine and the U.S. * Government have not placed any restriction on its use or reproduction. * * Although all reasonable efforts have been taken to ensure the accuracy * and reliability of the software and data, the NLM and the U.S. * Government do not and cannot warrant the performance or results that * may be obtained by using this software or data. The NLM and the U.S. * Government disclaim all warranties, express or implied, including * warranties of performance, merchantability or fitness for any particular * purpose. * * Please cite the author in any work or product based on this material. * * =========================================================================== * * Author: Denis Vakatov, Anton Lavrentiev * * File Description: * Auxiliary (optional) code mostly to support "ncbi_core.[ch]" * */ #include "ncbi_ansi_ext.h" #include "ncbi_priv.h" #ifndef NCBI_CXX_TOOLKIT # include # include # include #else # include # include # include # include #endif #if defined(NCBI_OS_UNIX) # ifndef HAVE_GETPWUID # error "HAVE_GETPWUID is undefined on a UNIX system!" # endif /*!HAVE_GETPWUID*/ # ifndef NCBI_OS_SOLARIS # include # endif /*!NCBI_OS_SOLARIS*/ # ifdef __MACH__ # include # elif defined(NCBI_OS_LINUX) # include # endif /*NCBI_OS_LINUX*/ # include # include # include #endif /*NCBI_OS_UNIX*/ #if defined(NCBI_OS_MSWIN) || defined(NCBI_OS_CYGWIN) # define WIN32_LEAN_AND_MEAN # include # include #endif /*NCBI_OS_MSWIN || NCBI_OS_CYGWIN*/ #if defined(PAGE_SIZE) && !defined(NCBI_OS_CYGWIN) # define NCBI_DEFAULT_PAGE_SIZE PAGE_SIZE #else # define NCBI_DEFAULT_PAGE_SIZE 0/*unknown*/ #endif /*PAGE_SIZE && !NCBI_OS_CYGWIN*/ #define NCBI_USE_ERRCODE_X Connect_Util #define NCBI_USE_PRECOMPILED_CRC32_TABLES 1 /****************************************************************************** * MT locking */ extern void CORE_SetLOCK(MT_LOCK lk) { MT_LOCK old_lk = g_CORE_MT_Lock; g_CORE_MT_Lock = lk; g_CORE_Set |= eCORE_SetLOCK; if (old_lk && old_lk != lk) MT_LOCK_Delete(old_lk); } extern MT_LOCK CORE_GetLOCK(void) { return g_CORE_MT_Lock; } /****************************************************************************** * ERROR HANDLING and LOGGING */ extern void CORE_SetLOG(LOG lg) { LOG old_lg; CORE_LOCK_WRITE; old_lg = g_CORE_Log; g_CORE_Log = lg; g_CORE_Set |= eCORE_SetLOG; CORE_UNLOCK; if (old_lg && old_lg != lg) LOG_Delete(old_lg); } extern LOG CORE_GetLOG(void) { return g_CORE_Log; } extern void CORE_SetLOGFILE_Ex (FILE* fp, ELOG_Level cut_off, ELOG_Level fatal_err, int/*bool*/ auto_close ) { LOG lg = LOG_Create(0, 0, 0, 0); LOG_ToFILE_Ex(lg, fp, cut_off, fatal_err, auto_close); CORE_SetLOG(lg); } extern void CORE_SetLOGFILE (FILE* fp, int/*bool*/ auto_close) { CORE_SetLOGFILE_Ex(fp, eLOG_Trace, eLOG_Fatal, auto_close); } extern int/*bool*/ CORE_SetLOGFILE_NAME_Ex (const char* logfile, ELOG_Level cut_off, ELOG_Level fatal_err) { FILE* fp = fopen(logfile, "a"); if (!fp) { CORE_LOGF_ERRNO_X(1, eLOG_Error, errno, ("Cannot open \"%s\"", logfile)); return 0/*false*/; } CORE_SetLOGFILE_Ex(fp, cut_off, fatal_err, 1/*autoclose*/); return 1/*true*/; } extern int/*bool*/ CORE_SetLOGFILE_NAME (const char* logfile ) { return CORE_SetLOGFILE_NAME_Ex(logfile, eLOG_Trace, eLOG_Fatal); } static TLOG_FormatFlags s_LogFormatFlags = fLOG_Default; extern TLOG_FormatFlags CORE_SetLOGFormatFlags(TLOG_FormatFlags flags) { TLOG_FormatFlags old_flags = s_LogFormatFlags; s_LogFormatFlags = flags; return old_flags; } extern size_t UTIL_PrintableStringSize(const char* data, size_t size) { const unsigned char* c; size_t count; if (!data) return 0; if (!size) size = strlen(data); count = size; for (c = (const unsigned char*) data; count; --count, ++c) { if (*c == '\t' || *c == '\v' || *c == '\b' || *c == '\r' || *c == '\f' || *c == '\a' || *c == '\\' || *c == '\'' || *c == '"') { size++; } else if (*c == '\n' || !isascii(*c) || !isprint(*c)) size += 3; } return size; } extern char* UTIL_PrintableString(const char* data, size_t size, char* buf, int/*bool*/ full_octal) { const unsigned char* s; unsigned char* d; if (!data || !buf) return 0; if (!size) size = strlen(data); d = (unsigned char*) buf; for (s = (const unsigned char*) data; size; size--, s++) { switch (*s) { case '\t': *d++ = '\\'; *d++ = 't'; continue; case '\v': *d++ = '\\'; *d++ = 'v'; continue; case '\b': *d++ = '\\'; *d++ = 'b'; continue; case '\r': *d++ = '\\'; *d++ = 'r'; continue; case '\f': *d++ = '\\'; *d++ = 'f'; continue; case '\a': *d++ = '\\'; *d++ = 'a'; continue; case '\n': *d++ = '\\'; *d++ = 'n'; /*FALLTHRU*/ case '\\': case '\'': case '"': *d++ = '\\'; break; default: if (!isascii(*s) || !isprint(*s)) { int/*bool*/ reduce; unsigned char v; if (full_octal) reduce = 0/*false*/; else { reduce = (size == 1 || s[1] < '0' || s[1] > '7' ? 1/*t*/ : 0/*f*/); } *d++ = '\\'; v = *s >> 6; if (v || !reduce) { *d++ = '0' + v; reduce = 0; } v = (*s >> 3) & 7; if (v || !reduce) *d++ = '0' + v; v = *s & 7; *d++ = '0' + v; continue; } break; } *d++ = *s; } return (char*) d; } extern const char* NcbiMessagePlusError (int/*bool*/ *dynamic, const char* message, int error, const char* descr) { int/*bool*/ release; char* buf; size_t mlen; size_t dlen; /* Check for an empty addition */ if (!error && (!descr || !*descr)) { if (message) return message; *dynamic = 0/*false*/; return ""; } /* Adjust description, if necessary and possible */ release = 0/*false*/; if (error > 0 && !descr) { #if defined(NCBI_OS_MSWIN) && defined(_UNICODE) descr = UTIL_TcharToUtf8( _wcserror(error) ); release = 1/*true*/; #else descr = strerror(error); #endif /*NCBI_OS_MSWIN && _UNICODE*/ } if (descr && *descr) { dlen = strlen(descr); while (dlen && isspace((unsigned char) descr[dlen - 1])) dlen--; if (dlen > 1 && descr[dlen - 1] == '.') dlen--; } else { descr = ""; dlen = 0; } mlen = message ? strlen(message) : 0; if (!(buf = (char*)(*dynamic && message ? realloc((void*) message, mlen + dlen + 40) : malloc ( mlen + dlen + 40)))) { if (*dynamic && message) free((void*) message); *dynamic = 0; if (release) UTIL_ReleaseBuffer(descr); return "Ouch! Out of memory"; } if (message) { if (!*dynamic) memcpy(buf, message, mlen); buf[mlen++] = ' '; } memcpy(buf + mlen, "{error=", 7); mlen += 7; if (error) mlen += sprintf(buf + mlen, "%d%s", error, &","[!*descr]); memcpy((char*) memcpy(buf + mlen, descr, dlen) + dlen, "}", 2); if (release) UTIL_ReleaseBuffer(descr); *dynamic = 1/*true*/; return buf; } extern char* LOG_ComposeMessage (const SLOG_Handler* call_data, TLOG_FormatFlags format_flags) { static const char kRawData_Begin[] = "\n#################### [BEGIN] Raw Data (%lu byte%s):\n"; static const char kRawData_End[] = "\n#################### [END] Raw Data\n"; const char *function, *level = 0; char *str, *s, datetime[32]; /* Calculated length of ... */ size_t datetime_len = 0; size_t level_len = 0; size_t module_len = 0; size_t function_len = 0; size_t file_line_len = 0; size_t message_len = 0; size_t data_len = 0; size_t total_len; /* Adjust formatting flags */ if (call_data->level == eLOG_Trace && !(format_flags & fLOG_None)) format_flags |= fLOG_Full; if (format_flags == fLOG_Default) { #if !defined(_DEBUG) || defined(NDEBUG) format_flags = fLOG_Short; #else format_flags = fLOG_Full; #endif /*!_DEBUG || NDEBUG*/ } /* Pre-calculate total message length */ if ((format_flags & fLOG_DateTime) != 0) { #ifdef NCBI_OS_MSWIN /*Should be compiler-dependent but C-Tkit lacks it*/ _strdate(&datetime[datetime_len]); datetime_len += strlen(&datetime[datetime_len]); datetime[datetime_len++] = ' '; _strtime(&datetime[datetime_len]); datetime_len += strlen(&datetime[datetime_len]); datetime[datetime_len++] = ' '; datetime[datetime_len] = '\0'; #else /*NCBI_OS_MSWIN*/ static const char timefmt[] = "%m/%d/%y %H:%M:%S "; struct tm* tm; # ifdef NCBI_CXX_TOOLKIT time_t t = time(0); # ifdef HAVE_LOCALTIME_R struct tm temp; localtime_r(&t, &temp); tm = &temp; # else /*HAVE_LOCALTIME_R*/ tm = localtime(&t); # endif/*HAVE_LOCALTIME_R*/ # else /*NCBI_CXX_TOOLKIT*/ struct tm temp; Nlm_GetDayTime(&temp); tm = &temp; # endif /*NCBI_CXX_TOOLKIT*/ datetime_len = strftime(datetime, sizeof(datetime), timefmt, tm); #endif /*NCBI_OS_MSWIN*/ } if ((format_flags & fLOG_Level) != 0 && (call_data->level != eLOG_Note || !(format_flags & fLOG_OmitNoteLevel))) { level = LOG_LevelStr(call_data->level); level_len = strlen(level) + 2; } if ((format_flags & fLOG_Module) != 0 && call_data->module && *call_data->module) { module_len = strlen(call_data->module) + 3; } if ((format_flags & fLOG_Function) != 0 && call_data->func && *call_data->func) { function = call_data->func; if (!module_len) function_len = 3; function_len += strlen(function) + 2; if (strncmp(function, "::", 2) == 0 && !*(function += 2)) function_len = 0; } else function = 0; if ((format_flags & fLOG_FileLine) != 0 && call_data->file && *call_data->file) { file_line_len = 12 + strlen(call_data->file) + 11; } if (call_data->message && *call_data->message) { message_len = strlen(call_data->message); } if (call_data->raw_size) { data_len = (sizeof(kRawData_Begin) + 20 + UTIL_PrintableStringSize((const char*) call_data->raw_data, call_data->raw_size) + sizeof(kRawData_End)); } /* Allocate memory for the resulting message */ total_len = (datetime_len + file_line_len + module_len + function_len + level_len + message_len + data_len); if (!(str = (char*) malloc(total_len + 1))) { assert(0); return 0; } s = str; /* Compose the message */ if (datetime_len) { memcpy(s, datetime, datetime_len); s += datetime_len; } if (file_line_len) { s += sprintf(s, "\"%s\", line %d: ", call_data->file, (int) call_data->line); } if (module_len | function_len) *s++ = '['; if (module_len) { memcpy(s, call_data->module, module_len -= 3); s += module_len; } if (function_len) { memcpy(s, "::", 2); s += 2; memcpy(s, function, function_len -= module_len ? 2 : 5); s += function_len; } if (module_len | function_len) { *s++ = ']'; *s++ = ' '; } if (level_len) { memcpy(s, level, level_len -= 2); s += level_len; *s++ = ':'; *s++ = ' '; } if (message_len) { memcpy(s, call_data->message, message_len); s += message_len; } if (data_len) { s += sprintf(s, kRawData_Begin, (unsigned long) call_data->raw_size, &"s"[call_data->raw_size == 1]); s = UTIL_PrintableString((const char*) call_data->raw_data, call_data->raw_size, s, format_flags & fLOG_FullOctal); memcpy(s, kRawData_End, sizeof(kRawData_End)); } else *s = '\0'; assert(strlen(str) <= total_len); return str; } typedef struct { FILE* fp; ELOG_Level cut_off; ELOG_Level fatal_err; int/*bool*/ auto_close; } SLogData; /* Callback for LOG_ToFILE[_Ex]() */ #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ static void s_LOG_FileHandler(void* user_data, SLOG_Handler* call_data) { SLogData* data = (SLogData*) user_data; assert(data && data->fp); assert(call_data); if (call_data->level >= data->cut_off || call_data->level >= data->fatal_err) { char* str = LOG_ComposeMessage(call_data, s_LogFormatFlags); if (str) { fprintf(data->fp, "%s\n", str); fflush(data->fp); free(str); } if (call_data->level >= data->fatal_err) { #ifdef NDEBUG exit(1); #else abort(); #endif /*NDEBUG*/ } } } #ifdef __cplusplus } #endif /*__cplusplus*/ /* Callback for LOG_ToFILE[_Ex]() */ #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ static void s_LOG_FileCleanup(void* user_data) { SLogData* data = (SLogData*) user_data; assert(data && data->fp); if (data->auto_close) fclose(data->fp); else fflush(data->fp); free(user_data); } #ifdef __cplusplus } #endif /*__cplusplus*/ extern void LOG_ToFILE_Ex (LOG lg, FILE* fp, ELOG_Level cut_off, ELOG_Level fatal_err, int/*bool*/ auto_close ) { SLogData* data = (SLogData*)(fp ? malloc(sizeof(*data)) : 0); if (data) { data->fp = fp; data->cut_off = cut_off; data->fatal_err = fatal_err; data->auto_close = auto_close; LOG_Reset(lg, data, s_LOG_FileHandler, s_LOG_FileCleanup); } else { LOG_Reset(lg, 0/*data*/, 0/*handler*/, 0/*cleanup*/); } } extern void LOG_ToFILE (LOG lg, FILE* fp, int/*bool*/ auto_close ) { LOG_ToFILE_Ex(lg, fp, eLOG_Trace, eLOG_Fatal, auto_close); } /****************************************************************************** * REGISTRY */ extern void CORE_SetREG(REG rg) { REG old_rg; CORE_LOCK_WRITE; old_rg = g_CORE_Registry; g_CORE_Registry = rg; g_CORE_Set |= eCORE_SetREG; CORE_UNLOCK; if (old_rg && old_rg != rg) REG_Delete(old_rg); } extern REG CORE_GetREG(void) { return g_CORE_Registry; } /****************************************************************************** * CORE_GetAppName */ extern const char* CORE_GetAppName(void) { const char* an; return !g_CORE_GetAppName || !(an = g_CORE_GetAppName()) ? "" : an; } /****************************************************************************** * CORE_GetNcbiRequestID */ extern char* CORE_GetNcbiRequestID(ENcbiRequestID reqid) { char* id; CORE_LOCK_READ; if (g_CORE_GetRequestID) { id = g_CORE_GetRequestID(reqid); assert(!id || *id); if (id) goto out; } switch (reqid) { case eNcbiRequestID_SID: id = getenv("HTTP_NCBI_SID"); if (id && *id) break; id = getenv("NCBI_LOG_SESSION_ID"); break; case eNcbiRequestID_HitID: id = getenv("HTTP_NCBI_PHID"); if (id && *id) break; id = getenv("NCBI_LOG_HIT_ID"); break; default: id = 0; goto out; } id = id && *id ? strdup(id) : 0; out: CORE_UNLOCK; return id; } /****************************************************************************** * CORE_GetPlatform */ extern const char* CORE_GetPlatform(void) { #ifndef NCBI_CXX_TOOLKIT return Nlm_PlatformName(); #else return HOST; #endif /*NCBI_CXX_TOOLKIT*/ } /**************************************************************************** * CORE_GetUsername */ static char* x_Savestr(const char* str, char* buf, size_t bufsize) { assert(str); if (buf) { size_t len = strlen(str); if (len++ < bufsize) return (char*) memcpy(buf, str, len); if (bufsize) *buf = '\0'; errno = ERANGE; } else errno = EINVAL; return 0; } /*ARGSUSED*/ extern const char* CORE_GetUsernameEx(char* buf, size_t bufsize, ECORE_Username username) { #if defined(NCBI_OS_UNIX) struct passwd* pwd; struct stat st; uid_t uid; # ifndef NCBI_OS_SOLARIS # define NCBI_GETUSERNAME_MAXBUFSIZE 1024 # ifdef HAVE_GETLOGIN_R # ifndef LOGIN_NAME_MAX # ifdef _POSIX_LOGIN_NAME_MAX # define LOGIN_NAME_MAX _POSIX_LOGIN_NAME_MAX # else # define LOGIN_NAME_MAX 256 # endif /*_POSIX_LOGIN_NAME_MAX*/ # endif /*!LOGIN_NAME_MAX*/ # define NCBI_GETUSERNAME_BUFSIZE LOGIN_NAME_MAX # endif /*HAVE_GETLOGIN_R*/ # ifdef NCBI_HAVE_GETPWUID_R # ifndef NCBI_GETUSERNAME_BUFSIZE # define NCBI_GETUSERNAME_BUFSIZE NCBI_GETUSERNAME_MAXBUFSIZE # else # if NCBI_GETUSERNAME_BUFSIZE < NCBI_GETUSERNAME_MAXBUFSIZE # undef NCBI_GETUSERNAME_BUFSIZE # define NCBI_GETUSERNAME_BUFSIZE NCBI_GETUSERNAME_MAXBUFSIZE # endif /* NCBI_GETUSERNAME_BUFSIZE < NCBI_GETUSERNAME_MAXBUFSIZE */ # endif /*NCBI_GETUSERNAME_BUFSIZE*/ # endif /*NCBI_HAVE_GETPWUID_R*/ # ifdef NCBI_GETUSERNAME_BUFSIZE char temp [NCBI_GETUSERNAME_BUFSIZE + sizeof(*pwd)]; # endif /* NCBI_GETUSERNAME_BUFSIZE */ # endif /*!NCBI_OS_SOLARIS*/ #elif defined(NCBI_OS_MSWIN) # ifdef UNLEN # define NCBI_GETUSERNAME_BUFSIZE UNLEN # else # define NCBI_GETUSERNAME_BUFSIZE 256 # endif /*UNLEN*/ TCHAR temp [NCBI_GETUSERNAME_BUFSIZE + 2]; DWORD size = sizeof(temp)/sizeof(temp[0]) - 1; #endif /*NCBI_OS*/ const char* login; assert(buf && bufsize); #ifndef NCBI_OS_UNIX # ifdef NCBI_OS_MSWIN if (GetUserName(temp, &size)) { assert(size < sizeof(temp)/sizeof(temp[0]) - 1); temp[size] = (TCHAR) '\0'; login = UTIL_TcharToUtf8(temp); buf = x_Savestr(login, buf, bufsize); UTIL_ReleaseBuffer(login); return buf; } CORE_LOCK_READ; if ((login = getenv("USERNAME")) != 0) { buf = x_Savestr(login, buf, bufsize); CORE_UNLOCK; return buf; } # endif /*NCBI_OS_MSWIN*/ #else /* NOTE: getlogin() is not a very reliable call at least on Linux * especially if programs mess up with "utmp": since getlogin() first * calls ttyname() to get the line name for FD 0, then searches "utmp" * for the record of this line and returns the user name, any discrepancy * can cause a false (stale) name to be returned. So we use getlogin() * here only as a fallback. */ switch (username) { case eCORE_UsernameCurrent: uid = geteuid(); break; case eCORE_UsernameLogin: if (isatty(STDIN_FILENO) && fstat(STDIN_FILENO, &st) == 0) { uid = st.st_uid; break; } # if defined(NCBI_OS_SOLARIS) || !defined(HAVE_GETLOGIN_R) /* NB: getlogin() is MT-safe on Solaris, yet getlogin_r() comes in two * flavors that differ only in return type, so to make things simpler, * use plain getlogin() here */ # ifndef NCBI_OS_SOLARIS CORE_LOCK_WRITE; # endif /*!NCBI_OS_SOLARIS*/ if ((login = getlogin()) != 0) buf = x_Savestr(login, buf, bufsize); # ifndef NCBI_OS_SOLARIS CORE_UNLOCK; # endif /*!NCBI_OS_SOLARIS*/ if (login) return buf; # else if (getlogin_r(temp, sizeof(temp) - 1) == 0) { temp[sizeof(temp) - 1] = '\0'; return x_Savestr(temp, buf, bufsize); } # endif /*NCBI_OS_SOLARIS || !HAVE_GETLOGIN_R*/ /*FALLTHRU*/ case eCORE_UsernameReal: uid = getuid(); break; default: assert(0); uid = (uid_t)(-1); break; } # if defined(NCBI_OS_SOLARIS) \ || (defined(HAVE_GETPWUID) && !defined(NCBI_HAVE_GETPWUID_R)) /* NB: getpwuid() is MT-safe on Solaris, so use it here, if available */ # ifndef NCBI_OS_SOLARIS CORE_LOCK_WRITE; # endif /*!NCBI_OS_SOLARIS*/ if ((pwd = getpwuid(uid)) != 0) { if (pwd->pw_name) buf = x_Savestr(pwd->pw_name, buf, bufsize); else pwd = 0; } # ifndef NCBI_OS_SOLARIS CORE_UNLOCK; # endif /*!NCBI_OS_SOLARIS*/ if (pwd) return buf; # elif defined(NCBI_HAVE_GETPWUID_R) # if NCBI_HAVE_GETPWUID_R == 4 /* obsolete but still existent */ pwd = getpwuid_r(uid, (struct passwd*) temp, temp + sizeof(*pwd), sizeof(temp) - sizeof(*pwd)); # elif NCBI_HAVE_GETPWUID_R == 5 /* POSIX-conforming */ if (getpwuid_r(uid, (struct passwd*) temp, temp + sizeof(*pwd), sizeof(temp) - sizeof(*pwd), &pwd) != 0) { pwd = 0; } # else # error "Unknown value of NCBI_HAVE_GETPWUID_R: 4 or 5 expected." # endif /*NCBI_HAVE_GETPWUID_R*/ if (pwd && pwd->pw_name) return x_Savestr(pwd->pw_name, buf, bufsize); # endif /*NCBI_HAVE_GETPWUID_R*/ #endif /*!NCBI_OS_UNIX*/ /* last resort */ CORE_LOCK_READ; if (!(login = getenv("USER")) && !(login = getenv("LOGNAME"))) login = ""; buf = x_Savestr(login, buf, bufsize); CORE_UNLOCK; return buf; } extern const char* CORE_GetUsername(char* buf, size_t bufsize) { const char* rv = CORE_GetUsernameEx(buf, bufsize, eCORE_UsernameLogin); return rv && *rv ? rv : 0; } /**************************************************************************** * CORE_GetVMPageSize: Get page size granularity * See also at corelib's ncbi_system.cpp::GetVirtualMemoryPageSize(). */ extern size_t CORE_GetVMPageSize(void) { static size_t s_PS = 0; if (!s_PS) { #if defined(NCBI_OS_MSWIN) || defined(NCBI_OS_CYGWIN) /* NB: CYGWIN's PAGESIZE (== PAGE_SIZE) is actually the granularity */ SYSTEM_INFO si; GetSystemInfo(&si); s_PS = (size_t) si.dwPageSize; #elif defined(NCBI_OS_UNIX) # if defined(_SC_PAGESIZE) # define NCBI_SC_PAGESIZE _SC_PAGESIZE # elif defined(_SC_PAGE_SIZE) # define NCBI_SC_PAGESIZE _SC_PAGE_SIZE # elif defined(NCBI_SC_PAGESIZE) # undef NCBI_SC_PAGESIZE # endif # ifndef NCBI_SC_PAGESIZE long x = 0; # else long x = sysconf(NCBI_SC_PAGESIZE); # undef NCBI_SC_PAGESIZE # endif if (x <= 0) { # ifdef HAVE_GETPAGESIZE if ((x = getpagesize()) <= 0) return NCBI_DEFAULT_PAGE_SIZE; # else return NCBI_DEFAULT_PAGE_SIZE; # endif /*HAVE_GETPAGESIZE*/ } s_PS = (size_t) x; #endif /*OS_TYPE*/ } return s_PS; } /**************************************************************************** * CRC32 */ /* Standard Ethernet/ZIP polynomial */ #define CRC32_POLY 0x04C11DB7UL #ifdef NCBI_USE_PRECOMPILED_CRC32_TABLES static const unsigned int s_CRC32Table[256] = { 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 }; #else static unsigned int s_CRC32Table[256]; static void s_CRC32_Init(void) { size_t i; if (s_CRC32Table[255]) return; for (i = 0; i < 256; i++) { unsigned int byteCRC = (unsigned int) i << 24; int j; for (j = 0; j < 8; j++) { if (byteCRC & 0x80000000UL) { byteCRC <<= 1; byteCRC ^= CRC32_POLY; } else byteCRC <<= 1; } s_CRC32Table[i] = byteCRC; } } #endif /*NCBI_USE_PRECOMPILED_CRC32_TABLES*/ extern unsigned int UTIL_CRC32_Update(unsigned int checksum, const void *ptr, size_t len) { const unsigned char* data = (const unsigned char*) ptr; size_t i; #ifndef NCBI_USE_PRECOMPILED_CRC32_TABLES s_CRC32_Init(); #endif /*NCBI_USE_PRECOMPILED_CRC32_TABLES*/ for (i = 0; i < len; i++) { size_t k = ((checksum >> 24) ^ *data++) & 0xFF; checksum <<= 8; checksum ^= s_CRC32Table[k]; } return checksum; } #define MOD_ADLER 65521 #define MAXLEN_ADLER 5548 /* max len to run without overflows */ #define ADJUST_ADLER(a) a = (a & 0xFFFF) + (a >> 16) * (0x10000 - MOD_ADLER) #define FINALIZE_ADLER(a) if (a >= MOD_ADLER) a -= MOD_ADLER unsigned int UTIL_Adler32_Update(unsigned int checksum, const void* ptr, size_t len) { const unsigned char* data = (const unsigned char*) ptr; unsigned int a = checksum & 0xFFFF, b = checksum >> 16; while (len) { size_t i; if (len >= MAXLEN_ADLER) { len -= MAXLEN_ADLER; for (i = 0; i < MAXLEN_ADLER/4; ++i) { b += a += data[0]; b += a += data[1]; b += a += data[2]; b += a += data[3]; data += 4; } } else { for (i = len >> 2; i; --i) { b += a += data[0]; b += a += data[1]; b += a += data[2]; b += a += data[3]; data += 4; } for (len &= 3; len; --len) { b += a += *data++; } } ADJUST_ADLER(a); ADJUST_ADLER(b); } /* It can be shown that a <= 0x1013A here, so a single subtract will do. */ FINALIZE_ADLER(a); /* It can be shown that b can reach 0xFFEF1 here. */ ADJUST_ADLER(b); FINALIZE_ADLER(b); return (b << 16) | a; } #undef MOD_ADLER #undef MAXLEN_ADLER #undef ADJUST_ADLER #undef FINALIZE_ADLER extern void* UTIL_GenerateHMAC(const SHASH_Descriptor* hash, const void* text, size_t text_len, const void* key, size_t key_len, void* digest) { unsigned char* pad; void* ctx; size_t i; if (!hash || !text || !key || !digest) return 0; if (!(pad = (unsigned char*) malloc(hash->block_len + hash->digest_len))) return 0; if (key_len > hash->block_len) { void* tmp; if (!hash->init(&ctx)) { free(pad); return 0; } tmp = pad + hash->block_len; hash->update(ctx, key, key_len); hash->fini(ctx, tmp); key = tmp; key_len = hash->digest_len; } if (!hash->init(&ctx)) { free(pad); return 0; } for (i = 0; i < key_len; ++i) pad[i] = 0x36 ^ ((unsigned char*) key)[i]; for (; i < hash->block_len; ++i) pad[i] = 0x36; hash->update(ctx, pad, hash->block_len); hash->update(ctx, text, text_len); hash->fini(ctx, digest); if (!hash->init(&ctx)) { free(pad); return 0; } for (i = 0; i < key_len; ++i) pad[i] = 0x5C ^ ((unsigned char*) key)[i]; for (; i < hash->block_len; ++i) pad[i] = 0x5C; hash->update(ctx, pad, hash->block_len); hash->update(ctx, digest, hash->digest_len); hash->fini(ctx, digest); free(pad); return digest; } /****************************************************************************** * MISCELLANEOUS */ extern int/*bool*/ UTIL_MatchesMaskEx(const char* name, const char* mask, int/*bool*/ ignore_case) { for (;;) { char c = *mask++; char d; if (!c) { break; } else if (c == '?') { if (!*name++) return 0/*false*/; } else if (c == '*') { c = *mask; while (c == '*') c = *++mask; if (!c) return 1/*true*/; while (*name) { if (UTIL_MatchesMaskEx(name, mask, ignore_case)) return 1/*true*/; name++; } return 0/*false*/; } else { d = *name++; if (ignore_case) { c = tolower((unsigned char) c); d = tolower((unsigned char) d); } if (c != d) return 0/*false*/; } } return !*name; } extern int/*bool*/ UTIL_MatchesMask(const char* name, const char* mask) { return UTIL_MatchesMaskEx(name, mask, 1/*ignore case*/); } extern char* UTIL_NcbiLocalHostName(char* hostname) { static const struct { const char* text; const size_t len; } kEndings[] = { {".ncbi.nlm.nih.gov", 17}, {".ncbi.nih.gov", 13} }; size_t len = hostname ? strlen(hostname) : 0; if (len) { size_t i; for (i = 0; i < sizeof(kEndings) / sizeof(kEndings[0]); ++i) { assert(strlen(kEndings[i].text) == kEndings[i].len); if (len > kEndings[i].len) { size_t prefix = len - kEndings[i].len; if (strcasecmp(hostname + prefix, kEndings[i].text) == 0) { hostname[prefix] = '\0'; return hostname; } } } } return 0; } #ifdef NCBI_OS_MSWIN # ifdef _UNICODE extern const char* UTIL_TcharToUtf8OnHeap(const TCHAR* str) { const char* s = UTIL_TcharToUtf8(str); UTIL_ReleaseBufferOnHeap(str); return s; } /* * UTIL_TcharToUtf8() is defined in ncbi_strerror.c */ extern const TCHAR* UTIL_Utf8ToTchar(const char* str) { TCHAR* s = NULL; if (str) { /* Note "-1" means to consume all input including the trailing NUL */ int n = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); if (n > 0) { s = (wchar_t*) LocalAlloc(LMEM_FIXED, n * sizeof(*s)); if (s) MultiByteToWideChar(CP_UTF8, 0, str, -1, s, n); } } return s; } # endif /*_UNICODE*/ /* * UTIL_ReleaseBufferOnHeap() is defined in ncbi_strerror.c */ #endif /*NCBI_OS_MSWIN*/