Home | History | Annotate | Download | only in Common
      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