1 #ifndef CONNECT___NCBI_CORE__H 2 #define CONNECT___NCBI_CORE__H 3 4 /* $Id: ncbi_core.h 604951 2020-04-05 03:12:01Z lavr $ 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 * Author: Denis Vakatov 30 * 31 * File Description: 32 * @file ncbi_core.h 33 * Types and code shared by all "ncbi_*.[ch]" modules. 34 * 35 * I/O status and direction: 36 * enum: EIO_ReadMethod 37 * enum: EIO_WriteMethod 38 * enum: EIO_Status, verbal: IO_StatusStr() 39 * enum: EIO_Event 40 * 41 * Critical section (basic multi-thread synchronization): 42 * handle: MT_LOCK 43 * enum: EMT_Lock 44 * callbacks: (*FMT_LOCK_Handler)(), (*FMT_LOCK_Cleanup)() 45 * methods: MT_LOCK_Create(), MT_LOCK_AddRef(), MT_LOCK_Delete(), 46 * MT_LOCK_Do() 47 * 48 * Tracing and logging: 49 * handle: LOG 50 * enum: ELOG_Level, verbal: LOG_LevelStr() 51 * flags: TLOG_FormatFlags, ELOG_FormatFlags 52 * callbacks: (*FLOG_Handler)(), (*FLOG_Cleanup)() 53 * methods: LOG_Create(), LOG_Reset(), LOG_AddRef(), LOG_Delete(), 54 * LOG_Write(), LOG_WriteInternal() 55 * 56 * Registry: 57 * handle: REG 58 * enum: EREG_Storage 59 * callbacks: (*FREG_Get)(), (*FREG_Set)(), (*FREG_Cleanup)() 60 * methods: REG_Create(), REG_Reset(), REG_AddRef(), REG_Delete(), 61 * REG_Get(), REG_Set() 62 * 63 */ 64 65 #include <connect/ncbi_types.h> 66 67 68 /** @addtogroup UtilityFunc 69 * 70 * @{ 71 */ 72 73 74 #ifdef __cplusplus 75 extern "C" { 76 #endif 77 78 79 /****************************************************************************** 80 * I/O 81 */ 82 83 84 /** I/O read method. 85 * @sa 86 * EIO_WriteMethod 87 */ 88 typedef enum { 89 eIO_ReadPeek, /**< do eIO_ReadPlain but leave data in input queue */ 90 eIO_ReadPlain, /**< read readily available data only, wait if none */ 91 eIO_ReadPersist /**< read exactly as much as requested, w/waits */ 92 } EIO_ReadMethod; 93 94 95 /** I/O write method. 96 * @sa 97 * EIO_ReadMethod 98 */ 99 typedef enum { 100 eIO_WriteNone, /**< invalid reserved opcode, not for use! */ 101 eIO_WritePlain, /**< write as much as possible, report back how much */ 102 eIO_WritePersist, /**< write exactly as much as specified, w/waits */ 103 eIO_WriteOutOfBand /**< write out-of-band chunk of urgent data (if supp)*/ 104 } EIO_WriteMethod; 105 106 107 /** I/O event (or direction). 108 * @note 109 * Internally, these constants are used as bit-values, and therefore must not 110 * be changed in this header. On the other hand, user code should not rely 111 * on the values of these constants, either. 112 * @warning 113 * Careful with an unfortunate naming similarity of eIO_Close from this set 114 * and eIO_Closed from EIO_Status -- do not mix the two! 115 * @sa 116 * SOCK_Wait, SOCK_Poll, CONN_Wait, SOCK_SetTimeout, CONN_SetTimeout 117 */ 118 typedef enum { 119 eIO_Open = 0, /**< also serves as no-event indicator in SOCK_Poll */ 120 eIO_Read = 1, /**< read */ 121 eIO_Write = 2, /**< write */ 122 eIO_ReadWrite = 3, /**< eIO_Read | eIO_Write (also, eCONN_OnFlush) */ 123 eIO_Close = 4 /**< also serves as an error indicator in SOCK_Poll */ 124 } EIO_Event; 125 126 127 /** I/O status. 128 * @warning 129 * Careful with an unfortunate naming similarity of eIO_Closed from this set 130 * and eIO_Close from EIO_Event -- do not mix the two! 131 */ 132 typedef enum { 133 eIO_Success = 0, /**< everything is fine, no error occurred */ 134 eIO_Timeout, /**< timeout expired before any I/O succeeded */ 135 eIO_Reserved, /**< reserved status code -- do not use! */ 136 eIO_Interrupt, /**< signal arrival prevented any I/O to succeed */ 137 eIO_InvalidArg, /**< bad argument / parameter value(s) supplied */ 138 eIO_NotSupported, /**< operation is not supported or is not available */ 139 eIO_Unknown, /**< unknown I/O error (likely fatal but can retry) */ 140 eIO_Closed /**< connection is / has been closed, EOF condition */ 141 #define EIO_N_STATUS 8 142 } EIO_Status; 143 144 145 /** Get the text form of an enum status value. 146 * @param status 147 * An enum value to get the text form for 148 * @return 149 * Verbal description of the I/O status 150 * @warning 151 * Returns NULL on out-of-bound values 152 * @note 153 * Reserved status code(s) returned as an empty string ("") 154 * @sa 155 * EIO_Status 156 */ 157 extern NCBI_XCONNECT_EXPORT const char* IO_StatusStr(EIO_Status status); 158 159 160 161 /****************************************************************************** 162 * MT locking 163 */ 164 165 166 /** Lock handle -- keeps all data needed for the locking and for the cleanup. 167 * @sa 168 * CORE_SetLOCK 169 */ 170 struct MT_LOCK_tag; 171 typedef struct MT_LOCK_tag* MT_LOCK; 172 173 174 /** Set the lock/unlock callback function and its data for MT critical section. 175 * @note 176 * If the RW-lock functionality is not provided by the callback, then: 177 * eMT_LockRead <==> eMT_Lock 178 * 179 */ 180 typedef enum { 181 eMT_Lock, /**< lock critical section */ 182 eMT_LockRead, /**< lock critical section for reading */ 183 eMT_Unlock, /**< unlock critical section */ 184 eMT_TryLock, /**< try to lock, return immediately */ 185 eMT_TryLockRead /**< try to lock for reading, return immediately */ 186 } EMT_Lock; 187 188 189 /** MT locking callback (operates like a [recursive] mutex or RW-lock). 190 * @param data 191 * See "data" in MT_LOCK_Create() 192 * @param how 193 * As passed to MT_LOCK_Do() 194 * @return 195 * Non-zero value if the requested operation was successful. 196 * @note 197 * The "-1" value is reserved for unset handler; you also may want to return 198 * "-1" if your locking function does no locking, and you don't consider it as 199 * an error, but still want the caller to be aware of this "rightful 200 * non-doing" as opposed to the "rightful doing". 201 * @sa 202 * MT_LOCK_Create, MT_LOCK_Delete 203 */ 204 typedef int/*bool*/ (*FMT_LOCK_Handler) 205 (void* data, 206 EMT_Lock how 207 ); 208 209 /** MT lock cleanup callback. 210 * @param data 211 * See "data" in MT_LOCK_Create() 212 * @sa 213 * MT_LOCK_Create, MT_LOCK_Delete 214 */ 215 typedef void (*FMT_LOCK_Cleanup) 216 (void* data 217 ); 218 219 220 /** Create a new MT lock (with an internal reference count set to 1). 221 * @param data 222 * Unspecified data to call "handler" and "cleanup" with 223 * @param handler 224 * Locking callback 225 * @param cleanup 226 * Cleanup callback 227 * @sa 228 * FMT_LOCK_Handler, FMT_LOCK_Cleanup, MT_LOCK_Delete 229 */ 230 extern NCBI_XCONNECT_EXPORT MT_LOCK MT_LOCK_Create 231 (void* data, 232 FMT_LOCK_Handler handler, 233 FMT_LOCK_Cleanup cleanup 234 ); 235 236 237 /** Increment internal reference count by 1, then return "lk". 238 * @param lk 239 * A handle previously obtained from MT_LOCK_Create 240 * @sa 241 * MT_LOCK_Create, MT_LOCK_Delete 242 */ 243 extern NCBI_XCONNECT_EXPORT MT_LOCK MT_LOCK_AddRef(MT_LOCK lk); 244 245 246 /** Decrement internal reference count by 1, and if it reaches 0, then 247 * destroy the handle, call "lk->cleanup(lk->data)", and return NULL; 248 * otherwise (if the reference count is still > 0), return "lk". 249 * @param lk 250 * A handle previously obtained from MT_LOCK_Create 251 * @sa 252 * MT_LOCK_Create, FMT_LOCK_Cleanup 253 */ 254 extern NCBI_XCONNECT_EXPORT MT_LOCK MT_LOCK_Delete(MT_LOCK lk); 255 256 257 /** Call "lk->handler(lk->data, how)". 258 * @param lk 259 * A handle previously obtained from MT_LOCK_Create 260 * @param how 261 * Whether to lock (and how: read, write) or to unlock 262 * @return 263 * Value returned by the lock handler ("handler" in MT_LOCK_Create()). 264 * If lock handler is not specified then always return "-1". 265 * @note 266 * Use MT_LOCK_Do to avoid overhead! 267 * @sa 268 * MT_LOCK_Create, FMT_LOCK_Handler, EMT_Lock 269 */ 270 #define MT_LOCK_Do(lk, how) ((lk) ? MT_LOCK_DoInternal((lk), (how)) : -1) 271 extern NCBI_XCONNECT_EXPORT int/*bool*/ MT_LOCK_DoInternal 272 (MT_LOCK lk, 273 EMT_Lock how 274 ); 275 276 277 /****************************************************************************** 278 * Error handling and logging 279 */ 280 281 282 /** Log handle -- keeps all data needed for the logging and for the cleanup. 283 * @sa 284 * CORE_SetLOG 285 */ 286 struct LOG_tag; 287 typedef struct LOG_tag* LOG; 288 289 290 /** Log severity level. 291 */ 292 typedef enum { 293 eLOG_Trace = 0, 294 eLOG_Note, 295 eLOG_Info = eLOG_Note, /**< In C++ Toolkit "Info" is used, not "Note" */ 296 eLOG_Warning, 297 eLOG_Error, 298 eLOG_Critical, 299 eLOG_Fatal 300 } ELOG_Level; 301 302 303 /** Obtain verbal representation of an enum level value. 304 * @param level 305 * An enum value to get the text form for 306 * @return 307 * Verbal description of the log level 308 * @sa 309 * ELOG_Level 310 */ 311 extern NCBI_XCONNECT_EXPORT const char* LOG_LevelStr(ELOG_Level level); 312 313 314 /** Message and miscellaneous data to pass to log post callback FLOG_Handler. 315 * @param dynamic 316 * if non-zero then LOG_WriteInternal() will call free(message) before return 317 * @param message 318 * A message to post, can be NULL 319 * @param level 320 * A message level 321 * @param module 322 * A module string to post, can be NULL 323 * @param file 324 * A file name to post, can be NULL 325 * @param line 326 * A line number within the file (above) to post, can be 0 327 * @param raw_data 328 * Raw data to log (usually NULL) 329 * @param raw_size 330 * Size of the raw data (usually zero) 331 * @param err_code 332 * Error code of the message 333 * @param err_subcode 334 * Error subcode of the message 335 * @sa 336 * FLOG_Handler, LOG_Create, LOG_WriteInternal, LOG_Write 337 */ 338 typedef struct { 339 int/*bool*/ dynamic; 340 const char* message; 341 ELOG_Level level; 342 const char* module; 343 const char* func; 344 const char* file; 345 int line; 346 const void* raw_data; 347 size_t raw_size; 348 int err_code; 349 int err_subcode; 350 } SLOG_Message; 351 352 353 /** Log post callback. 354 * @param data 355 * Unspeficied data as passed to LOG_Create() or LOG_Reset() 356 * @param mess 357 * Composed from arguments passed to LOG_WriteInternal() 358 * @sa 359 * SLOG_Message, LOG_Create, LOG_Reset, LOG_WriteInternal 360 */ 361 typedef void (*FLOG_Handler) 362 (void* data, 363 const SLOG_Message* mess 364 ); 365 366 367 /** Log cleanup callback. 368 * @param data 369 * Unspeficied data as passed to LOG_Create() or LOG_Reset() 370 * @sa 371 * LOG_Create, LOG_Reset 372 * 373 */ 374 typedef void (*FLOG_Cleanup) 375 (void* data 376 ); 377 378 379 /** Create a new LOG (with an internal reference count set to 1). 380 * @warning 381 * If non-NULL "lock" is specified then MT_LOCK_AddRef() is called on it here, 382 * and MT_LOCK_Delete() will be called on it when this LOG gets deleted. 383 * @param data 384 * Unspecified data to call "handler" and "cleanup" with 385 * @param handler 386 * Log post callback 387 * @param cleanup 388 * Cleanup callback 389 * @param lock 390 * Protective MT lock (may be NULL) 391 * @sa 392 * MT_LOCK, MT_LOCK_AddRef, FLOG_Handler, FLOG_Cleanup, LOG_Reset, LOG_Delete 393 */ 394 extern NCBI_XCONNECT_EXPORT LOG LOG_Create 395 (void* data, 396 FLOG_Handler handler, 397 FLOG_Cleanup cleanup, 398 MT_LOCK lock 399 ); 400 401 402 /** Reset the "lg" to use the new "data", "handler" and "cleanup". 403 * @note 404 * It does not change the reference count of the log. 405 * @param lg 406 * A log handle previously obtained from LOG_Create 407 * @param data 408 * New user data 409 * @param handler 410 * New log post callback 411 * @param cleanup 412 * New cleanup callback 413 * @return 414 * lg (as passed in the first parameter) 415 * @sa 416 * LOG_Create 417 */ 418 extern NCBI_XCONNECT_EXPORT LOG LOG_Reset 419 (LOG lg, 420 void* data, 421 FLOG_Handler handler, 422 FLOG_Cleanup cleanup 423 ); 424 425 426 /** Increment internal reference count by 1, then return "lg". 427 * @param lg 428 * A log handle previously obtained from LOG_Create 429 * @sa 430 * LOG_Create 431 */ 432 extern NCBI_XCONNECT_EXPORT LOG LOG_AddRef(LOG lg); 433 434 435 /** Decrement internal reference count by 1, and if it reaches 0, then 436 * call "lg->cleanup(lg->data)", destroy the handle, and return NULL; 437 * otherwise (if reference count is still > 0), return "lg". 438 * @param lg 439 * A log handle previously obtained from LOG_Create 440 * @sa 441 * LOG_Create 442 */ 443 extern NCBI_XCONNECT_EXPORT LOG LOG_Delete(LOG lg); 444 445 446 /** Upon having filled SLOG_Message data from parameters, write a message 447 * (perhaps with raw data attached) to the log by calling LOG_WriteInternal(). 448 * @note 449 * Do not call this function directly, if possible. Instead, use the 450 * LOG_WRITE() and LOG_DATA() macros from <connect/ncbi_util.h>! 451 * @param code 452 * Error code of the message 453 * @param subcode 454 * Error subcode of the message 455 * @param level 456 * The message severity 457 * @param module 458 * Module name (can be NULL) 459 * @param func 460 * Function name (can be NULL) 461 * @param file 462 * Source file name (can be NULL) 463 * @param line 464 * Source line within the file (can be 0 to omit the line number) 465 * @param message 466 * Message content 467 * @param raw_data 468 * Raw data to log (can be NULL) 469 * @param raw_size 470 * Size of the raw data (can be zero) 471 * @sa 472 * LOG_Create, ELOG_Level, FLOG_Handler, LOG_WriteInternal 473 */ 474 extern NCBI_XCONNECT_EXPORT void LOG_Write 475 (LOG lg, 476 int code, 477 int subcode, 478 ELOG_Level level, 479 const char* module, 480 const char* func, 481 const char* file, 482 int line, 483 const char* message, 484 const void* raw_data, 485 size_t raw_size 486 ); 487 488 489 /** Write message (perhaps with raw data attached) to the log by calling 490 * "lg->handler(lg->data, mess)". 491 * @note 492 * Do not call this function directly, if possible. Instead, use the 493 * LOG_WRITE() and LOG_DATA() macros from <ncbi_util.h>! 494 * @warning 495 * This call free()s "mess->message" when "mess->dynamic" is set non-zero! 496 * @param lg 497 * A log handle previously obtained from LOG_Create 498 * @sa 499 * LOG_Create, ELOG_Level, FLOG_Handler, LOG_Write 500 */ 501 extern NCBI_XCONNECT_EXPORT void LOG_WriteInternal 502 (LOG lg, 503 const SLOG_Message* mess 504 ); 505 506 507 /****************************************************************************** 508 * Registry 509 */ 510 511 512 /** Registry handle (keeps all data needed for the registry get/set/cleanup). 513 * @sa 514 * CORE_SetReg 515 */ 516 struct REG_tag; 517 typedef struct REG_tag* REG; 518 519 520 /** Transient/Persistent storage. 521 * @sa 522 * REG_Get, REG_Set 523 */ 524 typedef enum { 525 eREG_Transient = 0, /**< only in-memory storage while program runs */ 526 eREG_Persistent /**< hard-copy storage across program runs */ 527 } EREG_Storage; 528 529 530 /** Registry getter callback. 531 * Copy registry value stored in "section" under name "name" to buffer "value". 532 * Look for the matching entry first in the transient storage, and then in 533 * the persistent storage. Do not modify the "value" (leave it "as is", 534 * i.e. default) if the requested entry is not found in the registry. 535 * @note 536 * Always terminate value with '\0'. 537 * @note 538 * Do not put more than "value_size" bytes to "value". 539 * @param data 540 * Unspecified data as passed to REG_Create or REG_Reset 541 * @param section 542 * Section name to search 543 * @param name 544 * Key name to search within the section 545 * @param value 546 * Default value passed in (cut to "value_size") symbols, found value out 547 * @param value_size 548 * Size of "value" storage, must be greater than 0 549 * @return 550 * 1 if successfully found and stored; -1 if not found (the default is to be 551 * used); 0 if an error (including truncation) occurred 552 * @sa 553 * REG_Create, REG_Reset 554 */ 555 typedef int (*FREG_Get) 556 (void* data, 557 const char* section, 558 const char* name, 559 char* value, 560 size_t value_size 561 ); 562 563 564 /** Registry setter callback. 565 * Store the "value" to the registry section "section" under name "name", 566 * and according to "storage". 567 * @param data 568 * Unspecified data as passed to REG_Create or REG_Reset 569 * @param section 570 * Section name to add the key to 571 * @param name 572 * Key name to add to the section 573 * @param value 574 * Key value to associate with the key (NULL to deassociate, i.e. unset) 575 * @param storage 576 * How to store the new setting, temporarily or permanently 577 * @return 578 * Non-zero if successful (including replacing a value with itself) 579 * @sa 580 * REG_Create, REG_Reset, EREG_Storage 581 */ 582 typedef int/*bool*/ (*FREG_Set) 583 (void* data, 584 const char* section, 585 const char* name, 586 const char* value, 587 EREG_Storage storage 588 ); 589 590 591 /** Registry cleanup callback. 592 * @param data 593 * Unspecified data as passed to REG_Create or REG_Reset 594 * @sa 595 * REG_Reset, REG_Delete 596 */ 597 typedef void (*FREG_Cleanup) 598 (void* data 599 ); 600 601 602 /** Create a new registry (with an internal reference count set to 1). 603 * @warning 604 * if non-NULL "lock" is specified then MT_LOCK_AddRef() is called on it here, 605 * and MT_LOCK_Delete() will be called on it when this REG gets destroyed. 606 * Passing NULL callbacks below causes limiting the functionality 607 * only to those operations that have the callbacks set for. 608 * @param data 609 * Unspecified data to call "set", "get" and "cleanup" with 610 * @param get 611 * Getter callback 612 * @param set 613 * Setter callback 614 * @param cleanup 615 * Cleanup callback 616 * @param lock 617 * Protective MT lock (may be NULL) 618 * @sa 619 * MT_LOCK, MT_LOCK_AddRef, REG_Get, REG_Set, REG_Reset, REG_Delete 620 */ 621 extern NCBI_XCONNECT_EXPORT REG REG_Create 622 (void* data, 623 FREG_Get get, 624 FREG_Set set, 625 FREG_Cleanup cleanup, 626 MT_LOCK lock 627 ); 628 629 630 /** Reset the registry handle to use the new "data", "set", "get", 631 * and "cleanup". 632 * @note 633 * No change to the internal reference count. 634 * @param rg 635 * Registry handle as previously obtained from REG_Create 636 * @param data 637 * New user data 638 * @param get 639 * New getter callback 640 * @param set 641 * New setter callback 642 * @param cleanup 643 * New cleanup callback 644 * @param do_cleanup 645 * Whether to call old cleanup (if any specified) for old data 646 * @sa 647 * REG_Create, REG_Delete 648 */ 649 extern NCBI_XCONNECT_EXPORT void REG_Reset 650 (REG rg, 651 void* data, 652 FREG_Get get, 653 FREG_Set set, 654 FREG_Cleanup cleanup, 655 int/*bool*/ do_cleanup 656 ); 657 658 659 /** Increment internal reference count by 1, then return "rg". 660 * @param rg 661 * Registry handle as previously obtained from REG_Create 662 * @sa 663 * REG_Create 664 */ 665 extern NCBI_XCONNECT_EXPORT REG REG_AddRef(REG rg); 666 667 668 /** Decrement internal reference count by 1, and if it reaches 0, then 669 * call "rg->cleanup(rg->data)", destroy the handle, and return NULL; 670 * otherwise (if the reference count is still > 0), return "rg". 671 * @param rg 672 * Registry handle as previously obtained from REG_Create 673 * @sa 674 * REG_Create 675 */ 676 extern NCBI_XCONNECT_EXPORT REG REG_Delete(REG rg); 677 678 679 /** Copy the registry value stored in "section" under name "name" to buffer 680 * "value"; if the entry is found in both transient and persistent storages, 681 * then copy the one from the transient storage. 682 * If the specified entry is not found in the registry (or if there is no 683 * registry defined), and "def_value" is not NULL, then copy "def_value" to 684 * "value" (although, only up to "value_size" characters). 685 * @param rg 686 * Registry handle as previously obtained from REG_Create 687 * @param section 688 * Registry section name 689 * @param name 690 * Registry entry name 691 * @param value 692 * Buffer to receive the value of the requested entry, must be non-NULL 693 * @param value_size 694 * Maximal size of buffer "value", must be greater than 0 695 * @param def_value 696 * Default value (none if passed NULL or "") 697 * @return 698 * Return "value" if the found value, including the default, and with its '\0' 699 * terminator, fits entirely within "value_size"; return NULL if there was an 700 * error retrieving the value, or if it had to be truncated (but regardless, 701 * "value" must always be kept '\0'-terminated unless "value_size" was zero). 702 * @sa 703 * REG_Create, REG_Set 704 */ 705 extern NCBI_XCONNECT_EXPORT const char* REG_Get 706 (REG rg, 707 const char* section, 708 const char* name, 709 char* value, 710 size_t value_size, 711 const char* def_value 712 ); 713 714 715 /** Store the "value" into the registry section "section" under the key "name", 716 * and according to "storage". 717 * @param rg 718 * Registry handle as previously obtained from REG_Create 719 * @param section 720 * Section name to store the value into 721 * @param name 722 * Name to store the value under 723 * @param value 724 * The value to store (NULL to unset the parameter) 725 * @param storage 726 * Whether to store temporarily or permanently 727 * @return 728 * Non-zero if successful (including replacing a value with itself) 729 * @sa 730 * REG_Create, EREG_Storage, REG_Get 731 */ 732 extern NCBI_XCONNECT_EXPORT int REG_Set 733 (REG rg, 734 const char* section, 735 const char* name, 736 const char* value, 737 EREG_Storage storage 738 ); 739 740 741 #ifdef __cplusplus 742 } /* extern "C" */ 743 #endif 744 745 746 /* @} */ 747 748 #endif /* CONNECT___NCBI_CORE__H */ 749