1 #ifndef CONNECT___NCBI_UTIL__H 2 #define CONNECT___NCBI_UTIL__H 3 4 /* $Id: ncbi_util.h,v 6.63 2016/01/06 13:49:16 fukanchi Exp $ 5 * =========================================================================== 6 * 7 * PUBLIC DOMAIN NOTICE 8 * National Center for Biotechnology Information 9 * 10 * This software/database is a "United States Government Work" under the 11 * terms of the United States Copyright Act. It was written as part of 12 * the author's official duties as a United States Government employee and 13 * thus cannot be copyrighted. This software/database is freely available 14 * to the public for use. The National Library of Medicine and the U.S. 15 * Government have not placed any restriction on its use or reproduction. 16 * 17 * Although all reasonable efforts have been taken to ensure the accuracy 18 * and reliability of the software and data, the NLM and the U.S. 19 * Government do not and cannot warrant the performance or results that 20 * may be obtained by using this software or data. The NLM and the U.S. 21 * Government disclaim all warranties, express or implied, including 22 * warranties of performance, merchantability or fitness for any particular 23 * purpose. 24 * 25 * Please cite the author in any work or product based on this material. 26 * 27 * =========================================================================== 28 * 29 * Authors: Denis Vakatov, Anton Lavrentiev 30 * 31 * @file 32 * File Description: 33 * Auxiliaries (mostly optional core to back and complement "ncbi_core.[ch]") 34 * @sa 35 * ncbi_core.h 36 * 37 * 1. CORE support: 38 * macros: LOG_WRITE(), LOG_DATA(), 39 * THIS_MODULE, CORE_CURRENT_FUNCTION 40 * flags: TLOG_FormatFlags, ELOG_FormatFlags 41 * methods: LOG_ComposeMessage(), LOG_ToFILE(), NcbiMessagePlusError(), 42 * CORE_SetLOCK(), CORE_GetLOCK(), 43 * CORE_SetLOG(), CORE_GetLOG(), 44 * CORE_SetLOGFILE[_Ex](), CORE_SetLOGFILE_NAME[_Ex]() 45 * LOG_ToFILE[_Ex]() 46 * 47 * 2. Auxiliary API: 48 * CORE_GetAppName() 49 * CORE_GetNcbiRequestID() 50 * CORE_GetPlatform() 51 * CORE_GetUsername[Ex]() 52 * CORE_GetVMPageSize() 53 * 54 * 3. Checksumming support: 55 * UTIL_CRC32_Update() 56 * UTIL_Adler32_Update() 57 * 58 * 4. Miscellaneous: 59 * UTIL_MatchesMask[Ex]() 60 * UTIL_NcbiLocalHostName() 61 * UTIL_PrintableString[Size]() 62 * 63 * 5. Internal MSWIN support for Unicode (mostly in error messages) 64 * 65 */ 66 67 #include <connect/ncbi_core.h> 68 #include <stdio.h> 69 70 71 /** @addtogroup UtilityFunc 72 * 73 * @{ 74 */ 75 76 77 #ifdef __cplusplus 78 extern "C" { 79 #endif 80 81 82 /****************************************************************************** 83 * MT locking 84 */ 85 86 /** Set the MT critical section lock/unlock handler -- to be used by the core 87 * internals for protection of internal static variables and other MT-sensitive 88 * code from being accessed/changed by several threads simultaneously. 89 * It is also to fully protect the core log handler, including its setting up, 90 * and its callback and cleanup functions. 91 * @li <b>NOTES:</b> This function itself is NOT MT-safe! 92 * @li <b>NOTES:</b> If there is an active CORE MT-lock set already, which 93 * is different from the new one, then MT_LOCK_Delete() is called for 94 * the old lock (i.e. the one being replaced). 95 * @param lk 96 * MT-Lock as created by MT_LOCK_Create 97 * @sa 98 * MT_LOCK_Create, CORE_SetLOG 99 */ 100 extern NCBI_XCONNECT_EXPORT void CORE_SetLOCK(MT_LOCK lk); 101 extern NCBI_XCONNECT_EXPORT MT_LOCK CORE_GetLOCK(void); 102 103 104 105 /****************************************************************************** 106 * Error handling and logging 107 */ 108 109 /** Auxiliary plain macros to write message (maybe, with raw data) to the log. 110 * @sa 111 * LOG_Write 112 */ 113 #define LOG_WRITE(lg, code, subcode, level, message) \ 114 LOG_Write(lg, code, subcode, level, THIS_MODULE, CORE_CURRENT_FUNCTION, \ 115 __FILE__, __LINE__, message, 0, 0) 116 117 #ifdef LOG_DATA 118 /* AIX's <pthread.h> defines LOG_DATA to be an integer constant; 119 we must explicitly drop such definitions to avoid trouble */ 120 # undef LOG_DATA 121 #endif 122 #define LOG_DATA(lg, code, subcode, level, data, size, message) \ 123 LOG_Write(lg, code, subcode, level, THIS_MODULE, CORE_CURRENT_FUNCTION, \ 124 __FILE__, __LINE__, message, data, size) 125 126 127 /** Default for THIS_MODULE. 128 */ 129 #ifndef THIS_MODULE 130 # define THIS_MODULE 0 131 #endif 132 133 134 /** Get current function name. 135 * @note Defined inside of either a method or a function body only. 136 * See <corelib/ncbidiag.hpp> for definition of NCBI_CURRENT_FUNCTION. 137 */ 138 #if defined(__GNUC__) || \ 139 (defined(__MWERKS__) && (__MWERKS__ >= 0x3000)) || \ 140 (defined(__ICC) && (__ICC >= 600)) 141 # define CORE_CURRENT_FUNCTION __PRETTY_FUNCTION__ 142 #elif defined(__FUNCSIG__) 143 # define CORE_CURRENT_FUNCTION __FUNCSIG__ 144 #elif (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 600)) || \ 145 (defined(__IBMCPP__) && (__IBMCPP__ >= 500)) 146 # define CORE_CURRENT_FUNCTION __FUNCTION__ 147 #elif defined(__BORLANDC__) && (__BORLANDC__ >= 0x550) 148 # define CORE_CURRENT_FUNCTION __FUNC__ 149 #elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901) 150 # define CORE_CURRENT_FUNCTION __func__ 151 #else 152 # define CORE_CURRENT_FUNCTION 0 153 #endif 154 155 156 /** Set the log handle (no logging if "lg" is passed zero) -- to be used by 157 * the core internals. 158 * If there is an active log handler set already, and it is different from 159 * the new one, then LOG_Delete is called for the old logger (that is, 160 * the one being replaced). 161 * @param lg 162 * LOG handle as returned by LOG_Create, or NULL to stop logging 163 * @sa 164 * LOG_Create, LOG_Delete, CORE_GetLOG 165 */ 166 extern NCBI_XCONNECT_EXPORT void CORE_SetLOG(LOG lg); 167 168 169 /** Get the log handle which is be used by the core internals. 170 * @return 171 * LOG handle as set by CORE_SetLOG or NULL if no logging is currently active 172 * @li <b>NOTE:</b> You may not delete the handle (by means of LOG_Delete). 173 * @sa 174 * CORE_SetLOG, LOG_Create, LOG_Delete 175 */ 176 extern NCBI_XCONNECT_EXPORT LOG CORE_GetLOG(void); 177 178 179 /** Standard logging to the specified file stream. 180 * @param fp 181 * The file stream to log to 182 * @param cut_off 183 * Do not post messages with severity levels lower than specified 184 * @param fatal_err 185 * Severity greater or equal to "fatal_err" always logs and aborts the program 186 * @param auto_close 187 * Do "fclose(fp)" when the LOG is reset/destroyed 188 * @sa 189 * LOG_ToFILE_Ex, CORE_SetLOG 190 */ 191 extern NCBI_XCONNECT_EXPORT void CORE_SetLOGFILE_Ex 192 (FILE* fp, 193 ELOG_Level cut_off, 194 ELOG_Level fatal_err, 195 int/*bool*/ auto_close 196 ); 197 198 199 /** Same as CORE_SetLOGFILE_Ex(fp, eLOG_Trace, eLOG_Fatal, auto_close). 200 * @sa 201 * CORE_SetLOGFILE_Ex, CORE_SetLOG 202 */ 203 extern NCBI_XCONNECT_EXPORT void CORE_SetLOGFILE 204 (FILE* fp, 205 int/*bool*/ auto_close 206 ); 207 208 209 /** Same as CORE_SetLOGFILE_Ex(fopen(logfile, "a"), cut_off, fatal_err, TRUE). 210 * @param logile 211 * Filename to write the log into 212 * @param cut_off 213 * Do not post messages with severity levels lower than specified 214 * @param fatal_err 215 * Severity greater or equal to "fatal_err" always logs and aborts the program 216 * @return 217 * Return zero on error, non-zero on success 218 * @sa 219 * CORE_SetLOGFILE_Ex, CORE_SetLOG 220 */ 221 extern NCBI_XCONNECT_EXPORT int/*bool*/ CORE_SetLOGFILE_NAME_Ex 222 (const char* logfile, 223 ELOG_Level cut_off, 224 ELOG_Level fatal_err 225 ); 226 227 228 /** Same as CORE_SetLOGFILE_NAME_Ex(logfile, eLOG_Trace, eLOG_Fatal). 229 * @sa 230 * CORE_SetLOGFILE_NAME_Ex, CORE_SetLOG 231 */ 232 extern NCBI_XCONNECT_EXPORT int/*bool*/ CORE_SetLOGFILE_NAME 233 (const char* logfile 234 ); 235 236 237 /** LOG formatting flags: what parts of the message to actually appear. 238 * @sa 239 * CORE_SetLOGFormatFlags 240 */ 241 enum ELOG_FormatFlag { 242 fLOG_Default = 0x0, /**< fLOG_Short if NDEBUG, else fLOG_Full */ 243 fLOG_Level = 0x1, 244 fLOG_Module = 0x2, 245 fLOG_FileLine = 0x4, 246 fLOG_DateTime = 0x8, 247 fLOG_Function = 0x10, 248 fLOG_FullOctal = 0x2000, /**< do not do reduction in octal data bytes*/ 249 fLOG_OmitNoteLevel = 0x4000, /**< do not add NOTE if eLOG_Note is level */ 250 fLOG_None = 0x8000 /**< nothing but spec'd parts, msg and data */ 251 }; 252 typedef unsigned int TLOG_FormatFlags; /**< bitwise OR of "ELOG_FormatFlag" */ 253 #define fLOG_Short fLOG_Level 254 #define fLOG_Full (fLOG_Level | fLOG_Module | fLOG_FileLine) 255 256 extern NCBI_XCONNECT_EXPORT TLOG_FormatFlags CORE_SetLOGFormatFlags 257 (TLOG_FormatFlags 258 ); 259 260 261 /** Compose message using the "call_data" info. 262 * Full log record format: 263 * mm/dd/yy HH:MM:SS "<file>", line <line>: [<module>::<function>] <level>: <message> 264 * \n----- [BEGIN] Raw Data (<raw_size> bytes) -----\n 265 * <raw_data> 266 * \n----- [END] Raw Data -----\n 267 * 268 * @note The returned string must be deallocated using "free()". 269 * 270 * @param call_data 271 * Parts of the message 272 * @param format_flags 273 * Which fields of "call_data" to use 274 * @sa 275 * CORE_SetLOG, CORE_SetLOGFormatFlags 276 */ 277 extern NCBI_XCONNECT_EXPORT char* LOG_ComposeMessage 278 (const SLOG_Handler* call_data, 279 TLOG_FormatFlags format_flags 280 ); 281 282 283 /** LOG_Reset specialized to log to a "FILE*" stream using LOG_ComposeMessage. 284 * @param lg 285 * Created by LOG_Create 286 * @param fp 287 * The file stream to log to 288 * @param cut_off 289 * Do not post messages with severity levels lower than specified 290 * @param fatal_err 291 * Severity greater or equal to "fatal_err" always logs and aborts the program 292 * @param auto_close 293 * Whether to do "fclose(fp)" when the LOG is reset/destroyed 294 * @sa 295 * LOG_Create, LOG_Reset, LOG_ComposeMessage, LOG_ToFILE 296 */ 297 extern NCBI_XCONNECT_EXPORT void LOG_ToFILE_Ex 298 (LOG lg, 299 FILE* fp, 300 ELOG_Level cut_off, 301 ELOG_Level fatal_err, 302 int/*bool*/ auto_close 303 ); 304 305 306 /** Same as LOG_ToFILEx(lg, fp, eLOG_Trace, eLOG_Fatal, auto_close). 307 * @sa 308 * LOG_ToFILE_Ex 309 */ 310 extern NCBI_XCONNECT_EXPORT void LOG_ToFILE 311 (LOG lg, 312 FILE* fp, 313 int/*bool*/ auto_close 314 ); 315 316 317 /** Add current "error" (and maybe its description) to the message: 318 * <message>[ {error=[[<error>][,]][<descr>]}] 319 * @param dynamic 320 * [inout] non-zero pointed value means message was allocated from heap 321 * @param message 322 * [in] message text (can be NULL) 323 * @param error 324 * [in] error code (if it is zero, then use "descr" only if non-NULL/empty) 325 * @param descr 326 * [in] error description (if NULL, then use "strerror(error)" if error!=0) 327 * @return 328 * Always non-NULL message (perhaps, "") and re-set "*dynamic" as appropriate. 329 * @li <b>NOTE:</b> this routine may call "free(message)" if it had 330 * to reallocate the original message that had been allocated dynamically 331 * before the call (and "*dynamic" thus had been passed non-zero). 332 * @sa 333 * LOG_ComposeMessage 334 */ 335 extern NCBI_XCONNECT_EXPORT const char* NcbiMessagePlusError 336 (int/*bool*/ *dynamic, 337 const char* message, 338 int error, 339 const char* descr 340 ); 341 342 343 344 /****************************************************************************** 345 * Registry 346 */ 347 348 /** Set the registry (no registry if "rg" is passed zero) -- to be used by 349 * the core internals. 350 * If there is an active registry set already, and it is different from 351 * the new one, then REG_Delete() is called for the old(replaced) registry. 352 * @param rg 353 * Registry handle as returned by REG_Create() 354 * @sa 355 * REG_Create, CORE_GetREG 356 */ 357 extern NCBI_XCONNECT_EXPORT void CORE_SetREG(REG rg); 358 359 360 /** Get the registry previously set by CORE_SetREG(). 361 * @return 362 * Registry handle. 363 * <li>NOTE:</li> You may not delete the handle with REG_Delete(). 364 * @sa 365 * CORE_SetREG 366 */ 367 extern NCBI_XCONNECT_EXPORT REG CORE_GetREG(void); 368 369 370 /****************************************************************************** 371 * Auxiliary API 372 */ 373 374 /** Obtain current application name (toolkit dependent). 375 * @return 376 * Return an empty string ("") when the application name cannot be determined; 377 * otherwise, return a '\0'-terminated string 378 * 379 * NOTE that setting an application name concurrently with this 380 * call can cause undefined behavior or a stale pointer returned. 381 */ 382 extern NCBI_XCONNECT_EXPORT const char* CORE_GetAppName(void); 383 384 385 /** NCBI request ID enumerator */ 386 typedef enum { 387 eNcbiRequestID_None = 0, 388 eNcbiRequestID_HitID, /**< NCBI Hit ID */ 389 eNcbiRequestID_SID /**< NCBI Session ID */ 390 } ENcbiRequestID; 391 392 393 /** NCBI request "DTab-Local" header */ 394 extern NCBI_XCONNECT_EXPORT char* CORE_GetNcbiRequestDtab; 395 396 397 /** Obtain current NCBI request ID (if known, per thread). 398 * @return 399 * Return NULL when the ID cannot be determined or an error has occurred; 400 * otherwise, return a '\0'-terminated, non-empty string that is allocated 401 * on the heap, and must be free()'d when no longer needed. 402 */ 403 extern NCBI_XCONNECT_EXPORT char* CORE_GetNcbiRequestID 404 (ENcbiRequestID reqid); 405 406 407 /** Return NCBI platrofm ID (if known). 408 * @return 409 * Return read-only textual but machine-readable platform description. 410 */ 411 extern NCBI_XCONNECT_EXPORT const char* CORE_GetPlatform(void); 412 413 414 /** Select which username is the most preferable to obtain from the system. */ 415 typedef enum { 416 eCORE_UsernameCurrent, /**< process UID */ 417 eCORE_UsernameLogin, /**< login UID */ 418 eCORE_UsernameReal /**< real UID */ 419 } ECORE_Username; 420 421 422 /** Obtain and store in the buffer provided, the best (as possible) user name 423 * that matches the requested username selector. 424 * Both "buf" and "bufsize" must not be zeros. 425 * @param buf 426 * Pointer to buffer to store the user name at 427 * @param bufsize 428 * Size of buffer in bytes 429 * @param username 430 * Selects which username to get (most preferably) 431 * @return 432 * Return NULL when the user name cannot be stored (e.g. buffer too small); 433 * otherwise, return "buf". Return "buf" as an empty string "" if the user 434 * name cannot be determined. 435 * @note 436 * For some OSes the username selector may not effect any differences, 437 * and for some OS releases, it may cause different results. 438 * @sa 439 * CORE_GetUsername, ECORE_Username 440 */ 441 extern NCBI_XCONNECT_EXPORT const char* CORE_GetUsernameEx 442 (char* buf, 443 size_t bufsize, 444 ECORE_Username username 445 ); 446 447 448 /** Equivalent to CORE_GetUsernameEx(buf, bufsize, eNCBI_UsernameLogin) 449 * except that it always returns non-empty "buf" when successful, or NULL 450 * otherwise (i.e. when the username cannot be either obtained or stored). 451 * @sa 452 * CORE_GetUsernameEx, ECORE_Username 453 */ 454 extern NCBI_XCONNECT_EXPORT const char* CORE_GetUsername 455 (char* buf, 456 size_t bufsize 457 ); 458 459 460 /** Obtain virtual memory page size. 461 * @return 462 * 0 if the page size cannot be determined. 463 */ 464 extern NCBI_XCONNECT_EXPORT size_t CORE_GetVMPageSize(void); 465 466 467 468 /****************************************************************************** 469 * Checksumming 470 */ 471 472 /** Calculate/Update CRC-32 checksum 473 * NB: Initial checksum is "0". 474 * @param checksum 475 * Checksum to update (start with 0) 476 * @param ptr 477 * Block of data 478 * @param len 479 * Size of block of data 480 * @return 481 * Return the checksum updated according to the contents of the block 482 * pointed to by "ptr" and having "len" bytes in it. 483 */ 484 extern NCBI_XCONNECT_EXPORT unsigned int UTIL_CRC32_Update 485 (unsigned int checksum, 486 const void* ptr, 487 size_t len 488 ); 489 490 491 /** Calculate/Update Adler-32 checksum 492 * NB: Initial checksum is "1". 493 * @param checksum 494 * Checksum to update (start with 1) 495 * @param ptr 496 * Block of data 497 * @param len 498 * Size of block of data 499 * @return 500 * Return the checksum updated according to the contents of the block 501 * pointed to by "ptr" and having "len" bytes in it. 502 */ 503 extern NCBI_XCONNECT_EXPORT unsigned int UTIL_Adler32_Update 504 (unsigned int checksum, 505 const void* ptr, 506 size_t len 507 ); 508 509 510 /** Cryptographic hash function descriptor: 511 * @var block_len 512 * Byte length of hashing blocks (e.g. 64 bytes for MD5, SHA1, SHA256) 513 * @var digest_len 514 * Byte length of the resultant digest (e.g. MD5: 16, SHA1: 20, SHA256: 32) 515 * @var init 516 * Init and set a hash context; return 0 on failure, non-zero on success 517 * @var update 518 * Update the hash with data provided 519 * @var fini 520 * Write out the resultant digest (if non-0) and destroy the context 521 * @sa 522 * UTIL_GenerateHMAC 523 */ 524 typedef struct { 525 size_t block_len; 526 size_t digest_len; 527 528 int/*bool*/ (*init) (void** ctx); 529 void (*update)(void* ctx, const void* data, size_t data_len); 530 void (*fini) (void* ctx, void* digest); 531 } SHASH_Descriptor; 532 533 534 /** Generate an RFC2401 digest (HMAC). 535 * @param hash 536 * Hash function descriptor 537 * @param text 538 * Text to get a digest for 539 * @param text_key 540 * Byte length of the text 541 * @param key 542 * Key to hash the text with 543 * @param key_len 544 * Byte length of the key (recommended to be no less than "hash::digest_len") 545 * @param digest 546 * The resultant HMAC storage (must be of an adequate size) 547 * @return 548 * NULL on errors ("digest" will not be valid), or "digest" on success. 549 * @sa 550 * SHASH_Descriptor 551 */ 552 extern NCBI_XCONNECT_EXPORT void* UTIL_GenerateHMAC 553 (const SHASH_Descriptor* hash, 554 const void* text, 555 size_t text_len, 556 const void* key, 557 size_t key_len, 558 void* digest); 559 560 561 562 /****************************************************************************** 563 * Miscellanea 564 */ 565 /** 566 * @param name 567 * TODO! 568 * @param mask 569 * TODO! 570 * @param ignore_case 571 * TODO! 572 */ 573 extern NCBI_XCONNECT_EXPORT int/*bool*/ UTIL_MatchesMaskEx 574 (const char* name, 575 const char* mask, 576 int/*bool*/ ignore_case 577 ); 578 579 /** Same as UTIL_MatchesMaskEx(name, mask, 1) 580 * @param name 581 * TODO! 582 * @param mask 583 * TODO! 584 */ 585 extern NCBI_XCONNECT_EXPORT int/*bool*/ UTIL_MatchesMask 586 (const char* name, 587 const char* mask 588 ); 589 590 591 /** Cut off well-known NCBI domain suffix out of the passed "hostname". 592 * @param hostname 593 * Hostname to shorten (if possible) 594 * @return 0 if the hostname wasn't modified, otherwise return "hostname". 595 */ 596 extern NCBI_XCONNECT_EXPORT char* UTIL_NcbiLocalHostName 597 (char* hostname 598 ); 599 600 601 /** Calculate size of buffer needed to store printable representation of the 602 * block of data of the specified size (or, if size is 0, strlen(data)). 603 * NOTE: The calculated size does not account for a terminating '\0'. 604 * @param data 605 * Block of data (NULL causes 0 to return regardless of "size") 606 * @param size 607 * Size of block (0 causes strlen(data) to be used) 608 * @return the buffer size needed (0 for NULL or empty (size==0) block). 609 * @sa UTIL_PrintableString 610 */ 611 extern NCBI_XCONNECT_EXPORT size_t UTIL_PrintableStringSize 612 (const char* data, 613 size_t size 614 ); 615 616 617 /** Create printable representation of the block of data of the specified size 618 * (or, if size is 0, strlen(data), and return buffer pointer past the last 619 * stored character (non '\0'-terminated). 620 * NOTE: The input buffer "buf" where to store the printable representation 621 * is assumed to be of adequate size to hold the resultant string. 622 * Non-printable characters can be represented in a reduced octal form 623 * as long as the result is unambiguous (unless "full" passed true (non-zero), 624 * in which case all non-printable characters get represented by full 625 * octal tetrads). NB: Hexadecimal output is not used because it is 626 * ambiguous by the standard (can contain undefined number of hex digits). 627 * @param data 628 * Block of data (NULL causes NULL to return regardless of "size" or "buf") 629 * @param size 630 * Size of block (0 causes strlen(data) to be used) 631 * @param buf 632 * Buffer to store the result (NULL always causes NULL to return) 633 * @param full 634 * Whether to print full octal representation of non-printable characters 635 * @return next position in the buffer past the last stored character. 636 * @sa 637 * UTIL_PrintableStringSize 638 */ 639 extern NCBI_XCONNECT_EXPORT char* UTIL_PrintableString 640 (const char* data, 641 size_t size, 642 char* buf, 643 int full 644 ); 645 646 647 /** Conversion from Unicode to UTF8, and back. MSWIN-specific and internal. 648 * 649 * NOTE: UTIL_ReleaseBufferOnHeap() must be used to free the buffers returned 650 * from UTIL_TcharToUtf8OnHeap(), and UTIL_ReleaseBuffer() to free the 651 * ones returned from UTIL_TcharToUtf8(). 652 */ 653 654 #if defined(NCBI_OS_MSWIN) && defined(_UNICODE) 655 extern const char* UTIL_TcharToUtf8OnHeap(const wchar_t* str); 656 extern const char* UTIL_TcharToUtf8 (const wchar_t* str); 657 extern const wchar_t* UTIL_Utf8ToTchar (const char* str); 658 /* 659 * NOTE: If you change these macros (here and in #else) you need to make 660 * similar changes in ncbi_strerror.c as well. 661 */ 662 # define UTIL_ReleaseBuffer(x) UTIL_ReleaseBufferOnHeap(x) 663 #else 664 # define UTIL_TcharToUtf8OnHeap(x) (x) 665 # define UTIL_TcharToUtf8(x) (x) 666 # define UTIL_Utf8ToTchar(x) (x) 667 # define UTIL_ReleaseBuffer(x) /*void*/ 668 #endif /*NCBI_OS_MSWIN && _UNICODE*/ 669 670 #ifdef NCBI_OS_MSWIN 671 extern void UTIL_ReleaseBufferOnHeap(const void* ptr); 672 #else 673 # define UTIL_ReleaseBufferOnHeap(x) /*void*/ 674 #endif /*NCBI_OS_MSWIN*/ 675 676 677 #ifdef __cplusplus 678 } /* extern "C" */ 679 #endif 680 681 682 /* @} */ 683 684 #endif /* CONNECT___NCBI_UTIL__H */ 685