1 /*++ 2 3 Copyright (c) 2004, Intel Corporation. All rights reserved.<BR> 4 This program and the accompanying materials 5 are licensed and made available under the terms and conditions of the BSD License 6 which accompanies this distribution. The full text of the license may be found at 7 http://opensource.org/licenses/bsd-license.php 8 9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 11 12 Module Name: 13 14 EfiUtilityMsgs.c 15 16 Abstract: 17 18 EFI tools utility functions to display warning, error, and informational 19 messages. 20 21 --*/ 22 23 #include <stdio.h> 24 #include <string.h> 25 #include <ctype.h> 26 #include <stdarg.h> 27 28 #include "Tiano.h" 29 #include "EfiUtilityMsgs.h" 30 31 #define MAX_LINE_LEN 200 32 33 // 34 // Declare module globals for keeping track of the the utility's 35 // name and other settings. 36 // 37 static STATUS mStatus = STATUS_SUCCESS; 38 static INT8 mUtilityName[50] = { 0 }; 39 static UINT32 mDebugMsgMask = 0; 40 static INT8 *mSourceFileName = NULL; 41 static UINT32 mSourceFileLineNum = 0; 42 static UINT32 mErrorCount = 0; 43 static UINT32 mWarningCount = 0; 44 static UINT32 mMaxErrors = 0; 45 static UINT32 mMaxWarnings = 0; 46 static UINT32 mMaxWarningsPlusErrors = 0; 47 static INT8 mPrintLimitsSet = 0; 48 49 static 50 void 51 PrintMessage ( 52 INT8 *Type, 53 INT8 *FileName, 54 UINT32 LineNumber, 55 UINT32 MessageCode, 56 INT8 *Text, 57 INT8 *MsgFmt, 58 va_list List 59 ); 60 61 static 62 void 63 PrintLimitExceeded ( 64 VOID 65 ); 66 67 void 68 Error ( 69 INT8 *FileName, 70 UINT32 LineNumber, 71 UINT32 MessageCode, 72 INT8 *Text, 73 INT8 *MsgFmt, 74 ... 75 ) 76 /*++ 77 78 Routine Description: 79 Prints an error message. 80 81 Arguments: 82 All arguments are optional, though the printed message may be useless if 83 at least something valid is not specified. 84 85 FileName - name of the file or application. If not specified, then the 86 utilty name (as set by the utility calling SetUtilityName() 87 earlier) is used. Otherwise "Unknown utility" is used. 88 89 LineNumber - the line number of error, typically used by parsers. If the 90 utility is not a parser, then 0 should be specified. Otherwise 91 the FileName and LineNumber info can be used to cause 92 MS Visual Studio to jump to the error. 93 94 MessageCode - an application-specific error code that can be referenced in 95 other documentation. 96 97 Text - the text in question, typically used by parsers. 98 99 MsgFmt - the format string for the error message. Can contain formatting 100 controls for use with the varargs. 101 102 Returns: 103 None. 104 105 Notes: 106 We print the following (similar to the Warn() and Debug() 107 W 108 Typical error/warning message format: 109 110 bin\VfrCompile.cpp(330) : error C2660: 'AddVfrDataStructField' : function does not take 2 parameters 111 112 BUGBUG -- these three utility functions are almost identical, and 113 should be modified to share code. 114 115 Visual Studio does not find error messages with: 116 117 " error :" 118 " error 1:" 119 " error c1:" 120 " error 1000:" 121 " error c100:" 122 123 It does find: 124 " error c1000:" 125 --*/ 126 { 127 va_list List; 128 // 129 // If limits have been set, then check that we have not exceeded them 130 // 131 if (mPrintLimitsSet) { 132 // 133 // See if we've exceeded our total count 134 // 135 if (mMaxWarningsPlusErrors != 0) { 136 if (mErrorCount + mWarningCount > mMaxWarningsPlusErrors) { 137 PrintLimitExceeded (); 138 return ; 139 } 140 } 141 // 142 // See if we've exceeded our error count 143 // 144 if (mMaxErrors != 0) { 145 if (mErrorCount > mMaxErrors) { 146 PrintLimitExceeded (); 147 return ; 148 } 149 } 150 } 151 152 mErrorCount++; 153 va_start (List, MsgFmt); 154 PrintMessage ("error", FileName, LineNumber, MessageCode, Text, MsgFmt, List); 155 va_end (List); 156 // 157 // Set status accordingly 158 // 159 if (mStatus < STATUS_ERROR) { 160 mStatus = STATUS_ERROR; 161 } 162 } 163 164 void 165 ParserError ( 166 UINT32 MessageCode, 167 INT8 *Text, 168 INT8 *MsgFmt, 169 ... 170 ) 171 /*++ 172 173 Routine Description: 174 Print a parser error, using the source file name and line number 175 set by a previous call to SetParserPosition(). 176 177 Arguments: 178 MessageCode - application-specific error code 179 Text - text to print in the error message 180 MsgFmt - format string to print at the end of the error message 181 182 Returns: 183 NA 184 185 --*/ 186 { 187 va_list List; 188 // 189 // If limits have been set, then check them 190 // 191 if (mPrintLimitsSet) { 192 // 193 // See if we've exceeded our total count 194 // 195 if (mMaxWarningsPlusErrors != 0) { 196 if (mErrorCount + mWarningCount > mMaxWarningsPlusErrors) { 197 PrintLimitExceeded (); 198 return ; 199 } 200 } 201 // 202 // See if we've exceeded our error count 203 // 204 if (mMaxErrors != 0) { 205 if (mErrorCount > mMaxErrors) { 206 PrintLimitExceeded (); 207 return ; 208 } 209 } 210 } 211 212 mErrorCount++; 213 va_start (List, MsgFmt); 214 PrintMessage ("error", mSourceFileName, mSourceFileLineNum, MessageCode, Text, MsgFmt, List); 215 va_end (List); 216 // 217 // Set status accordingly 218 // 219 if (mStatus < STATUS_ERROR) { 220 mStatus = STATUS_ERROR; 221 } 222 } 223 224 void 225 ParserWarning ( 226 UINT32 ErrorCode, 227 INT8 *OffendingText, 228 INT8 *MsgFmt, 229 ... 230 ) 231 /*++ 232 233 Routine Description: 234 Print a parser warning, using the source file name and line number 235 set by a previous call to SetParserPosition(). 236 237 Arguments: 238 ErrorCode - application-specific error code 239 OffendingText - text to print in the warning message 240 MsgFmt - format string to print at the end of the warning message 241 242 Returns: 243 NA 244 245 --*/ 246 { 247 va_list List; 248 // 249 // If limits have been set, then check them 250 // 251 if (mPrintLimitsSet) { 252 // 253 // See if we've exceeded our total count 254 // 255 if (mMaxWarningsPlusErrors != 0) { 256 if (mErrorCount + mWarningCount > mMaxWarningsPlusErrors) { 257 PrintLimitExceeded (); 258 return ; 259 } 260 } 261 // 262 // See if we've exceeded our warning count 263 // 264 if (mMaxWarnings != 0) { 265 if (mWarningCount > mMaxWarnings) { 266 PrintLimitExceeded (); 267 return ; 268 } 269 } 270 } 271 272 mWarningCount++; 273 va_start (List, MsgFmt); 274 PrintMessage ("warning", mSourceFileName, mSourceFileLineNum, ErrorCode, OffendingText, MsgFmt, List); 275 va_end (List); 276 // 277 // Set status accordingly 278 // 279 if (mStatus < STATUS_WARNING) { 280 mStatus = STATUS_WARNING; 281 } 282 } 283 284 void 285 Warning ( 286 INT8 *FileName, 287 UINT32 LineNumber, 288 UINT32 MessageCode, 289 INT8 *Text, 290 INT8 *MsgFmt, 291 ... 292 ) 293 /*++ 294 295 Routine Description: 296 Print a warning message. 297 298 Arguments: 299 FileName - name of the file where the warning was detected, or the name 300 of the application that detected the warning 301 302 LineNumber - the line number where the warning was detected (parsers). 303 0 should be specified if the utility is not a parser. 304 305 MessageCode - an application-specific warning code that can be referenced in 306 other documentation. 307 308 Text - the text in question (parsers) 309 310 MsgFmt - the format string for the warning message. Can contain formatting 311 controls for use with varargs. 312 313 Returns: 314 None. 315 316 --*/ 317 { 318 va_list List; 319 // 320 // If limits have been set, then check them 321 // 322 if (mPrintLimitsSet) { 323 // 324 // See if we've exceeded our total count 325 // 326 if (mMaxWarningsPlusErrors != 0) { 327 if (mErrorCount + mWarningCount > mMaxWarningsPlusErrors) { 328 PrintLimitExceeded (); 329 return ; 330 } 331 } 332 // 333 // See if we've exceeded our warning count 334 // 335 if (mMaxWarnings != 0) { 336 if (mWarningCount > mMaxWarnings) { 337 PrintLimitExceeded (); 338 return ; 339 } 340 } 341 } 342 343 mWarningCount++; 344 va_start (List, MsgFmt); 345 PrintMessage ("warning", FileName, LineNumber, MessageCode, Text, MsgFmt, List); 346 va_end (List); 347 // 348 // Set status accordingly 349 // 350 if (mStatus < STATUS_WARNING) { 351 mStatus = STATUS_WARNING; 352 } 353 } 354 355 void 356 DebugMsg ( 357 INT8 *FileName, 358 UINT32 LineNumber, 359 UINT32 MsgMask, 360 INT8 *Text, 361 INT8 *MsgFmt, 362 ... 363 ) 364 /*++ 365 366 Routine Description: 367 Print a warning message. 368 369 Arguments: 370 FileName - typically the name of the utility printing the debug message, but 371 can be the name of a file being parsed. 372 373 LineNumber - the line number in FileName (parsers) 374 375 MsgMask - an application-specific bitmask that, in combination with mDebugMsgMask, 376 determines if the debug message gets printed. 377 378 Text - the text in question (parsers) 379 380 MsgFmt - the format string for the debug message. Can contain formatting 381 controls for use with varargs. 382 383 Returns: 384 None. 385 386 --*/ 387 { 388 va_list List; 389 // 390 // If the debug mask is not applicable, then do nothing. 391 // 392 if ((MsgMask != 0) && ((mDebugMsgMask & MsgMask) == 0)) { 393 return ; 394 } 395 396 va_start (List, MsgFmt); 397 PrintMessage ("debug", FileName, LineNumber, 0, Text, MsgFmt, List); 398 va_end (List); 399 } 400 401 static 402 void 403 PrintMessage ( 404 INT8 *Type, 405 INT8 *FileName, 406 UINT32 LineNumber, 407 UINT32 MessageCode, 408 INT8 *Text, 409 INT8 *MsgFmt, 410 va_list List 411 ) 412 /*++ 413 414 Routine Description: 415 Worker routine for all the utility printing services. Prints the message in 416 a format that Visual Studio will find when scanning build outputs for 417 errors or warnings. 418 419 Arguments: 420 Type - "warning" or "error" string to insert into the message to be 421 printed. The first character of this string (converted to uppercase) 422 is used to preceed the MessageCode value in the output string. 423 424 FileName - name of the file where the warning was detected, or the name 425 of the application that detected the warning 426 427 LineNumber - the line number where the warning was detected (parsers). 428 0 should be specified if the utility is not a parser. 429 430 MessageCode - an application-specific warning code that can be referenced in 431 other documentation. 432 433 Text - part of the message to print 434 435 MsgFmt - the format string for the message. Can contain formatting 436 controls for use with varargs. 437 List - the variable list. 438 439 Returns: 440 None. 441 442 Notes: 443 If FileName == NULL then this utility will use the string passed into SetUtilityName(). 444 445 LineNumber is only used if the caller is a parser, in which case FileName refers to the 446 file being parsed. 447 448 Text and MsgFmt are both optional, though it would be of little use calling this function with 449 them both NULL. 450 451 Output will typically be of the form: 452 <FileName>(<LineNumber>) : <Type> <Type[0]><MessageCode>: <Text> : <MsgFmt> 453 454 Parser (LineNumber != 0) 455 VfrCompile.cpp(330) : error E2660: AddVfrDataStructField : function does not take 2 parameters 456 Generic utility (LineNumber == 0) 457 UtilityName : error E1234 : Text string : MsgFmt string and args 458 459 --*/ 460 { 461 INT8 Line[MAX_LINE_LEN]; 462 INT8 Line2[MAX_LINE_LEN]; 463 INT8 *Cptr; 464 // 465 // If given a filename, then add it (and the line number) to the string. 466 // If there's no filename, then use the program name if provided. 467 // 468 if (FileName != NULL) { 469 Cptr = FileName; 470 } else if (mUtilityName[0] != 0) { 471 Cptr = mUtilityName; 472 } else { 473 Cptr = "Unknown utility"; 474 } 475 476 strcpy (Line, Cptr); 477 if (LineNumber != 0) { 478 sprintf (Line2, "(%d)", LineNumber); 479 strcat (Line, Line2); 480 } 481 // 482 // Have to print an error code or Visual Studio won't find the 483 // message for you. It has to be decimal digits too. 484 // 485 sprintf (Line2, " : %s %c%04d", Type, toupper (Type[0]), MessageCode); 486 strcat (Line, Line2); 487 fprintf (stdout, "%s", Line); 488 // 489 // If offending text was provided, then print it 490 // 491 if (Text != NULL) { 492 fprintf (stdout, ": %s ", Text); 493 } 494 // 495 // Print formatted message if provided 496 // 497 if (MsgFmt != NULL) { 498 vsprintf (Line2, MsgFmt, List); 499 fprintf (stdout, ": %s", Line2); 500 } 501 502 fprintf (stdout, "\n"); 503 } 504 505 void 506 ParserSetPosition ( 507 INT8 *SourceFileName, 508 UINT32 LineNum 509 ) 510 /*++ 511 512 Routine Description: 513 Set the position in a file being parsed. This can be used to 514 print error messages deeper down in a parser. 515 516 Arguments: 517 SourceFileName - name of the source file being parsed 518 LineNum - line number of the source file being parsed 519 520 Returns: 521 NA 522 523 --*/ 524 { 525 mSourceFileName = SourceFileName; 526 mSourceFileLineNum = LineNum; 527 } 528 529 void 530 SetUtilityName ( 531 INT8 *UtilityName 532 ) 533 /*++ 534 535 Routine Description: 536 All printed error/warning/debug messages follow the same format, and 537 typically will print a filename or utility name followed by the error 538 text. However if a filename is not passed to the print routines, then 539 they'll print the utility name if you call this function early in your 540 app to set the utility name. 541 542 Arguments: 543 UtilityName - name of the utility, which will be printed with all 544 error/warning/debug messags. 545 546 Returns: 547 NA 548 549 --*/ 550 { 551 // 552 // Save the name of the utility in our local variable. Make sure its 553 // length does not exceed our buffer. 554 // 555 if (UtilityName != NULL) { 556 if (strlen (UtilityName) >= sizeof (mUtilityName)) { 557 Error (UtilityName, 0, 0, "application error", "utility name length exceeds internal buffer size"); 558 strncpy (mUtilityName, UtilityName, sizeof (mUtilityName) - 1); 559 mUtilityName[sizeof (mUtilityName) - 1] = 0; 560 return ; 561 } else { 562 strcpy (mUtilityName, UtilityName); 563 } 564 } else { 565 Error (NULL, 0, 0, "application error", "SetUtilityName() called with NULL utility name"); 566 } 567 } 568 569 STATUS 570 GetUtilityStatus ( 571 VOID 572 ) 573 /*++ 574 575 Routine Description: 576 When you call Error() or Warning(), this module keeps track of it and 577 sets a local mStatus to STATUS_ERROR or STATUS_WARNING. When the utility 578 exits, it can call this function to get the status and use it as a return 579 value. 580 581 Arguments: 582 None. 583 584 Returns: 585 Worst-case status reported, as defined by which print function was called. 586 587 --*/ 588 { 589 return mStatus; 590 } 591 592 void 593 SetDebugMsgMask ( 594 UINT32 DebugMask 595 ) 596 /*++ 597 598 Routine Description: 599 Set the debug printing mask. This is used by the DebugMsg() function 600 to determine when/if a debug message should be printed. 601 602 Arguments: 603 DebugMask - bitmask, specific to the calling application 604 605 Returns: 606 NA 607 608 --*/ 609 { 610 mDebugMsgMask = DebugMask; 611 } 612 613 void 614 SetPrintLimits ( 615 UINT32 MaxErrors, 616 UINT32 MaxWarnings, 617 UINT32 MaxWarningsPlusErrors 618 ) 619 /*++ 620 621 Routine Description: 622 Set the limits of how many errors, warnings, and errors+warnings 623 we will print. 624 625 Arguments: 626 MaxErrors - maximum number of error messages to print 627 MaxWarnings - maximum number of warning messages to print 628 MaxWarningsPlusErrors 629 - maximum number of errors+warnings to print 630 631 Returns: 632 NA 633 634 --*/ 635 { 636 mMaxErrors = MaxErrors; 637 mMaxWarnings = MaxWarnings; 638 mMaxWarningsPlusErrors = MaxWarningsPlusErrors; 639 mPrintLimitsSet = 1; 640 } 641 642 static 643 void 644 PrintLimitExceeded ( 645 VOID 646 ) 647 { 648 static INT8 mPrintLimitExceeded = 0; 649 // 650 // If we've already printed the message, do nothing. Otherwise 651 // temporarily increase our print limits so we can pass one 652 // more message through. 653 // 654 if (mPrintLimitExceeded == 0) { 655 mPrintLimitExceeded++; 656 mMaxErrors++; 657 mMaxWarnings++; 658 mMaxWarningsPlusErrors++; 659 Error (NULL, 0, 0, "error/warning print limit exceeded", NULL); 660 mMaxErrors--; 661 mMaxWarnings--; 662 mMaxWarningsPlusErrors--; 663 } 664 } 665 666 #if 0 667 void 668 TestUtilityMessages ( 669 VOID 670 ) 671 { 672 char *ArgStr = "ArgString"; 673 int ArgInt; 674 675 ArgInt = 0x12345678; 676 // 677 // Test without setting utility name 678 // 679 fprintf (stdout, "* Testing without setting utility name\n"); 680 fprintf (stdout, "** Test debug message not printed\n"); 681 DebugMsg (NULL, 0, 0x00000001, NULL, NULL); 682 fprintf (stdout, "** Test warning with two strings and two args\n"); 683 Warning (NULL, 0, 1234, "Text1", "Text2 %s 0x%X", ArgStr, ArgInt); 684 fprintf (stdout, "** Test error with two strings and two args\n"); 685 Warning (NULL, 0, 1234, "Text1", "Text2 %s 0x%X", ArgStr, ArgInt); 686 fprintf (stdout, "** Test parser warning with nothing\n"); 687 ParserWarning (0, NULL, NULL); 688 fprintf (stdout, "** Test parser error with nothing\n"); 689 ParserError (0, NULL, NULL); 690 // 691 // Test with utility name set now 692 // 693 fprintf (stdout, "** Testingin with utility name set\n"); 694 SetUtilityName ("MyUtilityName"); 695 // 696 // Test debug prints 697 // 698 SetDebugMsgMask (2); 699 fprintf (stdout, "** Test debug message with one string\n"); 700 DebugMsg (NULL, 0, 0x00000002, "Text1", NULL); 701 fprintf (stdout, "** Test debug message with one string\n"); 702 DebugMsg (NULL, 0, 0x00000002, NULL, "Text2"); 703 fprintf (stdout, "** Test debug message with two strings\n"); 704 DebugMsg (NULL, 0, 0x00000002, "Text1", "Text2"); 705 fprintf (stdout, "** Test debug message with two strings and two args\n"); 706 DebugMsg (NULL, 0, 0x00000002, "Text1", "Text2 %s 0x%X", ArgStr, ArgInt); 707 // 708 // Test warning prints 709 // 710 fprintf (stdout, "** Test warning with no strings\n"); 711 Warning (NULL, 0, 1234, NULL, NULL); 712 fprintf (stdout, "** Test warning with one string\n"); 713 Warning (NULL, 0, 1234, "Text1", NULL); 714 fprintf (stdout, "** Test warning with one string\n"); 715 Warning (NULL, 0, 1234, NULL, "Text2"); 716 fprintf (stdout, "** Test warning with two strings and two args\n"); 717 Warning (NULL, 0, 1234, "Text1", "Text2 %s 0x%X", ArgStr, ArgInt); 718 // 719 // Test error prints 720 // 721 fprintf (stdout, "** Test error with no strings\n"); 722 Error (NULL, 0, 1234, NULL, NULL); 723 fprintf (stdout, "** Test error with one string\n"); 724 Error (NULL, 0, 1234, "Text1", NULL); 725 fprintf (stdout, "** Test error with one string\n"); 726 Error (NULL, 0, 1234, NULL, "Text2"); 727 fprintf (stdout, "** Test error with two strings and two args\n"); 728 Error (NULL, 0, 1234, "Text1", "Text2 %s 0x%X", ArgStr, ArgInt); 729 // 730 // Test parser prints 731 // 732 fprintf (stdout, "** Test parser errors\n"); 733 ParserSetPosition (__FILE__, __LINE__ + 1); 734 ParserError (1234, NULL, NULL); 735 ParserSetPosition (__FILE__, __LINE__ + 1); 736 ParserError (1234, "Text1", NULL); 737 ParserSetPosition (__FILE__, __LINE__ + 1); 738 ParserError (1234, NULL, "Text2"); 739 ParserSetPosition (__FILE__, __LINE__ + 1); 740 ParserError (1234, "Text1", "Text2"); 741 ParserSetPosition (__FILE__, __LINE__ + 1); 742 ParserError (1234, "Text1", "Text2 %s 0x%X", ArgStr, ArgInt); 743 744 fprintf (stdout, "** Test parser warnings\n"); 745 ParserSetPosition (__FILE__, __LINE__ + 1); 746 ParserWarning (4321, NULL, NULL); 747 ParserSetPosition (__FILE__, __LINE__ + 1); 748 ParserWarning (4321, "Text1", NULL); 749 ParserSetPosition (__FILE__, __LINE__ + 1); 750 ParserWarning (4321, NULL, "Text2"); 751 ParserSetPosition (__FILE__, __LINE__ + 1); 752 ParserWarning (4321, "Text1", "Text2"); 753 ParserSetPosition (__FILE__, __LINE__ + 1); 754 ParserWarning (4321, "Text1", "Text2 %s 0x%X", ArgStr, ArgInt); 755 } 756 #endif 757