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