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   UtilsMsgs.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 INT8   *mSourceFileName    = NULL;
40 static UINT32 mSourceFileLineNum  = 0;
41 static UINT32 mErrorCount         = 0;
42 static UINT32 mWarningCount       = 0;
43 static UINT32 mDebugMsgMask       = 0;
44 
45 static
46 void
47 PrintMessage (
48   INT8    *Type,
49   INT8    *FileName,
50   UINT32  LineNumber,
51   UINT32  MessageCode,
52   INT8    *Text,
53   INT8    *MsgFmt,
54   va_list List
55   );
56 
57 void
Error(INT8 * FileName,UINT32 LineNumber,UINT32 MessageCode,INT8 * Text,INT8 * MsgFmt,...)58 Error (
59   INT8    *FileName,
60   UINT32  LineNumber,
61   UINT32  MessageCode,
62   INT8    *Text,
63   INT8    *MsgFmt,
64   ...
65   )
66 /*++
67 
68 Routine Description:
69   Prints an error message.
70 
71 Arguments:
72   All arguments are optional, though the printed message may be useless if
73   at least something valid is not specified.
74 
75   FileName - name of the file or application. If not specified, then the
76              utilty name (as set by the utility calling SetUtilityName()
77              earlier) is used. Otherwise "Unknown utility" is used.
78 
79   LineNumber - the line number of error, typically used by parsers. If the
80                utility is not a parser, then 0 should be specified. Otherwise
81                the FileName and LineNumber info can be used to cause
82                MS Visual Studio to jump to the error.
83 
84   MessageCode - an application-specific error code that can be referenced in
85               other documentation.
86 
87   Text        - the text in question, typically used by parsers.
88 
89   MsgFmt - the format string for the error message. Can contain formatting
90            controls for use with the varargs.
91 
92 Returns:
93   None.
94 
95 Notes:
96   We print the following (similar to the Warn() and Debug()
97   W
98   Typical error/warning message format:
99 
100   bin\VfrCompile.cpp(330) : error C2660: 'AddVfrDataStructField' : function does not take 2 parameters
101 
102   BUGBUG -- these three utility functions are almost identical, and
103   should be modified to share code.
104 
105   Visual Studio does not find error messages with:
106 
107      " error :"
108      " error 1:"
109      " error c1:"
110      " error 1000:"
111      " error c100:"
112 
113   It does find:
114      " error c1000:"
115 --*/
116 {
117   va_list List;
118   mErrorCount++;
119   va_start (List, MsgFmt);
120   PrintMessage ("error", FileName, LineNumber, MessageCode, Text, MsgFmt, List);
121   va_end (List);
122   //
123   // Set status accordingly
124   //
125   if (mStatus < STATUS_ERROR) {
126     mStatus = STATUS_ERROR;
127   }
128 }
129 
130 void
ParserError(UINT32 MessageCode,INT8 * Text,INT8 * MsgFmt,...)131 ParserError (
132   UINT32  MessageCode,
133   INT8    *Text,
134   INT8    *MsgFmt,
135   ...
136   )
137 /*++
138 
139 Routine Description:
140   Print a parser error, using the source file name and line number
141   set by a previous call to SetParserPosition().
142 
143 Arguments:
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
147   ...
148 
149 Returns:
150   NA
151 
152 --*/
153 {
154   va_list List;
155   mErrorCount++;
156   va_start (List, MsgFmt);
157   PrintMessage ("error", mSourceFileName, mSourceFileLineNum, MessageCode, Text, MsgFmt, List);
158   va_end (List);
159   //
160   // Set status accordingly
161   //
162   if (mStatus < STATUS_ERROR) {
163     mStatus = STATUS_ERROR;
164   }
165 }
166 
167 void
ParserWarning(UINT32 ErrorCode,INT8 * OffendingText,INT8 * MsgFmt,...)168 ParserWarning (
169   UINT32  ErrorCode,
170   INT8    *OffendingText,
171   INT8    *MsgFmt,
172   ...
173   )
174 /*++
175 
176 Routine Description:
177   Print a parser warning, using the source file name and line number
178   set by a previous call to SetParserPosition().
179 
180 Arguments:
181   ErrorCode     - application-specific error code
182   OffendingText - text to print in the warning message
183   MsgFmt        - format string to print at the end of the warning message
184   ...
185 
186 Returns:
187   NA
188 
189 --*/
190 {
191   va_list List;
192   mWarningCount++;
193   va_start (List, MsgFmt);
194   PrintMessage ("warning", mSourceFileName, mSourceFileLineNum, ErrorCode, OffendingText, MsgFmt, List);
195   va_end (List);
196   //
197   // Set status accordingly
198   //
199   if (mStatus < STATUS_WARNING) {
200     mStatus = STATUS_WARNING;
201   }
202 }
203 
204 void
Warning(INT8 * FileName,UINT32 LineNumber,UINT32 MessageCode,INT8 * Text,INT8 * MsgFmt,...)205 Warning (
206   INT8    *FileName,
207   UINT32  LineNumber,
208   UINT32  MessageCode,
209   INT8    *Text,
210   INT8    *MsgFmt,
211   ...
212   )
213 /*++
214 
215 Routine Description:
216   Print a warning message.
217 
218 Arguments:
219   FileName    - name of the file where the warning was detected, or the name
220                 of the application that detected the warning
221 
222   LineNumber  - the line number where the warning was detected (parsers).
223                 0 should be specified if the utility is not a parser.
224 
225   MessageCode - an application-specific warning code that can be referenced in
226                 other documentation.
227 
228   Text        - the text in question (parsers)
229 
230   MsgFmt      - the format string for the warning message. Can contain formatting
231                 controls for use with varargs.
232 
233   ...
234 
235 Returns:
236   None.
237 
238 --*/
239 {
240   va_list List;
241   mWarningCount++;
242   va_start (List, MsgFmt);
243   PrintMessage ("warning", FileName, LineNumber, MessageCode, Text, MsgFmt, List);
244   va_end (List);
245   //
246   // Set status accordingly
247   //
248   if (mStatus < STATUS_WARNING) {
249     mStatus = STATUS_WARNING;
250   }
251 }
252 
253 void
DebugMsg(INT8 * FileName,UINT32 LineNumber,UINT32 MsgMask,INT8 * Text,INT8 * MsgFmt,...)254 DebugMsg (
255   INT8    *FileName,
256   UINT32  LineNumber,
257   UINT32  MsgMask,
258   INT8    *Text,
259   INT8    *MsgFmt,
260   ...
261   )
262 /*++
263 
264 Routine Description:
265   Print a warning message.
266 
267 Arguments:
268   FileName    - typically the name of the utility printing the debug message, but
269                 can be the name of a file being parsed.
270 
271   LineNumber  - the line number in FileName (parsers)
272 
273   MsgMask     - an application-specific bitmask that, in combination with mDebugMsgMask,
274                 determines if the debug message gets printed.
275 
276   Text        - the text in question (parsers)
277 
278   MsgFmt      - the format string for the debug message. Can contain formatting
279                 controls for use with varargs.
280 
281   ...
282 Returns:
283   None.
284 
285 --*/
286 {
287   va_list List;
288   //
289   // If the debug mask is not applicable, then do nothing.
290   //
291   if ((MsgMask != 0) && ((mDebugMsgMask & MsgMask) == 0)) {
292     return ;
293   }
294 
295   va_start (List, MsgFmt);
296   PrintMessage ("debug", FileName, LineNumber, 0, Text, MsgFmt, List);
297   va_end (List);
298 }
299 
300 static
301 void
PrintMessage(INT8 * Type,INT8 * FileName,UINT32 LineNumber,UINT32 MessageCode,INT8 * Text,INT8 * MsgFmt,va_list List)302 PrintMessage (
303   INT8    *Type,
304   INT8    *FileName,
305   UINT32  LineNumber,
306   UINT32  MessageCode,
307   INT8    *Text,
308   INT8    *MsgFmt,
309   va_list List
310   )
311 /*++
312 
313 Routine Description:
314   Worker routine for all the utility printing services. Prints the message in
315   a format that Visual Studio will find when scanning build outputs for
316   errors or warnings.
317 
318 Arguments:
319   Type        - "warning" or "error" string to insert into the message to be
320                 printed. The first character of this string (converted to uppercase)
321                 is used to preceed the MessageCode value in the output string.
322 
323   FileName    - name of the file where the warning was detected, or the name
324                 of the application that detected the warning
325 
326   LineNumber  - the line number where the warning was detected (parsers).
327                 0 should be specified if the utility is not a parser.
328 
329   MessageCode - an application-specific warning code that can be referenced in
330                 other documentation.
331 
332   Text        - part of the message to print
333 
334   MsgFmt      - the format string for the message. Can contain formatting
335                 controls for use with varargs.
336 
337   List        - Variable function parameter list.
338 Returns:
339   None.
340 
341 Notes:
342   If FileName == NULL then this utility will use the string passed into SetUtilityName().
343 
344   LineNumber is only used if the caller is a parser, in which case FileName refers to the
345   file being parsed.
346 
347   Text and MsgFmt are both optional, though it would be of little use calling this function with
348   them both NULL.
349 
350   Output will typically be of the form:
351     <FileName>(<LineNumber>) : <Type> <Type[0]><MessageCode>: <Text> : <MsgFmt>
352 
353     Parser (LineNumber != 0)
354       VfrCompile.cpp(330) : error E2660: AddVfrDataStructField : function does not take 2 parameters
355     Generic utility (LineNumber == 0)
356       UtilityName : error E1234 : Text string : MsgFmt string and args
357 
358 --*/
359 {
360   INT8  Line[MAX_LINE_LEN];
361   INT8  Line2[MAX_LINE_LEN];
362   INT8  *Cptr;
363   //
364   // If given a filename, then add it (and the line number) to the string.
365   // If there's no filename, then use the program name if provided.
366   //
367   if (FileName != NULL) {
368     Cptr = FileName;
369   } else if (mUtilityName[0] != 0) {
370     Cptr = mUtilityName;
371   } else {
372     Cptr = "Unknown utility";
373   }
374 
375   strcpy (Line, Cptr);
376   if (LineNumber != 0) {
377     sprintf (Line2, "(%d)", LineNumber);
378     strcat (Line, Line2);
379   }
380   //
381   // Have to print an error code or Visual Studio won't find the
382   // message for you. It has to be decimal digits too.
383   //
384   sprintf (Line2, " : %s %c%04d", Type, toupper (Type[0]), MessageCode);
385   strcat (Line, Line2);
386   fprintf (stdout, "%s", Line);
387   //
388   // If offending text was provided, then print it
389   //
390   if (Text != NULL) {
391     fprintf (stdout, ": %s ", Text);
392   }
393   //
394   // Print formatted message if provided
395   //
396   if (MsgFmt != NULL) {
397     vsprintf (Line2, MsgFmt, List);
398     fprintf (stdout, ": %s", Line2);
399   }
400 
401   fprintf (stdout, "\n");
402 }
403 
404 void
ParserSetPosition(INT8 * SourceFileName,UINT32 LineNum)405 ParserSetPosition (
406   INT8    *SourceFileName,
407   UINT32  LineNum
408   )
409 /*++
410 
411 Routine Description:
412   Set the position in a file being parsed. This can be used to
413   print error messages deeper down in a parser.
414 
415 Arguments:
416   SourceFileName - name of the source file being parsed
417   LineNum        - line number of the source file being parsed
418 
419 Returns:
420   NA
421 
422 --*/
423 {
424   mSourceFileName     = SourceFileName;
425   mSourceFileLineNum  = LineNum;
426 }
427 
428 void
SetUtilityName(INT8 * UtilityName)429 SetUtilityName (
430   INT8    *UtilityName
431   )
432 /*++
433 
434 Routine Description:
435   All printed error/warning/debug messages follow the same format, and
436   typically will print a filename or utility name followed by the error
437   text. However if a filename is not passed to the print routines, then
438   they'll print the utility name if you call this function early in your
439   app to set the utility name.
440 
441 Arguments:
442   UtilityName  -  name of the utility, which will be printed with all
443                   error/warning/debug messags.
444 
445 Returns:
446   NA
447 
448 --*/
449 {
450   //
451   // Save the name of the utility in our local variable. Make sure its
452   // length does not exceed our buffer.
453   //
454   if (UtilityName != NULL) {
455     if (strlen (UtilityName) >= sizeof (mUtilityName)) {
456       Error (UtilityName, 0, 0, "application error", "utility name length exceeds internal buffer size");
457       strncpy (mUtilityName, UtilityName, sizeof (mUtilityName) - 1);
458       mUtilityName[sizeof (mUtilityName) - 1] = 0;
459       return ;
460     } else {
461       strcpy (mUtilityName, UtilityName);
462     }
463   } else {
464     Error (NULL, 0, 0, "application error", "SetUtilityName() called with NULL utility name");
465   }
466 }
467 
468 STATUS
GetUtilityStatus(VOID)469 GetUtilityStatus (
470   VOID
471   )
472 /*++
473 
474 Routine Description:
475   When you call Error() or Warning(), this module keeps track of it and
476   sets a local mStatus to STATUS_ERROR or STATUS_WARNING. When the utility
477   exits, it can call this function to get the status and use it as a return
478   value.
479 
480 Arguments:
481   None.
482 
483 Returns:
484   Worst-case status reported, as defined by which print function was called.
485 
486 --*/
487 {
488   return mStatus;
489 }
490