1 /* ncbierr.c
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 * $Id: ncbierr.c,v 6.26 2009/08/14 18:01:09 lavr Exp $
27 *
28 * $Revision: 6.26 $
29 *
30 * Authors: Schuler, Sirotkin (UserErr stuff)
31 *
32 * Version Creation Date: 9-19-91
33 *
34 * File Description: Error handling functions
35 *
36 * Modifications:
37 * --------------------------------------------------------------------------
38 * Date Name Description of modification
39 * ------- ---------- -----------------------------------------------------
40 * 04-13-93 Schuler Added TRACE, VERIFY, ASSERT macros.
41 * 04-13-93 Schuler Added AbnormalExit function.
42 * 05-11-93 Schuler Added ErrSetHandler function.
43 * 05-21-93 Schuler Remove PROTO from ErrSetHandler implementation (oops)
44 * 05-26-93 Schuler Nlm_TraceStr flushes stderr, if appropriate
45 * 07-26-93 Schuler Moved globals into a (per-app) context struct
46 * 07-26-93 Schuler Fixed ErrClear()
47 * 11-15-93 Schuler Fixed double error reporting problem in ErrPost()
48 * 12-13-93 Schuler Message file support and lots of other changes.
49 * 12-22-93 Schuler Added log_level setting (min. severity to log)
50 * 01-03-94 Schuler Added ErrSaveOptions and ErrRestoreOptions
51 * 01-04-94 Schuler Added code to get settings from NCBI config file
52 * 01-07-94 Schuler Fixed bug in ErrMsgRoot_Read().
53 * 01-10-94 Schuler Added check for not_avail in ErrMsgRoot_fopen()
54 * 01-10-94 Schuler Fixed bug in ErrGetMsgRoot()
55 * 01-13-94 Schuler Added an handful of typecasts to supress warnings
56 * 01-23-94 Schuler Fixed bug in ErrSetOpts
57 * 02-02-94 Schuler ErrOpt structure has fields for actopt, logopt
58 * 02-02-94 Schuler Revisions related to change in message file format
59 * 02-02-94 Schuler Use TEST_BITS macro throughout
60 * 02-02-94 Schuler Improved back.compatability of ErrGetOpts/ErrSetOpts
61 * 02-10-94 Schuler Workaround for obsolete ERR_IGNORE option
62 * 02-10-94 Schuler Fixed bug in ErrSetFatalLevel
63 * 02-18-94 Schuler Fix to deal with possibility of userstrings being NULL
64 * 03-23-94 Schuler Fix memory leak in ErrGetExplanation
65 * 04-19-94 Schuler Keep error log file open all the time
66 * 08-23-94 Schuler ErrLogStr, ErrLogPrintStr modified
67 * 08-09-94 Schuler Dont try to open message file if FileLength ==0
68 * 11-15-94 Schuler Tweaks to ErrPostStr to avoid acc errors
69 * 11-18-94 Schuler Changed return type of Get/SetXXXLevel() family
70 * of functions from int to ErrSev to eliminate warnings
71 * 03-06-95 Schuler Fixed problem with ErrMsgRoot_fopen
72 *
73 * $Log: ncbierr.c,v $
74 * Revision 6.26 2009/08/14 18:01:09 lavr
75 * Use {Get|Set}ProgramName()
76 *
77 * Revision 6.25 2008/01/18 17:09:13 lavr
78 * Use SEV_MIN (instead of explicit SEV_INFO) in level setting routines
79 *
80 * Revision 6.24 2006/11/09 17:46:58 kans
81 * added cast to quiet CodeWarrior complaint
82 *
83 * Revision 6.23 2006/07/13 17:10:35 bollin
84 * use Uint4 instead of Uint2 for itemID values
85 *
86 * Revision 6.22 2005/04/06 19:34:13 lavr
87 * Reassign severity (if found in message file) in case of C++ Tkit hook
88 *
89 * Revision 6.21 2003/03/25 14:56:08 ivanov
90 * Nlm_AbnormalExitPure(): FatalAppExit() call changed to exit() under MS Windows (by Howard Feldman feldman@mshri.on.ca)
91 *
92 * Revision 6.20 2002/10/03 16:22:03 kans
93 * changed fgets to Nlm_FileGets
94 *
95 * Revision 6.19 2002/08/13 20:44:19 lavr
96 * Force logging to stderr/stdout if DEBUG_PRINTOUT env.var. is set as follows:
97 * STDOUT (case-insensitively) - log to stdout; anything else - log to stderr.
98 * By Denis Vakatov and Anton Lavrentiev.
99 *
100 * Revision 6.18 2002/07/11 20:26:03 lavr
101 * Prevent possible buffer overruns in storing text parts of a message
102 *
103 * Revision 6.17 2001/02/08 22:27:04 vakatov
104 * + Nlm_CallErrHandlerOnly() -- to allow processing of posted
105 * err.messages by the hook only.
106 *
107 * Revision 6.16 2000/06/14 22:27:52 vakatov
108 * Nlm_AbnormalExit() -- print message only if called for the first time
109 *
110 * Revision 6.15 1999/10/01 14:41:39 kans
111 * added SEV_REJECT between SEV_ERROR and SEV_FATAL
112 *
113 * Revision 6.14 1999/08/23 19:14:34 vakatov
114 * Let SEV_MAX not be an exception among the "SEV_*"
115 *
116 * Revision 6.13 1998/12/29 06:16:21 vakatov
117 * Nlm_ErrPostStr() -- Check for the severity code validity
118 *
119 * Revision 6.12 1998/10/22 16:52:40 shavirin
120 * Added function *Nlm_GetErrLongText able to retrieve long error messages
121 *
122 * Revision 6.11 1998/09/29 16:20:53 vakatov
123 * Nlm_AssertionFailed(): printout the module name and file/line in Message
124 *
125 * Revision 6.10 1998/08/24 17:42:00 kans
126 * fixed old style function definition warnings
127 *
128 * Revision 6.9 1998/06/11 21:02:23 shavirin
129 * Fixed few warnings
130 *
131 * Revision 6.8 1998/05/04 23:25:46 vakatov
132 * Raised the message posting level to SEV_ERROR(for non-_DEBUG only)
133 *
134 * Revision 6.7 1998/02/24 19:06:19 vakatov
135 * [DEBUG_HARD] Nlm_ErrShow(): init. "*message"(by garyt@timelogic.com)
136 *
137 * Revision 6.6 1998/02/17 20:57:45 vakatov
138 * Fixed delete_ErrNode() and started to use it; use Nlm_ErrUserClear()
139 * too(got rid of mem.leaks) // in cooperation with S.Bazhin.
140 *
141 * Revision 6.5 1998/02/13 15:22:40 vakatov
142 * ReleaseAppErrInfo(): dont forget to destroy list of error message;
143 * +fixed a minor mem.leak(free _szSeverity[SEV_MAX])
144 *
145 * Revision 6.4 1997/12/04 22:00:15 vakatov
146 * Nlm_ErrPostEx(): dont forget to zero "info->busy" flag when do nothing
147 *
148 * Revision 6.3 1997/11/26 21:26:14 vakatov
149 * Fixed errors and warnings issued by C and C++ (GNU and Sun) compilers
150 *
151 * Revision 6.2 1997/11/04 19:08:25 ostell
152 * added ErrGetUserStrings() to eliminate direct access to ErrDesc.userstr
153 * so this could become a thread specific chain
154 *
155 * Revision 6.1 1997/08/27 20:40:23 kans
156 * added ErrPathReset
157 *
158 * Revision 6.0 1997/08/25 18:15:24 madden
159 * Revision changed to 6.0
160 *
161 * Revision 5.12 1997/07/22 19:11:22 vakatov
162 * Separated Main() from GetArg[svc]() functions; [WIN_MSWIN] converged
163 * console and GUI libraries; [for WIN32-DLL] encapsulated global variables
164 *
165 * Revision 5.11 1997/03/31 18:52:11 vakatov
166 * Minor fix to pass through the C++ compiler
167 *
168 * Revision 5.10 1997/03/17 21:51:01 vakatov
169 * Nlm_ErrSetLogfile(): put the logfile banner as a monolith string
170 *
171 * Revision 5.9 1997/01/29 16:52:48 vakatov
172 * Nlm_ErrSetLogfile(): fixed an unsafe StrNCpy() use(might produce
173 * a non-'\0'-terminated string)
174 *
175 * Revision 5.8 1996/12/17 05:49:04 vakatov
176 * Got rid of some ugly warnings (JK)
177 *
178 * Revision 5.7 1996/12/16 22:37:54 vakatov
179 * Added more protection from recursive error posing function calls. Rolled
180 * back the changes made in "* Revision 5.6 1996/12/11 23:01:48 vakatov"
181 *
182 * Revision 5.6 1996/12/11 23:01:48 vakatov
183 * ErrMsgRoot_fopen(): Suppressed error posting when opening "*.msg"
184 * (often non-existing) auxiliary files.
185 *
186 * Revision 5.5 1996/12/03 21:48:33 vakatov
187 * Adopted for 32-bit MS-Windows DLLs
188 *
189 * Revision 5.4 1996/11/25 19:03:58 vakatov
190 * Moved 'eo_save'(formerly MT-unsafe 'static _eo_save') and
191 * 'busy'(formerly MT-unsafe 'static _busy') to the 'AppErrInfo' structure.
192 * Added Nlm_ErrGetLogfile() and Nlm_AbnormalExitPure(); the latter
193 * does nothing but exit without any error posting, etc.
194 * "MT-safed" error context initialization and posting functions.
195 *
196 * Revision 5.3 1996/08/12 18:40:31 vakatov
197 * Nlm_ErrPostEx(), Nlm_ErrPostEx() -- prevented from crashing when an
198 * empty formatting string specified(<fmt> === "")
199 *
200 * Revision 5.2 1996/08/07 19:24:31 vakatov
201 * [_DEBUG] Nlm_AbnormalExit(): "exit()" replaced by "abort()"
202 *
203 * Revision 5.1 1996/07/16 19:56:37 vakatov
204 * VSPRINTF macros has been replaced by the TSPRINTF macros in the
205 * code responsible for the error message composing -- in order to
206 * avoid the memory limits overrun when printing the error messages
207 * (by the means of function "vsprintf()") to a memory-located string.
208 * The application name is added as the error message caption.
209 * Added ReleaseAppErrInfo() function to clean dynamically allocated
210 * memory used by the error posing routines; other memory-leak-
211 * resulting flaws fixed; and eliminated multiple(duplicated) reading
212 * of the parameter file.
213 *
214 * Revision 5.0 1996/05/28 13:18:57 ostell
215 * Set to revision 5.0
216 *
217 * Revision 4.0 1995/07/26 13:46:50 ostell
218 * force revision to 4.0
219 *
220 * Revision 2.50 1995/06/27 16:21:45 kans
221 * protect ErrPostEx against single strings > ERRTEXT_MAX in length
222 *
223 * Revision 2.49 1995/05/15 18:45:58 ostell
224 * added Log line
225 *
226 *
227 *
228 * ==========================================================================
229 */
230
231
232 static char *_filename = __FILE__;
233 #define THIS_FILE _filename
234
235 #include "corepriv.h"
236 #include <tsprintf.h>
237
238 char * g_corelib = "CoreLib";
239
240 struct AppErrInfo
241 {
242 ErrDesc desc;
243 ErrOpts opts;
244 ErrHookProc hook;
245 unsigned long ini_mask;
246 unsigned long ini_bits;
247 unsigned int any_error :1;
248 unsigned int err_formatted :1;
249 unsigned int debug_mode :1;
250 size_t ustrcnt;
251 size_t ustrlen;
252 FILE *fdLog;
253 char logfile[PATH_MAX];
254 char msgpath[PATH_MAX];
255 ErrMsgRoot *idxlist;
256 ErrMsgNode *node;
257 ErrOpts _eo_save[2];
258 #define AEI_BUSY_1 0x1
259 #define AEI_BUSY_2 0x2
260 #define AEI_BUSY_3 0x4
261 int busy;
262 };
263
264
265 typedef struct AppErrInfo *AppErrInfoPtr;
266
267
268 static char * _szPropKey = "_AppErrInfo";
269
270 static char * _szSevKey [SEV_MAX + 1] = {
271 "", "SEV_INFO", "SEV_WARNING", "SEV_ERROR", "SEV_REJECT", "SEV_FATAL", "SEV_MAX"};
272
273 static char * _szSevDef [SEV_MAX + 1] = {
274 "", "NOTE:", "WARNING:", "ERROR:", "REJECT:", "FATAL ERROR:", "FATAL ERROR:" };
275
276 static char * _szSeverity[SEV_MAX + 1];
277
278 static AppErrInfoPtr GetAppErrInfo PROTO((void));
279
280 #define FUSE_BITS(inf) ( ((inf)->ini_bits & (inf)->ini_mask) | ((inf)->opts.flags & ~((inf)->ini_mask)) )
281 #define TEST_BITS(inf,x) (FUSE_BITS(inf) & (x))
282
283
284 static Nlm_Boolean s_HookOnly = FALSE;
285
286
287
288 /***************************************************************************\
289 | POSTING AN ERROR |
290 \***************************************************************************/
291
die_if_necessary(ErrSev sev,AppErrInfoPtr info)292 static void die_if_necessary(ErrSev sev, AppErrInfoPtr info)
293 {
294 if (sev >= info->opts.die_level)
295 Nlm_AbnormalExitPure( info->desc.errcode );
296 }
297
298
299 /*-------------------------------------------------------------------------
300 * ErrPost [Schuler]
301 *
302 * MODIFICATIONS:
303 * 04-13-93 Schuler
304 * 07-26-93 Schuler Modified to use AppErrInfo struct
305 * 11-15-93 Schuler Fixed bug that resulted in reporting errors twice
306 * 12-14-93 Schuler Modified to call the new ErrPostStr function
307 * 01-14-94 Schuler Check _busy flag
308 */
309
310 #ifdef VAR_ARGS
Nlm_ErrPost(context,errcode,fmt,va_alist)311 NLM_EXTERN void CDECL Nlm_ErrPost (context, errcode, fmt, va_alist)
312 int context;
313 int errcode;
314 const char *fmt;
315 va_dcl
316 #else
317 NLM_EXTERN void CDECL Nlm_ErrPost (int context, int errcode, const char *fmt, ...)
318 #endif
319 {
320 AppErrInfoPtr info = GetAppErrInfo();
321 ErrSev sev = (context==CTX_DEBUG) ? SEV_INFO : SEV_FATAL;
322
323 if ( info->busy )
324 {
325 die_if_necessary(sev, info);
326 return;
327 }
328 info->busy = AEI_BUSY_1;
329
330 info->desc.context = (short)context;
331
332 {{
333 const Nlm_Char PNTR scratch_str = NULL;
334 TSPRINTF(scratch_str, fmt);
335 if (scratch_str == NULL)
336 {
337 ErrClear();
338 return;
339 }
340 Nlm_StrNCpy(info->desc.errtext, scratch_str,
341 sizeof(info->desc.errtext) - 1);
342 info->desc.errtext[sizeof(info->desc.errtext) - 1] = '\0';
343 }}
344
345 info->err_formatted = 1;
346 Nlm_ErrPostStr(sev,errcode,0,NULL);
347
348 info->busy = 0;
349 }
350
351
352 /*-------------------------------------------------------------------------
353 * ErrPostEx [Schuler, 12-13-93]
354 *
355 * MODIFICATIONS:
356 * 01-14-94 Schuler Check _busy flag
357 */
358
359 #ifdef VAR_ARGS
Nlm_ErrPostEx(sev,lev1,lev2,fmt,va_alist)360 NLM_EXTERN int CDECL Nlm_ErrPostEx (sev, lev1, lev2, fmt, va_alist)
361 ErrSev sev;
362 int lev1;
363 int lev2;
364 const char *fmt;
365 va_dcl
366 #else
367 NLM_EXTERN int CDECL Nlm_ErrPostEx (ErrSev sev, int lev1, int lev2, const char *fmt, ...)
368 #endif
369 {
370 AppErrInfoPtr info = GetAppErrInfo();
371
372 if ( info->busy )
373 {
374 die_if_necessary(sev, info);
375 return ANS_NONE;
376 }
377 info->busy = AEI_BUSY_1;
378
379 {{
380 const Nlm_Char PNTR scratch_str = NULL;
381 TSPRINTF(scratch_str, fmt);
382 if (scratch_str == NULL) {
383 ErrClear();
384 info->busy = 0;
385 return ANS_NONE;
386 }
387 Nlm_StrNCpy(info->desc.errtext, scratch_str,
388 sizeof(info->desc.errtext) - 1);
389 info->desc.errtext[sizeof(info->desc.errtext) - 1] = '\0';
390 }}
391
392 info->err_formatted =1;
393 {{
394 int code = Nlm_ErrPostStr(sev,lev1,lev2,NULL);
395 info->busy = 0;
396 return code;
397 }}
398 }
399
400
401 /*-------------------------------------------------------------------------
402 * ErrPostStr [Schuler, 12-13-93]
403 *
404 * MODIFICATIONS:
405 * 12-22-93 Schuler Only logs error if severity >= log_level
406 * 01-14-94 Schuler Check _busy flag
407 * 02-03-94 Schuler Use severity from message file if there is one
408 * 02-10-94 Schuler Workaround for obsolete ERR_IGNORE option
409 * 02-18-94 Schuler Check for NULL user strings before printing
410 * 08-23-94 Schuler Clear the err_formatted flag after use
411 * 11-15-94 Schuler De-const some pointers that need to be lvalues
412 */
413
Nlm_ErrPostStr(ErrSev sev,int lev1,int lev2,const char * str)414 NLM_EXTERN int LIBCALL Nlm_ErrPostStr (ErrSev sev, int lev1, int lev2, const char *str)
415 {
416 AppErrInfoPtr info = GetAppErrInfo();
417 ErrMsgRoot *root = NULL;
418 ErrMsgNode *node1 = NULL;
419 ErrMsgNode *node2 = NULL;
420
421 int severity;
422 if (sev < 0 || SEV_MAX < sev)
423 sev = SEV_FATAL;
424 severity = sev;
425
426 if (info->busy & AEI_BUSY_2)
427 {
428 die_if_necessary(sev, info);
429 return ANS_NONE;
430 }
431 info->busy |= AEI_BUSY_2;
432
433 /* ----- Fill in the fields of the error descriptor ----- */
434 info->any_error = 1;
435 info->desc.severity = (short)sev;
436 info->desc.errcode = lev1;
437 info->desc.subcode = lev2;
438
439 /* ----- set up the root and node for message file ----- */
440 if ( (info->desc.module[0] != '\0') )
441 {
442 root = (ErrMsgRoot*) ErrGetMsgRoot(info->desc.module);
443 for (node1=root->list; node1; node1=node1->next)
444 {
445 if (node1->code == info->desc.errcode)
446 {
447 for (node2=node1->list; node2; node2=node2->next)
448 if (node2->code == info->desc.subcode)
449 break;
450 break;
451 }
452 }
453 }
454 info->desc.root = root;
455 info->desc.node = node2 ? node2 : node1;
456 if (info->desc.node != NULL && info->desc.node->sev != SEV_NONE)
457 severity = info->desc.node->sev;
458
459 /* ----- format some strings ----- */
460 if (!info->err_formatted)
461 {
462 info->desc.errtext[0] = '\0';
463 if (str != NULL)
464 strncat(info->desc.errtext,str,ERRTEXT_MAX - 1);
465 }
466 info->err_formatted = 0;
467
468 if (info->desc.context != 0)
469 sprintf(info->desc.codestr,"[%03d:%03d] ",info->desc.context,info->desc.errcode);
470 else if (node1 != NULL && (TEST_BITS(info,EO_XLATE_CODES)))
471 {
472 if (node2 != NULL)
473 sprintf(info->desc.codestr,"[%s.%s] ",node1->name,node2->name);
474 else
475 sprintf(info->desc.codestr,"[%s] ",node1->name);
476 }
477 else
478 {
479 sprintf(info->desc.codestr,"[%03d.%03d] ",info->desc.errcode,info->desc.subcode);
480 }
481
482
483 /* ----- Log the error according to the current options ----- */
484 if (!s_HookOnly && severity >= info->opts.log_level)
485 {
486 NlmMutexLockEx( &corelibMutex );
487
488 #ifdef WIN_DUMB
489 if (TEST_BITS(info,EO_LOGTO_STDOUT))
490 fflush(stderr);
491 if (TEST_BITS(info,EO_LOGTO_STDERR))
492 fflush(stdout);
493 #endif
494
495 if (TEST_BITS(info,EO_LOG_SEVERITY))
496 {
497 ErrLogPrintf("%s ",_szSeverity[severity]);
498 }
499 if (TEST_BITS(info,EO_LOG_CODES))
500 {
501 if (info->desc.module[0])
502 ErrLogPrintf("%s ",info->desc.module);
503 ErrLogPrintStr(info->desc.codestr);
504 }
505 if (TEST_BITS(info,EO_LOG_FILELINE))
506 {
507 ErrLogPrintf("{%s, line %d} ",info->desc.srcfile,info->desc.srcline);
508 }
509 if (TEST_BITS(info,EO_LOG_USERSTR))
510 {
511 const ValNode *node;
512 for (node=info->desc.userstr; node; node=node->next)
513 {
514 if (node->data.ptrvalue != NULL)
515 ErrLogPrintf("%s ",(char*)node->data.ptrvalue);
516 }
517 }
518 if (TEST_BITS(info,EO_LOG_ERRTEXT))
519 {
520 ErrLogPrintStr(info->desc.errtext);
521 ErrLogPrintStr("\n");
522 }
523 if (node1 != NULL && TEST_BITS(info,EO_LOG_MSGTEXT))
524 {
525 ErrMsgNodePtr node = (node2==NULL) ? node1 : node2;
526 const char *text = ErrGetExplanation(root,node);
527 ErrLogPrintStr(text);
528 }
529
530 NlmMutexUnlock( corelibMutex );
531 }
532
533 info->busy &= ~AEI_BUSY_2;
534
535 /* ----- Call the user-installed hook function if there is one ----- */
536 if (info->hook != NULL)
537 {
538 int retval;
539 info->desc.severity = severity;
540 if ((retval = (*info->hook)(&info->desc)) != 0)
541 {
542 ErrClear();
543 return retval;
544 }
545 }
546
547 if ( s_HookOnly ) {
548 die_if_necessary((ErrSev)severity, info);
549 ErrClear();
550 return ANS_NONE;
551 }
552
553 /* ----- Workaround for obsolete ERR_IGNORE option ----- */
554 if (info->opts.actopt == ERR_IGNORE)
555 {
556 ErrClear();
557 return ANS_NONE;
558 }
559
560 /* ----- If not already handled, perform default error handling ----- */
561 if (severity >= info->opts.msg_level || severity >= info->opts.die_level)
562 return ErrShow();
563
564 return ANS_OK;
565 }
566
567
568 /*-------------------------------------------------------------------------
569 * ErrLogPrintf [Schuler, 12-13-93]
570 *
571 * Formats the string and passes it along to ErrLogPrintStr().
572 */
573 #ifdef VAR_ARGS
Nlm_ErrLogPrintf(fmt,va_alist)574 NLM_EXTERN void CDECL Nlm_ErrLogPrintf (fmt, va_alist)
575 const char *fmt;
576 va_dcl
577 #else
578 NLM_EXTERN void CDECL Nlm_ErrLogPrintf (const char *fmt, ...)
579 #endif
580 {
581 const Nlm_Char PNTR scratch_str = NULL;
582 TSPRINTF(scratch_str, fmt);
583 if (scratch_str != NULL)
584 ErrLogPrintStr( scratch_str );
585 }
586
587
588 /*-------------------------------------------------------------------------
589 * ErrLogPrintStr [Schuler, 12-13-93]
590 *
591 * Sends a string of text to whichever output streams have been enabled
592 * for error logging (stderr, trace, or logfile).
593 *
594 * MODIFICATIONS
595 * 12-15-93 Schuler Added fflush(stdout) before writing to stderr.
596 * 04-19-94 Schuler Open file if not already open, but don't close
597 * 08-23-94 Schuler stdout/stderr output only #ifndef _WINDLL
598 */
Nlm_ErrLogPrintStr(const char * str)599 NLM_EXTERN void LIBCALL Nlm_ErrLogPrintStr (const char *str)
600 {
601 AppErrInfoPtr info;
602 size_t bytes;
603
604 if (str == NULL || *str == '\0' ||
605 (info = GetAppErrInfo()) == NULL || info->busy & AEI_BUSY_3)
606 return;
607 info->busy |= AEI_BUSY_3;
608
609 bytes = strlen( str );
610
611 #ifdef WIN_DUMB
612 {{
613 static unsigned long s_ForceBits = EO_ALL_FLAGS;
614 if (s_ForceBits == EO_ALL_FLAGS) {
615 char buf[64];
616 static const char s_SecretDefault[] = "_NoOneCanGuessThisValue_Duh_";
617 Nlm_GetEnvParam(0, 0, "DEBUG_PRINTOUT",
618 buf, sizeof(buf), s_SecretDefault);
619 if (Nlm_StrCmp(buf, s_SecretDefault) == 0) {
620 s_ForceBits = 0;
621 } else if (Nlm_StrICmp(buf, "stdout") == 0) {
622 s_ForceBits = EO_LOGTO_STDOUT;
623 } else {
624 s_ForceBits = EO_LOGTO_STDERR;
625 }
626 }
627
628 if ((s_ForceBits & EO_LOGTO_STDOUT) || TEST_BITS(info,EO_LOGTO_STDOUT))
629 {
630 fflush(stderr);
631 fwrite(str,1,bytes,stdout);
632 fflush(stdout);
633 }
634
635 if ((s_ForceBits & EO_LOGTO_STDERR) || TEST_BITS(info,EO_LOGTO_STDERR))
636 {
637 fflush(stdout);
638 fwrite(str,1,bytes,stderr);
639 fflush(stderr);
640 }
641 }}
642 #endif
643
644 info->busy &= ~AEI_BUSY_3;
645
646 if (TEST_BITS(info,EO_LOGTO_TRACE))
647 {
648 Nlm_TraceStr(str);
649 }
650
651 if (TEST_BITS(info,EO_LOGTO_USRFILE))
652 {
653 if (info->fdLog == NULL && info->logfile[0] != '\0')
654 info->fdLog = FileOpen(info->logfile, "a+");
655
656 if (info->fdLog != NULL)
657 {
658 fwrite(str, 1, bytes, info->fdLog);
659 fflush(info->fdLog);
660 }
661 }
662 }
663
664
665 /*-------------------------------------------------------------------------
666 * ErrSetContext [Schuler, 12-13-93]
667 *
668 * NOTE: Don't call this function directly
669 *
670 * MODIFICATIONS
671 * 02-03-94 Schuler Return 1 if busy
672 */
Nlm_ErrSetContext(const char * ctx,const char * fname,int line,int db,Nlm_Uint2 entityID,Nlm_Uint4 itemID,Nlm_Uint2 itemtype)673 NLM_EXTERN int LIBCALL Nlm_ErrSetContext (const char *ctx, const char *fname, int line, int db,
674 Nlm_Uint2 entityID, Nlm_Uint4 itemID, Nlm_Uint2 itemtype)
675 {
676 AppErrInfoPtr info = GetAppErrInfo();
677
678 if ( info->busy )
679 return 1;
680
681 info->desc.module[0] = '\0';
682 if (ctx != NULL)
683 strncat(info->desc.module,ctx,MODSTR_MAX - 1);
684 info->desc.srcfile[0] = '\0';
685 if (fname != NULL)
686 {
687 const char *p;
688 if ((p = strrchr(fname,DIRDELIMCHR)) != NULL)
689 ++p;
690 else
691 p = fname;
692 strncat(info->desc.srcfile,p,SRCFILE_MAX - 1);
693 }
694 info->desc.srcline = line;
695 info->desc.entityID = entityID;
696 info->desc.itemID = itemID;
697 info->desc.itemtype = itemtype;
698 info->debug_mode = (unsigned)db;
699 return 0;
700 }
701
702
703 /***************************************************************************\
704 | FETCHING AND REPORTING ERRORS |
705 \***************************************************************************/
706
707 /*-------------------------------------------------------------------------
708 * ErrFetch [Schuler]
709 *
710 * MODIFICATIONS
711 * 07-26-93 Schuler Modified to use AppErrInfo struct
712 */
Nlm_ErrFetch(ErrDesc * err)713 NLM_EXTERN int LIBCALL Nlm_ErrFetch (ErrDesc *err)
714 {
715 if (!Nlm_ErrCopy(err))
716 return FALSE;
717 ErrClear();
718 return TRUE;
719 }
720
721
722 /*-------------------------------------------------------------------------
723 * ErrCopy [Schuler, 07-26-93]
724 *
725 * MODIFICATIONS:
726 * 12-12-93 Schuler Check info->any_error flag before copying
727 */
Nlm_ErrCopy(ErrDesc FAR * err)728 NLM_EXTERN int LIBCALL Nlm_ErrCopy (ErrDesc FAR *err)
729 {
730 AppErrInfoPtr info = GetAppErrInfo();
731 if (info->any_error)
732 {
733 if (err != NULL)
734 memcpy((void*)err,(void*)&(info->desc),sizeof(ErrDesc));
735 return TRUE;
736 }
737 return FALSE;
738 }
739
740
741 /*-------------------------------------------------------------------------
742 * ErrClear [Schuler, 07-26-93]
743 *
744 * MODIFICATIONS
745 * 12-13-93 Schuler Just clear flags instead of zeroing the whole struct.
746 */
Nlm_ErrClear(void)747 NLM_EXTERN void LIBCALL Nlm_ErrClear (void)
748 {
749 AppErrInfoPtr info = GetAppErrInfo();
750 info->any_error = 0;
751 info->err_formatted = 0;
752 info->debug_mode = 0;
753 info->desc.context = 0;
754 info->desc.entityID = 0;
755 info->desc.itemID = 0;
756 info->desc.itemtype = 0;
757 }
758
759 /*-------------------------------------------------------------------------
760 * ErrShow [Schuler]
761 *
762 * MODIFICATIONS
763 * 12-13-93 Schuler Rewritten to use msg_level and die_level settings.
764 * 12-14-93 Schuler Now returns the result of Message().
765 * 12-15-93 Schuler Added proper handling of Abort/Retry/Ignore choice.
766 * 12-21-93 Schuler Added special case for WIN_DUMB + logging to stderr
767 * 12-24-94 Schuler Changed Message to MsgAlert
768 * 12-27-94 Schuler Removed Beep() because MsgAlert is taking care of it
769 * 01-31-94 Schuler Put Beep() back because MsgAlert is no longer doing it.
770 * 02-03-94 Schuler Now honors all EO_MSG_... option flags.
771 * 02-18-94 Schuler Check for NULL user strings before copying.
772 *
773 * TO DO
774 * - allocate buffer for the message
775 */
Nlm_ErrShow(void)776 NLM_EXTERN int LIBCALL Nlm_ErrShow (void)
777 {
778 AppErrInfoPtr info = GetAppErrInfo();
779 if (info->any_error)
780 {
781 int answer = ANS_OK;
782 int severity = info->desc.severity;
783 if (info->desc.node != NULL && info->desc.node->sev != SEV_NONE)
784 severity = info->desc.node->sev;
785 if (severity >= info->opts.msg_level)
786 {
787 size_t bytes;
788 const char *caption = GetProgramName();
789 char *message;
790 const char *msgtext;
791 char *p;
792 MsgKey key;
793
794 /* ----- beep if requested ----- */
795 if (TEST_BITS(info,EO_BEEP))
796 Nlm_Beep();
797
798 /* ----- set up the buffer to hold the error message ---- */
799 if (TEST_BITS(info,EO_MSG_MSGTEXT))
800 msgtext = ErrGetExplanation(info->desc.root,info->desc.node);
801 else
802 msgtext = NULL;
803 /* forget about the options for now -- this is the max we would need*/
804 bytes = 2 + strlen(info->desc.module)
805 + 32 /* severity string. TEMPORARY (need to keep track of longest string) */
806 + 2 + strlen(info->desc.codestr) /* error codes */
807 + 16 + strlen(info->desc.srcfile) /* source file and line number */
808 + 2 + info->ustrcnt + info->ustrlen /* user strings */
809 + 2 + strlen(info->desc.errtext) /* error message */
810 + 2 + ((msgtext) ? strlen(msgtext) : 0); /* verbose message */
811
812 if ((message = (char*)Malloc(bytes)) == NULL)
813 message = info->desc.errtext;
814 else
815 {
816 /* ----- format the message in the buffer ----- */
817 *message = '\0';
818 p = message;
819 if (TEST_BITS(info,EO_MSG_SEVERITY))
820 {
821 NlmMutexLockEx( &corelibMutex );
822 p = strchr(strcpy(p,_szSeverity[severity]),'\0');
823 NlmMutexUnlock( corelibMutex );
824 *p++ = ' ';
825 }
826 if (TEST_BITS(info,EO_MSG_CODES))
827 {
828 p = strchr(strcpy(p,info->desc.module),'\0');
829 *p++ = ' ';
830 p = strchr(strcpy(p,info->desc.codestr),'\0');
831 *p++ = ' ';
832 }
833 if (TEST_BITS(info,EO_MSG_FILELINE))
834 {
835 /*p = strchr(strcpy(p,info->desc.srcfile),'\0');*/
836 sprintf(p,"{%s line %d} \n",info->desc.srcfile,info->desc.srcline);
837 p = strchr(p,'\0');
838 }
839 if (TEST_BITS(info,EO_MSG_USERSTR))
840 {
841 const ValNode *node;
842 for (node=info->desc.userstr; node; node=node->next)
843 {
844 if (node->data.ptrvalue != NULL)
845 {
846 p = strchr(strcpy(p,(char*)node->data.ptrvalue),'\0');
847 *p++ = ' ';
848 }
849 }
850 }
851 if (TEST_BITS(info,EO_MSG_ERRTEXT))
852 {
853 p = strchr(strcpy(p,info->desc.errtext),'\0');
854 }
855 if (TEST_BITS(info,EO_MSG_MSGTEXT) && msgtext!=NULL)
856 {
857 if (p != message) *p++ = '\n';
858 p = strchr(strcpy(p,msgtext),'\0');
859 }
860 ASSERT_HARD ( strlen(p) < bytes );
861 }
862
863 /* ----- show the message ----- */
864 if (TEST_BITS(info,EO_PROMPT_ABORT)) key = KEY_ARI;
865 else if (TEST_BITS(info,EO_WAIT_KEY)) key = KEY_OK;
866 else key = KEY_NONE;
867 answer = MsgAlertStr(key,(ErrSev)severity,caption,message);
868
869 /* ----- clean up ----- */
870 if (message != info->desc.errtext)
871 Free(message);
872 }
873
874 /* ----- die if appropriate ----- */
875 die_if_necessary((ErrSev)severity, info);
876
877 ErrClear();
878 return answer;
879 }
880 return 0;
881 }
882
883
884
885 /***************************************************************************\
886 | MESSAGE FILE SUPPORT |
887 \***************************************************************************/
888 static FILE * ErrMsgRoot_fopen PROTO((ErrMsgRoot *ctx));
889 static ErrMsgNode * new_ErrMsgNode PROTO((const char *name, int code, ErrSev sev));
890 static void delete_ErrMsgNode PROTO((ErrMsgNode *item));
891 static ErrSev atosev PROTO((const char *sevstr));
892
893
new_ErrMsgRoot(const char * context)894 static ErrMsgRoot * new_ErrMsgRoot (const char *context)
895 {
896 ErrMsgRoot *idx = (ErrMsgRoot*) MemNew(sizeof(ErrMsgRoot));
897 if (idx != NULL)
898 idx->name = (context) ? StrSave(context) : 0;
899 return idx;
900 }
901
delete_ErrMsgRoot(ErrMsgRoot * idx)902 static void delete_ErrMsgRoot(ErrMsgRoot *idx)
903 {
904 if ( idx->name )
905 MemFree((void *)idx->name);
906 if ( idx->name )
907 delete_ErrMsgNode(idx->list);
908 MemFree(idx);
909 }
910
911
912 /*-------------------------------------------------------------------------
913 * ErrMsgRoot_fopen [Schuler, 12-09-93]
914 *
915 * Opens an error message file corresponding to an error context.
916 *
917 * MODIFICATIONS
918 * 01-07-94 Schuler Looks in the current directory first.
919 * 01-10-94 Schuler Uses FileOpen() instead of fopen() (now that
920 * reentrancy problem is solved).
921 * 09-08-94 Schuler Don't try to open file if FileLength ==0
922 * 03-06-95 Schuler Eliminated the mode argument to this function. The
923 * required for proper operation depends on the platform.
924 */
925
926 #if defined(OS_MSWIN) || defined(OS_NT)
927 static char * s_msg_mode = "rb";
928 #else
929 static char * s_msg_mode = "r";
930 #endif
931
932 #define MODFNAME_MAX 32
933
934
ErrMsgRoot_fopen(ErrMsgRoot * ctx)935 static FILE * ErrMsgRoot_fopen (ErrMsgRoot *ctx)
936 {
937 AppErrInfoPtr info = GetAppErrInfo();
938 FILE *fd;
939 char file[MODFNAME_MAX];
940 char path[PATH_MAX];
941 char *p1 = file;
942 const char *p2 = ctx->name;
943 int i, ch;
944
945 for (i=0; (ch= *p2++) != 0 && i<MODFNAME_MAX-5; ++i)
946 {
947 if (isalpha(ch)) ch = tolower(ch);
948 *p1++ = (char)ch;
949 }
950 strcpy(p1,".msg");
951
952 if (FileLength(file)==0 || (fd = FileOpen(file,s_msg_mode)) == NULL)
953 {
954 strcpy(path,info->msgpath);
955 strncat(path,file,sizeof(path));
956 fd = FileOpen(path,s_msg_mode);
957 }
958
959 return fd;
960 }
961
962
963 /*-------------------------------------------------------------------------
964 * ErrMsgRoot_Read [Schuler, 12-08-93]
965 *
966 * Scans an error message file and builds a data structure that contains
967 * the mappings between integer error codes and strings as well as file
968 * offset for the verbose error explanations so they can later be retrieved
969 * when (or if) needed.
970 *
971 * MODIFICATIONS
972 * 01-07-94 Schuler Fixed bug that resulted in failure to set the text
973 * length for the last item in the file.
974 * 01-10-94 Schuler Added _busy flag to indicate that we are in the process
975 * of parsing the file. Otherwise, there is a problem if
976 * you post an error while attempting to read corelib.msg
977 * (leads to infinite recursion).
978 * 01-10-94 Schuler Added linenumber reporting for all error messages.
979 * 01-23-94 Schuler Changed all ErrPostEx to ErrLogPrintf (don't want to
980 * be posting errors in here -- will recurse ad infinitum).
981 * 01-21-94 Schuler Changed fclose() to FileClose()
982 * 02-02-94 Schuler Revisions for new file format
983 *
984 * TO DO
985 * Check for missing integer code
986 * Capture comments
987 */
988
atosev(const char * sevstr)989 static ErrSev atosev (const char *sevstr)
990 {
991 int i;
992 if (sevstr)
993 {
994 for (i=SEV_MIN; i <= SEV_MAX; ++i)
995 {
996 if (strcmp(sevstr,_szSevKey[i]) == 0)
997 return (ErrSev)i;
998 }
999 }
1000 return SEV_NONE;
1001 }
1002
ErrMsgRoot_Read(ErrMsgRoot * idx)1003 static int ErrMsgRoot_Read (ErrMsgRoot *idx)
1004 {
1005 FILE *fd;
1006
1007 if (idx->list != NULL)
1008 return TRUE;
1009 if ( idx->busy )
1010 return FALSE;
1011
1012 idx->busy = 1;
1013
1014 if ((fd = ErrMsgRoot_fopen(idx)) == NULL)
1015 {
1016 idx->busy = 0;
1017 return FALSE;
1018 }
1019
1020 {{
1021 char line[80], *p;
1022 int linenum = 0;
1023 long tofs = 0, cofs = 0, tmpofs;
1024 ErrMsgNode *lev1;
1025 ErrMsgNode *lev2;
1026 int any_text;
1027 int any_comt;
1028
1029 /* ----- Look for MODULE line ----- */
1030 while (Nlm_FileGets(line,sizeof line,fd))
1031 {
1032 linenum++;
1033 if ( strchr("#\r\n", line[0]) )
1034 continue;
1035
1036 if (strncmp(line,"MODULE",6) == 0)
1037 {
1038 p = strtok(line," \t\r\n");
1039 p = strtok(NULL," \t\r\n");
1040 if (strcmp(idx->name,p) !=0)
1041 ErrLogPrintf("Context string mismatch (%s vs %s)\n",idx->name,p);
1042 break;
1043 }
1044 else
1045 {
1046 idx->busy = 0;
1047 ErrLogPrintf("Syntax error: \"MODULE\" expected, line %d\n",linenum);
1048 return FALSE;
1049 }
1050 }
1051
1052 /* ----- Process the rest of the file ----- */
1053 any_text = any_comt = FALSE;
1054 lev1 = lev2 = NULL;
1055 tmpofs = ftell(fd);
1056
1057 while (Nlm_FileGets(line,sizeof line,fd))
1058 {
1059 linenum++;
1060
1061 if (line[0] == '$')
1062 {
1063 if (any_text)
1064 {
1065 ErrMsgNode *n = lev2 ? lev2 : lev1;
1066 if (n != NULL)
1067 {
1068 n->tofs = tofs;
1069 n->tlen = tmpofs - tofs;
1070 }
1071 any_text = FALSE;
1072 }
1073 }
1074
1075 if (line[0]=='$' && line[1]=='$')
1076 {
1077 /*** NEED ERROR CHECKING HERE ***/
1078 char *tok1 = strtok(line+2,", \t\r\n");
1079 char *tok2 = strtok(NULL,", \t\r\n");
1080 char *tok3 = strtok(NULL,", \t\r\n");
1081
1082 ASSERT(tok1 && tok2);
1083
1084 lev2 = NULL;
1085 lev1 = new_ErrMsgNode(tok1,atoi(tok2),atosev(tok3));
1086 if (idx->list == NULL)
1087 idx->list = lev1;
1088 else
1089 {
1090 ErrMsgNode *t0=NULL, *t1;
1091 for (t1=idx->list; TRUE; t1=t1->next)
1092 {
1093 if (t1==NULL || lev1->code < t1->code)
1094 {
1095 if (t0 == NULL)
1096 idx->list = lev1;
1097 else
1098 t0->next = lev1;
1099 lev1->next = t1;
1100 break;
1101 }
1102 if (lev1->code == t1->code)
1103 {
1104 ErrLogPrintf("Code %d duplicated, line %d\n",t1->code,linenum);
1105 break;
1106 }
1107 t0 = t1;
1108 }
1109 }
1110 /*any_text = FALSE;*/
1111 }
1112 else if (line[0]=='$' && line[1]=='^')
1113 {
1114 /*** NEED ERROR CHECKING HERE ***/
1115 char *tok1 = strtok(line+2,", \t\r\n");
1116 char *tok2 = strtok(NULL,", \t\r\n");
1117 char *tok3 = strtok(NULL,", \t\r\n");
1118
1119 ASSERT(tok1 && tok2);
1120
1121 lev2 = new_ErrMsgNode(tok1,atoi(tok2),atosev(tok3));
1122 if (lev1->list == NULL)
1123 lev1->list = lev2;
1124 else
1125 {
1126 ErrMsgNode *t0=NULL, *t1;
1127 for (t1=lev1->list; TRUE; t1=t1->next)
1128 {
1129 if (t1==NULL || lev2->code < t1->code)
1130 {
1131 if (t0 == NULL)
1132 lev1->list = lev2;
1133 else
1134 t0->next = lev2;
1135 lev2->next = t1;
1136 break;
1137 }
1138 if (lev2->code == t1->code)
1139 {
1140 ErrLogPrintf("Code %d duplicated, line %d\n",t1->code,linenum);
1141 break;
1142 }
1143 t0 = t1;
1144 }
1145 }
1146 /*any_text = FALSE;*/
1147 }
1148 else if (line[0] == '#')
1149 {
1150 if (!any_comt)
1151 {
1152 cofs = tmpofs;
1153 any_comt = TRUE;
1154 }
1155 }
1156 else
1157 {
1158 if (any_comt)
1159 {
1160 ErrMsgNode *n = lev2 ? lev2 : lev1;
1161 if (n != NULL)
1162 {
1163 n->cofs = cofs;
1164 n->clen = tmpofs - cofs;
1165 }
1166 }
1167 if (!any_text)
1168 {
1169 /* if (not a blank line) */
1170 tofs = tmpofs;
1171 any_text = TRUE;
1172 }
1173 }
1174 tmpofs = ftell(fd);
1175 }
1176
1177 if (any_text)
1178 {
1179 ErrMsgNode *n = lev2 ? lev2 : lev1;
1180 if (n != NULL)
1181 {
1182 n->tofs = tofs;
1183 n->tlen = tmpofs - tofs;
1184 }
1185 }
1186
1187 FileClose(fd);
1188 }}
1189
1190 idx->busy = 0;
1191 return TRUE;
1192 }
1193
1194
1195 /*-------------------------------------------------------------------------
1196 * new_ErrMsgNode, delete_ErrMsgNode
1197 * Constructor/Destructor for ErrMsgNode
1198 */
1199
new_ErrMsgNode(const char * name,int code,ErrSev sev)1200 static ErrMsgNode * new_ErrMsgNode(const char *name, int code, ErrSev sev)
1201 {
1202 ErrMsgNode *item = (ErrMsgNode*)MemNew(sizeof(ErrMsgNode));
1203 if ( item ) {
1204 item->name = (name) ? StrSave(name) : 0;
1205 item->code = code;
1206 item->sev = sev;
1207 }
1208 return item;
1209 }
1210
delete_ErrMsgNode(ErrMsgNode * item)1211 static void delete_ErrMsgNode(ErrMsgNode *item)
1212 {
1213 ErrMsgNode *next;
1214
1215 while ( item ) {
1216 next = item->next;
1217
1218 delete_ErrMsgNode(item->list);
1219 MemFree((void *)item->name);
1220 MemFree((void *)item->tstr);
1221 MemFree((void *)item->cstr);
1222 MemSet(item, '\xFF', sizeof(*item));
1223 MemFree(item);
1224
1225 item = next;
1226 }
1227 }
1228
1229
1230 /*-------------------------------------------------------------------------
1231 * ErrGetMsgRoot [Schuler, 12-09-93]
1232 *
1233 * Gets the index structure for an error context, creating and initializing
1234 * it if necessary.
1235 *
1236 * MODIFICATIONS
1237 * 01-10-94 Schuler Changed to call ErrMsgRoot_Read() *after* linking
1238 * into list. Otherwise, if an error is posted from
1239 * within ErrMsgRoot_Read(), it won't find the CoreLib
1240 * modlue and will read it again (ad infinitum).
1241 */
1242
ErrGetMsgRoot(const char * context)1243 NLM_EXTERN ErrMsgRootPtr LIBCALL ErrGetMsgRoot (const char *context)
1244 {
1245 AppErrInfoPtr info = GetAppErrInfo();
1246 ErrMsgRoot *idx, *idx0=NULL;
1247 int d;
1248
1249 for (idx=info->idxlist; TRUE; idx=idx->next)
1250 {
1251 if (idx==NULL || (d = strcmp(idx->name,context)) > 0)
1252 {
1253 ErrMsgRoot *idx2 = new_ErrMsgRoot(context);
1254 idx2->next = idx;
1255 if (idx0 == NULL)
1256 info->idxlist = idx2;
1257 else
1258 idx0->next = idx2;
1259 ErrMsgRoot_Read(idx2);
1260 return (ErrMsgRootPtr) idx2;
1261 }
1262
1263 if (d == 0)
1264 break;
1265
1266 idx0 = idx;
1267 }
1268
1269 return (ErrMsgRootPtr)idx;
1270 }
1271
1272
1273 /*-------------------------------------------------------------------------
1274 * ErrGetExplanation [Schuler, 12-09-93]
1275 *
1276 * Gets the explanatory text for a particular error from an error
1277 * message file.
1278 *
1279 * MODIFICATIONS
1280 * 02-02-94 Schuler Fix for memory leak when length==0
1281 * 02-02-94 Schuler Now exported (was static)
1282 */
1283
ErrGetExplanation(ErrMsgRootPtr idx,ErrMsgNodePtr item)1284 NLM_EXTERN const char* LIBCALL ErrGetExplanation (ErrMsgRootPtr idx, ErrMsgNodePtr item)
1285 {
1286 if (idx != NULL && item != NULL && item->tlen >0)
1287 {
1288 size_t bytes;
1289 char *text;
1290
1291 if (item->tstr != NULL)
1292 return item->tstr;
1293
1294 bytes = (size_t)item->tlen;
1295 if ((text=(char *)MemNew(bytes+1)) != NULL)
1296 {
1297 FILE *fd = ErrMsgRoot_fopen((ErrMsgRoot *) idx);
1298 if (fd != NULL)
1299 {
1300 if (fseek(fd,item->tofs,SEEK_SET) !=0)
1301 goto ErrReturn;
1302 if (fread(text,1,bytes,fd) != bytes)
1303 goto ErrReturn;
1304 fclose(fd);
1305 *(text+bytes) = '\0'; /* make sure null-terminated */
1306 ((ErrMsgNode*)item)->tstr = text;
1307 return text;
1308 }
1309 ErrReturn :
1310 fclose(fd);
1311 MemFree(text);
1312 return NULL;
1313 }
1314 }
1315 return NULL;
1316 }
1317
1318
1319 /***************************************************************************\
1320 | CUSTOMIZATION |
1321 \***************************************************************************/
1322
1323 /*-------------------------------------------------------------------------
1324 * ErrSetLogfile [Schuler]
1325 *
1326 * MODIFICATIONS
1327 * 07-26-93 Schuler Modified to use AppErrInfo struct
1328 * 12-17-93 Schuler Changed back to returning a Boolean
1329 * 01-21-94 Schuler Renamed & added flags argument.
1330 * 01-21-94 Schuler Changed fopen/fclose to FileOpen/FileClose
1331 * 04-19-94 Schuler Only open
1332 *
1333 * TO DO
1334 * - honor ELOG_NOCREATE flag
1335 */
1336
Nlm_ErrSetLogfile(const char * filename,unsigned long flags)1337 NLM_EXTERN int LIBCALL Nlm_ErrSetLogfile (const char *filename, unsigned long flags)
1338 {
1339 static char *fmode_append = "a+";
1340 static char *fmode_overwrite = "w";
1341
1342 AppErrInfoPtr info = GetAppErrInfo();
1343
1344 if (info->fdLog != NULL) /* close if already open */
1345 {
1346 FileClose(info->fdLog);
1347 info->fdLog = NULL;
1348 }
1349
1350 if (filename == NULL)
1351 info->logfile[0] = '\0';
1352 else
1353 {
1354 if ( !(flags & ELOG_NOCREATE) )
1355 {
1356 char *fmode = (flags & ELOG_APPEND) ? fmode_append : fmode_overwrite;
1357 FILE *fp;
1358
1359 if ((fp = FileOpen(filename,fmode)) == NULL)
1360 return FALSE;
1361 if (flags & ELOG_BANNER)
1362 {
1363 char buffer[64];
1364 Nlm_DayTimeStr(buffer,TRUE,TRUE);
1365 fprintf(fp, "\n========================[ %s ]========================\n", buffer);
1366 }
1367 FileClose(fp);
1368 }
1369 strncpy(info->logfile,filename,PATH_MAX - 1);
1370 info->logfile[PATH_MAX - 1] = '\0';
1371 }
1372 return TRUE;
1373 }
1374
1375
Nlm_ErrGetLogfile(void)1376 const char* LIBCALL Nlm_ErrGetLogfile( void )
1377 {
1378 AppErrInfoPtr info = GetAppErrInfo();
1379
1380 if (info->logfile != NULL && *info->logfile == '\0')
1381 return NULL;
1382
1383 return info->logfile;
1384 }
1385
1386
1387 /*-------------------------------------------------------------------------
1388 * ErrSetHandler [Schuler, 05-11-93]
1389 *
1390 * Allows the application to set a hook procedure that will be called
1391 * when an error is posted via ErrPost. It is always called regardless
1392 * of any error reporting/logging options that may have been set. The
1393 * return value is the pointer to the previous error hook procedure
1394 * if there was one.
1395 *
1396 * MODIFICATIONS
1397 * 05-21-93 Schuler
1398 */
Nlm_ErrSetHandler(ErrHookProc hookNew)1399 NLM_EXTERN ErrHookProc LIBCALL Nlm_ErrSetHandler (ErrHookProc hookNew)
1400 {
1401 AppErrInfoPtr info = GetAppErrInfo();
1402 ErrHookProc hookOld =info->hook;
1403 info->hook = hookNew;
1404 return hookOld;
1405 }
1406
1407
Nlm_CallErrHandlerOnly(Nlm_Boolean hook_only)1408 NLM_EXTERN Nlm_Boolean LIBCALL Nlm_CallErrHandlerOnly(Nlm_Boolean hook_only)
1409 {
1410 Nlm_Boolean prev;
1411 NlmMutexLockEx(&corelibMutex);
1412 prev = s_HookOnly;
1413 s_HookOnly = hook_only;
1414 NlmMutexUnlock(corelibMutex);
1415 return prev;
1416 }
1417
1418
1419 /*-------------------------------------------------------------------------
1420 * ErrUserInstall [Sirotkin]
1421 *
1422 * Add or replace a user-string.
1423 *
1424 * MODIFICATIONS
1425 * 12-15-93 Schuler No longer keeps track of string lengths.
1426 */
1427
1428 static char *_strNull = "(null)";
1429
Nlm_ErrUserInstall(const char * msg,ErrStrId magic_cookie)1430 NLM_EXTERN ErrStrId LIBCALL Nlm_ErrUserInstall (const char *msg, ErrStrId magic_cookie)
1431 {
1432 AppErrInfoPtr info = GetAppErrInfo();
1433 ValNode *list = (ValNode *) info->desc.userstr;
1434 ValNode *node;
1435 ErrStrId cookie;
1436
1437 if (msg == NULL)
1438 msg = _strNull;
1439
1440 if (magic_cookie)
1441 {
1442 for (node=list; node; node=node->next)
1443 {
1444 if (node->choice == magic_cookie)
1445 {
1446 /** replace **/
1447 info->ustrlen -= strlen((char*)node->data.ptrvalue);
1448 MemFree(node->data.ptrvalue);
1449 node->data.ptrvalue = (void*) StringSave(msg);
1450 info->ustrlen += strlen(msg);
1451 return magic_cookie;
1452 }
1453 }
1454 ErrPostEx(SEV_WARNING,-1,0,
1455 "ErrUserInstall: bad string id (%d)",
1456 (int) magic_cookie);
1457 return 0;
1458 }
1459 else
1460 {
1461 for (cookie = 1; cookie < 255; ++cookie)
1462 {
1463 for (node=list; node; node=node->next)
1464 {
1465 if (node->choice == cookie)
1466 break;
1467 }
1468 if (node==NULL) /* free cookie is magic */
1469 {
1470 node = ValNodeNew((ValNode*)info->desc.userstr);
1471 if ( ! info->desc.userstr)
1472 info->desc.userstr = node;
1473 node->choice = cookie;
1474 node->data.ptrvalue = StringSave(msg);
1475 info->ustrlen += strlen(msg);
1476 info->ustrcnt ++;
1477 return cookie;
1478 }
1479 }
1480 /*ErrPostEx(SEV_WARNING,-1,0,"ErrUserInstall: no more string id's");*/
1481 return 0;
1482 }
1483 }
1484
1485
1486 /*-------------------------------------------------------------------------
1487 * ErrUserDelete [Sirotkin]
1488 *
1489 * Delete a single user-string.
1490 *
1491 * MODIFICATIONS
1492 * 12-15-93 Schuler No longer keeps track of string lengths.
1493 */
1494
Nlm_ErrUserDelete(ErrStrId magic_cookie)1495 NLM_EXTERN Nlm_Boolean LIBCALL Nlm_ErrUserDelete (ErrStrId magic_cookie)
1496 {
1497 AppErrInfoPtr info = GetAppErrInfo();
1498 ValNodePtr node = ValNodeExtract((ValNode**)(&info->desc.userstr), magic_cookie);
1499
1500 if (node)
1501 {
1502 ASSERT(node->data.ptrvalue != NULL);
1503 info->ustrlen -= strlen((char*)node->data.ptrvalue);
1504 info->ustrcnt --;
1505 ValNodeFreeData(node);
1506 return TRUE;
1507 }
1508 return FALSE;
1509 }
1510
1511
1512 /*-------------------------------------------------------------------------
1513 * ErrUserClear [Sirotkin]
1514 *
1515 * Deletes the entire list of user-strings.
1516 */
Nlm_ErrUserClear(void)1517 NLM_EXTERN void LIBCALL Nlm_ErrUserClear (void)
1518 {
1519 AppErrInfoPtr info = GetAppErrInfo();
1520 ValNodeFreeData((ValNode*)info->desc.userstr);
1521 info->ustrlen = 0;
1522 info->ustrcnt = 0;
1523 }
1524
1525 /**************************************************************************
1526 *
1527 * ErrGetUserStrings(ErrDescPtr err)
1528 * returns ValNodePtr to chain of user strings for this thread
1529 *
1530 ***************************************************************************/
Nlm_ErrGetUserStrings(ErrDescPtr err)1531 NLM_EXTERN ValNodePtr LIBCALL Nlm_ErrGetUserStrings(ErrDescPtr err)
1532 {
1533 ValNodePtr vnp = NULL;
1534
1535 if (err != NULL)
1536 vnp = (ValNodePtr)(err->userstr);
1537 return vnp;
1538 }
1539
1540
1541
1542 /*-------------------------------------------------------------------------
1543 * ErrGetLogLevel, ErrSetLogLevel [Schuler, 12-22-93]
1544 *
1545 * Get/Set the minimum severity level that will be logged.
1546 */
ErrSetLogLevel(ErrSev level)1547 NLM_EXTERN ErrSev LIBCALL ErrSetLogLevel (ErrSev level)
1548 {
1549 AppErrInfoPtr info = GetAppErrInfo();
1550 ErrSev prev = (ErrSev) info->opts.log_level;
1551 info->opts.log_level = (short) MAX(SEV_MIN,MIN(level,SEV_MAX));
1552 return prev;
1553 }
1554
ErrGetLogLevel(void)1555 NLM_EXTERN ErrSev LIBCALL ErrGetLogLevel (void)
1556 {
1557 return (ErrSev)GetAppErrInfo()->opts.log_level;
1558 }
1559
1560
1561 /*-------------------------------------------------------------------------
1562 * ErrGetMessageLevel, ErrSetMessageLevel [Schuler, 12-14-93]
1563 *
1564 * Get/Set the minimum severity level that will be reported via Message().
1565 */
ErrSetMessageLevel(ErrSev level)1566 NLM_EXTERN ErrSev LIBCALL ErrSetMessageLevel (ErrSev level)
1567 {
1568 AppErrInfoPtr info = GetAppErrInfo();
1569 ErrSev prev = (ErrSev) info->opts.msg_level;
1570 info->opts.msg_level = (short) MAX(SEV_MIN,MIN(level,SEV_MAX));
1571 return prev;
1572 }
1573
ErrGetMessageLevel(void)1574 NLM_EXTERN ErrSev LIBCALL ErrGetMessageLevel (void)
1575 {
1576 return (ErrSev) GetAppErrInfo()->opts.msg_level;
1577 }
1578
1579
1580 /*-------------------------------------------------------------------------
1581 * ErrGetFatalLevel, ErrSetFatalLevel [Schuler, 12-14-93]
1582 *
1583 * Get/Set the minimum severity level that will cause an abnormal exit.
1584 */
ErrSetFatalLevel(ErrSev level)1585 NLM_EXTERN ErrSev LIBCALL ErrSetFatalLevel (ErrSev level)
1586 {
1587 AppErrInfoPtr info = GetAppErrInfo();
1588 ErrSev prev = (ErrSev) info->opts.die_level;
1589 info->opts.die_level = (short) MAX(SEV_MIN,MIN(level,SEV_MAX));
1590 return prev;
1591 }
1592
ErrGetFatalLevel(void)1593 NLM_EXTERN ErrSev LIBCALL ErrGetFatalLevel (void)
1594 {
1595 return (ErrSev) GetAppErrInfo()->opts.die_level;
1596 }
1597
1598
1599 /*-------------------------------------------------------------------------
1600 * ErrSetOptFlags, ErrClearOptFlags, ErrTestOptFlags [Schuler, 12-14-93]
1601 *
1602 * Set, clear, or test the current state of any error option flag.
1603 */
ErrSetOptFlags(unsigned long flags)1604 NLM_EXTERN unsigned long LIBCALL ErrSetOptFlags (unsigned long flags)
1605 {
1606 AppErrInfoPtr info = GetAppErrInfo();
1607 info->opts.flags |= (flags & EO_ALL_FLAGS);
1608 return info->opts.flags;
1609 }
1610
ErrClearOptFlags(unsigned long flags)1611 NLM_EXTERN unsigned long LIBCALL ErrClearOptFlags (unsigned long flags)
1612 {
1613 AppErrInfoPtr info = GetAppErrInfo();
1614 info->opts.flags &= ~(flags & EO_ALL_FLAGS);
1615 return info->opts.flags;
1616 }
1617
ErrTestOptFlags(unsigned long flags)1618 NLM_EXTERN unsigned long LIBCALL ErrTestOptFlags (unsigned long flags)
1619 {
1620 AppErrInfoPtr info = GetAppErrInfo();
1621 return (info->opts.flags & flags);
1622 }
1623
1624
1625 /*-------------------------------------------------------------------------
1626 * ErrSaveOptions [Schuler, 01-03-94]
1627 *
1628 */
ErrSaveOptions(ErrOpts * opts)1629 NLM_EXTERN void LIBCALL ErrSaveOptions (ErrOpts *opts)
1630 {
1631 AppErrInfoPtr info = GetAppErrInfo();
1632
1633 ASSERT(opts != NULL);
1634 memcpy((void*)opts,(void*)(&info->opts),sizeof(ErrOpts));
1635 }
1636
1637
1638 /*-------------------------------------------------------------------------
1639 * ErrRestoreOptions [Schuler, 01-03-94]
1640 */
1641
ErrRestoreOptions(const ErrOpts * opts)1642 NLM_EXTERN void LIBCALL ErrRestoreOptions (const ErrOpts *opts)
1643 {
1644 AppErrInfoPtr info = GetAppErrInfo();
1645
1646 ASSERT(opts != NULL);
1647 memcpy((void*)(&info->opts),(void*)opts,sizeof(ErrOpts));
1648 }
1649
1650
1651 /*-------------------------------------------------------------------------
1652 * ErrGetOpts [Schuler]
1653 *
1654 * MODIFICATIONS
1655 * 07-26-93 Schuler Modified to use AppErrInfo struct
1656 * 02-02-94 Schuler Added local option saving strategy
1657 */
1658
Nlm_ErrGetOpts(short * erract,short * errlog)1659 NLM_EXTERN void LIBCALL Nlm_ErrGetOpts (short * erract, short * errlog)
1660 {
1661 AppErrInfoPtr info = GetAppErrInfo();
1662
1663 if (erract != NULL)
1664 {
1665 size_t i;
1666 for (i=0; i<DIM(info->_eo_save); ++i)
1667 {
1668 if (info->_eo_save[i].flags ==0)
1669 break;
1670 }
1671 if (i<DIM(info->_eo_save))
1672 {
1673 info->_eo_save[i] = info->opts;
1674 *erract = (short)(-1-i);
1675 }
1676 else
1677 {
1678 TRACE("ErrGetOpts: overflow\n");
1679 *erract = info->opts.actopt;
1680 }
1681 }
1682 if (errlog != NULL)
1683 *errlog = info->opts.logopt;
1684 }
1685
1686
1687 /*-------------------------------------------------------------------------
1688 * ErrSetOpts [Schuler]
1689 *
1690 * MODIFICATIONS
1691 * 07-26-93 Schuler Modified to use AppErrInfo struct
1692 * 12-15-93 Schuler Modified to map old settings to the new options.
1693 * 12-21-93 Schuler Now always starts from defaults and then twiddles.
1694 * 01-27-94 Schuler Fixed bug whereby logopt not always saved.
1695 * 02-02-94 Schuler Added local option saving strategy
1696 */
1697
1698
Nlm_ErrSetOpts(short actopt,short logopt)1699 NLM_EXTERN void LIBCALL Nlm_ErrSetOpts (short actopt, short logopt)
1700 {
1701 AppErrInfoPtr info = GetAppErrInfo();
1702
1703 if (actopt < 0)
1704 {
1705 int i = -(actopt+1);
1706 ASSERT(i>=0 && i<DIM(info->_eo_save));
1707 if (info->_eo_save[i].flags !=0)
1708 {
1709 info->opts = info->_eo_save[i];
1710 info->_eo_save[i].flags =0;
1711 return;
1712 }
1713 ErrLogPrintf("*** Improper use of ErrGetOpts/ErrSetOpts ***\n");
1714 }
1715
1716 /****info->opts.flags = EO_DEFAULTS;
1717 info->opts.log_level = SEV_INFO;****/
1718
1719 if (actopt !=0)
1720 info->opts.flags &= ~EO_PROMPT_ABORT;
1721
1722 switch (actopt)
1723 {
1724 case ERR_CONTINUE:
1725 case ERR_IGNORE:
1726 info->opts.msg_level = SEV_MAX;
1727 info->opts.die_level = SEV_MAX;
1728 break;
1729 case ERR_TEE:
1730 info->opts.msg_level = SEV_WARNING;
1731 info->opts.die_level = SEV_MAX;
1732 break;
1733 case ERR_ADVISE:
1734 info->opts.msg_level = SEV_WARNING;
1735 info->opts.die_level = SEV_MAX;
1736 break;
1737 case ERR_ABORT:
1738 info->opts.msg_level = SEV_WARNING;
1739 info->opts.die_level = SEV_FATAL;
1740 break;
1741 case ERR_PROMPT:
1742 info->opts.msg_level = SEV_WARNING;
1743 info->opts.die_level = SEV_FATAL;
1744 info->opts.flags |= EO_PROMPT_ABORT;
1745 break;
1746 }
1747 if (actopt != 0)
1748 info->opts.actopt = actopt;
1749
1750
1751 switch(logopt)
1752 {
1753 case ERR_LOG_ON:
1754 info->opts.flags |= EO_LOGTO_USRFILE;
1755 break;
1756 case ERR_LOG_OFF:
1757 info->opts.flags &= ~EO_LOGTO_USRFILE;
1758 break;
1759 default:
1760 logopt = 0;
1761 }
1762 if (logopt != 0)
1763 info->opts.logopt = logopt;
1764
1765
1766 /***** if anybody liked this, I can put it back...
1767 if (logopt != 0)
1768 {
1769 int i;
1770 FILE *fp;
1771 if ((fp = FileOpen(info->logfile, "a+")) != NULL)
1772 {
1773 fputc ('\n', fp);
1774 for (i=0; i<4; i++) fputc (' ', fp);
1775 for (i=0; i<21; i++) fputc ('-', fp);
1776 fprintf (fp, " error logging %sabled ",
1777 logopt==ERR_LOG_ON ? " en" : "dis");
1778 for (i=0; i<21; i++) fputc ('-', fp);
1779 fputc ('\n', fp);
1780 FileClose(fp);
1781 }
1782 }
1783 *****/
1784 }
1785
1786
1787 /***************************************************************************\
1788 | DEBUGGING |
1789 \***************************************************************************/
1790
1791
1792 /*-------------------------------------------------------------------------
1793 * Trace [Schuler, 04-13-93]
1794 *
1795 * Formats a string and sends it to the "trace device" (see the
1796 * description of Nlm_TraceStr about "trace device"). Normally, it
1797 * is desirable to trace some (possibly verbose) informational messages
1798 * during the development phase of a program, but inhibit them in the
1799 * final version that is released to end users. The TRACE macro supports
1800 * this style of usage, calling Nlm_Trace only if _DEBUG is defined.
1801 * For example:
1802 *
1803 * TRACE("!@#$ screwed up (%s,%d)\n",__FILE__,___LINE__);
1804 *
1805 * Note that it is declared as CDECL (because of the variable argument
1806 * list) and may therefore not be callable from some other programming
1807 * languages, such as Basic and Pascal.
1808 *
1809 * MODIFICATIONS
1810 * Schuler 07-26-93
1811 * Schuler 12-14-93 Merged varargs and stdargs versions of the function
1812 */
1813
1814 #ifdef VAR_ARGS
Nlm_Trace(fmt,va_alist)1815 NLM_EXTERN void Nlm_Trace (fmt, va_alist)
1816 const char *fmt;
1817 va_dcl
1818 #else
1819 NLM_EXTERN void CDECL Nlm_Trace (const char *fmt, ...)
1820 #endif
1821 {
1822 const Nlm_Char PNTR scratch_str = NULL;
1823 TSPRINTF(scratch_str, fmt);
1824 if (scratch_str != NULL)
1825 Nlm_TraceStr( scratch_str );
1826 }
1827
1828
1829
1830 /*-------------------------------------------------------------------------
1831 * TraceStr [Schuler, 04-13-93]
1832 *
1833 * Users of the C and C++ should use the TRACE macro and not call this
1834 * function directly. This function, unlike Nlm_Trace, it may be called
1835 * other programming languages, such as Basic and Pascal.
1836 *
1837 * MODIFICATIONS
1838 * 05-26-93 Schuler
1839 * 12-15-93 Schuler Changed to use TRACE_TO_FILE macro.
1840 * 12-15-93 Schuler Removed tracing to stderr (caused an echo echo ...).
1841 * 01-21-94 Schuler Changed fopen/fclose to FileOpen/FileClose
1842 */
1843
Nlm_TraceStr(const char * str)1844 NLM_EXTERN void LIBCALL Nlm_TraceStr (const char *str)
1845 {
1846 if (str==NULL) return;
1847
1848 #ifdef TRACE_TO_STDOUT
1849 fprintf(stdout,"%s",str);
1850 #endif
1851
1852 #ifdef TRACE_TO_AUX
1853 #ifdef OS_MSWIN
1854 OutputDebugString(str);
1855 #endif
1856 #endif /* TRACE_TO_AUX */
1857
1858 #ifdef TRACE_TO_FILE
1859 {
1860 FILE *fd = FileOpen("trace.log","a+");
1861 if (fd != NULL)
1862 {
1863 fprintf(fd,"%s",str);
1864 FileClose(fd);
1865 }
1866 }
1867 #endif /* TRACE_TO_FILE */
1868 }
1869
1870
1871 /*-------------------------------------------------------------------------
1872 * Nlm_AssertionFailed [Schuler, 04-13-93]
1873 *
1874 * Function needed to support the ASSERT and VERIFY macros.
1875 *
1876 * MODIFICATIONS
1877 * 05-11-93 Schuler
1878 * 12-15-93 Schuler Use ErrLogPrintf() inseead of Nlm_Trace()
1879 * 12-15-93 Schuler Added call to Message() so user knows what happened!
1880 * 01-21-94 Schuler Changed MSG_OK to MSG_POST
1881 */
Nlm_AssertionFailed(const char * expression,const char * module,const char * fname,int linenum)1882 NLM_EXTERN void LIBCALL Nlm_AssertionFailed
1883 (const char *expression, const char *module,
1884 const char *fname, int linenum)
1885 {
1886 ErrLogPrintf("\nAssertion Failed: %s\n", expression);
1887 if (module && *module)
1888 ErrLogPrintf(" %s",module);
1889 if ( fname )
1890 ErrLogPrintf(" %s, line %d", fname, linenum);
1891 ErrLogPrintStr("\n");
1892
1893 Message(MSG_POST, "Assertion Failed:\n%s", expression);
1894 if (module && *module)
1895 Message(MSG_POST, "Module \"%s\"", module);
1896 if ( fname )
1897 Message(MSG_POST, "File \"%s\", line %d", fname, linenum);
1898
1899 AbnormalExit(1);
1900 }
1901
1902
1903 /*-------------------------------------------------------------------------
1904 * AbnormalExit [Schuler, 04-13-93]
1905 *
1906 * Terminates the application immediately. This should only be done
1907 * as a last resort since some (possibly necessary) cleanup code will
1908 * not get executed.
1909 *
1910 * MODIFICATIONS
1911 * Schuler 05-11-93
1912 * Schuler 07-26-93
1913 */
Nlm_AbnormalExitPure(int code)1914 NLM_EXTERN void LIBCALL Nlm_AbnormalExitPure(int code)
1915 {
1916 #if defined(_DEBUG)
1917 abort();
1918 #elif defined(OS_MAC)
1919 ExitToShell();
1920 #else
1921 exit( code );
1922 #endif
1923 }
1924
1925
Nlm_AbnormalExit(int code)1926 NLM_EXTERN void LIBCALL Nlm_AbnormalExit (int code)
1927 {
1928 static Nlm_Boolean s_Exiting = FALSE;
1929 if ( !s_Exiting ) {
1930 s_Exiting = TRUE;
1931 ErrLogPrintStr( "\n***** ABNORMAL PROGRAM EXIT *****\n" );
1932 }
1933 Nlm_AbnormalExitPure( code );
1934 }
1935
1936
1937 /***************************************************************************\
1938 | STATIC HELPER FUNCTIONS |
1939 \***************************************************************************/
1940
1941 /*-------------------------------------------------------------------------
1942 * GetAppErrInfo [Schuler, 07-26-93]
1943 *
1944 * MODIFICATIONS
1945 * 12-13-93 Schuler Added initialization for new settings.
1946 * 01-04-94 Schuler Added code to get settings from ncbi.ini
1947 * 01-27-94 Schuler Set & clear _busy when reading from ncbi.ini
1948 * 02-01-94 Schuler Updated _flag array
1949 */
1950
1951 static char * _file = "ncbi";
1952 static char * _section = "ErrorProcessing";
1953
1954 struct FlagInf { char *key; unsigned long bits; };
1955 static struct FlagInf _flag [] =
1956 {
1957 { "EO_LOG_SEVERITY", EO_LOG_SEVERITY },
1958 { "EO_LOG_CODES", EO_LOG_CODES },
1959 { "EO_LOG_FILELINE", EO_LOG_FILELINE },
1960 { "EO_LOG_USERSTR", EO_LOG_USERSTR },
1961 { "EO_LOG_ERRTEXT", EO_LOG_ERRTEXT },
1962 { "EO_LOG_MSGTEXT", EO_LOG_MSGTEXT },
1963 { "EO_MSG_SEVERITY", EO_MSG_SEVERITY },
1964 { "EO_MSG_CODES", EO_MSG_CODES },
1965 { "EO_MSG_FILELINE", EO_MSG_FILELINE },
1966 { "EO_MSG_USERSTR", EO_MSG_USERSTR },
1967 { "EO_MSG_ERRTEXT", EO_MSG_ERRTEXT },
1968 { "EO_MSG_MSGTEXT", EO_MSG_MSGTEXT },
1969 { "EO_LOGTO_STDOUT", EO_LOGTO_STDOUT },
1970 { "EO_LOGTO_STDERR", EO_LOGTO_STDERR },
1971 { "EO_LOGTO_TRACE", EO_LOGTO_TRACE },
1972 { "EO_LOGTO_USRFILE", EO_LOGTO_USRFILE },
1973 { "EO_XLATE_CODES", EO_XLATE_CODES },
1974 { "EO_WAIT_KEY", EO_WAIT_KEY },
1975 { "EO_PROMPT_ABORT", EO_PROMPT_ABORT },
1976 { "EO_BEEP", EO_BEEP }
1977 };
1978
1979
1980 static int _nAppErrInfo = 0;
1981
ReleaseAppErrInfo(void)1982 extern void ReleaseAppErrInfo( void )
1983 {
1984 AppErrInfoPtr info = (AppErrInfoPtr)GetAppProperty( _szPropKey );
1985
1986 if (info == NULL)
1987 return;
1988
1989 NlmMutexLockEx( &corelibMutex );
1990 ASSERT ( _nAppErrInfo > 0 );
1991
1992 if (--_nAppErrInfo == 0)
1993 {
1994 int i;
1995 for (i=SEV_MIN; i<=SEV_MAX; ++i)
1996 {
1997 Nlm_MemFree( _szSeverity[i] );
1998 _szSeverity[i] = NULL;
1999 }
2000 }
2001
2002 if (info->fdLog != NULL) {
2003 FileClose( info->fdLog );
2004 }
2005
2006 while ( info->idxlist ) {
2007 ErrMsgRoot *idx = info->idxlist;
2008 info->idxlist = idx->next;
2009 delete_ErrMsgRoot(idx);
2010 }
2011
2012 Nlm_ErrUserClear();
2013
2014 Nlm_MemFill(info, '\xFF', sizeof(*info));
2015 Nlm_MemFree( info );
2016
2017 RemoveAppProperty( _szPropKey );
2018
2019 NlmMutexUnlock( corelibMutex );
2020 }
2021
2022
GetAppErrInfo(void)2023 static struct AppErrInfo * GetAppErrInfo(void)
2024 {
2025 AppErrInfoPtr info = (AppErrInfoPtr) GetAppProperty(_szPropKey);
2026
2027 if (info == NULL)
2028 {
2029 char buffer[128], *p;
2030 int i;
2031
2032 int severity_init = 0;
2033 NlmMutexLockEx( &corelibMutex );
2034
2035 info = (struct AppErrInfo*) MemGet(sizeof(struct AppErrInfo), TRUE);
2036 if (info == NULL)
2037 Message(MSG_FATAL,"Out of memory");
2038 info->opts.actopt = ERR_ABORT; /* OBSOLETE */
2039 info->opts.logopt = ERR_LOG_OFF; /* OBSOLETE */
2040 info->opts.flags = EO_DEFAULTS;
2041 info->opts.log_level = SEV_INFO;
2042 #ifdef _DEBUG
2043 info->opts.msg_level = SEV_WARNING;
2044 #else
2045 info->opts.msg_level = SEV_ERROR;
2046 #endif
2047 info->opts.die_level = SEV_FATAL;
2048 strcpy(info->logfile,"error.log");
2049 for (i = SEV_MIN; i <= SEV_MAX; i++)
2050 {
2051 if (_szSeverity[i] == NULL)
2052 {
2053 severity_init = 1;
2054 sprintf(buffer, "*SEV*%d", i);
2055 _szSeverity[i] = StrSave( buffer );
2056 }
2057 }
2058 ++_nAppErrInfo;
2059 SetAppProperty(_szPropKey, (void*)info);
2060
2061 if (GetAppParam(_file, _section, "MsgPath", "",
2062 info->msgpath, PATH_MAX-2))
2063 FileBuildPath(info->msgpath, NULL, NULL);
2064
2065 if ( severity_init )
2066 {
2067 for (i = SEV_MIN; i <= SEV_MAX; i++)
2068 {
2069 GetAppParam(_file, _section, _szSevKey[i], _szSevDef[i],
2070 buffer,sizeof buffer);
2071 if (buffer[0] == '"')
2072 {
2073 if ((p = strchr(&buffer[1],'"')) != NULL) *p = '\0';
2074 p = &buffer[1];
2075 }
2076 else
2077 p = buffer;
2078
2079 {{
2080 char *dummy_sev = _szSeverity[i];
2081 _szSeverity[i] = StrSave(p);
2082 Nlm_MemFree( dummy_sev );
2083 }}
2084 }
2085 }
2086 NlmMutexUnlock( corelibMutex );
2087
2088 for (i=0; i<DIM(_flag); ++i)
2089 {
2090 p = _flag[i].key;
2091 if (GetAppParam(_file,_section,p,"",buffer,sizeof buffer))
2092 {
2093 info->ini_mask |= _flag[i].bits;
2094 if (strchr("1TtYy",buffer[0]))
2095 info->ini_bits |= _flag[i].bits;
2096 }
2097 }
2098
2099 SetAppProperty(_szPropKey,(void*)info);
2100 }
2101
2102 return info;
2103 }
2104
2105 /*-------------------------------------------------------------------------
2106 * ErrPathReset [Kans]
2107 *
2108 * Resets info->msgpath
2109 */
Nlm_ErrPathReset(void)2110 NLM_EXTERN void LIBCALL Nlm_ErrPathReset (void)
2111 {
2112 AppErrInfoPtr info = GetAppErrInfo();
2113 if (GetAppParam(_file, _section, "MsgPath", "",
2114 info->msgpath, PATH_MAX-2))
2115 FileBuildPath(info->msgpath, NULL, NULL);
2116 }
2117
Nlm_GetErrLongText(char * module,int errcode,int subcode)2118 NLM_EXTERN char *Nlm_GetErrLongText (char *module,
2119 int errcode, int subcode)
2120 {
2121 ErrMsgRoot *root = NULL;
2122 ErrMsgNode *node1 = NULL;
2123 ErrMsgNode *node2 = NULL;
2124 ErrMsgNode *the_node = NULL;
2125 char *text = NULL;
2126
2127 if (module != NULL) {
2128 root = (ErrMsgRoot*) ErrGetMsgRoot(module);
2129 for (node1=root->list; node1; node1=node1->next) {
2130 if (node1->code == errcode) {
2131 for (node2=node1->list; node2; node2=node2->next)
2132 if (node2->code == subcode)
2133 break;
2134 break;
2135 }
2136 }
2137 }
2138
2139 the_node = node2 ? node2 : node1;
2140
2141 text = (char *) ErrGetExplanation(root, the_node);
2142
2143 return text;
2144 }
2145
2146