1 /* $Id: ncbi_util.c 620617 2020-11-25 05:25:50Z lavr $
2  * ===========================================================================
3  *
4  *                            PUBLIC DOMAIN NOTICE
5  *               National Center for Biotechnology Information
6  *
7  *  This software/database is a "United States Government Work" under the
8  *  terms of the United States Copyright Act.  It was written as part of
9  *  the author's official duties as a United States Government employee and
10  *  thus cannot be copyrighted.  This software/database is freely available
11  *  to the public for use. The National Library of Medicine and the U.S.
12  *  Government have not placed any restriction on its use or reproduction.
13  *
14  *  Although all reasonable efforts have been taken to ensure the accuracy
15  *  and reliability of the software and data, the NLM and the U.S.
16  *  Government do not and cannot warrant the performance or results that
17  *  may be obtained by using this software or data. The NLM and the U.S.
18  *  Government disclaim all warranties, express or implied, including
19  *  warranties of performance, merchantability or fitness for any particular
20  *  purpose.
21  *
22  *  Please cite the author in any work or product based on this material.
23  *
24  * ===========================================================================
25  *
26  * Author:  Denis Vakatov, Anton Lavrentiev
27  *
28  * File Description:
29  *   Auxiliary (optional) code mostly to support "ncbi_core.[ch]"
30  *
31  */
32 
33 #include "ncbi_ansi_ext.h"
34 #include "ncbi_priv.h"
35 #ifndef NCBI_CXX_TOOLKIT
36 #  include <ncbistd.h>
37 #  include <ncbimisc.h>
38 #  include <ncbitime.h>
39 #else
40 #  include <ctype.h>
41 #  include <errno.h>
42 #  include <stdlib.h>
43 #  include <time.h>
44 #endif
45 #if !defined(NCBI_OS_DARWIN)  &&  defined(HAVE_POLL_H)
46 #  include <poll.h>
47 #endif /*!NCBI_OS_DARWIN && HAVE_POLL_H*/
48 #if defined(NCBI_OS_UNIX)
49 #  ifndef HAVE_GETPWUID
50 #    error "HAVE_GETPWUID is undefined on a UNIX system!"
51 #  endif /*!HAVE_GETPWUID*/
52 #  ifndef NCBI_OS_SOLARIS
53 #    include <limits.h>
54 #  endif /*!NCBI_OS_SOLARIS*/
55 #  ifdef NCBI_OS_LINUX
56 #    include <sys/user.h>
57 #  endif /*NCBI_OS_LINUX*/
58 #  include <pwd.h>
59 #  include <sys/time.h>
60 #  include <sys/types.h>
61 #  include <sys/stat.h>
62 #  include <unistd.h>
63 #endif /*NCBI_OS_UNIX*/
64 #if defined(NCBI_OS_MSWIN)  ||  defined(NCBI_OS_CYGWIN)
65 #  define WIN32_LEAN_AND_MEAN
66 #  include <windows.h>
67 #  include <lmcons.h>
68 #endif /*NCBI_OS_MSWIN || NCBI_OS_CYGWIN*/
69 #if defined(PAGE_SIZE)  &&  !defined(NCBI_OS_CYGWIN)
70 #  define NCBI_DEFAULT_PAGE_SIZE  PAGE_SIZE
71 #else
72 #  define NCBI_DEFAULT_PAGE_SIZE  0/*unknown*/
73 #endif /*PAGE_SIZE && !NCBI_OS_CYGWIN*/
74 
75 #define NCBI_USE_ERRCODE_X   Connect_Util
76 
77 #define NCBI_USE_PRECOMPILED_CRC32_TABLES 1
78 
79 
80 /******************************************************************************
81  *  MT locking
82  */
83 
CORE_SetLOCK(MT_LOCK lk)84 extern void CORE_SetLOCK(MT_LOCK lk)
85 {
86     MT_LOCK old_lk = g_CORE_MT_Lock;
87     g_CORE_MT_Lock = lk;
88     g_CORE_Set |= eCORE_SetLOCK;
89     if (old_lk  &&  old_lk != lk)
90         MT_LOCK_Delete(old_lk);
91 }
92 
93 
CORE_GetLOCK(void)94 extern MT_LOCK CORE_GetLOCK(void)
95 {
96     return g_CORE_MT_Lock;
97 }
98 
99 
100 
101 /******************************************************************************
102  *  ERROR HANDLING and LOGGING
103  */
104 
105 
CORE_SetLOG(LOG lg)106 extern void CORE_SetLOG(LOG lg)
107 {
108     LOG old_lg;
109     CORE_LOCK_WRITE;
110     old_lg = g_CORE_Log;
111     g_CORE_Log = lg;
112     g_CORE_Set |= eCORE_SetLOG;
113     CORE_UNLOCK;
114     if (old_lg  &&  old_lg != lg)
115         LOG_Delete(old_lg);
116 }
117 
118 
CORE_GetLOG(void)119 extern LOG CORE_GetLOG(void)
120 {
121     return g_CORE_Log;
122 }
123 
124 
CORE_SetLOGFILE_Ex(FILE * fp,ELOG_Level cut_off,ELOG_Level fatal_err,int auto_close)125 extern void CORE_SetLOGFILE_Ex
126 (FILE*       fp,
127  ELOG_Level  cut_off,
128  ELOG_Level  fatal_err,
129  int/*bool*/ auto_close
130  )
131 {
132     LOG lg = LOG_Create(0, 0, 0, 0);
133     LOG_ToFILE_Ex(lg, fp, cut_off, fatal_err, auto_close);
134     CORE_SetLOG(lg);
135 }
136 
137 
CORE_SetLOGFILE(FILE * fp,int auto_close)138 extern void CORE_SetLOGFILE
139 (FILE*       fp,
140  int/*bool*/ auto_close)
141 {
142     CORE_SetLOGFILE_Ex(fp, eLOG_Trace, eLOG_Fatal, auto_close);
143 }
144 
145 
CORE_SetLOGFILE_NAME_Ex(const char * logfile,ELOG_Level cut_off,ELOG_Level fatal_err)146 extern int/*bool*/ CORE_SetLOGFILE_NAME_Ex
147 (const char* logfile,
148  ELOG_Level  cut_off,
149  ELOG_Level  fatal_err)
150 {
151     FILE* fp = fopen(logfile, "a");
152     if (!fp) {
153         CORE_LOGF_ERRNO_X(1, eLOG_Error, errno,
154                           ("Cannot open \"%s\"", logfile));
155         return 0/*false*/;
156     }
157 
158     CORE_SetLOGFILE_Ex(fp, cut_off, fatal_err, 1/*autoclose*/);
159     return 1/*true*/;
160 }
161 
162 
CORE_SetLOGFILE_NAME(const char * logfile)163 extern int/*bool*/ CORE_SetLOGFILE_NAME
164 (const char* logfile
165  )
166 {
167     return CORE_SetLOGFILE_NAME_Ex(logfile, eLOG_Trace, eLOG_Fatal);
168 }
169 
170 
171 static TLOG_FormatFlags s_LogFormatFlags = fLOG_Default;
172 
CORE_SetLOGFormatFlags(TLOG_FormatFlags flags)173 extern TLOG_FormatFlags CORE_SetLOGFormatFlags(TLOG_FormatFlags flags)
174 {
175     TLOG_FormatFlags old_flags = s_LogFormatFlags;
176 
177     s_LogFormatFlags = flags;
178     return old_flags;
179 }
180 
181 
UTIL_PrintableStringSize(const char * data,size_t size)182 extern size_t UTIL_PrintableStringSize(const char* data, size_t size)
183 {
184     const unsigned char* c;
185     size_t count;
186     if (!data)
187         return 0;
188     if (!size)
189         size = strlen(data);
190     count = size;
191     for (c = (const unsigned char*) data;  count;  --count, ++c) {
192         if (*c == '\t'  ||  *c == '\v'  ||  *c == '\b'  ||
193             *c == '\r'  ||  *c == '\f'  ||  *c == '\a'  ||
194             *c == '\\'  ||  *c == '\''  ||  *c == '"') {
195             size++;
196         } else if (*c == '\n'  ||  !isascii(*c)  ||  !isprint(*c))
197             size += 3;
198     }
199     return size;
200 }
201 
202 
UTIL_PrintableString(const char * data,size_t size,char * buf,int flags)203 extern char* UTIL_PrintableString(const char* data, size_t size,
204                                   char* buf, int/*bool*/ flags)
205 {
206     const unsigned char* s;
207     unsigned char* d;
208 
209     if (!data  ||  !buf)
210         return 0;
211     if (!size)
212         size = strlen(data);
213 
214     d = (unsigned char*) buf;
215     for (s = (const unsigned char*) data;  size;  --size, ++s) {
216         switch (*s) {
217         case '\t':
218             *d++ = '\\';
219             *d++ = 't';
220             continue;
221         case '\v':
222             *d++ = '\\';
223             *d++ = 'v';
224             continue;
225         case '\b':
226             *d++ = '\\';
227             *d++ = 'b';
228             continue;
229         case '\r':
230             *d++ = '\\';
231             *d++ = 'r';
232             continue;
233         case '\f':
234             *d++ = '\\';
235             *d++ = 'f';
236             continue;
237         case '\a':
238             *d++ = '\\';
239             *d++ = 'a';
240             continue;
241         case '\n':
242             *d++ = '\\';
243             *d++ = 'n';
244             if (flags & eUTIL_PrintableNoNewLine)
245                 continue;
246             /*FALLTHRU*/
247         case '\\':
248         case '\'':
249         case '"':
250             *d++ = '\\';
251             break;
252         default:
253             if (!isascii(*s)  ||  !isprint(*s)) {
254                 int/*bool*/ reduce;
255                 unsigned char v;
256                 if (flags & eUTIL_PrintableFullOctal)
257                     reduce = 0/*false*/;
258                 else {
259                     reduce = (size == 1  ||
260                               s[1] < '0' || s[1] > '7' ? 1/*T*/ : 0/*F*/);
261                 }
262                 *d++     = '\\';
263                 v =  *s >> 6;
264                 if (v  ||  !reduce) {
265                     *d++ = (unsigned char)('0' + v);
266                     reduce = 0;
267                 }
268                 v = (*s >> 3) & 7;
269                 if (v  ||  !reduce)
270                     *d++ = (unsigned char)('0' + v);
271                 v = *s & 7;
272                 *d++ = (unsigned char)('0' + v);
273                 continue;
274             }
275             break;
276         }
277         *d++ = *s;
278     }
279 
280     return (char*) d;
281 }
282 
283 
284 #ifdef NCBI_OS_MSWIN
s_WinStrerror(DWORD error)285 static const char* s_WinStrerror(DWORD error)
286 {
287     TCHAR* str;
288     DWORD  rv;
289 
290     if (!error)
291         return 0;
292     str = NULL;
293     rv  = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
294                         FORMAT_MESSAGE_FROM_SYSTEM     |
295                         FORMAT_MESSAGE_MAX_WIDTH_MASK  |
296                         FORMAT_MESSAGE_IGNORE_INSERTS,
297                         NULL, error,
298                         MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
299                         (LPTSTR) &str, 0, NULL);
300     if (!rv  &&  str) {
301         LocalFree((HLOCAL) str);
302         return 0;
303     }
304     return UTIL_TcharToUtf8OnHeap(str);
305 }
306 #endif /*NCBI_OS_MSWIN*/
307 
308 
NcbiMessagePlusError(int * dynamic,const char * message,int error,const char * descr)309 extern const char* NcbiMessagePlusError
310 (int/*bool*/ *dynamic,
311  const char*  message,
312  int          error,
313  const char*  descr)
314 {
315     int/*bool*/ release;
316     char*  buf;
317     size_t mlen;
318     size_t dlen;
319 
320     /* Check for an empty addition */
321     if (!error  &&  (!descr  ||  !*descr)) {
322         if (message)
323             return message;
324         *dynamic = 0/*false*/;
325         return "";
326     }
327 
328     /* Adjust description, if necessary and possible */
329     release = 0/*false*/;
330     if (error > 0  &&  !descr) {
331 #if defined(NCBI_OS_MSWIN)  &&  defined(_UNICODE)
332         descr = UTIL_TcharToUtf8(_wcserror(error));
333         release = 1/*true*/;
334 #else
335         descr = strerror(error);
336 #endif /*NCBI_OS_MSWIN && _UNICODE*/
337 #ifdef NCBI_OS_MSWIN
338         if (!descr  ||  !*descr  ||  strncasecmp(descr, "Unknown ", 8) == 0) {
339             if (release)
340                 UTIL_ReleaseBuffer(descr);
341             descr = s_WinStrerror(error);
342             release = -1/*on heap*/;
343         }
344 #endif /*NCBI_OS_MSWIN*/
345     }
346     if (descr  &&  *descr) {
347         dlen = strlen(descr);
348         while (dlen  &&  isspace((unsigned char) descr[dlen - 1]))
349             dlen--;
350         if (dlen > 1  &&  descr[dlen - 1] == '.')
351             dlen--;
352     } else {
353         descr = "";
354         dlen = 0;
355     }
356 
357     mlen = message ? strlen(message) : 0;
358 
359     if (!(buf = (char*)(*dynamic  &&  message
360                         ? realloc((void*) message, mlen + dlen + 40)
361                         : malloc (                 mlen + dlen + 40)))) {
362         if (*dynamic  &&  message)
363             free((void*) message);
364         *dynamic = 0;
365         if (release > 0)
366             UTIL_ReleaseBuffer(descr);
367         else if (release < 0)
368             UTIL_ReleaseBufferOnHeap(descr);
369         return "Ouch! Out of memory";
370     }
371 
372     if (message) {
373         if (!*dynamic)
374             memcpy(buf, message, mlen);
375         buf[mlen++] = ' ';
376     }
377     memcpy(buf + mlen, "{error=", 7);
378     mlen += 7;
379 
380     if (error) {
381         mlen += (size_t) sprintf(buf + mlen,
382 #ifdef NCBI_OS_MSWIN
383                                  error < 0x10000 ? "%d%s" : "0x%08X%s",
384 #else
385                                                    "%d%s",
386 #endif /*NCBI_OS_MSWIN*/
387                                  error, &","[!*descr]);
388     }
389 
390     memcpy((char*) memcpy(buf + mlen, descr, dlen) + dlen, "}", 2);
391     if (release > 0)
392         UTIL_ReleaseBuffer(descr);
393     else if (release < 0)
394         UTIL_ReleaseBufferOnHeap(descr);
395 
396     *dynamic = 1/*true*/;
397     return buf;
398 }
399 
400 
LOG_ComposeMessage(const SLOG_Message * mess,TLOG_FormatFlags flags)401 extern char* LOG_ComposeMessage
402 (const SLOG_Message* mess,
403  TLOG_FormatFlags    flags)
404 {
405     static const char kRawData_Beg[] =
406         "\n#################### [BEGIN] Raw Data (%lu byte%s):\n";
407     static const char kRawData_End[] =
408         "\n#################### [_END_] Raw Data\n";
409 
410     const char *function, *level = 0;
411     char *str, *s, datetime[32];
412 
413     /* Calculated length of ... */
414     size_t datetime_len  = 0;
415     size_t level_len     = 0;
416     size_t module_len    = 0;
417     size_t function_len  = 0;
418     size_t file_line_len = 0;
419     size_t message_len   = 0;
420     size_t data_len      = 0;
421     size_t total_len;
422 
423     /* Adjust formatting flags */
424     if (mess->level == eLOG_Trace  &&  !(flags & fLOG_None))
425         flags |= fLOG_Full;
426     if (flags == fLOG_Default) {
427 #if !defined(_DEBUG)  ||  defined(NDEBUG)
428         flags = fLOG_Short;
429 #else
430         flags = fLOG_Full;
431 #endif /*!_DEBUG || NDEBUG*/
432     }
433 
434     /* Pre-calculate total message length */
435     if ((flags & fLOG_DateTime) != 0) {
436 #ifdef NCBI_OS_MSWIN /*Should be compiler-dependent but C-Tkit lacks it*/
437         _strdate(&datetime[datetime_len]);
438         datetime_len += strlen(&datetime[datetime_len]);
439         datetime[datetime_len++] = ' ';
440         _strtime(&datetime[datetime_len]);
441         datetime_len += strlen(&datetime[datetime_len]);
442         datetime[datetime_len++] = ' ';
443         datetime[datetime_len]   = '\0';
444 #else /*NCBI_OS_MSWIN*/
445         static const char timefmt[] = "%m/%d/%y %H:%M:%S ";
446         struct tm* tm;
447 #  ifdef NCBI_CXX_TOOLKIT
448         time_t t = time(0);
449 #    ifdef HAVE_LOCALTIME_R
450         struct tm temp;
451         localtime_r(&t, &temp);
452         tm = &temp;
453 #    else /*HAVE_LOCALTIME_R*/
454         tm = localtime(&t);
455 #    endif/*HAVE_LOCALTIME_R*/
456 #  else /*NCBI_CXX_TOOLKIT*/
457         struct tm temp;
458         Nlm_GetDayTime(&temp);
459         tm = &temp;
460 #  endif /*NCBI_CXX_TOOLKIT*/
461         datetime_len = strftime(datetime, sizeof(datetime), timefmt, tm);
462 #endif /*NCBI_OS_MSWIN*/
463     }
464     if ((flags & fLOG_Level) != 0
465         &&  (mess->level != eLOG_Note  ||  !(flags & fLOG_OmitNoteLevel))) {
466         level = LOG_LevelStr(mess->level);
467         level_len = strlen(level) + 2;
468     }
469     if ((flags & fLOG_Module) != 0
470         &&  mess->module  &&  *mess->module) {
471         module_len = strlen(mess->module) + 3;
472     }
473     if ((flags & fLOG_Function) != 0
474         &&  mess->func  &&  *mess->func) {
475         function = mess->func;
476         if (!module_len)
477             function_len = 3;
478         function_len += strlen(function) + 2;
479         if (strncmp(function, "::", 2) == 0  &&  !*(function += 2))
480             function_len = 0;
481     } else
482         function = 0;
483     if ((flags & fLOG_FileLine) != 0
484         &&  mess->file  &&  *mess->file) {
485         file_line_len = 12 + strlen(mess->file) + 11;
486     }
487     if (mess->message  &&  *mess->message)
488         message_len = strlen(mess->message);
489 
490     if (mess->raw_size) {
491         data_len = (sizeof(kRawData_Beg)
492                     + 20 + UTIL_PrintableStringSize((const char*)
493                                                     mess->raw_data,
494                                                     mess->raw_size) +
495                     sizeof(kRawData_End));
496     }
497 
498     /* Allocate memory for the resulting message */
499     total_len = (datetime_len + file_line_len + module_len + function_len
500                  + level_len + message_len + data_len);
501     if (!(str = (char*) malloc(total_len + 1))) {
502         assert(0);
503         return 0;
504     }
505 
506     s = str;
507     /* Compose the message */
508     if (datetime_len) {
509         memcpy(s, datetime, datetime_len);
510         s += datetime_len;
511     }
512     if (file_line_len) {
513         s += sprintf(s, "\"%s\", line %d: ",
514                      mess->file, (int) mess->line);
515     }
516     if (module_len | function_len)
517         *s++ = '[';
518     if (module_len) {
519         memcpy(s, mess->module, module_len -= 3);
520         s += module_len;
521     }
522     if (function_len) {
523         memcpy(s, "::", 2);
524         s += 2;
525         memcpy(s, function, function_len -= (module_len ? 2 : 5));
526         s += function_len;
527     }
528     if (module_len | function_len) {
529         *s++ = ']';
530         *s++ = ' ';
531     }
532     if (level_len) {
533         memcpy(s, level, level_len -= 2);
534         s += level_len;
535         *s++ = ':';
536         *s++ = ' ';
537     }
538     if (message_len) {
539         memcpy(s, mess->message, message_len);
540         s += message_len;
541     }
542     if (data_len) {
543         s += sprintf(s, kRawData_Beg,
544                      (unsigned long) mess->raw_size,
545                      &"s"[mess->raw_size == 1]);
546 
547         s = UTIL_PrintableString((const char*)
548                                  mess->raw_data,
549                                  mess->raw_size,
550                                  s, flags & fLOG_FullOctal
551                                  ? eUTIL_PrintableFullOctal : 0);
552 
553         memcpy(s, kRawData_End, sizeof(kRawData_End));
554     } else
555         *s = '\0';
556 
557     assert(strlen(str) <= total_len);
558     return str;
559 }
560 
561 
562 typedef struct {
563     FILE*       fp;
564     ELOG_Level  cut_off;
565     ELOG_Level  fatal_err;
566     int/*bool*/ auto_close;
567 } SLogData;
568 
569 
570 /* Callback for LOG_ToFILE[_Ex]() */
571 #ifdef __cplusplus
572 extern "C" {
573 #endif /*__cplusplus*/
s_LOG_FileHandler(void * data,const SLOG_Message * mess)574 static void s_LOG_FileHandler(void* data, const SLOG_Message* mess)
575 {
576     SLogData* logdata = (SLogData*) data;
577     assert(logdata->fp);
578 
579     if (mess->level >= logdata->cut_off  ||
580         mess->level >= logdata->fatal_err) {
581         char* str = LOG_ComposeMessage(mess, s_LogFormatFlags);
582         if (str) {
583             size_t len = strlen(str);
584             str[len++] = '\n';
585             fwrite(str, len, 1, logdata->fp);
586             fflush(logdata->fp);
587             free(str);
588         }
589         if (mess->level >= logdata->fatal_err) {
590 #ifdef NDEBUG
591             fflush(0);
592             _exit(255);
593 #else
594             abort();
595 #endif /*NDEBUG*/
596         }
597     }
598 }
599 #ifdef __cplusplus
600 }
601 #endif /*__cplusplus*/
602 
603 
604 /* Callback for LOG_ToFILE[_Ex]() */
605 #ifdef __cplusplus
606 extern "C" {
607 #endif /*__cplusplus*/
s_LOG_FileCleanup(void * data)608 static void s_LOG_FileCleanup(void* data)
609 {
610     SLogData* logdata = (SLogData*) data;
611 
612     assert(logdata->fp);
613     if (logdata->auto_close)
614         fclose(logdata->fp);
615     else
616         fflush(logdata->fp);
617     free(logdata);
618 }
619 #ifdef __cplusplus
620 }
621 #endif /*__cplusplus*/
622 
623 
LOG_ToFILE_Ex(LOG lg,FILE * fp,ELOG_Level cut_off,ELOG_Level fatal_err,int auto_close)624 extern void LOG_ToFILE_Ex
625 (LOG         lg,
626  FILE*       fp,
627  ELOG_Level  cut_off,
628  ELOG_Level  fatal_err,
629  int/*bool*/ auto_close
630  )
631 {
632     SLogData* logdata;
633     if (fp) {
634         fflush(fp);
635         logdata = (SLogData*) malloc(sizeof(*logdata));
636     } else
637         logdata = 0;
638     if (logdata) {
639         logdata->fp         = fp;
640         logdata->cut_off    = cut_off;
641         logdata->fatal_err  = fatal_err;
642         logdata->auto_close = auto_close;
643         LOG_Reset(lg, logdata, s_LOG_FileHandler, s_LOG_FileCleanup);
644     } else {
645         LOG_Reset(lg, 0/*data*/, 0/*handler*/, 0/*cleanup*/);
646         if (fp  &&  auto_close)
647             fclose(fp);
648     }
649 }
650 
651 
LOG_ToFILE(LOG lg,FILE * fp,int auto_close)652 extern void LOG_ToFILE
653 (LOG         lg,
654  FILE*       fp,
655  int/*bool*/ auto_close
656  )
657 {
658     LOG_ToFILE_Ex(lg, fp, eLOG_Trace, eLOG_Fatal, auto_close);
659 }
660 
661 
662 
663 /******************************************************************************
664  *  REGISTRY
665  */
666 
CORE_SetREG(REG rg)667 extern void CORE_SetREG(REG rg)
668 {
669     REG old_rg;
670     CORE_LOCK_WRITE;
671     old_rg = g_CORE_Registry;
672     g_CORE_Registry = rg;
673     g_CORE_Set |= eCORE_SetREG;
674     CORE_UNLOCK;
675     if (old_rg  &&  old_rg != rg)
676         REG_Delete(old_rg);
677 }
678 
679 
CORE_GetREG(void)680 extern REG CORE_GetREG(void)
681 {
682     return g_CORE_Registry;
683 }
684 
685 
686 
687 /******************************************************************************
688  *  CORE_GetAppName
689  */
690 
CORE_GetAppName(void)691 extern const char* CORE_GetAppName(void)
692 {
693     const char* an;
694     return !g_CORE_GetAppName  ||  !(an = g_CORE_GetAppName()) ? "" : an;
695 }
696 
697 
698 
699 /******************************************************************************
700  *  CORE_GetNcbiRequestID
701  */
702 
CORE_GetNcbiRequestID(ENcbiRequestID reqid)703 extern char* CORE_GetNcbiRequestID(ENcbiRequestID reqid)
704 {
705     char* id;
706 
707     CORE_LOCK_READ;
708     if (g_CORE_GetRequestID) {
709         id = g_CORE_GetRequestID(reqid);
710         assert(!id  ||  *id);
711         if (id)
712             goto out;
713     }
714     switch (reqid) {
715     case eNcbiRequestID_SID:
716         id = getenv("HTTP_NCBI_SID");
717         if (id  &&  *id)
718             break;
719         id = getenv("NCBI_LOG_SESSION_ID");
720         break;
721     case eNcbiRequestID_HitID:
722         id = getenv("HTTP_NCBI_PHID");
723         if (id  &&  *id)
724             break;
725         id = getenv("NCBI_LOG_HIT_ID");
726         break;
727     default:
728         id = 0;
729         goto out;
730     }
731     id = id  &&  *id ? strdup(id) : 0;
732  out:
733     CORE_UNLOCK;
734 
735     return id;
736 }
737 
738 
739 
740 /******************************************************************************
741  *  CORE_GetPlatform
742  */
743 
CORE_GetPlatform(void)744 extern const char* CORE_GetPlatform(void)
745 {
746 #ifndef NCBI_CXX_TOOLKIT
747     return Nlm_PlatformName();
748 #else
749     return HOST;
750 #endif /*NCBI_CXX_TOOLKIT*/
751 }
752 
753 
754 
755 /****************************************************************************
756  * CORE_GetUsername
757  */
758 
x_Savestr(const char * str,char * buf,size_t bufsize)759 static char* x_Savestr(const char* str, char* buf, size_t bufsize)
760 {
761     assert(str);
762     if (buf) {
763         size_t len = strlen(str);
764         if (len++ < bufsize)
765             return (char*) memcpy(buf, str, len);
766         if (bufsize)
767             *buf = '\0';
768         errno = ERANGE;
769     } else
770         errno = EINVAL;
771     return 0;
772 }
773 
774 
775 /*ARGSUSED*/
CORE_GetUsernameEx(char * buf,size_t bufsize,ECORE_Username username)776 extern const char* CORE_GetUsernameEx(char* buf, size_t bufsize,
777                                       ECORE_Username username)
778 {
779 #if defined(NCBI_OS_UNIX)
780     struct passwd* pwd;
781     struct stat    st;
782     uid_t          uid;
783 #  ifndef NCBI_OS_SOLARIS
784 #    define NCBI_GETUSERNAME_MAXBUFSIZE  1024
785 #    ifdef HAVE_GETLOGIN_R
786 #      ifndef LOGIN_NAME_MAX
787 #        ifdef _POSIX_LOGIN_NAME_MAX
788 #          define LOGIN_NAME_MAX _POSIX_LOGIN_NAME_MAX
789 #        else
790 #          define LOGIN_NAME_MAX 256
791 #        endif /*_POSIX_LOGIN_NAME_MAX*/
792 #      endif /*!LOGIN_NAME_MAX*/
793 #      define     NCBI_GETUSERNAME_BUFSIZE   LOGIN_NAME_MAX
794 #    endif /*HAVE_GETLOGIN_R*/
795 #    ifdef NCBI_HAVE_GETPWUID_R
796 #      ifndef     NCBI_GETUSERNAME_BUFSIZE
797 #        define   NCBI_GETUSERNAME_BUFSIZE   NCBI_GETUSERNAME_MAXBUFSIZE
798 #      else
799 #        if       NCBI_GETUSERNAME_BUFSIZE < NCBI_GETUSERNAME_MAXBUFSIZE
800 #          undef  NCBI_GETUSERNAME_BUFSIZE
801 #          define NCBI_GETUSERNAME_BUFSIZE   NCBI_GETUSERNAME_MAXBUFSIZE
802 #        endif /* NCBI_GETUSERNAME_BUFSIZE < NCBI_GETUSERNAME_MAXBUFSIZE */
803 #      endif /*NCBI_GETUSERNAME_BUFSIZE*/
804 #    endif /*NCBI_HAVE_GETPWUID_R*/
805 #    ifdef        NCBI_GETUSERNAME_BUFSIZE
806     char temp    [NCBI_GETUSERNAME_BUFSIZE + sizeof(*pwd)];
807 #    endif /*     NCBI_GETUSERNAME_BUFSIZE    */
808 #  endif /*!NCBI_OS_SOLARIS*/
809 #elif defined(NCBI_OS_MSWIN)
810 #  ifdef   UNLEN
811 #    define       NCBI_GETUSERNAME_BUFSIZE  UNLEN
812 #  else
813 #    define       NCBI_GETUSERNAME_BUFSIZE  256
814 #  endif /*UNLEN*/
815     TCHAR temp   [NCBI_GETUSERNAME_BUFSIZE + 2];
816     DWORD size = sizeof(temp)/sizeof(temp[0]) - 1;
817 #endif /*NCBI_OS*/
818     const char* login;
819 
820     assert(buf  &&  bufsize);
821 
822 #ifndef NCBI_OS_UNIX
823 
824 #  ifdef NCBI_OS_MSWIN
825     if (GetUserName(temp, &size)) {
826         assert(size < sizeof(temp)/sizeof(temp[0]) - 1);
827         temp[size] = (TCHAR) '\0';
828         login = UTIL_TcharToUtf8(temp);
829         buf = x_Savestr(login, buf, bufsize);
830         UTIL_ReleaseBuffer(login);
831         return buf;
832     }
833     CORE_LOCK_READ;
834     if ((login = getenv("USERNAME")) != 0) {
835         buf = x_Savestr(login, buf, bufsize);
836         CORE_UNLOCK;
837         return buf;
838     }
839     CORE_UNLOCK;
840 #  endif /*NCBI_OS_MSWIN*/
841 
842 #else
843 
844     /* NOTE:  getlogin() is not a very reliable call at least on Linux
845      * especially if programs mess up with "utmp":  since getlogin() first
846      * calls ttyname() to get the line name for FD 0, then searches "utmp"
847      * for the record of this line and returns the user name, any discrepancy
848      * can cause a false (stale) name to be returned.  So we use getlogin()
849      * here only as a fallback.
850      */
851     switch (username) {
852     case eCORE_UsernameCurrent:
853         uid = geteuid();
854         break;
855     case eCORE_UsernameLogin:
856         if (isatty(STDIN_FILENO)  &&  fstat(STDIN_FILENO, &st) == 0) {
857             uid = st.st_uid;
858             break;
859         }
860 #  if defined(NCBI_OS_SOLARIS)  ||  !defined(HAVE_GETLOGIN_R)
861         /* NB:  getlogin() is MT-safe on Solaris, yet getlogin_r() comes in two
862          * flavors that differ only in return type, so to make things simpler,
863          * use plain getlogin() here */
864 #    ifndef NCBI_OS_SOLARIS
865         CORE_LOCK_WRITE;
866 #    endif /*!NCBI_OS_SOLARIS*/
867         if ((login = getlogin()) != 0)
868             buf = x_Savestr(login, buf, bufsize);
869 #    ifndef NCBI_OS_SOLARIS
870         CORE_UNLOCK;
871 #    endif /*!NCBI_OS_SOLARIS*/
872         if (login)
873             return buf;
874 #  else
875         if (getlogin_r(temp, sizeof(temp) - 1) == 0) {
876             temp[sizeof(temp) - 1] = '\0';
877             return x_Savestr(temp, buf, bufsize);
878         }
879 #  endif /*NCBI_OS_SOLARIS || !HAVE_GETLOGIN_R*/
880         /*FALLTHRU*/
881     case eCORE_UsernameReal:
882         uid = getuid();
883         break;
884     default:
885         assert(0);
886         uid = (uid_t)(-1);
887         break;
888     }
889 
890 #  if defined(NCBI_OS_SOLARIS)                                          \
891     ||  (defined(HAVE_GETPWUID)  &&  !defined(NCBI_HAVE_GETPWUID_R))
892     /* NB:  getpwuid() is MT-safe on Solaris, so use it here, if available */
893 #    ifndef NCBI_OS_SOLARIS
894     CORE_LOCK_WRITE;
895 #    endif /*!NCBI_OS_SOLARIS*/
896     if ((pwd = getpwuid(uid)) != 0) {
897         if (pwd->pw_name)
898             buf = x_Savestr(pwd->pw_name, buf, bufsize);
899         else
900             pwd = 0;
901     }
902 #    ifndef NCBI_OS_SOLARIS
903     CORE_UNLOCK;
904 #    endif /*!NCBI_OS_SOLARIS*/
905     if (pwd)
906         return buf;
907 #  elif defined(NCBI_HAVE_GETPWUID_R)
908 #    if   NCBI_HAVE_GETPWUID_R == 4
909     /* obsolete but still existent */
910     pwd = getpwuid_r(uid, (struct passwd*) temp, temp + sizeof(*pwd),
911                      sizeof(temp) - sizeof(*pwd));
912 #    elif NCBI_HAVE_GETPWUID_R == 5
913     /* POSIX-conforming */
914     if (getpwuid_r(uid, (struct passwd*) temp, temp + sizeof(*pwd),
915                    sizeof(temp) - sizeof(*pwd), &pwd) != 0) {
916         pwd = 0;
917     }
918 #    else
919 #      error "Unknown value of NCBI_HAVE_GETPWUID_R: 4 or 5 expected."
920 #    endif /*NCBI_HAVE_GETPWUID_R*/
921     if (pwd  &&  pwd->pw_name)
922         return x_Savestr(pwd->pw_name, buf, bufsize);
923 #  endif /*NCBI_HAVE_GETPWUID_R*/
924 
925 #endif /*!NCBI_OS_UNIX*/
926 
927     /* last resort */
928     CORE_LOCK_READ;
929     if (!(login = getenv("USER"))  &&  !(login = getenv("LOGNAME")))
930         login = "";
931     buf = x_Savestr(login, buf, bufsize);
932     CORE_UNLOCK;
933     return buf;
934 }
935 
936 
CORE_GetUsername(char * buf,size_t bufsize)937 extern const char* CORE_GetUsername(char* buf, size_t bufsize)
938 {
939     const char* rv = CORE_GetUsernameEx(buf, bufsize, eCORE_UsernameLogin);
940     return rv  &&  *rv ? rv : 0;
941 }
942 
943 
944 
945 /****************************************************************************
946  * CORE_GetVMPageSize:  Get page size granularity
947  * See also at corelib's ncbi_system.cpp::GetVirtualMemoryPageSize().
948  */
949 
CORE_GetVMPageSize(void)950 extern size_t CORE_GetVMPageSize(void)
951 {
952     static size_t s_PS = 0;
953 
954     if (!s_PS) {
955 #if defined(NCBI_OS_MSWIN)  ||  defined(NCBI_OS_CYGWIN)
956         /* NB: CYGWIN's PAGESIZE (== PAGE_SIZE) is actually the granularity */
957         SYSTEM_INFO si;
958         GetSystemInfo(&si);
959         s_PS = (size_t) si.dwPageSize;
960 #elif defined(NCBI_OS_UNIX)
961 #  if   defined(_SC_PAGESIZE)
962 #    define NCBI_SC_PAGESIZE  _SC_PAGESIZE
963 #  elif defined(_SC_PAGE_SIZE)
964 #    define NCBI_SC_PAGESIZE  _SC_PAGE_SIZE
965 #  elif defined(NCBI_SC_PAGESIZE)
966 #    undef  NCBI_SC_PAGESIZE
967 #  endif
968 #  ifndef   NCBI_SC_PAGESIZE
969         long x = 0;
970 #  else
971         long x = sysconf(NCBI_SC_PAGESIZE);
972 #    undef  NCBI_SC_PAGESIZE
973 #  endif
974         if (x <= 0) {
975 #  ifdef HAVE_GETPAGESIZE
976             if ((x = getpagesize()) <= 0)
977                 return NCBI_DEFAULT_PAGE_SIZE;
978 #  else
979             return NCBI_DEFAULT_PAGE_SIZE;
980 #  endif /*HAVE_GETPAGESIZE*/
981         }
982         s_PS = (size_t) x;
983 #endif /*OS_TYPE*/
984     }
985     return s_PS;
986 }
987 
988 
989 
990 /****************************************************************************
991  * CORE_Msdelay
992  */
993 
CORE_Msdelay(unsigned long ms)994 extern void CORE_Msdelay(unsigned long ms)
995 {
996 #if   defined(NCBI_OS_MSWIN)
997     Sleep(ms);
998 #elif defined(NCBI_OS_UNIX)
999 #  if    defined(HAVE_NANOSLEEP)
1000     struct timespec ts;
1001     ts.tv_sec  = (time_t)(ms / 1000);
1002     ts.tv_nsec = (long) ((ms % 1000) * 1000000);
1003     nanosleep(&ts, 0);
1004 #  elif !defined(NCBI_OS_DARWIN)  &&  defined(HAVE_POLL_H)
1005     poll(0, 0, (int) ms);
1006 #  else
1007     struct timeval tv;
1008     tv.tv_sec  = (long) (ms / 1000);
1009     tv.tv_usec = (long)((ms % 1000) * 1000);
1010     select(0, 0, 0, 0, &tv);
1011 #  endif /*HAVE_NANOSLEEP*/
1012 #else
1013 #  error "Unsupported platform."
1014 #endif /*NCBI_OS*/
1015 }
1016 
1017 
1018 
1019 /****************************************************************************
1020  * CRC32
1021  */
1022 
1023 /* Standard Ethernet/ZIP polynomial */
1024 #define CRC32_POLY  0x04C11DB7U
1025 
1026 
1027 #ifdef NCBI_USE_PRECOMPILED_CRC32_TABLES
1028 
1029 static const unsigned int s_CRC32Table[256] = {
1030     0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9,
1031     0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005,
1032     0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61,
1033     0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD,
1034     0x4C11DB70, 0x48D0C6C7, 0x4593E01E, 0x4152FDA9,
1035     0x5F15ADAC, 0x5BD4B01B, 0x569796C2, 0x52568B75,
1036     0x6A1936C8, 0x6ED82B7F, 0x639B0DA6, 0x675A1011,
1037     0x791D4014, 0x7DDC5DA3, 0x709F7B7A, 0x745E66CD,
1038     0x9823B6E0, 0x9CE2AB57, 0x91A18D8E, 0x95609039,
1039     0x8B27C03C, 0x8FE6DD8B, 0x82A5FB52, 0x8664E6E5,
1040     0xBE2B5B58, 0xBAEA46EF, 0xB7A96036, 0xB3687D81,
1041     0xAD2F2D84, 0xA9EE3033, 0xA4AD16EA, 0xA06C0B5D,
1042     0xD4326D90, 0xD0F37027, 0xDDB056FE, 0xD9714B49,
1043     0xC7361B4C, 0xC3F706FB, 0xCEB42022, 0xCA753D95,
1044     0xF23A8028, 0xF6FB9D9F, 0xFBB8BB46, 0xFF79A6F1,
1045     0xE13EF6F4, 0xE5FFEB43, 0xE8BCCD9A, 0xEC7DD02D,
1046     0x34867077, 0x30476DC0, 0x3D044B19, 0x39C556AE,
1047     0x278206AB, 0x23431B1C, 0x2E003DC5, 0x2AC12072,
1048     0x128E9DCF, 0x164F8078, 0x1B0CA6A1, 0x1FCDBB16,
1049     0x018AEB13, 0x054BF6A4, 0x0808D07D, 0x0CC9CDCA,
1050     0x7897AB07, 0x7C56B6B0, 0x71159069, 0x75D48DDE,
1051     0x6B93DDDB, 0x6F52C06C, 0x6211E6B5, 0x66D0FB02,
1052     0x5E9F46BF, 0x5A5E5B08, 0x571D7DD1, 0x53DC6066,
1053     0x4D9B3063, 0x495A2DD4, 0x44190B0D, 0x40D816BA,
1054     0xACA5C697, 0xA864DB20, 0xA527FDF9, 0xA1E6E04E,
1055     0xBFA1B04B, 0xBB60ADFC, 0xB6238B25, 0xB2E29692,
1056     0x8AAD2B2F, 0x8E6C3698, 0x832F1041, 0x87EE0DF6,
1057     0x99A95DF3, 0x9D684044, 0x902B669D, 0x94EA7B2A,
1058     0xE0B41DE7, 0xE4750050, 0xE9362689, 0xEDF73B3E,
1059     0xF3B06B3B, 0xF771768C, 0xFA325055, 0xFEF34DE2,
1060     0xC6BCF05F, 0xC27DEDE8, 0xCF3ECB31, 0xCBFFD686,
1061     0xD5B88683, 0xD1799B34, 0xDC3ABDED, 0xD8FBA05A,
1062     0x690CE0EE, 0x6DCDFD59, 0x608EDB80, 0x644FC637,
1063     0x7A089632, 0x7EC98B85, 0x738AAD5C, 0x774BB0EB,
1064     0x4F040D56, 0x4BC510E1, 0x46863638, 0x42472B8F,
1065     0x5C007B8A, 0x58C1663D, 0x558240E4, 0x51435D53,
1066     0x251D3B9E, 0x21DC2629, 0x2C9F00F0, 0x285E1D47,
1067     0x36194D42, 0x32D850F5, 0x3F9B762C, 0x3B5A6B9B,
1068     0x0315D626, 0x07D4CB91, 0x0A97ED48, 0x0E56F0FF,
1069     0x1011A0FA, 0x14D0BD4D, 0x19939B94, 0x1D528623,
1070     0xF12F560E, 0xF5EE4BB9, 0xF8AD6D60, 0xFC6C70D7,
1071     0xE22B20D2, 0xE6EA3D65, 0xEBA91BBC, 0xEF68060B,
1072     0xD727BBB6, 0xD3E6A601, 0xDEA580D8, 0xDA649D6F,
1073     0xC423CD6A, 0xC0E2D0DD, 0xCDA1F604, 0xC960EBB3,
1074     0xBD3E8D7E, 0xB9FF90C9, 0xB4BCB610, 0xB07DABA7,
1075     0xAE3AFBA2, 0xAAFBE615, 0xA7B8C0CC, 0xA379DD7B,
1076     0x9B3660C6, 0x9FF77D71, 0x92B45BA8, 0x9675461F,
1077     0x8832161A, 0x8CF30BAD, 0x81B02D74, 0x857130C3,
1078     0x5D8A9099, 0x594B8D2E, 0x5408ABF7, 0x50C9B640,
1079     0x4E8EE645, 0x4A4FFBF2, 0x470CDD2B, 0x43CDC09C,
1080     0x7B827D21, 0x7F436096, 0x7200464F, 0x76C15BF8,
1081     0x68860BFD, 0x6C47164A, 0x61043093, 0x65C52D24,
1082     0x119B4BE9, 0x155A565E, 0x18197087, 0x1CD86D30,
1083     0x029F3D35, 0x065E2082, 0x0B1D065B, 0x0FDC1BEC,
1084     0x3793A651, 0x3352BBE6, 0x3E119D3F, 0x3AD08088,
1085     0x2497D08D, 0x2056CD3A, 0x2D15EBE3, 0x29D4F654,
1086     0xC5A92679, 0xC1683BCE, 0xCC2B1D17, 0xC8EA00A0,
1087     0xD6AD50A5, 0xD26C4D12, 0xDF2F6BCB, 0xDBEE767C,
1088     0xE3A1CBC1, 0xE760D676, 0xEA23F0AF, 0xEEE2ED18,
1089     0xF0A5BD1D, 0xF464A0AA, 0xF9278673, 0xFDE69BC4,
1090     0x89B8FD09, 0x8D79E0BE, 0x803AC667, 0x84FBDBD0,
1091     0x9ABC8BD5, 0x9E7D9662, 0x933EB0BB, 0x97FFAD0C,
1092     0xAFB010B1, 0xAB710D06, 0xA6322BDF, 0xA2F33668,
1093     0xBCB4666D, 0xB8757BDA, 0xB5365D03, 0xB1F740B4
1094 };
1095 
1096 #else
1097 
1098 static unsigned int s_CRC32Table[256];
1099 
s_CRC32_Init(void)1100 static void s_CRC32_Init(void)
1101 {
1102     size_t i;
1103 
1104     if (s_CRC32Table[255])
1105         return;
1106 
1107     for (i = 0;  i < 256;  ++i) {
1108         unsigned int byteCRC = (unsigned int) i << 24;
1109         int j;
1110         for (j = 0;  j < 8;  ++j) {
1111             if (byteCRC & 0x80000000U) {
1112                 byteCRC <<= 1;
1113                 byteCRC  ^= CRC32_POLY;
1114             } else
1115                 byteCRC <<= 1;
1116         }
1117         s_CRC32Table[i] = byteCRC;
1118     }
1119 }
1120 
1121 #endif /*NCBI_USE_PRECOMPILED_CRC32_TABLES*/
1122 
1123 
UTIL_CRC32_Update(unsigned int checksum,const void * ptr,size_t len)1124 extern unsigned int UTIL_CRC32_Update(unsigned int checksum,
1125                                       const void *ptr, size_t len)
1126 {
1127     const unsigned char* data = (const unsigned char*) ptr;
1128     size_t i;
1129 
1130 #ifndef NCBI_USE_PRECOMPILED_CRC32_TABLES
1131     s_CRC32_Init();
1132 #endif /*NCBI_USE_PRECOMPILED_CRC32_TABLES*/
1133 
1134     for (i = 0;  i < len;  ++i) {
1135         size_t k = ((checksum >> 24) ^ *data++) & 0xFF;
1136         checksum <<= 8;
1137         checksum  ^= s_CRC32Table[k];
1138     }
1139 
1140     return checksum;
1141 }
1142 
1143 
1144 #define MOD_ADLER          65521
1145 #define MAXLEN_ADLER       5548  /* max len to run without overflows */
1146 #define ADJUST_ADLER(a)    a = (a & 0xFFFF) + (a >> 16) * (0x10000 - MOD_ADLER)
1147 #define FINALIZE_ADLER(a)  if (a >= MOD_ADLER) a -= MOD_ADLER
1148 
UTIL_Adler32_Update(unsigned int checksum,const void * ptr,size_t len)1149 unsigned int UTIL_Adler32_Update(unsigned int checksum,
1150                                  const void* ptr, size_t len)
1151 {
1152     const unsigned char* data = (const unsigned char*) ptr;
1153     unsigned int a = checksum & 0xFFFF, b = checksum >> 16;
1154 
1155     while (len) {
1156         size_t i;
1157         if (len >= MAXLEN_ADLER) {
1158             len -= MAXLEN_ADLER;
1159             for (i = 0;  i < MAXLEN_ADLER/4;  ++i) {
1160                 b += a += data[0];
1161                 b += a += data[1];
1162                 b += a += data[2];
1163                 b += a += data[3];
1164                 data += 4;
1165             }
1166         } else {
1167             for (i = len >> 2;  i;  --i) {
1168                 b += a += data[0];
1169                 b += a += data[1];
1170                 b += a += data[2];
1171                 b += a += data[3];
1172                 data += 4;
1173             }
1174             for (len &= 3;  len;  --len) {
1175                 b += a += *data++;
1176             }
1177         }
1178         ADJUST_ADLER(a);
1179         ADJUST_ADLER(b);
1180     }
1181     /* It can be shown that a <= 0x1013A here, so a single subtract will do. */
1182     FINALIZE_ADLER(a);
1183     /* It can be shown that b can reach 0xFFEF1 here. */
1184     ADJUST_ADLER(b);
1185     FINALIZE_ADLER(b);
1186     return (b << 16) | a;
1187 }
1188 
1189 #undef MOD_ADLER
1190 #undef MAXLEN_ADLER
1191 #undef ADJUST_ADLER
1192 #undef FINALIZE_ADLER
1193 
1194 
UTIL_GenerateHMAC(const SHASH_Descriptor * hash,const void * text,size_t text_len,const void * key,size_t key_len,void * digest)1195 extern void* UTIL_GenerateHMAC(const SHASH_Descriptor* hash,
1196                                const void*             text,
1197                                size_t                  text_len,
1198                                const void*             key,
1199                                size_t                  key_len,
1200                                void*                   digest)
1201 {
1202     unsigned char* pad;
1203     void* ctx;
1204     size_t i;
1205 
1206     if (!hash  ||  !text  ||  !key  ||  !digest)
1207         return 0;
1208 
1209     if (!(pad = (unsigned char*) malloc(hash->block_len + hash->digest_len)))
1210         return 0;
1211 
1212     if (key_len > hash->block_len) {
1213         void* tmp;
1214         if (!hash->init(&ctx)) {
1215             free(pad);
1216             return 0;
1217         }
1218         tmp = pad + hash->block_len;
1219         hash->update(ctx, key, key_len);
1220         hash->fini(ctx, tmp);
1221         key     = tmp;
1222         key_len = hash->digest_len;
1223     }
1224 
1225     if (!hash->init(&ctx)) {
1226         free(pad);
1227         return 0;
1228     }
1229 
1230     for (i = 0;  i < key_len;  ++i)
1231         pad[i] = 0x36 ^ ((unsigned char*) key)[i];
1232     for (;  i < hash->block_len;  ++i)
1233         pad[i] = 0x36;
1234 
1235     hash->update(ctx, pad,  hash->block_len);
1236     hash->update(ctx, text, text_len);
1237 
1238     hash->fini(ctx, digest);
1239 
1240     if (!hash->init(&ctx)) {
1241         free(pad);
1242         return 0;
1243     }
1244 
1245     for (i = 0;  i < key_len;  ++i)
1246         pad[i] = 0x5C ^ ((unsigned char*) key)[i];
1247     for (;  i < hash->block_len;  ++i)
1248         pad[i] = 0x5C;
1249 
1250     hash->update(ctx, pad,    hash->block_len);
1251     hash->update(ctx, digest, hash->digest_len);
1252 
1253     hash->fini(ctx, digest);
1254 
1255     free(pad);
1256     return digest;
1257 }
1258 
1259 
1260 
1261 /******************************************************************************
1262  *  MISCELLANEOUS
1263  */
1264 
1265 
1266 /*  1 = match;
1267  *  0 = no match;
1268  * -1 = no match, stop search
1269  */
x_MatchesMask(const char * text,const char * mask,int ignore_case)1270 static int/*tri-state*/ x_MatchesMask(const char* text, const char* mask,
1271                                       int/*bool*/ ignore_case)
1272 {
1273     char a, b, c, p;
1274     for (;  (p = *mask++);  ++text) {
1275         c = *text;
1276         if (!c  &&  p != '*')
1277             return -1/*mismatch, stop*/;
1278         switch (p) {
1279         case '?':
1280             assert(c);
1281             continue;
1282         case '*':
1283             p = *mask;
1284             while (p == '*')
1285                 p = *++mask;
1286             if (!p)
1287                 return 1/*match*/;
1288             while (*text) {
1289                 int matches = x_MatchesMask(text++, mask, ignore_case);
1290                 if (matches/*!=0*/)
1291                     return matches;
1292             }
1293             return -1/*mismatch, stop*/;
1294         case '[':
1295             if (!(p = *mask))
1296                 return -1/*mismatch, pattern error*/;
1297             if (p == '!') {
1298                 p  = 1/*complement*/;
1299                 ++mask;
1300             } else
1301                 p  = 0;
1302             if (ignore_case)
1303                 c = (char) tolower((unsigned char) c);
1304             assert(c);
1305             do {
1306                 if (!(a = *mask++))
1307                     return -1/*mismatch, pattern error*/;
1308                 if (*mask == '-'  &&  mask[1] != ']') {
1309                     ++mask;
1310                     if (!(b = *mask++))
1311                         return -1/*mismatch, pattern error*/;
1312                 } else
1313                     b = a;
1314                 if (c) {
1315                     if (ignore_case) {
1316                         a = (char) tolower((unsigned char) a);
1317                         b = (char) tolower((unsigned char) b);
1318                     }
1319                     if (a <= c  &&  c <= b)
1320                         c = 0/*mark as found*/;
1321                 }
1322             } while (*mask != ']');
1323             if (p == !c)
1324                 return 0/*mismatch*/;
1325             ++mask/*skip ']'*/;
1326             continue;
1327         case '\\':
1328             if (!(p = *mask++))
1329                 return -1/*mismatch, pattern error*/;
1330             /*FALLTHRU*/
1331         default:
1332             assert(c  &&  p);
1333             if (ignore_case) {
1334                 c = (char) tolower((unsigned char) c);
1335                 p = (char) tolower((unsigned char) p);
1336             }
1337             if (c != p)
1338                 return 0/*mismatch*/;
1339             continue;
1340         }
1341     }
1342     return !*text;
1343 }
1344 
1345 
UTIL_MatchesMaskEx(const char * text,const char * mask,int ignore_case)1346 extern int/*bool*/ UTIL_MatchesMaskEx(const char* text, const char* mask,
1347                                       int/*bool*/ ignore_case)
1348 {
1349     return x_MatchesMask(text, mask, ignore_case) == 1 ? 1/*T*/ : 0/*F*/;
1350 }
1351 
1352 
UTIL_MatchesMask(const char * text,const char * mask)1353 extern int/*bool*/ UTIL_MatchesMask(const char* text, const char* mask)
1354 {
1355     return UTIL_MatchesMaskEx(text, mask, 1/*ignore case*/);
1356 }
1357 
1358 
UTIL_NcbiLocalHostName(char * hostname)1359 extern char* UTIL_NcbiLocalHostName(char* hostname)
1360 {
1361     static const struct {
1362         const char*  end;
1363         const size_t len;
1364     } kEndings[] = {
1365         {".ncbi.nlm.nih.gov", 17},
1366         {".ncbi.nih.gov",     13}
1367     };
1368     size_t len = hostname ? strlen(hostname) : 0;
1369     if (len  &&  hostname[len - 1] == '.')
1370         len--;
1371     if (len) {
1372         size_t i;
1373         for (i = 0;  i < sizeof(kEndings) / sizeof(kEndings[0]);  ++i) {
1374             assert(strlen(kEndings[i].end) == kEndings[i].len);
1375             if (len > kEndings[i].len) {
1376                 size_t beg = len - kEndings[i].len;
1377                 if (hostname[beg - 1] != '.'
1378                     &&  strncasecmp(hostname + beg,
1379                                     kEndings[i].end,
1380                                     kEndings[i].len) == 0) {
1381                     hostname[beg] = '\0';
1382                     return hostname;
1383                 }
1384             }
1385         }
1386     }
1387     return 0;
1388 }
1389 
1390 
1391 #ifdef NCBI_OS_MSWIN
1392 
1393 
1394 #  ifdef _UNICODE
1395 
UTIL_TcharToUtf8OnHeap(const TCHAR * str)1396 extern const char* UTIL_TcharToUtf8OnHeap(const TCHAR* str)
1397 {
1398     const char* s = UTIL_TcharToUtf8(str);
1399     UTIL_ReleaseBufferOnHeap(str);
1400     return s;
1401 }
1402 
1403 
1404 /*
1405  * UTIL_TcharToUtf8() is defined in ncbi_strerror.c
1406  */
1407 
1408 
UTIL_Utf8ToTchar(const char * str)1409 extern const TCHAR* UTIL_Utf8ToTchar(const char* str)
1410 {
1411     TCHAR* s = NULL;
1412     if (str) {
1413         /* Note "-1" means to consume all input including the trailing NUL */
1414         int n = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
1415         if (n > 0) {
1416             s = (wchar_t*) LocalAlloc(LMEM_FIXED, n * sizeof(*s));
1417             if (s)
1418                 MultiByteToWideChar(CP_UTF8, 0, str, -1, s,    n);
1419         }
1420     }
1421     return s;
1422 }
1423 
1424 #  endif /*_UNICODE*/
1425 
1426 
1427 /*
1428  * UTIL_ReleaseBufferOnHeap() is defined in ncbi_strerror.c
1429  */
1430 
1431 
1432 #endif /*NCBI_OS_MSWIN*/
1433