ncbi_util.c
上传用户:yhdzpy8989
上传日期:2007-06-13
资源大小:13604k
文件大小:16k
源码类别:

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: ncbi_util.c,v $
  4.  * PRODUCTION Revision 1000.1  2003/11/17 22:18:57  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [ORIGINAL] Dev-tree R6.31
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: ncbi_util.c,v 1000.1 2003/11/17 22:18:57 gouriano Exp $
  10.  * ===========================================================================
  11.  *
  12.  *                            PUBLIC DOMAIN NOTICE
  13.  *               National Center for Biotechnology Information
  14.  *
  15.  *  This software/database is a "United States Government Work" under the
  16.  *  terms of the United States Copyright Act.  It was written as part of
  17.  *  the author's official duties as a United States Government employee and
  18.  *  thus cannot be copyrighted.  This software/database is freely available
  19.  *  to the public for use. The National Library of Medicine and the U.S.
  20.  *  Government have not placed any restriction on its use or reproduction.
  21.  *
  22.  *  Although all reasonable efforts have been taken to ensure the accuracy
  23.  *  and reliability of the software and data, the NLM and the U.S.
  24.  *  Government do not and cannot warrant the performance or results that
  25.  *  may be obtained by using this software or data. The NLM and the U.S.
  26.  *  Government disclaim all warranties, express or implied, including
  27.  *  warranties of performance, merchantability or fitness for any particular
  28.  *  purpose.
  29.  *
  30.  *  Please cite the author in any work or product based on this material.
  31.  *
  32.  * ===========================================================================
  33.  *
  34.  * Author:  Denis Vakatov, Anton Lavrentiev
  35.  *
  36.  * File Description:
  37.  *   Auxiliary (optional) code for "ncbi_core.[ch]"
  38.  *
  39.  */
  40. #include "ncbi_config.h"
  41. #include "ncbi_priv.h"
  42. #ifndef NCBI_CXX_TOOLKIT
  43. #  include <ncbistd.h>
  44. #  include <ncbimisc.h>
  45. #  include <ncbitime.h>
  46. #else
  47. #  include <ctype.h>
  48. #  include <errno.h>
  49. #  include <stdlib.h>
  50. #  include <string.h>
  51. #  include <time.h>
  52. #endif
  53. /* Static function pre-declarations to avoid C++ compiler warnings
  54.  */
  55. #if defined(__cplusplus)
  56. extern "C" {
  57.     static void s_LOG_FileHandler(void* user_data, SLOG_Handler* call_data);
  58.     static void s_LOG_FileCleanup(void* user_data);
  59. }
  60. #endif /* __cplusplus */
  61. /******************************************************************************
  62.  *  MT locking
  63.  */
  64. extern void CORE_SetLOCK(MT_LOCK lk)
  65. {
  66.     if (g_CORE_MT_Lock  &&  lk != g_CORE_MT_Lock) {
  67.         MT_LOCK_Delete(g_CORE_MT_Lock);
  68.     }
  69.     g_CORE_MT_Lock = lk;
  70. }
  71. extern MT_LOCK CORE_GetLOCK(void)
  72. {
  73.     return g_CORE_MT_Lock;
  74. }
  75. /******************************************************************************
  76.  *  ERROR HANDLING and LOGGING
  77.  */
  78. extern void CORE_SetLOG(LOG lg)
  79. {
  80.     CORE_LOCK_WRITE;
  81.     if (g_CORE_Log  &&  lg != g_CORE_Log) {
  82.         LOG_Delete(g_CORE_Log);
  83.     }
  84.     g_CORE_Log = lg;
  85.     CORE_UNLOCK;
  86. }
  87. extern LOG CORE_GetLOG(void)
  88. {
  89.     return g_CORE_Log;
  90. }
  91. extern void CORE_SetLOGFILE
  92. (FILE*       fp,
  93.  int/*bool*/ auto_close)
  94. {
  95.     LOG lg = LOG_Create(0, 0, 0, 0);
  96.     LOG_ToFILE(lg, fp, auto_close);
  97.     CORE_SetLOG(lg);
  98. }
  99. extern int/*bool*/ CORE_SetLOGFILE_NAME(const char* filename)
  100. {
  101.     FILE* fp = fopen(filename, "a");
  102.     if ( !fp ) {
  103.         CORE_LOGF_ERRNO(eLOG_Error, errno, ("Cannot open "%s"", filename));
  104.         return 0/*false*/;
  105.     }
  106.     CORE_SetLOGFILE(fp, 1/*true*/);
  107.     return 1/*true*/;
  108. }
  109. static TLOG_FormatFlags s_LogFormatFlags = fLOG_Default;
  110. extern TLOG_FormatFlags CORE_SetLOGFormatFlags(TLOG_FormatFlags flags)
  111. {
  112.     TLOG_FormatFlags old_flags = s_LogFormatFlags;
  113.     s_LogFormatFlags = flags;
  114.     return old_flags;
  115. }
  116. extern char* LOG_ComposeMessage
  117. (const SLOG_Handler* call_data,
  118.  TLOG_FormatFlags    format_flags)
  119. {
  120.     static const char s_RawData_Begin[] =
  121.         "n#################### [BEGIN] Raw Data (%lu byte%s):n";
  122.     static const char s_RawData_End[] =
  123.         "n#################### [END] Raw Datan";
  124.     char* str, datetime[32];
  125.     /* Calculated length of ... */
  126.     size_t datetime_len  = 0;
  127.     size_t level_len     = 0;
  128.     size_t file_line_len = 0;
  129.     size_t module_len    = 0;
  130.     size_t message_len   = 0;
  131.     size_t data_len      = 0;
  132.     size_t total_len;
  133.     /* Adjust formatting flags */
  134.     if (call_data->level == eLOG_Trace) {
  135. #if defined(NDEBUG)  &&  !defined(_DEBUG)
  136.         if (!(format_flags & fLOG_None))
  137. #endif /*NDEBUG && !_DEBUG*/
  138.             format_flags |= fLOG_Full;
  139.     }
  140.     if (format_flags == fLOG_Default) {
  141. #if defined(NDEBUG)  &&  !defined(_DEBUG)
  142.         format_flags = fLOG_Short;
  143. #else
  144.         format_flags = fLOG_Full;
  145. #endif /*NDEBUG && !_DEBUG*/
  146.     }
  147.     /* Pre-calculate total message length */
  148.     if ((format_flags & fLOG_DateTime) != 0) {
  149. #ifdef NCBI_OS_MSWIN /*Should be compiler-dependent but C-Tkit lacks it*/
  150.         _strdate(&datetime[datetime_len]);
  151.         datetime_len += strlen(&datetime[datetime_len]);
  152.         datetime[datetime_len++] = ' ';
  153.         _strtime(&datetime[datetime_len]);
  154.         datetime_len += strlen(&datetime[datetime_len]);
  155.         datetime[datetime_len++] = ' ';
  156.         datetime[datetime_len]   = '';
  157. #else /*NCBI_OS_MSWIN*/
  158.         static const char timefmt[] = "%D %T ";
  159.         struct tm* tm;
  160. #  ifdef NCBI_CXX_TOOLKIT
  161.         time_t t = time(0);
  162. #    ifdef HAVE_LOCALTIME_R
  163.         struct tm temp;
  164.         localtime_r(&t, &temp);
  165.         tm = &temp;
  166. #    else /*HAVE_LOCALTIME_R*/
  167.         tm = localtime(&t);
  168. #    endif/*HAVE_LOCALTIME_R*/
  169. #  else /*NCBI_CXX_TOOLKIT*/
  170.         struct tm temp;
  171.         Nlm_GetDayTime(&temp);
  172.         tm = &temp;
  173. #  endif/*NCBI_CXX_TOOLKIT*/
  174.         datetime_len = strftime(datetime, sizeof(datetime), timefmt, tm);
  175. #endif/*NCBI_OS_MSWIN*/
  176.     }
  177.     if ((format_flags & fLOG_Level) != 0  &&
  178.         (call_data->level != eLOG_Note ||
  179.          !(format_flags & fLOG_OmitNoteLevel))) {
  180.         level_len = strlen(LOG_LevelStr(call_data->level)) + 2;
  181.     }
  182.     if ((format_flags & fLOG_Module) != 0  &&
  183.         call_data->module  &&  *call_data->module) {
  184.         module_len = strlen(call_data->module) + 3;
  185.     }
  186.     if ((format_flags & fLOG_FileLine) != 0  &&
  187.         call_data->file  &&  *call_data->file) {
  188.         file_line_len = 12 + strlen(call_data->file) + 11;
  189.     }
  190.     if (call_data->message  &&  *call_data->message) {
  191.         message_len = strlen(call_data->message);
  192.     }
  193.     if ( call_data->raw_size ) {
  194.         const unsigned char* d = (const unsigned char*) call_data->raw_data;
  195.         size_t      i = call_data->raw_size;
  196.         for (data_len = 0;  i;  i--, d++) {
  197.             if (*d == '\'  ||  *d == 'r'  ||  *d == 't') {
  198.                 data_len++;
  199.             } else if (!isprint(*d)  &&  *d != 'n') {
  200.                 data_len += 2;
  201.             }
  202.         }
  203.         data_len += sizeof(s_RawData_Begin) + 20 + call_data->raw_size +
  204.             sizeof(s_RawData_End);
  205.     }
  206.     /* Allocate memory for the resulting message */
  207.     total_len = datetime_len + file_line_len + module_len + level_len +
  208.         message_len + data_len;
  209.     str = (char*) malloc(total_len + 1);
  210.     if ( !str ) {
  211.         assert(0);
  212.         return 0;
  213.     }
  214.     /* Compose the message */
  215.     str[0] = '';
  216.     if ( datetime_len ) {
  217.         strcpy(str, datetime);
  218.     }
  219.     if ( file_line_len ) {
  220.         sprintf(str + strlen(str), ""%s", line %d: ",
  221.                 call_data->file, (int) call_data->line);
  222.     }
  223.     if ( module_len ) {
  224.         strcat(str, "[");
  225.         strcat(str, call_data->module);
  226.         strcat(str, "] ");
  227.     }
  228.     if ( level_len ) {
  229.         strcat(str, LOG_LevelStr(call_data->level));
  230.         strcat(str, ": ");
  231.     }
  232.     if ( message_len ) {
  233.         strcat(str, call_data->message);
  234.     }
  235.     if ( data_len ) {
  236.         size_t i;
  237.         char* s;
  238.         const unsigned char* d;
  239.         s = str + strlen(str);
  240.         sprintf(s, s_RawData_Begin, (unsigned long) call_data->raw_size,
  241.                 call_data->raw_size == 1 ? "" : "s");
  242.         s += strlen(s);
  243.         d = (const unsigned char*) call_data->raw_data;
  244.         for (i = call_data->raw_size;  i;  i--, d++) {
  245.             if (*d == '\') {
  246.                 *s++ = '\';
  247.                 *s++ = '\';
  248.             } else if (*d == 'r') {
  249.                 *s++ = '\';
  250.                 *s++ = 'r';
  251.             } else if (*d == 't') {
  252.                 *s++ = '\';
  253.                 *s++ = 't';
  254.             } else if (!isprint(*d)  &&  *d != 'n') {
  255.                 static const char s_Hex[16] = {
  256.                     '0', '1', '2', '3', '4', '5', '6', '7',
  257.                     '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
  258.                 };
  259.                 *s++ = '\';
  260.                 *s++ = s_Hex[*d / 16];
  261.                 *s++ = s_Hex[*d % 16];
  262.             } else {
  263.                 *s++ = (char) *d;
  264.             }
  265.         }
  266.         strcpy(s, s_RawData_End);
  267.     }
  268.     assert(strlen(str) <= total_len);
  269.     return str;
  270. }
  271. /* Callback for LOG_Reset_FILE() */
  272. static void s_LOG_FileHandler(void* user_data, SLOG_Handler* call_data)
  273. {
  274.     FILE* fp = (FILE*) user_data;
  275.     assert(call_data);
  276.     if ( fp ) {
  277.         char* str = LOG_ComposeMessage(call_data, s_LogFormatFlags);
  278.         if ( str ) {
  279.             fprintf(fp, "%sn", str);
  280.             fflush(fp);
  281.             free(str);
  282.         }
  283.     }
  284. }
  285. /* Callback for LOG_Reset_FILE() */
  286. static void s_LOG_FileCleanup(void* user_data)
  287. {
  288.     FILE* fp = (FILE*) user_data;
  289.     if ( fp )
  290.         fclose(fp);
  291. }
  292. extern void LOG_ToFILE
  293. (LOG         lg,
  294.  FILE*       fp,
  295.  int/*bool*/ auto_close)
  296. {
  297.     if ( fp ) {
  298.         if ( auto_close ) {
  299.             LOG_Reset(lg, fp, s_LOG_FileHandler, s_LOG_FileCleanup);
  300.         } else {
  301.             LOG_Reset(lg, fp, s_LOG_FileHandler, 0/*no cleaning up*/);
  302.         }
  303.     } else {
  304.         LOG_Reset(lg, 0/*data*/, 0/*handler*/, 0/*cleanup*/);
  305.     }
  306. }
  307. /* Return non-zero value if "*beg" has reached the "end"
  308.  */
  309. static int/*bool*/ s_SafeCopy(const char* src, char** beg, const char* end)
  310. {
  311.     assert(*beg <= end);
  312.     if ( src ) {
  313.         for ( ;  *src  &&  *beg != end;  src++, (*beg)++) {
  314.             **beg = *src;
  315.         }
  316.     }
  317.     **beg = '';
  318.     return (*beg == end);
  319. }
  320. extern char* MessagePlusErrno
  321. (const char*  message,
  322.  int          x_errno,
  323.  const char*  descr,
  324.  char*        buf,
  325.  size_t       buf_size)
  326. {
  327.     char* beg;
  328.     char* end;
  329.     /* Check and init */
  330.     if (!buf  ||  !buf_size)
  331.         return 0;
  332.     buf[0] = '';
  333.     if (buf_size < 2)
  334.         return buf;  /* empty */
  335.     /* Adjust the description, if necessary and possible */
  336.     if (x_errno  &&  !descr) {
  337.         descr = strerror(x_errno);
  338.         if ( !descr ) {
  339.             static const char s_UnknownErrno[] = "Error code is out of range";
  340.             descr = s_UnknownErrno;
  341.         }
  342.     }
  343.     /* Check for an empty result, calculate string lengths */
  344.     if ((!message  ||  !*message)  &&  !x_errno  &&  (!descr  ||  !*descr))
  345.         return buf;  /* empty */
  346.     /* Compose:   <message> {errno=<x_errno>,<descr>} */
  347.     beg = buf;
  348.     end = buf + buf_size - 1;
  349.     /* <message> */
  350.     if ( s_SafeCopy(message, &beg, end) )
  351.         return buf;
  352.     /* {errno=<x_errno>,<descr>} */
  353.     if (!x_errno  &&  (!descr  ||  !*descr))
  354.         return buf;
  355.     /* "{errno=" */
  356.     if ( s_SafeCopy(" {errno=", &beg, end) )
  357.         return buf;
  358.     /* <x_errno> */
  359.     if ( x_errno ) {
  360.         int/*bool*/ neg;
  361.         /* calculate length */
  362.         size_t len;
  363.         int    mod;
  364.         if (x_errno < 0) {
  365.             neg = 1/*true*/;
  366.             x_errno = -x_errno;
  367.         } else {
  368.             neg = 0/*false*/;
  369.         }
  370.         for (len = 1, mod = 1;  (x_errno / mod) > 9;  len++, mod *= 10)
  371.             continue;
  372.         if ( neg )
  373.             len++;
  374.         /* ? not enough space */
  375.         if (beg + len >= end) {
  376.             s_SafeCopy("...", &beg, end);
  377.             return buf;
  378.         }
  379.         /* ? add sign */ 
  380.         if (x_errno < 0) {
  381.             *beg++ = '-';
  382.         }
  383.         /* print error code */
  384.         for ( ;  mod;  mod /= 10) {
  385.             static const char s_Num[] = "0123456789";
  386.             assert(x_errno / mod < 10);
  387.             *beg++ = s_Num[x_errno / mod];
  388.             x_errno %= mod;
  389.         }
  390.         /* "," before "<descr>" */
  391.         if (descr  &&  *descr  &&  beg != end)
  392.             *beg++ = ',';
  393.     }
  394.     /* "<descr>" */
  395.     if ( s_SafeCopy(descr, &beg, end) )
  396.         return buf;
  397.     /* "}" */
  398.     assert(beg <= end);
  399.     if (beg != end)
  400.         *beg++ = '}';
  401.     *beg = '';
  402.     return buf;
  403. }
  404. /******************************************************************************
  405.  *  REGISTRY
  406.  */
  407. extern void CORE_SetREG(REG rg)
  408. {
  409.     CORE_LOCK_WRITE;
  410.     if (g_CORE_Registry  &&  rg != g_CORE_Registry) {
  411.         REG_Delete(g_CORE_Registry);
  412.     }
  413.     g_CORE_Registry = rg;
  414.     CORE_UNLOCK;
  415. }
  416. extern REG CORE_GetREG(void)
  417. {
  418.     return g_CORE_Registry;
  419. }
  420. /******************************************************************************
  421.  *  MISCELLANEOUS
  422.  */
  423. extern const char* CORE_GetPlatform(void)
  424. {
  425. #ifndef NCBI_CXX_TOOLKIT
  426.     return Nlm_PlatformName();
  427. #else
  428.     return HOST;
  429. #endif /*NCBI_CXX_TOOLKIT*/
  430. }
  431. /*
  432.  * ---------------------------------------------------------------------------
  433.  * $Log: ncbi_util.c,v $
  434.  * Revision 1000.1  2003/11/17 22:18:57  gouriano
  435.  * PRODUCTION: UPGRADED [ORIGINAL] Dev-tree R6.31
  436.  *
  437.  * Revision 6.31  2003/11/14 13:04:38  lavr
  438.  * Little changes in comments [no code changes]
  439.  *
  440.  * Revision 6.30  2003/11/13 19:53:41  rsmith
  441.  * Took out metrowerks specific #ifdef's (COMP_METRO). Not needed anymore.
  442.  *
  443.  * Revision 6.29  2003/09/02 21:05:14  lavr
  444.  * Proper indentation of compilation conditionals
  445.  *
  446.  * Revision 6.28  2003/05/05 20:19:13  lavr
  447.  * LOG_ComposeMessage() to check raw_size instead of raw_data ptr
  448.  *
  449.  * Revision 6.27  2003/05/05 11:41:09  rsmith
  450.  * added defines and declarations to allow cross compilation Mac->Win32
  451.  * using Metrowerks Codewarrior.
  452.  *
  453.  * Revision 6.26  2003/01/17 15:55:13  lavr
  454.  * Fix errno reporting (comma was missing if errno == 0)
  455.  *
  456.  * Revision 6.25  2003/01/17 01:23:07  lavr
  457.  * Always print full message for TRACE log in Debug mode
  458.  *
  459.  * Revision 6.24  2002/12/04 21:00:53  lavr
  460.  * -CORE_LOG[F]_SYS_ERRNO()
  461.  *
  462.  * Revision 6.23  2002/12/04 19:51:12  lavr
  463.  * No change
  464.  *
  465.  * Revision 6.22  2002/10/11 19:52:10  lavr
  466.  * Log moved to end
  467.  *
  468.  * Revision 6.21  2002/06/18 17:07:44  lavr
  469.  * Employ _strdate() & _strtime() if compiled by MSVC
  470.  *
  471.  * Revision 6.20  2002/05/07 18:22:10  lavr
  472.  * Use fLOG_None in LOG_ComposeMessage()
  473.  *
  474.  * Revision 6.19  2002/02/11 20:36:44  lavr
  475.  * Use "ncbi_config.h"
  476.  *
  477.  * Revision 6.18  2002/02/05 22:02:17  lavr
  478.  * Minor tweak
  479.  *
  480.  * Revision 6.17  2002/01/28 20:22:39  lavr
  481.  * Get rid of GCC warning about "'%D' yields only 2 last digits of year"
  482.  *
  483.  * Revision 6.16  2001/08/28 17:49:45  thiessen
  484.  * oops, sorry - incorrect fix; reverted
  485.  *
  486.  * Revision 6.15  2001/08/28 17:21:22  thiessen
  487.  * need ncbiconf.h for NCBI_CXX_TOOLKIT
  488.  *
  489.  * Revision 6.14  2001/08/09 16:25:06  lavr
  490.  * Remove last (unneeded) parameter from LOG_Reset()
  491.  * Added: fLOG_OmitNoteLevel format flag handling
  492.  *
  493.  * Revision 6.13  2001/07/30 14:41:37  lavr
  494.  * Added: CORE_SetLOGFormatFlags()
  495.  *
  496.  * Revision 6.12  2001/07/26 15:13:02  lavr
  497.  * Always do stream flush after message output (previously was in DEBUG only)
  498.  *
  499.  * Revision 6.11  2001/07/25 20:27:23  lavr
  500.  * Included header files rearranged
  501.  *
  502.  * Revision 6.10  2001/07/25 19:12:57  lavr
  503.  * Added date/time stamp for message logging
  504.  *
  505.  * Revision 6.9  2001/04/24 21:24:59  lavr
  506.  * Make log flush in DEBUG mode
  507.  *
  508.  * Revision 6.8  2001/01/23 23:20:14  lavr
  509.  * Comments added to some "boolean" 1s and 0s
  510.  *
  511.  * Revision 6.7  2001/01/12 23:50:38  lavr
  512.  * "a+" -> "a" as a mode in fopen() for a logfile
  513.  *
  514.  * Revision 6.6  2000/08/28 20:05:51  vakatov
  515.  * CORE_SetLOGFILE() -- typo fixed
  516.  *
  517.  * Revision 6.5  2000/06/23 19:34:45  vakatov
  518.  * Added means to log binary data
  519.  *
  520.  * Revision 6.4  2000/05/30 23:23:26  vakatov
  521.  * + CORE_SetLOGFILE_NAME()
  522.  *
  523.  * Revision 6.3  2000/03/31 17:19:11  kans
  524.  * added continue statement to for loop to suppress missing body warning
  525.  *
  526.  * Revision 6.2  2000/03/24 23:12:09  vakatov
  527.  * Starting the development quasi-branch to implement CONN API.
  528.  * All development is performed in the NCBI C++ tree only, while
  529.  * the NCBI C tree still contains "frozen" (see the last revision) code.
  530.  *
  531.  * Revision 6.1  2000/02/23 22:36:17  vakatov
  532.  * Initial revision
  533.  *
  534.  * ===========================================================================
  535.  */