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