Compiles in MSVC with cmake
[alexxy/gromacs.git] / src / gmxlib / gmx_fatal.c
1 /*
2  * 
3  *                This source code is part of
4  * 
5  *                 G   R   O   M   A   C   S
6  * 
7  *          GROningen MAchine for Chemical Simulations
8  * 
9  *                        VERSION 3.2.0
10  * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
11  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
12  * Copyright (c) 2001-2004, The GROMACS development team,
13  * check out http://www.gromacs.org for more information.
14
15  * This program is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU General Public License
17  * as published by the Free Software Foundation; either version 2
18  * of the License, or (at your option) any later version.
19  * 
20  * If you want to redistribute modifications, please consider that
21  * scientific software is very special. Version control is crucial -
22  * bugs must be traceable. We will be happy to consider code for
23  * inclusion in the official distribution, but derived work must not
24  * be called official GROMACS. Details are found in the README & COPYING
25  * files - if they are missing, get the official version at www.gromacs.org.
26  * 
27  * To help us fund GROMACS development, we humbly ask that you cite
28  * the papers on the package - you can find them in the top README file.
29  * 
30  * For more info, check our website at http://www.gromacs.org
31  * 
32  * And Hey:
33  * GROningen Mixture of Alchemy and Childrens' Stories
34  */
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif
38
39 #include <sysstuff.h>
40 #include <ctype.h>
41 #include <errno.h>
42 #include <stdarg.h>
43 #include <string.h>
44 #include "futil.h"
45 #include "statutil.h"
46 #include "main.h"
47 #include "network.h"
48 #include "gmx_fatal.h"
49 #include "copyrite.h"
50 #include "macros.h"
51 #include "string2.h"
52 #include "smalloc.h"
53 #include "gmxfio.h"
54
55 #ifdef GMX_THREADS
56 #include "thread_mpi.h"
57 #endif
58
59 static bool bDebug = FALSE;
60 static char *fatal_tmp_file = NULL;
61 static FILE *log_file = NULL;
62
63 #ifdef GMX_THREADS
64 static tMPI_Thread_mutex_t debug_mutex=TMPI_THREAD_MUTEX_INITIALIZER;
65 #endif
66
67 bool bDebugMode(void)
68 {
69     bool ret;
70 #ifdef GMX_THREADS
71     tMPI_Thread_mutex_lock(&debug_mutex);
72 #endif
73     ret=bDebug;
74 #ifdef GMX_THREADS
75     tMPI_Thread_mutex_unlock(&debug_mutex);
76 #endif
77     return bDebug;
78 }
79
80 void gmx_fatal_set_log_file(FILE *fp)
81 {
82   log_file = fp;
83 }
84
85 void _where(const char *file,int line)
86 {
87   static bool bFirst = TRUE;
88   static int  nskip  = -1;
89   static int  nwhere =  0;
90   FILE *fp;
91   char *temp; 
92   
93 #ifdef GMX_THREADS
94     tMPI_Thread_mutex_lock(&debug_mutex);
95 #endif
96   if ( bFirst ) {
97     if ((temp=getenv("WHERE")) != NULL)
98       nskip = strtol(temp, NULL, 0); 
99     bFirst = FALSE;
100   } 
101
102   if (nskip >= 0) {
103     /* Skip the first n occasions, this allows to see where it goes wrong */
104     if (nwhere >= nskip) {
105       if (log_file)
106         fp = log_file;
107       else
108         fp = stderr;
109       fprintf(fp,"WHERE %d, file %s - line %d\n",nwhere,file,line);
110     }
111     nwhere++;
112   }
113 #ifdef GMX_THREADS
114     tMPI_Thread_mutex_unlock(&debug_mutex);
115 #endif
116 }
117
118 static void bputc(char *msg,int *len,char ch)
119 {
120   msg[(*len)++]=ch;
121 }
122
123 static void bputs(char *msg,int *len,const char *s,int fld)
124 {
125   for (fld-=(int)strlen(s); fld>0; fld--) 
126     bputc(msg,len,' ');
127   while (*s) 
128     bputc(msg,len,*(s++));
129 }
130
131 static void bputd(char *msg,int *len,int d)
132 {
133   if (d<10) bputc(msg,len,d+'0'); else bputc(msg,len,d-10+'a');
134 }
135
136 static void bputi(char *msg,int *len,int val,int radix,int fld,bool bNeg)
137 {
138   int fmax=0;
139   
140   if (bNeg)
141     fmax=1;
142     
143   if (val<radix)
144     {
145       for (fld--; fld>fmax; fld--) 
146         bputc(msg,len,' ');
147       if (bNeg)
148         bputc(msg,len,'-');
149       bputd(msg,len,val);
150     }
151   else
152     {
153       if (bNeg)
154         bputc(msg,len,'-');
155       bputi(msg,len,val/radix,radix,fld-1,FALSE);
156       bputd(msg,len,val%radix);
157     }
158 }
159
160 static int getfld(const char **p)
161 {
162   int fld;
163
164   fld=0;
165   while (isdigit(**p)) fld=(fld*10)+((*((*p)++))-'0');
166   return fld;
167 }
168
169 /*static void _halt(char *file,int line,char *reason)
170 {
171   fprintf(stderr,"\nHALT in file %s line %d because:\n\t%s\n",
172           file,line,reason);
173   exit(1);
174 }
175 */
176
177 static int fatal_errno = 0;
178
179 static void quit_gmx(const char *msg)
180 {
181 #ifdef GMX_THREADS
182     tMPI_Thread_mutex_lock(&debug_mutex);
183 #endif
184   if (!fatal_errno) {
185     if (log_file) 
186       fprintf(log_file,"%s\n",msg);
187     fprintf(stderr,"%s\n",msg);
188   }
189   else {
190     if (fatal_errno != -1)
191       errno=fatal_errno;
192     perror(msg);
193   }
194   
195   if (gmx_parallel_env()) {
196     int  nnodes;
197     int  noderank;
198     
199     nnodes   = gmx_node_num();
200     noderank = gmx_node_rank();
201     
202     if (nnodes > 1) 
203       fprintf(stderr,"Error on node %d, will try to stop all the nodes\n",
204               noderank);
205     gmx_abort(noderank,nnodes,-1);
206   } else {
207     if (debug)
208       fflush(debug);
209     if (bDebugMode()) {
210       fprintf(stderr,"dump core (y/n):"); 
211       fflush(stderr);
212       if (toupper(getc(stdin))!='N') 
213         (void) abort(); 
214     }
215   }
216
217   exit(fatal_errno);
218 #ifdef GMX_THREADS
219     tMPI_Thread_mutex_unlock(&debug_mutex);
220 #endif
221 }
222
223 void _set_fatal_tmp_file(const char *fn, const char *file, int line)
224 {
225 #ifdef GMX_THREADS
226     tMPI_Thread_mutex_lock(&debug_mutex);
227 #endif
228   if (fatal_tmp_file == NULL)
229     fatal_tmp_file = strdup(fn);
230   else
231     fprintf(stderr,"BUGWARNING: fatal_tmp_file already set at %s:%d",
232             file,line);
233 #ifdef GMX_THREADS
234     tMPI_Thread_mutex_unlock(&debug_mutex);
235 #endif
236 }
237
238 void _unset_fatal_tmp_file(const char *fn, const char *file, int line)
239 {
240 #ifdef GMX_THREADS
241     tMPI_Thread_mutex_lock(&debug_mutex);
242 #endif
243   if (strcmp(fn,fatal_tmp_file) == 0) {
244     sfree(fatal_tmp_file);
245     fatal_tmp_file = NULL;
246   } else
247     fprintf(stderr,"BUGWARNING: file %s not set as fatal_tmp_file at %s:%d",
248             fn,file,line);
249 #ifdef GMX_THREADS
250     tMPI_Thread_mutex_unlock(&debug_mutex);
251 #endif
252 }
253
254 static void clean_fatal_tmp_file()
255 {
256 #ifdef GMX_THREADS
257     tMPI_Thread_mutex_lock(&debug_mutex);
258 #endif
259   if (fatal_tmp_file) {
260     fprintf(stderr,"Cleaning up temporary file %s\n",fatal_tmp_file);
261     remove(fatal_tmp_file);
262     sfree(fatal_tmp_file);
263     fatal_tmp_file = NULL;
264   }
265 #ifdef GMX_THREADS
266     tMPI_Thread_mutex_unlock(&debug_mutex);
267 #endif
268 }
269
270 /* Old function do not use */
271 static void fatal_error(int f_errno,const char *fmt,...)
272 {
273   va_list ap;
274   const char    *p;
275   char    cval,*sval,msg[STRLEN];
276   char    ibuf[64],ifmt[64];
277   int     index,ival,fld,len;
278   double  dval;
279 #ifdef _SPECIAL_VAR_ARG
280   int     f_errno;
281   char    *fmt;
282   
283 #ifdef GMX_THREADS
284     tMPI_Thread_mutex_lock(&debug_mutex);
285 #endif
286   va_start(ap,);
287   f_errno=va_arg(ap,int);
288   fmt=va_arg(ap,char *);
289 #else
290   va_start(ap,fmt);
291 #endif
292
293   clean_fatal_tmp_file();
294   
295   len=0;
296   for (p=fmt; *p; p++) {
297     if (*p!='%')
298       bputc(msg,&len,*p);
299     else {
300       p++;
301       fld=getfld(&p);
302       switch(*p) {
303       case 'x':
304         ival=va_arg(ap,int);
305         sprintf(ifmt,"0x%%%dx",fld);
306         sprintf(ibuf,ifmt,(unsigned int)ival);
307         for(index=0; (index<(int)strlen(ibuf)); index++)
308           bputc(msg,&len,ibuf[index]);
309         break;
310       case 'd':
311         ival=va_arg(ap,int);
312         sprintf(ifmt,"%%%dd",fld);
313         sprintf(ibuf,ifmt,ival);
314         for(index=0; (index<(int)strlen(ibuf)); index++)
315           bputc(msg,&len,ibuf[index]);
316         break;
317       case 'f':
318         dval=va_arg(ap,double);
319         sprintf(ifmt,"%%%df",fld);
320         sprintf(ibuf,ifmt,dval);
321         for(index=0; (index<(int)strlen(ibuf)); index++)
322           bputc(msg,&len,ibuf[index]);
323         break;
324       case 'c':
325         cval=(char) va_arg(ap,int); /* char is promoted to int */
326         bputc(msg,&len,cval);
327         break;
328       case 's':
329         sval=va_arg(ap,char *);
330         bputs(msg,&len,sval,fld);
331         break;
332      default:
333         break;
334       }
335     }
336   }
337   va_end(ap);
338   bputc(msg,&len,'\0');
339
340   fatal_errno = f_errno;
341 #ifdef GMX_THREADS
342     tMPI_Thread_mutex_unlock(&debug_mutex);
343 #endif
344   gmx_error("fatal",msg);
345 }
346
347 void gmx_fatal(int f_errno,const char *file,int line,const char *fmt,...)
348 {
349   va_list ap;
350   const char    *p;
351   char    cval,*sval,msg[STRLEN];
352   char    ibuf[64],ifmt[64];
353   int     index,ival,fld,len;
354   double  dval;
355 #ifdef _SPECIAL_VAR_ARG
356   int     f_errno,line;
357   char    *fmt,*file;
358   
359 #ifdef GMX_THREADS
360   tMPI_Thread_mutex_lock(&debug_mutex);
361 #endif
362   va_start(ap,);
363   f_errno = va_arg(ap,int);
364   file    = va_arg(ap,char *);
365   line    = va_arg(ap,int);
366   fmt     = va_arg(ap,char *);
367 #else
368   va_start(ap,fmt);
369 #endif
370
371   clean_fatal_tmp_file();
372   
373   len=0;
374   for (p=fmt; *p; p++) {
375     if (*p!='%')
376       bputc(msg,&len,*p);
377     else {
378       p++;
379       fld=getfld(&p);
380       switch(*p) {
381       case 'x':
382         ival=va_arg(ap,int);
383         sprintf(ifmt,"0x%%%dx",fld);
384         sprintf(ibuf,ifmt,(unsigned int)ival);
385         for(index=0; (index<(int)strlen(ibuf)); index++)
386           bputc(msg,&len,ibuf[index]);
387         break;
388       case 'd':
389         ival=va_arg(ap,int);
390         sprintf(ifmt,"%%%dd",fld);
391         sprintf(ibuf,ifmt,ival);
392         for(index=0; (index<(int)strlen(ibuf)); index++)
393           bputc(msg,&len,ibuf[index]);
394         break;
395       case 'u':
396         ival=va_arg(ap,unsigned);
397         sprintf(ifmt,"%%%du",fld);
398         sprintf(ibuf,ifmt,ival);
399         for(index=0; (index<(int)strlen(ibuf)); index++)
400           bputc(msg,&len,ibuf[index]);
401         break;
402       case 'f':
403         dval=va_arg(ap,double);
404         sprintf(ifmt,"%%%df",fld);
405         sprintf(ibuf,ifmt,dval);
406         for(index=0; (index<(int)strlen(ibuf)); index++)
407           bputc(msg,&len,ibuf[index]);
408         break;
409       case 'g':
410         dval=va_arg(ap,double);
411         sprintf(ifmt,"%%%dg",fld);
412         sprintf(ibuf,ifmt,dval);
413         for(index=0; (index<(int)strlen(ibuf)); index++)
414           bputc(msg,&len,ibuf[index]);
415         break;
416       case 'c':
417         cval=(char) va_arg(ap,int); /* char is promoted to int */
418         bputc(msg,&len,cval);
419         break;
420       case 's':
421         sval=va_arg(ap,char *);
422         if (sval == NULL)
423           sval = strdup("(null)");
424         bputs(msg,&len,sval,fld);
425         break;
426       case '%':
427         bputc(msg,&len,*p);
428         break;
429       default:
430         break;
431       }
432     }
433   }
434   va_end(ap);
435   bputc(msg,&len,'\0');
436
437   fatal_errno = f_errno;
438   
439 #ifdef GMX_THREADS
440   tMPI_Thread_mutex_unlock(&debug_mutex);
441 #endif
442   _gmx_error("fatal",msg,file,line);
443 }
444
445 static int  nwarn_note  = 0;
446 static int  nwarn_warn  = 0;
447 static int  nwarn_error = 0;
448 static int  maxwarn     = 10;
449 static int  lineno      = 1;
450 static char filenm[256] = "";
451 char   warn_buf[1024]   = "";
452
453 void init_warning(int maxwarning)
454 {
455 #ifdef GMX_THREADS
456   tMPI_Thread_mutex_lock(&debug_mutex);
457 #endif
458   maxwarn     = maxwarning;
459   nwarn_note  = 0;
460   nwarn_warn  = 0;
461   nwarn_error = 0;
462 #ifdef GMX_THREADS
463   tMPI_Thread_mutex_unlock(&debug_mutex);
464 #endif
465 }
466
467 void set_warning_line(const char *s,int line)
468 {
469 #ifdef GMX_THREADS
470   tMPI_Thread_mutex_lock(&debug_mutex);
471 #endif
472   if (s == NULL)
473     gmx_incons("Calling set_warning_line with NULL pointer");
474   strcpy(filenm,s);
475   lineno = line;
476 #ifdef GMX_THREADS
477   tMPI_Thread_mutex_unlock(&debug_mutex);
478 #endif
479 }
480
481 int get_warning_line()
482 {
483     int ret;
484 #ifdef GMX_THREADS
485     tMPI_Thread_mutex_lock(&debug_mutex);
486 #endif
487     ret=lineno;
488 #ifdef GMX_THREADS
489     tMPI_Thread_mutex_unlock(&debug_mutex);
490 #endif
491     return ret;
492 }
493
494 const char *get_warning_file()
495 {
496     return filenm;
497 }
498
499 static void low_warning(const char *wtype,int n,const char *s)
500 {
501 #define indent 2 
502   char linenobuf[32], *temp, *temp2;
503   int i;
504
505   if (s == NULL)
506     s = warn_buf;
507   if (lineno != -1)
508     sprintf(linenobuf,"%d",lineno);
509   else
510     strcpy(linenobuf,"unknown");
511   snew(temp,strlen(s)+indent+1);
512   for(i=0; i<indent; i++)
513     temp[i] = ' ';
514   temp[indent] = '\0';
515   strcat(temp,s);
516   temp2 = wrap_lines(temp,78-indent,indent,FALSE);
517   if (strlen(filenm) > 0) {
518     fprintf(stderr,"\n%s %d [file %s, line %s]:\n%s\n\n",
519             wtype,n,filenm,linenobuf,temp2);
520   } else {
521     fprintf(stderr,"\n%s %d:\n%s\n\n",wtype,n,temp2);
522   }
523   sfree(temp);
524   sfree(temp2);
525 }
526
527 void warning(const char *s)
528 {
529 #ifdef GMX_THREADS
530     tMPI_Thread_mutex_lock(&debug_mutex);
531 #endif
532     nwarn_warn++;
533     low_warning("WARNING",nwarn_warn,s);
534 #ifdef GMX_THREADS
535     tMPI_Thread_mutex_unlock(&debug_mutex);
536 #endif
537 }
538
539 void warning_note(const char *s)
540 {
541 #ifdef GMX_THREADS
542     tMPI_Thread_mutex_lock(&debug_mutex);
543 #endif
544     nwarn_note++;
545     low_warning("NOTE",nwarn_note,s);
546 #ifdef GMX_THREADS
547     tMPI_Thread_mutex_unlock(&debug_mutex);
548 #endif
549 }
550
551 void warning_error(const char *s)
552 {
553 #ifdef GMX_THREADS
554     tMPI_Thread_mutex_lock(&debug_mutex);
555 #endif
556     nwarn_error++;
557     low_warning("ERROR",nwarn_error,s);
558 #ifdef GMX_THREADS
559     tMPI_Thread_mutex_unlock(&debug_mutex);
560 #endif
561 }
562
563 static void print_warn_count(const char *type,int n)
564 {
565   if (n > 0) {
566     fprintf(stderr,"\nThere %s %d %s%s\n",
567             (n==1) ? "was" : "were", n, type, (n==1) ? "" : "s");
568   }
569 }
570
571 void print_warn_num(bool bFatalError)
572 {
573 #ifdef GMX_THREADS
574     tMPI_Thread_mutex_lock(&debug_mutex);
575 #endif
576     print_warn_count("note",nwarn_note);
577
578     print_warn_count("warning",nwarn_warn);
579     if (bFatalError && nwarn_warn > maxwarn) {
580         gmx_fatal(FARGS,"Too many warnings (%d), %s terminated.\n"
581                 "If you are sure all warnings are harmless, use the -maxwarn option.",nwarn_warn,Program());
582     }
583 #ifdef GMX_THREADS
584     tMPI_Thread_mutex_unlock(&debug_mutex);
585 #endif
586 }
587
588 void check_warning_error(int f_errno,const char *file,int line)
589 {
590 #ifdef GMX_THREADS
591     tMPI_Thread_mutex_lock(&debug_mutex);
592 #endif
593     if (nwarn_error > 0) {
594         print_warn_num(FALSE);
595         gmx_fatal(f_errno,file,line,"There %s %d error%s in input file(s)",
596                   (nwarn_error==1) ? "was" : "were",nwarn_error,
597                   (nwarn_error==1) ? ""    : "s");
598     }
599 #ifdef GMX_THREADS
600     tMPI_Thread_mutex_unlock(&debug_mutex);
601 #endif
602 }
603
604 void _too_few(const char *fn,int line)
605 {
606   sprintf(warn_buf,"Too few parameters on line (source file %s, line %d)",
607           fn,line);
608   warning(NULL);
609 }
610
611 void _invalid_case(const char *fn,int line)
612 {
613   gmx_fatal(FARGS,"Invalid case in switch statement, file %s, line %d",
614               fn,line);
615 }
616
617 void _unexpected_eof(const char *fn,int line,const char *srcfn,int srcline)
618 {
619   gmx_fatal(FARGS,"Unexpected end of file in file %s at line %d\n"
620               "(Source file %s, line %d)",fn,line,srcfn,srcline);
621 }
622
623 /* 
624  * These files are global variables in the gromacs preprocessor
625  * Every routine in a file that includes gmx_fatal.h can write to these
626  * debug channels. Depending on the debuglevel used
627  * 0 to 3 of these filed are redirected to /dev/null
628  *
629  */
630 FILE *debug=NULL;
631 bool gmx_debug_at=FALSE;
632
633 void init_debug (const int dbglevel,const char *dbgfile)
634 {
635 #ifdef GMX_THREADS
636     tMPI_Thread_mutex_lock(&debug_mutex);
637 #endif
638     if (!bDebug) /* another thread hasn't already run this*/
639     {
640         no_buffers();
641         debug=gmx_fio_fopen(dbgfile,"w");
642         bDebug = TRUE;
643         if (dbglevel >= 2)
644             gmx_debug_at = TRUE;
645     }
646 #ifdef GMX_THREADS
647     tMPI_Thread_mutex_unlock(&debug_mutex);
648 #endif
649 }
650
651 #if (defined __sgi && defined USE_SGI_FPE)
652 static void user_routine(unsigned us[5], int ii[2])
653 {
654   fprintf(stderr,"User routine us=(%u,%u,%u,%u,%u) ii=(%d,%d)\n",
655           us[0],us[1],us[2],us[3],us[4],ii[0],ii[1]);
656   fprintf(stderr,"Exception encountered! Dumping core\n");
657   abort();
658 }
659
660 static void abort_routine(unsigned int **ii)
661 {
662   fprintf(stderr,"Abort routine\n");
663   abort();
664 }
665
666 static void handle_signals(int n)
667 {
668   fprintf(stderr,"Handle signals: n = %d\n",n);
669   fprintf(stderr,"Dumping core\n");
670   abort();
671 }
672
673 void doexceptions(void)
674 {
675 #include <sigfpe.h>
676 #include <signal.h>
677   int hs[] = { SIGILL, SIGFPE, SIGTRAP, SIGEMT, SIGSYS };
678   
679   int onoff,en_mask,abort_action,i;
680
681 #ifdef GMX_THREADS
682     tMPI_Thread_mutex_lock(&debug_mutex);
683 #endif
684   onoff   = _DEBUG;
685   en_mask = _EN_UNDERFL | _EN_OVERFL | _EN_DIVZERO | 
686     _EN_INVALID | _EN_INT_OVERFL;
687   abort_action = _ABORT_ON_ERROR;
688   handle_sigfpes(onoff,en_mask,user_routine,abort_action,abort_routine);
689   
690   for(i=0; (i<asize(hs)); i++)
691     signal(hs[i],handle_signals);
692 #ifdef GMX_THREADS
693     tMPI_Thread_mutex_unlock(&debug_mutex);
694 #endif
695 }
696 #endif /* __sgi and FPE */
697
698 static const char *gmxuser = "Please report this to the mailing list (gmx-users@gromacs.org)";
699
700 static void (*gmx_error_handler)(const char *msg) = quit_gmx;
701
702 void set_gmx_error_handler(void (*func)(const char *msg))
703 {
704 #ifdef GMX_THREADS
705     tMPI_Thread_mutex_lock(&debug_mutex);
706 #endif
707     gmx_error_handler = func;
708 #ifdef GMX_THREADS
709     tMPI_Thread_mutex_unlock(&debug_mutex);
710 #endif
711 }
712
713 char *gmx_strerror(const char *key)
714 {
715   typedef struct {
716     const char *key,*msg;
717   } error_msg_t;
718   error_msg_t msg[] = {
719     { "bug",    "Possible bug" },
720     { "call",   "Routine should not have been called" },
721     { "comm",   "Communication (parallel processing) problem" },
722     { "fatal",  "Fatal error" },
723     { "cmd",    "Invalid command line argument" },
724     { "file",   "File input/output error" },
725     { "impl",   "Implementation restriction" },
726     { "incons", "Software inconsistency error" },
727     { "input",  "Input error or input inconsistency" },
728     { "mem",    "Memory allocation/freeing error" },
729     { "open",   "Can not open file" },
730     { "range",  "Range checking error" }
731   };
732 #define NMSG asize(msg)
733   char buf[1024];
734   size_t i;
735   
736   if (key == NULL)
737     return strdup("Empty message");
738   else {
739     for(i=0; (i<NMSG); i++)
740       if (strcmp(key,msg[i].key) == 0) 
741         break;
742     if (i == NMSG) {
743       sprintf(buf,"No error message associated with key %s\n%s",key,gmxuser);
744       return strdup(buf);
745     }
746     else
747       return strdup(msg[i].msg);
748   }
749 }
750
751 void _gmx_error(const char *key,const char *msg,const char *file,int line)
752 {
753   char buf[10240],tmpbuf[1024];
754   int  cqnum;
755   const char *llines = "-------------------------------------------------------";
756
757 #ifdef GMX_THREADS
758     tMPI_Thread_mutex_lock(&debug_mutex);
759 #endif
760   /* protect the audience from suggestive discussions */
761   
762   cool_quote(tmpbuf,1023,&cqnum);
763   sprintf(buf,"\n%s\nProgram %s, %s\n"
764           "Source code file: %s, line: %d\n\n"
765           "%s:\n%s\nFor more information and tips for trouble shooting please check the GROMACS Wiki at\n"
766           "http://wiki.gromacs.org/index.php/Errors\n%s\n\n%s\n",
767           llines,ShortProgram(),GromacsVersion(),file,line,
768           gmx_strerror(key),msg ? msg : warn_buf,llines,tmpbuf);
769 #ifdef GMX_THREADS
770     tMPI_Thread_mutex_unlock(&debug_mutex);
771 #endif
772   gmx_error_handler(buf);
773 }
774
775 void _range_check(int n,int n_min,int n_max,const char *var,const char *file,int line)
776 {
777   char buf[1024];
778   
779   if ((n < n_min) || (n >= n_max)) {
780     if (strlen(warn_buf) > 0) {
781       strcpy(buf,warn_buf);
782       strcat(buf,"\n");
783       warn_buf[0] = '\0';
784     }
785     else
786       buf[0] = '\0';
787     
788     sprintf(buf+strlen(buf),"Variable %s has value %d. It should have been "
789             "within [ %d .. %d ]\n",var,n,n_min,n_max);
790     
791     _gmx_error("range",buf,file,line);
792   }
793 }
794