1    	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2    	/*                                                                           */
3    	/*                  This1 file is part of the program and library             */
4    	/*         SCIP --- Solving Constraint Integer Programs                      */
5    	/*                                                                           */
6    	/*  Copyright (c) 2002-2023 Zuse Institute Berlin (ZIB)                      */
7    	/*                                                                           */
8    	/*  Licensed under the Apache License, Version 2.0 (the "License");          */
9    	/*  you may not use this file except in compliance with the License.         */
10   	/*  You may obtain a copy of the License at                                  */
11   	/*                                                                           */
12   	/*      http://www.apache.org/licenses/LICENSE-2.0                           */
13   	/*                                                                           */
14   	/*  Unless required by applicable law or agreed to in writing, software      */
15   	/*  distributed under the License is distributed on an "AS IS" BASIS,        */
16   	/*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17   	/*  See the License for the specific language governing permissions and      */
18   	/*  limitations under the License.                                           */
19   	/*                                                                           */
20   	/*  You should have received a copy of the Apache-2.0 license                */
21   	/*  along with SCIP; see the file LICENSE. If not visit scipopt.org.         */
22   	/*                                                                           */
23   	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24   	
25   	/**@file   message.c
26   	 * @ingroup OTHER_CFILES
27   	 * @brief  message output methods
28   	 * @author Tobias Achterberg
29   	 * @author Marc Pfetsch
30   	 * @author Michael Winkler
31   	 */
32   	
33   	/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
34   	
35   	#include <stdarg.h>
36   	#include <stdio.h>
37   	#include <assert.h>
38   	
39   	#include "scip/struct_message.h"
40   	#include "scip/pub_message.h"
41   	#include "scip/def.h"
42   	#include "scip/pub_misc.h"
43   	#include "blockmemshell/memory.h"
44   	
45   	
46   	#ifndef va_copy
47   	#define va_copy(dest, src) do { BMScopyMemory(&dest, &src); } while( 0 )
48   	#endif
49   	
50   	/* do defines for windows directly her to make the lpi more independent*/
51   	#if defined(_WIN32) || defined(_WIN64)
52   	#define snprintf _snprintf
53   	#define vsnprintf _vsnprintf
54   	#endif
55   	
56   	/** handles the output of the given message */
57   	static
58   	void handleMessage(
59   	   SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
60   	   SCIP_DECL_MESSAGEOUTPUTFUNC(outputfunc),  /**< message handler function used for output */
61   	   FILE*                 file1,              /**< file stream to print into, or NULL for stdout */
62   	   SCIP_Bool             usefile1,           /**< Should file1 be used? */
63   	   FILE*                 file2,              /**< file stream to print into */
64   	   SCIP_Bool             usefile2,           /**< Should file2 be used? */
65   	   const char*           msg,                /**< message to print; NULL to flush the output buffer */
66   	   char*                 buffer,             /**< message buffer */
67   	   int*                  bufferlen           /**< pointer to the currently used entries in the message buffer */
68   	   )
69   	{
70   	   const char* s;
71   	
72   	   assert( messagehdlr != NULL );
73   	   assert( outputfunc != NULL );
74   	   assert( !usefile2 || file2 != NULL );
75   	   assert( buffer == NULL || bufferlen != NULL );
76   	
77   	   /* if we do not have a buffer directly output the message */
78   	   if ( buffer == NULL )
79   	   {
80   	      /* we do not have a buffer, so it makes no sense to flush it if msg == NULL */
81   	      if ( msg != NULL )
82   	      {
83   	         if ( usefile1 )
84   	            outputfunc(messagehdlr, file1, msg);
85   	         if ( usefile2 )
86   	            outputfunc(messagehdlr, file2, msg);
87   	      }
88   	      return;
89   	   }
90   	   assert(bufferlen != NULL);
91   	
92   	   /* should the buffer be flushed? */
93   	   if ( msg == NULL )
94   	   {
95   	      assert( *bufferlen < SCIP_MAXSTRLEN );
96   	      assert( buffer[*bufferlen] == '\0' );
97   	      if ( usefile1 )
98   	         outputfunc(messagehdlr, file1, buffer);
99   	      if ( usefile2 )
100  	         outputfunc(messagehdlr, file2, buffer);
101  	      *bufferlen = 0;
102  	      buffer[0] = '\0';
103  	      return;
104  	   }
105  	   assert( msg != NULL && buffer != NULL );
106  	
107  	   /* if no output is activated, to not copy message into buffer */
108  	   if ( ! usefile1 && ! usefile2 )
109  	      return;
110  	
111  	   /* determine message length and last newline (if any) */
112  	   s = msg;
113  	   while ( *s != '\0' )
114  	   {
115  	      /* if we reached a newline or the size limit, empty buffer and reset (need possibly space for newline and '\0') */
116  	      if ( *s == '\n' || *bufferlen >= SCIP_MAXSTRLEN-2 )
117  	      {
118  	         if ( *s == '\n' )
119  	            buffer[(*bufferlen)++] = *(s++);
120  	         buffer[*bufferlen] = '\0';
121  	
122  	         if ( usefile1 )
123  	            outputfunc(messagehdlr, file1, buffer);
124  	         if ( usefile2 )
125  	            outputfunc(messagehdlr, file2, buffer);
126  	         *bufferlen = 0;
127  	         buffer[0] = '\0';
128  	      }
129  	      else
130  	         buffer[(*bufferlen)++] = *(s++);
131  	   }
132  	   buffer[*bufferlen] = '\0';
133  	
134  	   return;
135  	}
136  	
137  	/** default error printing method which is used to print all occurring errors */
138  	static
139  	SCIP_DECL_ERRORPRINTING(errorPrintingDefault)
140  	{  /*lint --e{715}*/
141  	   if ( msg != NULL )
142  	   {
143  	      if ( file != NULL )
144  	         fputs(msg, file);
145  	      else
146  	         fputs(msg, stderr);
147  	   }
148  	   fflush(stderr);
149  	}
150  	
151  	/** static variable which holds the error printing method */
152  	static SCIP_DECL_ERRORPRINTING((*staticErrorPrinting)) = errorPrintingDefault;
153  	
154  	/** static variable which holds a data pointer for the error prinint callback */
155  	static void* staticErrorPrintingData = NULL;
156  	
157  	/** prints error message with the current static message handler */
158  	static
159  	void messagePrintError(
160  	   FILE*                 file,               /**< file stream to print error, or NULL for stderr */
161  	   const char*           msg                 /**< message to print; NULL to flush the output buffer */
162  	   )
163  	{
164  	   if( staticErrorPrinting != NULL )
165  	      staticErrorPrinting(staticErrorPrintingData, file, msg);
166  	}
167  	
168  	/** prints warning message with the current message handler, or buffers the message if no newline exists */
169  	static
170  	void messagePrintWarning(
171  	   SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
172  	   const char*           msg                 /**< message to print; NULL to flush the output buffer */
173  	   )
174  	{  /*lint --e{715}*/
175  	   if ( messagehdlr != NULL && messagehdlr->messagewarning != NULL && (! messagehdlr->quiet || messagehdlr->logfile != NULL) )
176  	   {
177  	      handleMessage(messagehdlr, messagehdlr->messagewarning, stderr, ! messagehdlr->quiet, messagehdlr->logfile, (messagehdlr->logfile != NULL),
178  	         msg, messagehdlr->warningbuffer, &messagehdlr->warningbufferlen);
179  	   }
180  	}
181  	
182  	/** prints dialog message with the current message handler, or buffers the message if no newline exists */
183  	static
184  	void messagePrintDialog(
185  	   SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
186  	   FILE*                 file,               /**< file stream to print into, or NULL for stdout */
187  	   const char*           msg                 /**< message to print; NULL to flush the output buffer */
188  	   )
189  	{  /*lint --e{715}*/
190  	   if ( messagehdlr != NULL && messagehdlr->messagedialog != NULL )
191  	   {
192  	      if ( (file == NULL || file == stdout) && ! messagehdlr->quiet )
193  	      {
194  	         handleMessage(messagehdlr, messagehdlr->messagedialog, (file == NULL) ? stdout : file, TRUE, messagehdlr->logfile, (messagehdlr->logfile != NULL),
195  	            msg, messagehdlr->dialogbuffer, &messagehdlr->dialogbufferlen);
196  	      }
197  	      else if ( msg != NULL )
198  	      {
199  	         /* file output cannot be buffered because the output file may change */
200  	         if ( *msg != '\0' )
201  	         {
202  	            handleMessage(messagehdlr, messagehdlr->messagedialog, file, !messagehdlr->quiet || (file != NULL && file != stdout), messagehdlr->logfile, (messagehdlr->logfile != NULL), msg, NULL, NULL);
203  	         }
204  	      }
205  	   }
206  	}
207  	
208  	/** prints info message with the current message handler, or buffers the message if no newline exists */
209  	static
210  	void messagePrintInfo(
211  	   SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
212  	   FILE*                 file,               /**< file stream to print into, or NULL for stdout */
213  	   const char*           msg                 /**< message to print; NULL to flush the output buffer */
214  	   )
215  	{  /*lint --e{715}*/
216  	   if ( messagehdlr != NULL && messagehdlr->messageinfo != NULL )
217  	   {
218  	      if ( (file == NULL || file == stdout) && ! messagehdlr->quiet )
219  	      {
220  	         handleMessage(messagehdlr, messagehdlr->messageinfo, (file == NULL) ? stdout : file, TRUE, messagehdlr->logfile, (messagehdlr->logfile != NULL),
221  	            msg, messagehdlr->infobuffer, &messagehdlr->infobufferlen);
222  	      }
223  	      else if ( msg != NULL )
224  	      {
225  	         /* file output cannot be buffered because the output file may change or the message is to long */
226  	         if ( *msg != '\0' )
227  	         {
228  	            handleMessage(messagehdlr, messagehdlr->messagedialog, file, !messagehdlr->quiet || (file != NULL && file != stdout), messagehdlr->logfile, (messagehdlr->logfile != NULL), msg, NULL, NULL);
229  	         }
230  	      }
231  	   }
232  	}
233  	
234  	/** if the given file is not NULL a log file is opened */
235  	static
236  	void messagehdlrOpenLogfile(
237  	   SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
238  	   const char*           filename            /**< name of log file, or NULL (stdout) */
239  	   )
240  	{
241  	   if( filename != NULL )
242  	   {
243  	      messagehdlr->logfile = fopen(filename, "a"); /* append to log file */
244  	
245  	      if( messagehdlr->logfile == NULL )
246  	      {
247  	         SCIPerrorMessage("cannot open log file <%s> for writing\n", filename);
248  	      }
249  	   }
250  	   else
251  	      messagehdlr->logfile = NULL;
252  	}
253  	
254  	/** frees message handler */
255  	static
256  	SCIP_RETCODE messagehdlrFree(
257  	   SCIP_MESSAGEHDLR**    messagehdlr         /**< pointer to the message handler */
258  	   )
259  	{
260  	   assert(messagehdlr != NULL);
261  	
262  	   if( *messagehdlr != NULL )
263  	   {
264  	      /* flush message buffers */
265  	      messagePrintWarning(*messagehdlr, NULL);
266  	      messagePrintDialog(*messagehdlr, NULL, NULL);
267  	      messagePrintInfo(*messagehdlr, NULL, NULL);
268  	
269  	      if( (*messagehdlr)->messagehdlrfree != NULL )
270  	      {
271  	         /* call destructor method of message handler to free the message handler data */
272  	         SCIP_CALL( (*messagehdlr)->messagehdlrfree(*messagehdlr) );
273  	      }
274  	
275  	      /* close the log file if one exists */
276  	      if( (*messagehdlr)->logfile != NULL )
277  	      {
278  	         fclose((*messagehdlr)->logfile);
279  	      }
280  	
281  	      /* free buffer arrays */
282  	      BMSfreeMemoryArrayNull(&(*messagehdlr)->warningbuffer);
283  	      BMSfreeMemoryArrayNull(&(*messagehdlr)->dialogbuffer);
284  	      BMSfreeMemoryArrayNull(&(*messagehdlr)->infobuffer);
285  	      BMSfreeMemory(messagehdlr);
286  	   }
287  	
288  	   return SCIP_OKAY;
289  	}
290  	
291  	/** Creates and captures a message handler which deals with warning, information, and dialog (interactive shell) methods.
292  	 *
293  	 *  @note The message handler does not handle error messages; see SCIPmessageSetErrorPrinting()
294  	 */
295  	SCIP_RETCODE SCIPmessagehdlrCreate(
296  	   SCIP_MESSAGEHDLR**    messagehdlr,        /**< pointer to store the message handler */
297  	   SCIP_Bool             bufferedoutput,     /**< should the output be buffered up to the next newline? */
298  	   const char*           filename,           /**< name of log file, or NULL for no log */
299  	   SCIP_Bool             quiet,              /**< should screen messages be suppressed? */
300  	   SCIP_DECL_MESSAGEWARNING((*messagewarning)),/**< warning message print method of message handler */
301  	   SCIP_DECL_MESSAGEDIALOG((*messagedialog)),/**< dialog message print method of message handler */
302  	   SCIP_DECL_MESSAGEINFO ((*messageinfo)),   /**< info message print method of message handler */
303  	   SCIP_DECL_MESSAGEHDLRFREE((*messagehdlrfree)), /**< destructor of message handler to free message handler data */
304  	   SCIP_MESSAGEHDLRDATA* messagehdlrdata     /**< message handler data */
305  	   )
306  	{
307  	   SCIP_ALLOC( BMSallocMemory(messagehdlr) );
308  	   (*messagehdlr)->messagewarning = messagewarning;
309  	   (*messagehdlr)->messagedialog = messagedialog;
310  	   (*messagehdlr)->messageinfo = messageinfo;
311  	   (*messagehdlr)->messagehdlrfree = messagehdlrfree;
312  	   (*messagehdlr)->messagehdlrdata = messagehdlrdata;
313  	   (*messagehdlr)->warningbuffer = NULL;
314  	   (*messagehdlr)->dialogbuffer = NULL;
315  	   (*messagehdlr)->infobuffer = NULL;
316  	   (*messagehdlr)->warningbufferlen = 0;
317  	   (*messagehdlr)->dialogbufferlen = 0;
318  	   (*messagehdlr)->infobufferlen = 0;
319  	   (*messagehdlr)->nuses = 1;
320  	
321  	   (*messagehdlr)->quiet = quiet;
322  	   messagehdlrOpenLogfile(*messagehdlr, filename);
323  	
324  	   /* allocate buffer for buffered output */
325  	   if( bufferedoutput )
326  	   {
327  	      SCIP_ALLOC( BMSallocMemoryArray(&(*messagehdlr)->warningbuffer, SCIP_MAXSTRLEN) ); /*lint !e506*/
328  	      SCIP_ALLOC( BMSallocMemoryArray(&(*messagehdlr)->dialogbuffer, SCIP_MAXSTRLEN) ); /*lint !e506*/
329  	      SCIP_ALLOC( BMSallocMemoryArray(&(*messagehdlr)->infobuffer, SCIP_MAXSTRLEN) ); /*lint !e506*/
330  	      (*messagehdlr)->warningbuffer[0] = '\0';
331  	      (*messagehdlr)->dialogbuffer[0] = '\0';
332  	      (*messagehdlr)->infobuffer[0] = '\0';
333  	   }
334  	
335  	   return SCIP_OKAY;
336  	}
337  	
338  	/** captures message handler */
339  	void SCIPmessagehdlrCapture(
340  	   SCIP_MESSAGEHDLR*     messagehdlr         /**< message handler, or NULL */
341  	   )
342  	{
343  	   if( messagehdlr != NULL )
344  	      ++messagehdlr->nuses;
345  	}
346  	
347  	/** releases message handler */
348  	SCIP_RETCODE SCIPmessagehdlrRelease(
349  	   SCIP_MESSAGEHDLR**    messagehdlr         /**< pointer to the message handler */
350  	   )
351  	{
352  	   assert(messagehdlr != NULL);
353  	
354  	   if( *messagehdlr == NULL )
355  	      return SCIP_OKAY;
356  	
357  	   assert((*messagehdlr)->nuses >= 1);
358  	
359  	   /* decrement usage counter */
360  	   --(*messagehdlr)->nuses;
361  	
362  	   /* the last one turns the light off */
363  	   if( (*messagehdlr)->nuses == 0 )
364  	   {
365  	      SCIP_CALL( messagehdlrFree(messagehdlr) );
366  	      assert(*messagehdlr == NULL);
367  	   }
368  	   else
369  	   {
370  	      *messagehdlr = NULL;
371  	   }
372  	
373  	   return SCIP_OKAY;
374  	}
375  	
376  	/** sets the user data of the message handler */
377  	SCIP_RETCODE SCIPmessagehdlrSetData(
378  	   SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler; must not be NULL */
379  	   SCIP_MESSAGEHDLRDATA* messagehdlrdata     /**< new message handler data to attach to the handler */
380  	   )
381  	{
382  	   assert(messagehdlr != NULL);
383  	
384  	   if( messagehdlr == NULL ) /*lint !e774*/
385  	      return SCIP_INVALIDDATA;
386  	
387  	   messagehdlr->messagehdlrdata = messagehdlrdata;
388  	
389  	   return SCIP_OKAY;
390  	}
391  	
392  	/** sets the log file name for the message handler */
393  	void SCIPmessagehdlrSetLogfile(
394  	   SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
395  	   const char*           filename            /**< log file name where to copy messages into, or NULL */
396  	   )
397  	{
398  	   assert(messagehdlr != NULL);
399  	
400  	   /* close the old log file if one exists */
401  	   if( messagehdlr->logfile != NULL )
402  	   {
403  	      fclose(messagehdlr->logfile);
404  	   }
405  	
406  	   /* opens the log file */
407  	   messagehdlrOpenLogfile(messagehdlr, filename);
408  	}
409  	
410  	/** sets the messages handler to be quiet */
411  	void SCIPmessagehdlrSetQuiet(
412  	   SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
413  	   SCIP_Bool             quiet               /**< should screen messages be suppressed? */
414  	   )
415  	{
416  	   assert(messagehdlr != NULL);
417  	
418  	   /* flush message buffers in order to not loose information */
419  	   messagePrintWarning(messagehdlr, NULL);
420  	   messagePrintDialog(messagehdlr, NULL, NULL);
421  	   messagePrintInfo(messagehdlr, NULL, NULL);
422  	
423  	   messagehdlr->quiet = quiet;
424  	}
425  	
426  	/** prints a warning message, acting like the printf() command */
427  	void SCIPmessagePrintWarning(
428  	   SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
429  	   const char*           formatstr,          /**< format string like in printf() function */
430  	   ...                                       /**< format arguments line in printf() function */
431  	   )
432  	{
433  	   va_list ap;
434  	
435  	   va_start(ap, formatstr); /*lint !e838*/
436  	   SCIPmessageVFPrintWarning(messagehdlr, formatstr, ap);
437  	   va_end(ap);
438  	}
439  	
440  	/** prints a warning message, acting like the vprintf() command */
441  	void SCIPmessageVPrintWarning(
442  	   SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
443  	   const char*           formatstr,          /**< format string like in printf() function */
444  	   va_list               ap                  /**< variable argument list */
445  	   )
446  	{
447  	   SCIPmessageVFPrintWarning(messagehdlr, formatstr, ap);
448  	}
449  	
450  	/** prints a warning message, acting like the fprintf() command */
451  	void SCIPmessageFPrintWarning(
452  	   SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
453  	   const char*           formatstr,          /**< format string like in printf() function */
454  	   ...                                       /**< format arguments line in printf() function */
455  	   )
456  	{
457  	   va_list ap;
458  	
459  	   va_start(ap, formatstr); /*lint !e838*/
460  	   SCIPmessageVFPrintWarning(messagehdlr, formatstr, ap);
461  	   va_end(ap);
462  	}
463  	
464  	/** prints a warning message, acting like the vfprintf() command */
465  	void SCIPmessageVFPrintWarning(
466  	   SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
467  	   const char*           formatstr,          /**< format string like in printf() function */
468  	   va_list               ap                  /**< variable argument list */
469  	   )
470  	{
471  	   char msg[SCIP_MAXSTRLEN];
472  	   int n;
473  	   va_list aq;
474  	
475  	   va_copy(aq, ap); /*lint !e838*/
476  	
477  	   n = vsnprintf(msg, SCIP_MAXSTRLEN, formatstr, ap);
478  	   if( n < 0 )
479  	      msg[SCIP_MAXSTRLEN-1] = '\0';
480  	   else if( n >= SCIP_MAXSTRLEN )
481  	   {
482  	      char* bigmsg;
483  	#ifndef NDEBUG
484  	      int m;
485  	#endif
486  	
487  	      if( BMSallocMemorySize(&bigmsg, n+1) == NULL )
488  	      {
489  	         va_end(aq);
490  	         return;
491  	      }
492  	
493  	#ifndef NDEBUG
494  	      m = vsnprintf(bigmsg, (size_t) n+1, formatstr, aq); /*lint !e571*/
495  	#else
496  	      vsnprintf(bigmsg, (size_t) n+1, formatstr, aq); /*lint !e571*/
497  	#endif
498  	      assert(m == n);
499  	      va_end(aq);
500  	      messagePrintWarning(messagehdlr, bigmsg);
501  	      BMSfreeMemory(&bigmsg);
502  	      return;
503  	   }
504  	
505  	   messagePrintWarning(messagehdlr, msg);
506  	   va_end(aq);
507  	}
508  	
509  	/** prints a dialog message that requests user interaction, acting like the printf() command */
510  	void SCIPmessagePrintDialog(
511  	   SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
512  	   const char*           formatstr,          /**< format string like in printf() function */
513  	   ...                                       /**< format arguments line in printf() function */
514  	   )
515  	{
516  	   va_list ap;
517  	
518  	   va_start(ap, formatstr); /*lint !e838*/
519  	   SCIPmessageVFPrintDialog(messagehdlr, NULL, formatstr, ap);
520  	   va_end(ap);
521  	}
522  	
523  	/** prints a dialog message that requests user interaction, acting like the vprintf() command */
524  	void SCIPmessageVPrintDialog(
525  	   SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
526  	   const char*           formatstr,          /**< format string like in printf() function */
527  	   va_list               ap                  /**< variable argument list */
528  	   )
529  	{
530  	   SCIPmessageVFPrintDialog(messagehdlr, NULL, formatstr, ap);
531  	}
532  	
533  	/** prints a dialog message that requests user interaction into a file, acting like the fprintf() command */
534  	void SCIPmessageFPrintDialog(
535  	   SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
536  	   FILE*                 file,               /**< file stream to print into, or NULL for stdout */
537  	   const char*           formatstr,          /**< format string like in printf() function */
538  	   ...                                       /**< format arguments line in printf() function */
539  	   )
540  	{
541  	   va_list ap;
542  	
543  	   va_start(ap, formatstr); /*lint !e838*/
544  	   SCIPmessageVFPrintDialog(messagehdlr, file, formatstr, ap);
545  	   va_end(ap);
546  	}
547  	
548  	/** prints a dialog message that requests user interaction into a file, acting like the vfprintf() command */
549  	void SCIPmessageVFPrintDialog(
550  	   SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
551  	   FILE*                 file,               /**< file stream to print into, or NULL for stdout */
552  	   const char*           formatstr,          /**< format string like in printf() function */
553  	   va_list               ap                  /**< variable argument list */
554  	   )
555  	{
556  	   char msg[SCIP_MAXSTRLEN];
557  	   int n;
558  	   va_list aq;
559  	
560  	   va_copy(aq, ap); /*lint !e838*/
561  	
562  	   n = vsnprintf(msg, SCIP_MAXSTRLEN, formatstr, ap);
563  	   if( n < 0 )
564  	      msg[SCIP_MAXSTRLEN-1] = '\0';
565  	   else if( n >= SCIP_MAXSTRLEN )
566  	   {
567  	      char* bigmsg;
568  	#ifndef NDEBUG
569  	      int m;
570  	#endif
571  	
572  	      if( BMSallocMemorySize(&bigmsg, n+1) == NULL )
573  	      {
574  	         va_end(aq);
575  	         return;
576  	      }
577  	
578  	#ifndef NDEBUG
579  	      m = vsnprintf(bigmsg, (size_t) n+1, formatstr, aq); /*lint !e571*/
580  	#else
581  	      vsnprintf(bigmsg, (size_t) n+1, formatstr, aq); /*lint !e571*/
582  	#endif
583  	      assert(m == n);
584  	      va_end(aq);
585  	      messagePrintDialog(messagehdlr, file, bigmsg);
586  	      BMSfreeMemory(&bigmsg);
587  	      return;
588  	   }
589  	   messagePrintDialog(messagehdlr, file, msg);
590  	   va_end(aq);
591  	}
592  	
593  	/** prints a message, acting like the printf() command */
594  	void SCIPmessagePrintInfo(
595  	   SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
596  	   const char*           formatstr,          /**< format string like in printf() function */
597  	   ...                                       /**< format arguments line in printf() function */
598  	   )
599  	{
600  	   va_list ap;
601  	
602  	   va_start(ap, formatstr); /*lint !e838*/
603  	   SCIPmessageVFPrintInfo(messagehdlr, NULL, formatstr, ap);
604  	   va_end(ap);
605  	}
606  	
607  	/** prints a message, acting like the vprintf() command */
608  	void SCIPmessageVPrintInfo(
609  	   SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
610  	   const char*           formatstr,          /**< format string like in printf() function */
611  	   va_list               ap                  /**< variable argument list */
612  	   )
613  	{
614  	   SCIPmessageVFPrintInfo(messagehdlr, NULL, formatstr, ap);
615  	}
616  	
617  	/** prints a message into a file, acting like the fprintf() command */
618  	void SCIPmessageFPrintInfo(
619  	   SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
620  	   FILE*                 file,               /**< file stream to print into, or NULL for stdout */
621  	   const char*           formatstr,          /**< format string like in printf() function */
622  	   ...                                       /**< format arguments line in printf() function */
623  	   )
624  	{
625  	   va_list ap;
626  	
627  	   va_start(ap, formatstr); /*lint !e838*/
628  	   SCIPmessageVFPrintInfo(messagehdlr, file, formatstr, ap);
629  	   va_end(ap);
630  	}
631  	
632  	/** prints a message into a file, acting like the vfprintf() command */
633  	void SCIPmessageVFPrintInfo(
634  	   SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
635  	   FILE*                 file,               /**< file stream to print into, or NULL for stdout */
636  	   const char*           formatstr,          /**< format string like in printf() function */
637  	   va_list               ap                  /**< variable argument list */
638  	   )
639  	{
640  	   char msg[SCIP_MAXSTRLEN];
641  	   int n;
642  	   va_list aq;
643  	
644  	   va_copy(aq, ap); /*lint !e838*/
645  	
646  	   n = vsnprintf(msg, SCIP_MAXSTRLEN, formatstr, ap);
647  	   if( n < 0 )
648  	      msg[SCIP_MAXSTRLEN-1] = '\0';
649  	   else if( n >= SCIP_MAXSTRLEN )
650  	   {
651  	      char* bigmsg;
652  	#ifndef NDEBUG
653  	      int m;
654  	#endif
655  	
656  	      if( BMSallocMemorySize(&bigmsg, n+1) == NULL )
657  	      {
658  	         va_end(aq);
659  	         return;
660  	      }
661  	
662  	#ifndef NDEBUG
663  	      m = vsnprintf(bigmsg, (size_t) n+1, formatstr, aq); /*lint !e571*/
664  	#else
665  	      vsnprintf(bigmsg, (size_t) n+1, formatstr, aq); /*lint !e571*/
666  	#endif
667  	      assert(m == n);
668  	      va_end(aq);
669  	      messagePrintInfo(messagehdlr, file, bigmsg);
670  	      BMSfreeMemory(&bigmsg);
671  	      return;
672  	   }
673  	   messagePrintInfo(messagehdlr, file, msg);
674  	   va_end(aq);
675  	}
676  	
677  	/** prints a message depending on the verbosity level, acting like the printf() command */
678  	void SCIPmessagePrintVerbInfo(
679  	   SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
680  	   SCIP_VERBLEVEL        verblevel,          /**< current verbosity level */
681  	   SCIP_VERBLEVEL        msgverblevel,       /**< verbosity level of this message */
682  	   const char*           formatstr,          /**< format string like in printf() function */
683  	   ...                                       /**< format arguments line in printf() function */
684  	   )
685  	{
686  	   va_list ap;
687  	
688  	   va_start(ap, formatstr); /*lint !e838*/
689  	   SCIPmessageVFPrintVerbInfo(messagehdlr, verblevel, msgverblevel, NULL, formatstr, ap);
690  	   va_end(ap);
691  	}
692  	
693  	/** prints a message depending on the verbosity level, acting like the vprintf() command */
694  	void SCIPmessageVPrintVerbInfo(
695  	   SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
696  	   SCIP_VERBLEVEL        verblevel,          /**< current verbosity level */
697  	   SCIP_VERBLEVEL        msgverblevel,       /**< verbosity level of this message */
698  	   const char*           formatstr,          /**< format string like in printf() function */
699  	   va_list               ap                  /**< variable argument list */
700  	   )
701  	{
702  	   SCIPmessageVFPrintVerbInfo(messagehdlr, verblevel, msgverblevel, NULL, formatstr, ap);
703  	}
704  	
705  	/** prints a message into a file depending on the verbosity level, acting like the fprintf() command */
706  	void SCIPmessageFPrintVerbInfo(
707  	   SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
708  	   SCIP_VERBLEVEL        verblevel,          /**< current verbosity level */
709  	   SCIP_VERBLEVEL        msgverblevel,       /**< verbosity level of this message */
710  	   FILE*                 file,               /**< file stream to print into, or NULL for stdout */
711  	   const char*           formatstr,          /**< format string like in printf() function */
712  	   ...                                       /**< format arguments line in printf() function */
713  	   )
714  	{
715  	   va_list ap;
716  	
717  	   va_start(ap, formatstr); /*lint !e838*/
718  	   SCIPmessageVFPrintVerbInfo(messagehdlr, verblevel, msgverblevel, file, formatstr, ap);
719  	   va_end(ap);
720  	}
721  	
722  	/** prints a message into a file depending on the verbosity level, acting like the vfprintf() command */
723  	void SCIPmessageVFPrintVerbInfo(
724  	   SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
725  	   SCIP_VERBLEVEL        verblevel,          /**< current verbosity level */
726  	   SCIP_VERBLEVEL        msgverblevel,       /**< verbosity level of this message */
727  	   FILE*                 file,               /**< file stream to print into, or NULL for stdout */
728  	   const char*           formatstr,          /**< format string like in printf() function */
729  	   va_list               ap                  /**< variable argument list */
730  	   )
731  	{
732  	   assert(msgverblevel > SCIP_VERBLEVEL_NONE);
733  	   assert(msgverblevel <= SCIP_VERBLEVEL_FULL);
734  	   assert(verblevel <= SCIP_VERBLEVEL_FULL);
735  	
736  	   if( msgverblevel <= verblevel )
737  	   {
738  	      char msg[SCIP_MAXSTRLEN];
739  	      int n;
740  	      va_list aq;
741  	
742  	      va_copy(aq, ap); /*lint !e838*/
743  	
744  	      n = vsnprintf(msg, SCIP_MAXSTRLEN, formatstr, ap);
745  	      if( n < 0 )
746  	         msg[SCIP_MAXSTRLEN-1] = '\0';
747  	      else if( n >= SCIP_MAXSTRLEN )
748  	      {
749  	         char* bigmsg;
750  	#ifndef NDEBUG
751  	         int m;
752  	#endif
753  	
754  	         if( BMSallocMemorySize(&bigmsg, n+1) == NULL )
755  	         {
756  	            va_end(aq);
757  	            return;
758  	         }
759  	
760  	#ifndef NDEBUG
761  	         m = vsnprintf(bigmsg, (size_t) n+1, formatstr, aq); /*lint !e571*/
762  	#else
763  	         vsnprintf(bigmsg, (size_t) n+1, formatstr, aq); /*lint !e571*/
764  	#endif
765  	         assert(m == n);
766  	         va_end(aq);
767  	         messagePrintInfo(messagehdlr, file, bigmsg);
768  	         BMSfreeMemory(&bigmsg);
769  	         return;
770  	      }
771  	      messagePrintInfo(messagehdlr, file, msg);
772  	      va_end(aq);
773  	   }
774  	}
775  	
776  	/** prints the header with source file location for an error message using the static message handler */
777  	void SCIPmessagePrintErrorHeader(
778  	   const char*           sourcefile,         /**< name of the source file that called the function */
779  	   int                   sourceline          /**< line in the source file where the function was called */
780  	   )
781  	{
782  	   char msg[SCIP_MAXSTRLEN];
783  	
784  	   /* safe string printing - do not use SCIPsnprintf() since message.c should be independent */
785  	   (void) snprintf(msg, SCIP_MAXSTRLEN, "[%s:%d] ERROR: ", sourcefile, sourceline);
786  	   msg[SCIP_MAXSTRLEN-1] = '\0';
787  	   messagePrintError(NULL, msg);
788  	}
789  	
790  	/** prints a error message, acting like the printf() command */
791  	void SCIPmessagePrintError(
792  	   const char*           formatstr,          /**< format string like in printf() function */
793  	   ...                                       /**< format arguments line in printf() function */
794  	   )
795  	{
796  	   va_list ap;
797  	
798  	   va_start(ap, formatstr); /*lint !e838*/
799  	   SCIPmessageVPrintError(formatstr, ap);
800  	   va_end(ap);
801  	}
802  	
803  	/** prints an error message, acting like the vprintf() command using the static message handler */
804  	void SCIPmessageVPrintError(
805  	   const char*           formatstr,          /**< format string like in printf() function */
806  	   va_list               ap                  /**< variable argument list */
807  	   )
808  	{
809  	   char msg[SCIP_MAXSTRLEN];
810  	   int n;
811  	   va_list aq;
812  	
813  	   va_copy(aq, ap); /*lint !e838*/
814  	
815  	   n = vsnprintf(msg, SCIP_MAXSTRLEN, formatstr, ap);
816  	   if( n < 0 )
817  	      msg[SCIP_MAXSTRLEN-1] = '\0';
818  	   else if( n >= SCIP_MAXSTRLEN )
819  	   {
820  	      char* bigmsg;
821  	#ifndef NDEBUG
822  	      int m;
823  	#endif
824  	
825  	      if( BMSallocMemorySize(&bigmsg, n+1) == NULL )
826  	      {
827  	         va_end(aq);
828  	         return;
829  	      }
830  	
831  	#ifndef NDEBUG
832  	      m = vsnprintf(bigmsg, (size_t) n+1, formatstr, aq); /*lint !e571*/
833  	#else
834  	      vsnprintf(bigmsg, (size_t) n+1, formatstr, aq); /*lint !e571*/
835  	#endif
836  	      assert(m == n);
837  	      va_end(aq);
838  	      messagePrintError(NULL, bigmsg);
839  	      BMSfreeMemory(&bigmsg);
840  	      return;
841  	   }
842  	
843  	   messagePrintError(NULL, msg);
844  	   va_end(aq);
845  	}
846  	
847  	/** Method to set the error printing method. Setting the error printing method to NULL will suspend all error methods.
848  	 *
849  	 *  @note The error printing method is static variable. That means all occurring errors are handled via that methods
850  	 */
851  	void SCIPmessageSetErrorPrinting(
852  	   SCIP_DECL_ERRORPRINTING((*errorPrinting)),/**< error message print method of message handler, or NULL */
853  	   void*                 data                /**< data pointer which will be passed to the error printing method, or NULL */
854  	   )
855  	{
856  	   staticErrorPrinting = errorPrinting;
857  	   staticErrorPrintingData = data;
858  	}
859  	
860  	/** Method to set the error printing method to default version prints everything the stderr.
861  	 *
862  	 *  @note The error printing method is a static variable. This means that all occurring errors are handled via this method.
863  	 */
864  	void SCIPmessageSetErrorPrintingDefault(
865  	   void
866  	   )
867  	{
868  	   staticErrorPrinting = errorPrintingDefault;
869  	   staticErrorPrintingData = NULL;
870  	}
871  	
872  	/*
873  	 * simple functions implemented as defines
874  	 */
875  	
876  	/* In debug mode, the following methods are implemented as function calls to ensure
877  	 * type validity.
878  	 * In optimized mode, the methods are implemented as defines to improve performance.
879  	 * However, we want to have them in the library anyways, so we have to undef the defines.
880  	 */
881  	
882  	#undef SCIPmessagehdlrGetData
883  	#undef SCIPmessagehdlrGetLogfile
884  	#undef SCIPmessagehdlrIsQuiet
885  	
886  	/** returns the user data of the message handler */
887  	SCIP_MESSAGEHDLRDATA* SCIPmessagehdlrGetData(
888  	   SCIP_MESSAGEHDLR*     messagehdlr         /**< message handler */
889  	   )
890  	{
891  	   if( messagehdlr != NULL )
892  	      return messagehdlr->messagehdlrdata;
893  	   else
894  	      return NULL;
895  	}
896  	
897  	
898  	/** returns the log file or NULL for stdout */
899  	FILE* SCIPmessagehdlrGetLogfile(
900  	   SCIP_MESSAGEHDLR*     messagehdlr         /**< message handler */
901  	   )
902  	{
903  	   if( messagehdlr == NULL )
904  	      return NULL;
905  	
906  	   return messagehdlr->logfile;
907  	}
908  	
909  	/** returns TRUE if the message handler is set to be quiet */
910  	SCIP_Bool SCIPmessagehdlrIsQuiet(
911  	   SCIP_MESSAGEHDLR*     messagehdlr         /**< message handler */
912  	   )
913  	{
914  	   return (messagehdlr == NULL || messagehdlr->quiet);
915  	}
916