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