1 /** @file
2   Print Library internal worker functions.
3 
4   Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
5   This program and the accompanying materials
6   are licensed and made available under the terms and conditions of the BSD License
7   which accompanies this distribution.  The full text of the license may be found at
8   http://opensource.org/licenses/bsd-license.php.
9 
10   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 
13 **/
14 
15 #include "PrintLibInternal.h"
16 
17 #define WARNING_STATUS_NUMBER         5
18 #define ERROR_STATUS_NUMBER           33
19 
20 GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 mHexStr[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
21 
22 GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 * CONST mStatusString[] = {
23   "Success",                      //  RETURN_SUCCESS                = 0
24   "Warning Unknown Glyph",        //  RETURN_WARN_UNKNOWN_GLYPH     = 1
25   "Warning Delete Failure",       //  RETURN_WARN_DELETE_FAILURE    = 2
26   "Warning Write Failure",        //  RETURN_WARN_WRITE_FAILURE     = 3
27   "Warning Buffer Too Small",     //  RETURN_WARN_BUFFER_TOO_SMALL  = 4
28   "Warning Stale Data",           //  RETURN_WARN_STALE_DATA        = 5
29   "Load Error",                   //  RETURN_LOAD_ERROR             = 1  | MAX_BIT
30   "Invalid Parameter",            //  RETURN_INVALID_PARAMETER      = 2  | MAX_BIT
31   "Unsupported",                  //  RETURN_UNSUPPORTED            = 3  | MAX_BIT
32   "Bad Buffer Size",              //  RETURN_BAD_BUFFER_SIZE        = 4  | MAX_BIT
33   "Buffer Too Small",             //  RETURN_BUFFER_TOO_SMALL,      = 5  | MAX_BIT
34   "Not Ready",                    //  RETURN_NOT_READY              = 6  | MAX_BIT
35   "Device Error",                 //  RETURN_DEVICE_ERROR           = 7  | MAX_BIT
36   "Write Protected",              //  RETURN_WRITE_PROTECTED        = 8  | MAX_BIT
37   "Out of Resources",             //  RETURN_OUT_OF_RESOURCES       = 9  | MAX_BIT
38   "Volume Corrupt",               //  RETURN_VOLUME_CORRUPTED       = 10 | MAX_BIT
39   "Volume Full",                  //  RETURN_VOLUME_FULL            = 11 | MAX_BIT
40   "No Media",                     //  RETURN_NO_MEDIA               = 12 | MAX_BIT
41   "Media changed",                //  RETURN_MEDIA_CHANGED          = 13 | MAX_BIT
42   "Not Found",                    //  RETURN_NOT_FOUND              = 14 | MAX_BIT
43   "Access Denied",                //  RETURN_ACCESS_DENIED          = 15 | MAX_BIT
44   "No Response",                  //  RETURN_NO_RESPONSE            = 16 | MAX_BIT
45   "No mapping",                   //  RETURN_NO_MAPPING             = 17 | MAX_BIT
46   "Time out",                     //  RETURN_TIMEOUT                = 18 | MAX_BIT
47   "Not started",                  //  RETURN_NOT_STARTED            = 19 | MAX_BIT
48   "Already started",              //  RETURN_ALREADY_STARTED        = 20 | MAX_BIT
49   "Aborted",                      //  RETURN_ABORTED                = 21 | MAX_BIT
50   "ICMP Error",                   //  RETURN_ICMP_ERROR             = 22 | MAX_BIT
51   "TFTP Error",                   //  RETURN_TFTP_ERROR             = 23 | MAX_BIT
52   "Protocol Error",               //  RETURN_PROTOCOL_ERROR         = 24 | MAX_BIT
53   "Incompatible Version",         //  RETURN_INCOMPATIBLE_VERSION   = 25 | MAX_BIT
54   "Security Violation",           //  RETURN_SECURITY_VIOLATION     = 26 | MAX_BIT
55   "CRC Error",                    //  RETURN_CRC_ERROR              = 27 | MAX_BIT
56   "End of Media",                 //  RETURN_END_OF_MEDIA           = 28 | MAX_BIT
57   "Reserved (29)",                //  RESERVED                      = 29 | MAX_BIT
58   "Reserved (30)",                //  RESERVED                      = 30 | MAX_BIT
59   "End of File",                  //  RETURN_END_OF_FILE            = 31 | MAX_BIT
60   "Invalid Language",             //  RETURN_INVALID_LANGUAGE       = 32 | MAX_BIT
61   "Compromised Data"              //  RETURN_COMPROMISED_DATA       = 33 | MAX_BIT
62 };
63 
64 
65 /**
66   Internal function that places the character into the Buffer.
67 
68   Internal function that places ASCII or Unicode character into the Buffer.
69 
70   @param  Buffer      The buffer to place the Unicode or ASCII string.
71   @param  EndBuffer   The end of the input Buffer. No characters will be
72                       placed after that.
73   @param  Length      The count of character to be placed into Buffer.
74                       (Negative value indicates no buffer fill.)
75   @param  Character   The character to be placed into Buffer.
76   @param  Increment   The character increment in Buffer.
77 
78   @return Buffer.
79 
80 **/
81 CHAR8 *
BasePrintLibFillBuffer(OUT CHAR8 * Buffer,IN CHAR8 * EndBuffer,IN INTN Length,IN UINTN Character,IN INTN Increment)82 BasePrintLibFillBuffer (
83   OUT CHAR8   *Buffer,
84   IN  CHAR8   *EndBuffer,
85   IN  INTN    Length,
86   IN  UINTN   Character,
87   IN  INTN    Increment
88   )
89 {
90   INTN  Index;
91 
92   for (Index = 0; Index < Length && Buffer < EndBuffer; Index++) {
93     *Buffer = (CHAR8) Character;
94     if (Increment != 1) {
95       *(Buffer + 1) = (CHAR8)(Character >> 8);
96     }
97     Buffer += Increment;
98   }
99 
100   return Buffer;
101 }
102 
103 /**
104   Internal function that convert a number to a string in Buffer.
105 
106   Print worker function that converts a decimal or hexadecimal number to an ASCII string in Buffer.
107 
108   @param  Buffer    Location to place the ASCII string of Value.
109   @param  Value     The value to convert to a Decimal or Hexadecimal string in Buffer.
110   @param  Radix     Radix of the value
111 
112   @return A pointer to the end of buffer filled with ASCII string.
113 
114 **/
115 CHAR8 *
BasePrintLibValueToString(IN OUT CHAR8 * Buffer,IN INT64 Value,IN UINTN Radix)116 BasePrintLibValueToString (
117   IN OUT CHAR8  *Buffer,
118   IN INT64      Value,
119   IN UINTN      Radix
120   )
121 {
122   UINT32  Remainder;
123 
124   //
125   // Loop to convert one digit at a time in reverse order
126   //
127   *Buffer = 0;
128   do {
129     Value = (INT64)DivU64x32Remainder ((UINT64)Value, (UINT32)Radix, &Remainder);
130     *(++Buffer) = mHexStr[Remainder];
131   } while (Value != 0);
132 
133   //
134   // Return pointer of the end of filled buffer.
135   //
136   return Buffer;
137 }
138 
139 /**
140   Internal function that converts a decimal value to a Null-terminated string.
141 
142   Converts the decimal number specified by Value to a Null-terminated
143   string specified by Buffer containing at most Width characters.
144   If Width is 0 then a width of  MAXIMUM_VALUE_CHARACTERS is assumed.
145   The total number of characters placed in Buffer is returned.
146   If the conversion contains more than Width characters, then only the first
147   Width characters are returned, and the total number of characters
148   required to perform the conversion is returned.
149   Additional conversion parameters are specified in Flags.
150   The Flags bit LEFT_JUSTIFY is always ignored.
151   All conversions are left justified in Buffer.
152   If Width is 0, PREFIX_ZERO is ignored in Flags.
153   If COMMA_TYPE is set in Flags, then PREFIX_ZERO is ignored in Flags, and commas
154   are inserted every 3rd digit starting from the right.
155   If Value is < 0, then the fist character in Buffer is a '-'.
156   If PREFIX_ZERO is set in Flags and PREFIX_ZERO is not being ignored,
157   then Buffer is padded with '0' characters so the combination of the optional '-'
158   sign character, '0' characters, digit characters for Value, and the Null-terminator
159   add up to Width characters.
160 
161   If Buffer is NULL, then ASSERT().
162   If unsupported bits are set in Flags, then ASSERT().
163   If Width >= MAXIMUM_VALUE_CHARACTERS, then ASSERT()
164 
165   @param  Buffer    The pointer to the output buffer for the produced Null-terminated
166                     string.
167   @param  Flags     The bitmask of flags that specify left justification, zero pad,
168                     and commas.
169   @param  Value     The 64-bit signed value to convert to a string.
170   @param  Width     The maximum number of characters to place in Buffer, not including
171                     the Null-terminator.
172   @param  Increment The character increment in Buffer.
173 
174   @return Total number of characters required to perform the conversion.
175 
176 **/
177 UINTN
BasePrintLibConvertValueToString(IN OUT CHAR8 * Buffer,IN UINTN Flags,IN INT64 Value,IN UINTN Width,IN UINTN Increment)178 BasePrintLibConvertValueToString (
179   IN OUT CHAR8   *Buffer,
180   IN UINTN       Flags,
181   IN INT64       Value,
182   IN UINTN       Width,
183   IN UINTN       Increment
184   )
185 {
186   CHAR8  *OriginalBuffer;
187   CHAR8  *EndBuffer;
188   CHAR8  ValueBuffer[MAXIMUM_VALUE_CHARACTERS];
189   CHAR8  *ValueBufferPtr;
190   UINTN  Count;
191   UINTN  Digits;
192   UINTN  Index;
193   UINTN  Radix;
194 
195   //
196   // Make sure Buffer is not NULL and Width < MAXIMUM
197   //
198   ASSERT (Buffer != NULL);
199   ASSERT (Width < MAXIMUM_VALUE_CHARACTERS);
200   //
201   // Make sure Flags can only contain supported bits.
202   //
203   ASSERT ((Flags & ~(LEFT_JUSTIFY | COMMA_TYPE | PREFIX_ZERO | RADIX_HEX)) == 0);
204 
205   //
206   // If both COMMA_TYPE and RADIX_HEX are set, then ASSERT ()
207   //
208   ASSERT (((Flags & COMMA_TYPE) == 0) || ((Flags & RADIX_HEX) == 0));
209 
210   OriginalBuffer = Buffer;
211 
212   //
213   // Width is 0 or COMMA_TYPE is set, PREFIX_ZERO is ignored.
214   //
215   if (Width == 0 || (Flags & COMMA_TYPE) != 0) {
216     Flags &= ~((UINTN) PREFIX_ZERO);
217   }
218   //
219   // If Width is 0 then a width of  MAXIMUM_VALUE_CHARACTERS is assumed.
220   //
221   if (Width == 0) {
222     Width = MAXIMUM_VALUE_CHARACTERS - 1;
223   }
224   //
225   // Set the tag for the end of the input Buffer.
226   //
227   EndBuffer = Buffer + Width * Increment;
228 
229   //
230   // Convert decimal negative
231   //
232   if ((Value < 0) && ((Flags & RADIX_HEX) == 0)) {
233     Value = -Value;
234     Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, 1, '-', Increment);
235     Width--;
236   }
237 
238   //
239   // Count the length of the value string.
240   //
241   Radix = ((Flags & RADIX_HEX) == 0)? 10 : 16;
242   ValueBufferPtr = BasePrintLibValueToString (ValueBuffer, Value, Radix);
243   Count = ValueBufferPtr - ValueBuffer;
244 
245   //
246   // Append Zero
247   //
248   if ((Flags & PREFIX_ZERO) != 0) {
249     Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, Width - Count, '0', Increment);
250   }
251 
252   //
253   // Print Comma type for every 3 characters
254   //
255   Digits = Count % 3;
256   if (Digits != 0) {
257     Digits = 3 - Digits;
258   }
259   for (Index = 0; Index < Count; Index++) {
260     Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, 1, *ValueBufferPtr--, Increment);
261     if ((Flags & COMMA_TYPE) != 0) {
262       Digits++;
263       if (Digits == 3) {
264         Digits = 0;
265         if ((Index + 1) < Count) {
266           Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, 1, ',', Increment);
267         }
268       }
269     }
270   }
271 
272   //
273   // Print Null-terminator
274   //
275   BasePrintLibFillBuffer (Buffer, EndBuffer + Increment, 1, 0, Increment);
276 
277   return ((Buffer - OriginalBuffer) / Increment);
278 }
279 
280 /**
281   Worker function that produces a Null-terminated string in an output buffer
282   based on a Null-terminated format string and a VA_LIST argument list.
283 
284   VSPrint function to process format and place the results in Buffer. Since a
285   VA_LIST is used this routine allows the nesting of Vararg routines. Thus
286   this is the main print working routine.
287 
288   If COUNT_ONLY_NO_PRINT is set in Flags, Buffer will not be modified at all.
289 
290   @param[out] Buffer          The character buffer to print the results of the
291                               parsing of Format into.
292   @param[in]  BufferSize      The maximum number of characters to put into
293                               buffer.
294   @param[in]  Flags           Initial flags value.
295                               Can only have FORMAT_UNICODE, OUTPUT_UNICODE,
296                               and COUNT_ONLY_NO_PRINT set.
297   @param[in]  Format          A Null-terminated format string.
298   @param[in]  VaListMarker    VA_LIST style variable argument list consumed by
299                               processing Format.
300   @param[in]  BaseListMarker  BASE_LIST style variable argument list consumed
301                               by processing Format.
302 
303   @return The number of characters printed not including the Null-terminator.
304           If COUNT_ONLY_NO_PRINT was set returns the same, but without any
305           modification to Buffer.
306 
307 **/
308 UINTN
BasePrintLibSPrintMarker(OUT CHAR8 * Buffer,IN UINTN BufferSize,IN UINTN Flags,IN CONST CHAR8 * Format,IN VA_LIST VaListMarker,OPTIONAL IN BASE_LIST BaseListMarker OPTIONAL)309 BasePrintLibSPrintMarker (
310   OUT CHAR8        *Buffer,
311   IN  UINTN        BufferSize,
312   IN  UINTN        Flags,
313   IN  CONST CHAR8  *Format,
314   IN  VA_LIST      VaListMarker,   OPTIONAL
315   IN  BASE_LIST    BaseListMarker  OPTIONAL
316   )
317 {
318   CHAR8             *OriginalBuffer;
319   CHAR8             *EndBuffer;
320   CHAR8             ValueBuffer[MAXIMUM_VALUE_CHARACTERS];
321   UINT32            BytesPerOutputCharacter;
322   UINTN             BytesPerFormatCharacter;
323   UINTN             FormatMask;
324   UINTN             FormatCharacter;
325   UINTN             Width;
326   UINTN             Precision;
327   INT64             Value;
328   CONST CHAR8       *ArgumentString;
329   UINTN             Character;
330   GUID              *TmpGuid;
331   TIME              *TmpTime;
332   UINTN             Count;
333   UINTN             ArgumentMask;
334   INTN              BytesPerArgumentCharacter;
335   UINTN             ArgumentCharacter;
336   BOOLEAN           Done;
337   UINTN             Index;
338   CHAR8             Prefix;
339   BOOLEAN           ZeroPad;
340   BOOLEAN           Comma;
341   UINTN             Digits;
342   UINTN             Radix;
343   RETURN_STATUS     Status;
344   UINT32            GuidData1;
345   UINT16            GuidData2;
346   UINT16            GuidData3;
347   UINTN             LengthToReturn;
348 
349   //
350   // If you change this code be sure to match the 2 versions of this function.
351   // Nearly identical logic is found in the BasePrintLib and
352   // DxePrintLibPrint2Protocol (both PrintLib instances).
353   //
354 
355   if ((Flags & COUNT_ONLY_NO_PRINT) != 0) {
356     if (BufferSize == 0) {
357       Buffer = NULL;
358     }
359   } else {
360     //
361     // We can run without a Buffer for counting only.
362     //
363     if (BufferSize == 0) {
364       return 0;
365     }
366     ASSERT (Buffer != NULL);
367   }
368 
369   if ((Flags & OUTPUT_UNICODE) != 0) {
370     BytesPerOutputCharacter = 2;
371   } else {
372     BytesPerOutputCharacter = 1;
373   }
374 
375   LengthToReturn = 0;
376   EndBuffer = NULL;
377   OriginalBuffer = NULL;
378 
379   //
380   // Reserve space for the Null terminator.
381   //
382   if (Buffer != NULL) {
383     BufferSize--;
384     OriginalBuffer = Buffer;
385 
386     //
387     // Set the tag for the end of the input Buffer.
388     //
389     EndBuffer = Buffer + BufferSize * BytesPerOutputCharacter;
390   }
391 
392   if ((Flags & FORMAT_UNICODE) != 0) {
393     //
394     // Make sure format string cannot contain more than PcdMaximumUnicodeStringLength
395     // Unicode characters if PcdMaximumUnicodeStringLength is not zero.
396     //
397     ASSERT (StrSize ((CHAR16 *) Format) != 0);
398     BytesPerFormatCharacter = 2;
399     FormatMask = 0xffff;
400   } else {
401     //
402     // Make sure format string cannot contain more than PcdMaximumAsciiStringLength
403     // Ascii characters if PcdMaximumAsciiStringLength is not zero.
404     //
405     ASSERT (AsciiStrSize (Format) != 0);
406     BytesPerFormatCharacter = 1;
407     FormatMask = 0xff;
408   }
409 
410   //
411   // Get the first character from the format string
412   //
413   FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;
414 
415   //
416   // Loop until the end of the format string is reached or the output buffer is full
417   //
418   while (FormatCharacter != 0) {
419     if ((Buffer != NULL) && (Buffer >= EndBuffer)) {
420       break;
421     }
422     //
423     // Clear all the flag bits except those that may have been passed in
424     //
425     Flags &= (UINTN) (OUTPUT_UNICODE | FORMAT_UNICODE | COUNT_ONLY_NO_PRINT);
426 
427     //
428     // Set the default width to zero, and the default precision to 1
429     //
430     Width     = 0;
431     Precision = 1;
432     Prefix    = 0;
433     Comma     = FALSE;
434     ZeroPad   = FALSE;
435     Count     = 0;
436     Digits    = 0;
437 
438     switch (FormatCharacter) {
439     case '%':
440       //
441       // Parse Flags and Width
442       //
443       for (Done = FALSE; !Done; ) {
444         Format += BytesPerFormatCharacter;
445         FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;
446         switch (FormatCharacter) {
447         case '.':
448           Flags |= PRECISION;
449           break;
450         case '-':
451           Flags |= LEFT_JUSTIFY;
452           break;
453         case '+':
454           Flags |= PREFIX_SIGN;
455           break;
456         case ' ':
457           Flags |= PREFIX_BLANK;
458           break;
459         case ',':
460           Flags |= COMMA_TYPE;
461           break;
462         case 'L':
463         case 'l':
464           Flags |= LONG_TYPE;
465           break;
466         case '*':
467           if ((Flags & PRECISION) == 0) {
468             Flags |= PAD_TO_WIDTH;
469             if (BaseListMarker == NULL) {
470               Width = VA_ARG (VaListMarker, UINTN);
471             } else {
472               Width = BASE_ARG (BaseListMarker, UINTN);
473             }
474           } else {
475             if (BaseListMarker == NULL) {
476               Precision = VA_ARG (VaListMarker, UINTN);
477             } else {
478               Precision = BASE_ARG (BaseListMarker, UINTN);
479             }
480           }
481           break;
482         case '0':
483           if ((Flags & PRECISION) == 0) {
484             Flags |= PREFIX_ZERO;
485           }
486         case '1':
487         case '2':
488         case '3':
489         case '4':
490         case '5':
491         case '6':
492         case '7':
493         case '8':
494         case '9':
495           for (Count = 0; ((FormatCharacter >= '0') &&  (FormatCharacter <= '9')); ){
496             Count = (Count * 10) + FormatCharacter - '0';
497             Format += BytesPerFormatCharacter;
498             FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;
499           }
500           Format -= BytesPerFormatCharacter;
501           if ((Flags & PRECISION) == 0) {
502             Flags |= PAD_TO_WIDTH;
503             Width = Count;
504           } else {
505             Precision = Count;
506           }
507           break;
508 
509         case '\0':
510           //
511           // Make no output if Format string terminates unexpectedly when
512           // looking up for flag, width, precision and type.
513           //
514           Format   -= BytesPerFormatCharacter;
515           Precision = 0;
516           //
517           // break skipped on purpose.
518           //
519         default:
520           Done = TRUE;
521           break;
522         }
523       }
524 
525       //
526       // Handle each argument type
527       //
528       switch (FormatCharacter) {
529       case 'p':
530         //
531         // Flag space, +, 0, L & l are invalid for type p.
532         //
533         Flags &= ~((UINTN) (PREFIX_BLANK | PREFIX_SIGN | PREFIX_ZERO | LONG_TYPE));
534         if (sizeof (VOID *) > 4) {
535           Flags |= LONG_TYPE;
536         }
537         //
538         // break skipped on purpose
539         //
540       case 'X':
541         Flags |= PREFIX_ZERO;
542         //
543         // break skipped on purpose
544         //
545       case 'x':
546         Flags |= RADIX_HEX;
547         //
548         // break skipped on purpose
549         //
550       case 'u':
551         if ((Flags & RADIX_HEX) == 0) {
552           Flags &= ~((UINTN) (PREFIX_SIGN));
553           Flags |= UNSIGNED_TYPE;
554         }
555         //
556         // break skipped on purpose
557         //
558       case 'd':
559         if ((Flags & LONG_TYPE) == 0) {
560           //
561           // 'd', 'u', 'x', and 'X' that are not preceded by 'l' or 'L' are assumed to be type "int".
562           // This assumption is made so the format string definition is compatible with the ANSI C
563           // Specification for formatted strings.  It is recommended that the Base Types be used
564           // everywhere, but in this one case, compliance with ANSI C is more important, and
565           // provides an implementation that is compatible with that largest possible set of CPU
566           // architectures.  This is why the type "int" is used in this one case.
567           //
568           if (BaseListMarker == NULL) {
569             Value = VA_ARG (VaListMarker, int);
570           } else {
571             Value = BASE_ARG (BaseListMarker, int);
572           }
573         } else {
574           if (BaseListMarker == NULL) {
575             Value = VA_ARG (VaListMarker, INT64);
576           } else {
577             Value = BASE_ARG (BaseListMarker, INT64);
578           }
579         }
580         if ((Flags & PREFIX_BLANK) != 0) {
581           Prefix = ' ';
582         }
583         if ((Flags & PREFIX_SIGN) != 0) {
584           Prefix = '+';
585         }
586         if ((Flags & COMMA_TYPE) != 0) {
587           Comma = TRUE;
588         }
589         if ((Flags & RADIX_HEX) == 0) {
590           Radix = 10;
591           if (Comma) {
592             Flags &= ~((UINTN) PREFIX_ZERO);
593             Precision = 1;
594           }
595           if (Value < 0 && (Flags & UNSIGNED_TYPE) == 0) {
596             Flags |= PREFIX_SIGN;
597             Prefix = '-';
598             Value = -Value;
599           } else if ((Flags & UNSIGNED_TYPE) != 0 && (Flags & LONG_TYPE) == 0) {
600             //
601             // 'd', 'u', 'x', and 'X' that are not preceded by 'l' or 'L' are assumed to be type "int".
602             // This assumption is made so the format string definition is compatible with the ANSI C
603             // Specification for formatted strings.  It is recommended that the Base Types be used
604             // everywhere, but in this one case, compliance with ANSI C is more important, and
605             // provides an implementation that is compatible with that largest possible set of CPU
606             // architectures.  This is why the type "unsigned int" is used in this one case.
607             //
608             Value = (unsigned int)Value;
609           }
610         } else {
611           Radix = 16;
612           Comma = FALSE;
613           if ((Flags & LONG_TYPE) == 0 && Value < 0) {
614             //
615             // 'd', 'u', 'x', and 'X' that are not preceded by 'l' or 'L' are assumed to be type "int".
616             // This assumption is made so the format string definition is compatible with the ANSI C
617             // Specification for formatted strings.  It is recommended that the Base Types be used
618             // everywhere, but in this one case, compliance with ANSI C is more important, and
619             // provides an implementation that is compatible with that largest possible set of CPU
620             // architectures.  This is why the type "unsigned int" is used in this one case.
621             //
622             Value = (unsigned int)Value;
623           }
624         }
625         //
626         // Convert Value to a reversed string
627         //
628         Count = BasePrintLibValueToString (ValueBuffer, Value, Radix) - ValueBuffer;
629         if (Value == 0 && Precision == 0) {
630           Count = 0;
631         }
632         ArgumentString = (CHAR8 *)ValueBuffer + Count;
633 
634         Digits = Count % 3;
635         if (Digits != 0) {
636           Digits = 3 - Digits;
637         }
638         if (Comma && Count != 0) {
639           Count += ((Count - 1) / 3);
640         }
641         if (Prefix != 0) {
642           Count++;
643           Precision++;
644         }
645         Flags |= ARGUMENT_REVERSED;
646         ZeroPad = TRUE;
647         if ((Flags & PREFIX_ZERO) != 0) {
648           if ((Flags & LEFT_JUSTIFY) == 0) {
649             if ((Flags & PAD_TO_WIDTH) != 0) {
650               if ((Flags & PRECISION) == 0) {
651                 Precision = Width;
652               }
653             }
654           }
655         }
656         break;
657 
658       case 's':
659       case 'S':
660         Flags |= ARGUMENT_UNICODE;
661         //
662         // break skipped on purpose
663         //
664       case 'a':
665         if (BaseListMarker == NULL) {
666           ArgumentString = VA_ARG (VaListMarker, CHAR8 *);
667         } else {
668           ArgumentString = BASE_ARG (BaseListMarker, CHAR8 *);
669         }
670         if (ArgumentString == NULL) {
671           Flags &= ~((UINTN) ARGUMENT_UNICODE);
672           ArgumentString = "<null string>";
673         }
674         //
675         // Set the default precision for string to be zero if not specified.
676         //
677         if ((Flags & PRECISION) == 0) {
678           Precision = 0;
679         }
680         break;
681 
682       case 'c':
683         if (BaseListMarker == NULL) {
684           Character = VA_ARG (VaListMarker, UINTN) & 0xffff;
685         } else {
686           Character = BASE_ARG (BaseListMarker, UINTN) & 0xffff;
687         }
688         ArgumentString = (CHAR8 *)&Character;
689         Flags |= ARGUMENT_UNICODE;
690         break;
691 
692       case 'g':
693         if (BaseListMarker == NULL) {
694           TmpGuid = VA_ARG (VaListMarker, GUID *);
695         } else {
696           TmpGuid = BASE_ARG (BaseListMarker, GUID *);
697         }
698         if (TmpGuid == NULL) {
699           ArgumentString = "<null guid>";
700         } else {
701           GuidData1 = ReadUnaligned32 (&(TmpGuid->Data1));
702           GuidData2 = ReadUnaligned16 (&(TmpGuid->Data2));
703           GuidData3 = ReadUnaligned16 (&(TmpGuid->Data3));
704           BasePrintLibSPrint (
705             ValueBuffer,
706             MAXIMUM_VALUE_CHARACTERS,
707             0,
708             "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
709             GuidData1,
710             GuidData2,
711             GuidData3,
712             TmpGuid->Data4[0],
713             TmpGuid->Data4[1],
714             TmpGuid->Data4[2],
715             TmpGuid->Data4[3],
716             TmpGuid->Data4[4],
717             TmpGuid->Data4[5],
718             TmpGuid->Data4[6],
719             TmpGuid->Data4[7]
720             );
721           ArgumentString = ValueBuffer;
722         }
723         break;
724 
725       case 't':
726         if (BaseListMarker == NULL) {
727           TmpTime = VA_ARG (VaListMarker, TIME *);
728         } else {
729           TmpTime = BASE_ARG (BaseListMarker, TIME *);
730         }
731         if (TmpTime == NULL) {
732           ArgumentString = "<null time>";
733         } else {
734           BasePrintLibSPrint (
735             ValueBuffer,
736             MAXIMUM_VALUE_CHARACTERS,
737             0,
738             "%02d/%02d/%04d  %02d:%02d",
739             TmpTime->Month,
740             TmpTime->Day,
741             TmpTime->Year,
742             TmpTime->Hour,
743             TmpTime->Minute
744             );
745           ArgumentString = ValueBuffer;
746         }
747         break;
748 
749       case 'r':
750         if (BaseListMarker == NULL) {
751           Status = VA_ARG (VaListMarker, RETURN_STATUS);
752         } else {
753           Status = BASE_ARG (BaseListMarker, RETURN_STATUS);
754         }
755         ArgumentString = ValueBuffer;
756         if (RETURN_ERROR (Status)) {
757           //
758           // Clear error bit
759           //
760           Index = Status & ~MAX_BIT;
761           if (Index > 0 && Index <= ERROR_STATUS_NUMBER) {
762             ArgumentString = mStatusString [Index + WARNING_STATUS_NUMBER];
763           }
764         } else {
765           Index = Status;
766           if (Index <= WARNING_STATUS_NUMBER) {
767             ArgumentString = mStatusString [Index];
768           }
769         }
770         if (ArgumentString == ValueBuffer) {
771           BasePrintLibSPrint ((CHAR8 *) ValueBuffer, MAXIMUM_VALUE_CHARACTERS, 0, "%08X", Status);
772         }
773         break;
774 
775       case '\r':
776         Format += BytesPerFormatCharacter;
777         FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;
778         if (FormatCharacter == '\n') {
779           //
780           // Translate '\r\n' to '\r\n'
781           //
782           ArgumentString = "\r\n";
783         } else {
784           //
785           // Translate '\r' to '\r'
786           //
787           ArgumentString = "\r";
788           Format   -= BytesPerFormatCharacter;
789         }
790         break;
791 
792       case '\n':
793         //
794         // Translate '\n' to '\r\n' and '\n\r' to '\r\n'
795         //
796         ArgumentString = "\r\n";
797         Format += BytesPerFormatCharacter;
798         FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;
799         if (FormatCharacter != '\r') {
800           Format   -= BytesPerFormatCharacter;
801         }
802         break;
803 
804       case '%':
805       default:
806         //
807         // if the type is '%' or unknown, then print it to the screen
808         //
809         ArgumentString = (CHAR8 *)&FormatCharacter;
810         Flags |= ARGUMENT_UNICODE;
811         break;
812       }
813       break;
814 
815     case '\r':
816       Format += BytesPerFormatCharacter;
817       FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;
818       if (FormatCharacter == '\n') {
819         //
820         // Translate '\r\n' to '\r\n'
821         //
822         ArgumentString = "\r\n";
823       } else {
824         //
825         // Translate '\r' to '\r'
826         //
827         ArgumentString = "\r";
828         Format   -= BytesPerFormatCharacter;
829       }
830       break;
831 
832     case '\n':
833       //
834       // Translate '\n' to '\r\n' and '\n\r' to '\r\n'
835       //
836       ArgumentString = "\r\n";
837       Format += BytesPerFormatCharacter;
838       FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;
839       if (FormatCharacter != '\r') {
840         Format   -= BytesPerFormatCharacter;
841       }
842       break;
843 
844     default:
845       ArgumentString = (CHAR8 *)&FormatCharacter;
846       Flags |= ARGUMENT_UNICODE;
847       break;
848     }
849 
850     //
851     // Retrieve the ArgumentString attriubutes
852     //
853     if ((Flags & ARGUMENT_UNICODE) != 0) {
854       ArgumentMask = 0xffff;
855       BytesPerArgumentCharacter = 2;
856     } else {
857       ArgumentMask = 0xff;
858       BytesPerArgumentCharacter = 1;
859     }
860     if ((Flags & ARGUMENT_REVERSED) != 0) {
861       BytesPerArgumentCharacter = -BytesPerArgumentCharacter;
862     } else {
863       //
864       // Compute the number of characters in ArgumentString and store it in Count
865       // ArgumentString is either null-terminated, or it contains Precision characters
866       //
867       for (Count = 0; Count < Precision || ((Flags & PRECISION) == 0); Count++) {
868         ArgumentCharacter = ((ArgumentString[Count * BytesPerArgumentCharacter] & 0xff) | ((ArgumentString[Count * BytesPerArgumentCharacter + 1]) << 8)) & ArgumentMask;
869         if (ArgumentCharacter == 0) {
870           break;
871         }
872       }
873     }
874 
875     if (Precision < Count) {
876       Precision = Count;
877     }
878 
879     //
880     // Pad before the string
881     //
882     if ((Flags & (PAD_TO_WIDTH | LEFT_JUSTIFY)) == (PAD_TO_WIDTH)) {
883       LengthToReturn += ((Width - Precision) * BytesPerOutputCharacter);
884       if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
885         Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, Width - Precision, ' ', BytesPerOutputCharacter);
886       }
887     }
888 
889     if (ZeroPad) {
890       if (Prefix != 0) {
891         LengthToReturn += (1 * BytesPerOutputCharacter);
892         if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
893           Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, 1, Prefix, BytesPerOutputCharacter);
894         }
895       }
896       LengthToReturn += ((Precision - Count) * BytesPerOutputCharacter);
897       if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
898         Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, Precision - Count, '0', BytesPerOutputCharacter);
899       }
900     } else {
901       LengthToReturn += ((Precision - Count) * BytesPerOutputCharacter);
902       if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
903         Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, Precision - Count, ' ', BytesPerOutputCharacter);
904       }
905       if (Prefix != 0) {
906         LengthToReturn += (1 * BytesPerOutputCharacter);
907         if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
908           Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, 1, Prefix, BytesPerOutputCharacter);
909         }
910       }
911     }
912 
913     //
914     // Output the Prefix character if it is present
915     //
916     Index = 0;
917     if (Prefix != 0) {
918       Index++;
919     }
920 
921     //
922     // Copy the string into the output buffer performing the required type conversions
923     //
924     while (Index < Count) {
925       ArgumentCharacter = ((*ArgumentString & 0xff) | (*(ArgumentString + 1) << 8)) & ArgumentMask;
926 
927       LengthToReturn += (1 * BytesPerOutputCharacter);
928       if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
929         Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, 1, ArgumentCharacter, BytesPerOutputCharacter);
930       }
931       ArgumentString    += BytesPerArgumentCharacter;
932       Index++;
933       if (Comma) {
934         Digits++;
935         if (Digits == 3) {
936           Digits = 0;
937           Index++;
938           if (Index < Count) {
939             LengthToReturn += (1 * BytesPerOutputCharacter);
940             if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
941               Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, 1, ',', BytesPerOutputCharacter);
942             }
943           }
944         }
945       }
946     }
947 
948     //
949     // Pad after the string
950     //
951     if ((Flags & (PAD_TO_WIDTH | LEFT_JUSTIFY)) == (PAD_TO_WIDTH | LEFT_JUSTIFY)) {
952       LengthToReturn += ((Width - Precision) * BytesPerOutputCharacter);
953       if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
954         Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, Width - Precision, ' ', BytesPerOutputCharacter);
955       }
956     }
957 
958     //
959     // Get the next character from the format string
960     //
961     Format += BytesPerFormatCharacter;
962 
963     //
964     // Get the next character from the format string
965     //
966     FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;
967   }
968 
969   if ((Flags & COUNT_ONLY_NO_PRINT) != 0) {
970     return (LengthToReturn / BytesPerOutputCharacter);
971   }
972 
973   ASSERT (Buffer != NULL);
974   //
975   // Null terminate the Unicode or ASCII string
976   //
977   BasePrintLibFillBuffer (Buffer, EndBuffer + BytesPerOutputCharacter, 1, 0, BytesPerOutputCharacter);
978   //
979   // Make sure output buffer cannot contain more than PcdMaximumUnicodeStringLength
980   // Unicode characters if PcdMaximumUnicodeStringLength is not zero.
981   //
982   ASSERT ((((Flags & OUTPUT_UNICODE) == 0)) || (StrSize ((CHAR16 *) OriginalBuffer) != 0));
983   //
984   // Make sure output buffer cannot contain more than PcdMaximumAsciiStringLength
985   // ASCII characters if PcdMaximumAsciiStringLength is not zero.
986   //
987   ASSERT ((((Flags & OUTPUT_UNICODE) != 0)) || (AsciiStrSize (OriginalBuffer) != 0));
988 
989   return ((Buffer - OriginalBuffer) / BytesPerOutputCharacter);
990 }
991 
992 /**
993   Worker function that produces a Null-terminated string in an output buffer
994   based on a Null-terminated format string and variable argument list.
995 
996   VSPrint function to process format and place the results in Buffer. Since a
997   VA_LIST is used this routine allows the nesting of Vararg routines. Thus
998   this is the main print working routine
999 
1000   @param  StartOfBuffer The character buffer to print the results of the parsing
1001                         of Format into.
1002   @param  BufferSize    The maximum number of characters to put into buffer.
1003                         Zero means no limit.
1004   @param  Flags         Initial flags value.
1005                         Can only have FORMAT_UNICODE and OUTPUT_UNICODE set
1006   @param  FormatString  A Null-terminated format string.
1007   @param  ...           The variable argument list.
1008 
1009   @return The number of characters printed.
1010 
1011 **/
1012 UINTN
1013 EFIAPI
BasePrintLibSPrint(OUT CHAR8 * StartOfBuffer,IN UINTN BufferSize,IN UINTN Flags,IN CONST CHAR8 * FormatString,...)1014 BasePrintLibSPrint (
1015   OUT CHAR8        *StartOfBuffer,
1016   IN  UINTN        BufferSize,
1017   IN  UINTN        Flags,
1018   IN  CONST CHAR8  *FormatString,
1019   ...
1020   )
1021 {
1022   VA_LIST  Marker;
1023   UINTN    NumberOfPrinted;
1024 
1025   VA_START (Marker, FormatString);
1026   NumberOfPrinted = BasePrintLibSPrintMarker (StartOfBuffer, BufferSize, Flags, FormatString, Marker, NULL);
1027   VA_END (Marker);
1028   return NumberOfPrinted;
1029 }
1030