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