2 EFI tools utility functions to display warning, error, and informational messages
4 Copyright (c) 2004 - 2017, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
15 #include "EfiUtilityMsgs.h"
18 // Declare module globals for keeping track of the utility's
19 // name and other settings.
21 STATIC STATUS mStatus
= STATUS_SUCCESS
;
22 STATIC CHAR8 mUtilityName
[50] = { 0 };
23 STATIC UINT64 mPrintLogLevel
= INFO_LOG_LEVEL
;
24 STATIC CHAR8
*mSourceFileName
= NULL
;
25 STATIC UINT32 mSourceFileLineNum
= 0;
26 STATIC UINT32 mErrorCount
= 0;
27 STATIC UINT32 mWarningCount
= 0;
28 STATIC UINT32 mMaxErrors
= 0;
29 STATIC UINT32 mMaxWarnings
= 0;
30 STATIC UINT32 mMaxWarningsPlusErrors
= 0;
31 STATIC INT8 mPrintLimitsSet
= 0;
51 Prints an error message.
54 All arguments are optional, though the printed message may be useless if
55 at least something valid is not specified.
57 FileName - name of the file or application. If not specified, then the
58 utility name (as set by the utility calling SetUtilityName()
59 earlier) is used. Otherwise "Unknown utility" is used.
61 LineNumber - the line number of error, typically used by parsers. If the
62 utility is not a parser, then 0 should be specified. Otherwise
63 the FileName and LineNumber info can be used to cause
64 MS Visual Studio to jump to the error.
66 MessageCode - an application-specific error code that can be referenced in
69 Text - the text in question, typically used by parsers.
71 MsgFmt - the format string for the error message. Can contain formatting
72 controls for use with the varargs.
78 We print the following (similar to the Warn() and Debug()
80 Typical error/warning message format:
82 bin\VfrCompile.cpp(330) : error C2660: 'AddVfrDataStructField' : function does not take 2 parameters
84 BUGBUG -- these three utility functions are almost identical, and
85 should be modified to share code.
87 Visual Studio does not find error messages with:
101 // If limits have been set, then check that we have not exceeded them
103 if (mPrintLimitsSet
) {
105 // See if we've exceeded our total count
107 if (mMaxWarningsPlusErrors
!= 0) {
108 if (mErrorCount
+ mWarningCount
> mMaxWarningsPlusErrors
) {
109 PrintLimitExceeded ();
114 // See if we've exceeded our error count
116 if (mMaxErrors
!= 0) {
117 if (mErrorCount
> mMaxErrors
) {
118 PrintLimitExceeded ();
125 va_start (List
, MsgFmt
);
126 PrintMessage ("ERROR", FileName
, LineNumber
, MessageCode
, Text
, MsgFmt
, List
);
140 Print a parser error, using the source file name and line number
141 set by a previous call to SetParserPosition().
144 MessageCode - application-specific error code
145 Text - text to print in the error message
146 MsgFmt - format string to print at the end of the error message
155 // If limits have been set, then check them
157 if (mPrintLimitsSet
) {
159 // See if we've exceeded our total count
161 if (mMaxWarningsPlusErrors
!= 0) {
162 if (mErrorCount
+ mWarningCount
> mMaxWarningsPlusErrors
) {
163 PrintLimitExceeded ();
168 // See if we've exceeded our error count
170 if (mMaxErrors
!= 0) {
171 if (mErrorCount
> mMaxErrors
) {
172 PrintLimitExceeded ();
179 va_start (List
, MsgFmt
);
180 PrintMessage ("ERROR", mSourceFileName
, mSourceFileLineNum
, MessageCode
, Text
, MsgFmt
, List
);
187 CHAR8
*OffendingText
,
194 Print a parser warning, using the source file name and line number
195 set by a previous call to SetParserPosition().
198 ErrorCode - application-specific error code
199 OffendingText - text to print in the warning message
200 MsgFmt - format string to print at the end of the warning message
209 // If limits have been set, then check them
211 if (mPrintLimitsSet
) {
213 // See if we've exceeded our total count
215 if (mMaxWarningsPlusErrors
!= 0) {
216 if (mErrorCount
+ mWarningCount
> mMaxWarningsPlusErrors
) {
217 PrintLimitExceeded ();
222 // See if we've exceeded our warning count
224 if (mMaxWarnings
!= 0) {
225 if (mWarningCount
> mMaxWarnings
) {
226 PrintLimitExceeded ();
233 va_start (List
, MsgFmt
);
234 PrintMessage ("WARNING", mSourceFileName
, mSourceFileLineNum
, ErrorCode
, OffendingText
, MsgFmt
, List
);
237 // Don't set warning status accordingly
239 // if (mStatus < STATUS_WARNING) {
240 // mStatus = STATUS_WARNING;
256 Print a warning message.
259 FileName - name of the file where the warning was detected, or the name
260 of the application that detected the warning
262 LineNumber - the line number where the warning was detected (parsers).
263 0 should be specified if the utility is not a parser.
265 MessageCode - an application-specific warning code that can be referenced in
268 Text - the text in question (parsers)
270 MsgFmt - the format string for the warning message. Can contain formatting
271 controls for use with varargs.
281 // Current Print Level not output warning information.
283 if (WARNING_LOG_LEVEL
< mPrintLogLevel
) {
287 // If limits have been set, then check them
289 if (mPrintLimitsSet
) {
291 // See if we've exceeded our total count
293 if (mMaxWarningsPlusErrors
!= 0) {
294 if (mErrorCount
+ mWarningCount
> mMaxWarningsPlusErrors
) {
295 PrintLimitExceeded ();
300 // See if we've exceeded our warning count
302 if (mMaxWarnings
!= 0) {
303 if (mWarningCount
> mMaxWarnings
) {
304 PrintLimitExceeded ();
311 va_start (List
, MsgFmt
);
312 PrintMessage ("WARNING", FileName
, LineNumber
, MessageCode
, Text
, MsgFmt
, List
);
328 Print a Debug message.
331 FileName - typically the name of the utility printing the debug message, but
332 can be the name of a file being parsed.
334 LineNumber - the line number in FileName (parsers)
336 MsgLevel - Debug message print level (0~9)
338 Text - the text in question (parsers)
340 MsgFmt - the format string for the debug message. Can contain formatting
341 controls for use with varargs.
350 // If the debug level is less than current print level, then do nothing.
352 if (MsgLevel
< mPrintLogLevel
) {
356 va_start (List
, MsgFmt
);
357 PrintMessage ("DEBUG", FileName
, LineNumber
, 0, Text
, MsgFmt
, List
);
374 Worker routine for all the utility printing services. Prints the message in
375 a format that Visual Studio will find when scanning build outputs for
379 Type - "warning" or "error" string to insert into the message to be
380 printed. The first character of this string (converted to uppercase)
381 is used to precede the MessageCode value in the output string.
383 FileName - name of the file where the warning was detected, or the name
384 of the application that detected the warning
386 LineNumber - the line number where the warning was detected (parsers).
387 0 should be specified if the utility is not a parser.
389 MessageCode - an application-specific warning code that can be referenced in
392 Text - part of the message to print
394 MsgFmt - the format string for the message. Can contain formatting
395 controls for use with varargs.
396 List - the variable list.
402 If FileName == NULL then this utility will use the string passed into SetUtilityName().
404 LineNumber is only used if the caller is a parser, in which case FileName refers to the
407 Text and MsgFmt are both optional, though it would be of little use calling this function with
410 Output will typically be of the form:
411 <FileName>(<LineNumber>) : <Type> <Type[0]><MessageCode>: <Text> : <MsgFmt>
413 Parser (LineNumber != 0)
414 VfrCompile.cpp(330) : error E2660: AddVfrDataStructField : function does not take 2 parameters
415 Generic utility (LineNumber == 0)
416 UtilityName : error E1234 : Text string : MsgFmt string and args
420 CHAR8 Line
[MAX_LINE_LEN
];
421 CHAR8 Line2
[MAX_LINE_LEN
];
427 // init local variable
433 // If given a filename, then add it (and the line number) to the string.
434 // If there's no filename, then use the program name if provided.
436 if (FileName
!= NULL
) {
442 if (strcmp (Type
, "DEBUG") == 0) {
444 // Debug Message requires current time.
447 NewTime
= localtime (&CurrentTime
);
448 if (NewTime
!= NULL
) {
449 fprintf (stdout
, "%04d-%02d-%02d %02d:%02d:%02d",
450 NewTime
->tm_year
+ 1900,
460 strncat (Line
, Cptr
, MAX_LINE_LEN
- strlen (Line
) - 1);
461 if (LineNumber
!= 0) {
462 sprintf (Line2
, "(%u)", (unsigned) LineNumber
);
463 strncat (Line
, Line2
, MAX_LINE_LEN
- strlen (Line
) - 1);
468 // Error and Warning Information.
471 if (mUtilityName
[0] != '\0') {
472 fprintf (stdout
, "%s...\n", mUtilityName
);
474 strncpy (Line
, Cptr
, MAX_LINE_LEN
- 1);
475 Line
[MAX_LINE_LEN
- 1] = 0;
476 if (LineNumber
!= 0) {
477 sprintf (Line2
, "(%u)", (unsigned) LineNumber
);
478 strncat (Line
, Line2
, MAX_LINE_LEN
- strlen (Line
) - 1);
481 if (mUtilityName
[0] != '\0') {
482 strncpy (Line
, mUtilityName
, MAX_LINE_LEN
- 1);
483 Line
[MAX_LINE_LEN
- 1] = 0;
487 if (strcmp (Type
, "ERROR") == 0) {
489 // Set status accordingly for ERROR information.
491 if (mStatus
< STATUS_ERROR
) {
492 mStatus
= STATUS_ERROR
;
498 // Have to print an error code or Visual Studio won't find the
499 // message for you. It has to be decimal digits too.
501 strncat (Line
, ": ", MAX_LINE_LEN
- strlen (Line
) - 1);
502 strncat (Line
, Type
, MAX_LINE_LEN
- strlen (Line
) - 1);
503 if (MessageCode
!= 0) {
504 sprintf (Line2
, " %04u", (unsigned) MessageCode
);
505 strncat (Line
, Line2
, MAX_LINE_LEN
- strlen (Line
) - 1);
507 fprintf (stdout
, "%s", Line
);
509 // If offending text was provided, then print it
512 fprintf (stdout
, ": %s", Text
);
514 fprintf (stdout
, "\n");
517 // Print formatted message if provided
519 if (MsgFmt
!= NULL
) {
520 vsprintf (Line2
, MsgFmt
, List
);
521 fprintf (stdout
, " %s\n", Line2
);
534 Print message into stdout.
537 MsgFmt - the format string for the message. Can contain formatting
538 controls for use with varargs.
539 List - the variable list.
545 CHAR8 Line
[MAX_LINE_LEN
];
547 // Print formatted message if provided
549 if (MsgFmt
!= NULL
) {
550 vsprintf (Line
, MsgFmt
, List
);
551 fprintf (stdout
, "%s\n", Line
);
557 CHAR8
*SourceFileName
,
563 Set the position in a file being parsed. This can be used to
564 print error messages deeper down in a parser.
567 SourceFileName - name of the source file being parsed
568 LineNum - line number of the source file being parsed
575 mSourceFileName
= SourceFileName
;
576 mSourceFileLineNum
= LineNum
;
586 All printed error/warning/debug messages follow the same format, and
587 typically will print a filename or utility name followed by the error
588 text. However if a filename is not passed to the print routines, then
589 they'll print the utility name if you call this function early in your
590 app to set the utility name.
593 UtilityName - name of the utility, which will be printed with all
594 error/warning/debug messages.
602 // Save the name of the utility in our local variable. Make sure its
603 // length does not exceed our buffer.
605 if (UtilityName
!= NULL
) {
606 if (strlen (UtilityName
) >= sizeof (mUtilityName
)) {
607 Error (UtilityName
, 0, 0, "application error", "utility name length exceeds internal buffer size");
609 strncpy (mUtilityName
, UtilityName
, sizeof (mUtilityName
) - 1);
610 mUtilityName
[sizeof (mUtilityName
) - 1] = 0;
612 Error (NULL
, 0, 0, "application error", "SetUtilityName() called with NULL utility name");
623 When you call Error() or Warning(), this module keeps track of it and
624 sets a local mStatus to STATUS_ERROR or STATUS_WARNING. When the utility
625 exits, it can call this function to get the status and use it as a return
632 Worst-case status reported, as defined by which print function was called.
646 Set the printing message Level. This is used by the PrintMsg() function
647 to determine when/if a message should be printed.
650 LogLevel - 0~50 to specify the different level message.
657 mPrintLogLevel
= LogLevel
;
668 Print a verbose level message.
671 MsgFmt - the format string for the message. Can contain formatting
672 controls for use with varargs.
673 List - the variable list.
682 // If the debug level is less than current print level, then do nothing.
684 if (VERBOSE_LOG_LEVEL
< mPrintLogLevel
) {
688 va_start (List
, MsgFmt
);
689 PrintSimpleMessage (MsgFmt
, List
);
701 Print a default level message.
704 MsgFmt - the format string for the message. Can contain formatting
705 controls for use with varargs.
706 List - the variable list.
715 // If the debug level is less than current print level, then do nothing.
717 if (INFO_LOG_LEVEL
< mPrintLogLevel
) {
721 va_start (List
, MsgFmt
);
722 PrintSimpleMessage (MsgFmt
, List
);
734 Print a key level message.
737 MsgFmt - the format string for the message. Can contain formatting
738 controls for use with varargs.
739 List - the variable list.
748 // If the debug level is less than current print level, then do nothing.
750 if (KEY_LOG_LEVEL
< mPrintLogLevel
) {
754 va_start (List
, MsgFmt
);
755 PrintSimpleMessage (MsgFmt
, List
);
763 UINT32 MaxWarningsPlusErrors
768 Set the limits of how many errors, warnings, and errors+warnings
772 MaxErrors - maximum number of error messages to print
773 MaxWarnings - maximum number of warning messages to print
774 MaxWarningsPlusErrors
775 - maximum number of errors+warnings to print
782 mMaxErrors
= MaxErrors
;
783 mMaxWarnings
= MaxWarnings
;
784 mMaxWarningsPlusErrors
= MaxWarningsPlusErrors
;
794 STATIC INT8 mPrintLimitExceeded
= 0;
796 // If we've already printed the message, do nothing. Otherwise
797 // temporarily increase our print limits so we can pass one
798 // more message through.
800 if (mPrintLimitExceeded
== 0) {
801 mPrintLimitExceeded
++;
804 mMaxWarningsPlusErrors
++;
805 Error (NULL
, 0, 0, "error/warning print limit exceeded", NULL
);
808 mMaxWarningsPlusErrors
--;
814 TestUtilityMessages (
818 CHAR8
*ArgStr
= "ArgString";
823 // Test without setting utility name
825 fprintf (stdout
, "* Testing without setting utility name\n");
826 fprintf (stdout
, "** Test debug message not printed\n");
827 DebugMsg (NULL
, 0, 0x00000001, NULL
, NULL
);
828 fprintf (stdout
, "** Test warning with two strings and two args\n");
829 Warning (NULL
, 0, 1234, "Text1", "Text2 %s 0x%X", ArgStr
, ArgInt
);
830 fprintf (stdout
, "** Test error with two strings and two args\n");
831 Warning (NULL
, 0, 1234, "Text1", "Text2 %s 0x%X", ArgStr
, ArgInt
);
832 fprintf (stdout
, "** Test parser warning with nothing\n");
833 ParserWarning (0, NULL
, NULL
);
834 fprintf (stdout
, "** Test parser error with nothing\n");
835 ParserError (0, NULL
, NULL
);
837 // Test with utility name set now
839 fprintf (stdout
, "** Testingin with utility name set\n");
840 SetUtilityName ("MyUtilityName");
845 fprintf (stdout
, "** Test debug message with one string\n");
846 DebugMsg (NULL
, 0, 0x00000002, "Text1", NULL
);
847 fprintf (stdout
, "** Test debug message with one string\n");
848 DebugMsg (NULL
, 0, 0x00000002, NULL
, "Text2");
849 fprintf (stdout
, "** Test debug message with two strings\n");
850 DebugMsg (NULL
, 0, 0x00000002, "Text1", "Text2");
851 fprintf (stdout
, "** Test debug message with two strings and two args\n");
852 DebugMsg (NULL
, 0, 0x00000002, "Text1", "Text2 %s 0x%X", ArgStr
, ArgInt
);
854 // Test warning prints
856 fprintf (stdout
, "** Test warning with no strings\n");
857 Warning (NULL
, 0, 1234, NULL
, NULL
);
858 fprintf (stdout
, "** Test warning with one string\n");
859 Warning (NULL
, 0, 1234, "Text1", NULL
);
860 fprintf (stdout
, "** Test warning with one string\n");
861 Warning (NULL
, 0, 1234, NULL
, "Text2");
862 fprintf (stdout
, "** Test warning with two strings and two args\n");
863 Warning (NULL
, 0, 1234, "Text1", "Text2 %s 0x%X", ArgStr
, ArgInt
);
867 fprintf (stdout
, "** Test error with no strings\n");
868 Error (NULL
, 0, 1234, NULL
, NULL
);
869 fprintf (stdout
, "** Test error with one string\n");
870 Error (NULL
, 0, 1234, "Text1", NULL
);
871 fprintf (stdout
, "** Test error with one string\n");
872 Error (NULL
, 0, 1234, NULL
, "Text2");
873 fprintf (stdout
, "** Test error with two strings and two args\n");
874 Error (NULL
, 0, 1234, "Text1", "Text2 %s 0x%X", ArgStr
, ArgInt
);
876 // Test parser prints
878 fprintf (stdout
, "** Test parser errors\n");
879 ParserSetPosition (__FILE__
, __LINE__
+ 1);
880 ParserError (1234, NULL
, NULL
);
881 ParserSetPosition (__FILE__
, __LINE__
+ 1);
882 ParserError (1234, "Text1", NULL
);
883 ParserSetPosition (__FILE__
, __LINE__
+ 1);
884 ParserError (1234, NULL
, "Text2");
885 ParserSetPosition (__FILE__
, __LINE__
+ 1);
886 ParserError (1234, "Text1", "Text2");
887 ParserSetPosition (__FILE__
, __LINE__
+ 1);
888 ParserError (1234, "Text1", "Text2 %s 0x%X", ArgStr
, ArgInt
);
890 fprintf (stdout
, "** Test parser warnings\n");
891 ParserSetPosition (__FILE__
, __LINE__
+ 1);
892 ParserWarning (4321, NULL
, NULL
);
893 ParserSetPosition (__FILE__
, __LINE__
+ 1);
894 ParserWarning (4321, "Text1", NULL
);
895 ParserSetPosition (__FILE__
, __LINE__
+ 1);
896 ParserWarning (4321, NULL
, "Text2");
897 ParserSetPosition (__FILE__
, __LINE__
+ 1);
898 ParserWarning (4321, "Text1", "Text2");
899 ParserSetPosition (__FILE__
, __LINE__
+ 1);
900 ParserWarning (4321, "Text1", "Text2 %s 0x%X", ArgStr
, ArgInt
);